You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

139407 lines
4.7 MiB

//日志输出类
var JSConsole=
{
Chart:{ Log:console.log, Warn:console.warn }, //图形日志
Complier:{ Log:console.log, Warn:console.warn}, //编译器日志
JSTable:{ Log:console.log, Warn:console.warn } //表格日志
};
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
系统指标 (H5版本)
*/
/*
指标数据脚本 系统内置指标都写在这里
Name:指标名字
Description:指标描述信息
Args:参数 { Name:名字, Value=值 }
IsMainIndex:是否是主图指标 true=主图指标 false=副图指标
KLineType:K线设置 -1=主图不显示K线(只在主图有效) 0=在副图显示K线 1=在副图显示K线(收盘价线) 2=在副图显示K线(美国线)
InstructionType: 1=专家指示 2=五彩K线
FloatPrecision: 小数位数 缺省=2
YSplitScale: Y固定刻度 [1,8,10]
YSpecificMaxMin: 固定Y轴最大最小值 { Max: 9, Min: 0, Count: 3 };
StringFormat: 1=带单位万/亿 2=原始格式
Condition: 限制条件 { Symbol:'Index'/'Stock'(只支持指数/股票),Period:[](支持的周期), Include:[](指定支持的股票,代码全部大写包括后缀, Message:"提示信息")}
OutName:动态输出变量名字 [{Name:原始变量名, DynamicName:动态名字格式}] 如 {Name:"MA1", DynamicName:"MA{M1}"};
SplitType: Y轴分割类型,
YAxis:{ FloatPrecision:小数位数, StringFormat:, EnableRemoveZero, ExcludeValue:不参数Y轴的计算 } //Y轴刻度输出格式
*/
//周期条件枚举
var CONDITION_PERIOD=
{
MINUTE_ID:101, //分钟 走势图
MULTIDAY_MINUTE_ID:102, //多日分钟 走势图
HISTORY_MINUTE_ID:103, //历史分钟 走势图
//K线周期
KLINE_DAY_ID:0,
KLINE_WEEK_ID:1,
KLINE_TWOWEEK_ID:21,
KLINE_MONTH_ID:2,
KLINE_QUARTER_ID:9,
KLINE_YEAR_ID:3,
KLINE_MINUTE_ID:4,
KLINE_5_MINUTE_ID:5,
KLINE_15_MINUTE_ID:6,
KLINE_30_MINUTE_ID:7,
KLINE_60_MINUTE_ID:8,
};
//自定义的指标脚本
function CustomIndexScript()
{
this.DataMap=new Map(); //key=指标id, value=data {ID:, Name:指标名字, Description:指标描述信息 Args:参数 ......}
this.Get=function(id)
{
if (!this.DataMap.has(id)) return null;
return this.DataMap.get(id);
}
this.Add=function(data)
{
this.DataMap.set(data.ID, data);
}
}
var g_CustomIndex=new CustomIndexScript();
function JSIndexScript()
{
this.DataMap=new Map(
[
['MA', this.MA],['均线', this.MA],
["MA4", this.MA4],["MA5", this.MA5],["MA6", this.MA6],["MA7", this.MA7],["MA8", this.MA8],
['BOLL', this.BOLL],['BOLL副图', this.BOLL2],['BBI', this.BBI],
['DKX', this.DKX],['MIKE', this.MIKE],['PBX', this.PBX],
['ENE', this.ENE],['MACD', this.MACD],['KDJ', this.KDJ],["MACD2", this.MACD2],
['VOL', this.VOL],['VOL2', this.VOL2],["VOL_OVERLAY", this.VOL_OVERLAY], ['RSI', this.RSI],['BRAR', this.BRAR],
['WR', this.WR],['BIAS', this.BIAS],['OBV', this.OBV],
['DMI', this.DMI],['CR', this.CR],['PSY', this.PSY],
['CCI', this.CCI],['DMA', this.DMA],['TRIX', this.TRIX],
['VR', this.VR],['EMV', this.EMV],['ROC', this.ROC],
['MTM', this.MTM],['FSL', this.FSL],['CYR', this.CYR],
['MASS', this.MASS],['WAD', this.WAD],['CHO', this.CHO],
['ADTM', this.ADTM],['HSL', this.HSL],['BIAS36', this.BIAS36],
['BIAS_QL', this.BIAS_QL],['DPO', this.DPO],['OSC', this.OSC],
['ATR', this.ATR],['NVI', this.NVI],['PVI', this.PVI],
['UOS', this.UOS],['CYW', this.CYW],['LON', this.LON],
['NDB', this.NDB],['SKDJ',this.SKDJ],['KD',this.KD],['FKX',this.FKX],
['DKCOL',this.DKCOL],['UDL',this.UDL],['MFI',this.MFI],['LWR',this.LWR],
['MARSI',this.MARSI],['CYD',this.CYD],['CYF',this.CYF],['TAPI',this.TAPI],
['VMACD',this.VMACD],['QACD',this.QACD],['VPT',this.VPT],['WVAD',this.WVAD],
['DBQR',this.DBQR],['JS',this.JS],['CYE',this.CYE],['QR',this.QR],['GDX',this.GDX],
['JLHB',this.JLHB],['PCNT',this.PCNT],['BTX', this.BTX],['AMO',this.AMO],
['VRSI',this.VRSI],['HSCOL',this.HSCOL],['DBQRV',this.DBQRV],['DBLB',this.DBLB],
['ACD',this.ACD],['EXPMA',this.EXPMA],['EXPMA_S',this.EXPMA_S],['HMA',this.HMA],
['LMA',this.LMA],['VMA',this.VMA],['AMV',this.AMV],['BBIBOLL',this.BBIBOLL],
['ALLIGAT',this.ALLIGAT],['ZX',this.ZX],['XS',this.XS],['XS2',this.XS2],
['SG-XDT',this.SG_XDT],['SG-SMX',this.SG_SMX],['SG-LB',this.SG_LB],['SG-PF',this.SG_PF],
['RAD',this.RAD],['SHT',this.SHT],['ZLJC',this.ZLJC],['ZLMM',this.ZLMM],['SLZT',this.SLZT],
['ADVOL',this.ADVOL],['CYC',this.CYC],['CYS',this.CYS],['CYQKL',this.CYQKL],
['SCR',this.SCR],['ASR',this.ASR],['SAR',this.SAR],['TJCJL',this.TJCJL],['量比',this.VOLRate],
['平均K线',this.HeikinAshi], ["ADL", this.ADL],["SQJZ", this.SQJZ],["XT", this.XT],["CFJT", this.CFJT],["CYX",this.CYX],
["WAVE",this.WAVE],
['VOL-TDX',this.VOL_TDX],
['EMPTY', this.EMPTY], //什么都不显示的指标
['神奇九转', this.NineTurns],
['EMA', this.EMA3], ['EMA4', this.EMA4], ['EMA5', this.EMA5],['EMA6', this.EMA6],
["ICHIMOKU",this.ICHIMOKU],["CDP-STD", this.CDP_STD],["TBP-STD",this.TBP_STD],
["ADX", this.ADX],
["持仓量", this.VOL_POSITION], //成交量+持仓量
//通达信特色指标
["散户线", this.ShareholderCount],["NXTS", this.NXTS],["FKX", this.FKX],["两融资金", this.Margin4],
["ZSDB",this.ZSDB],
['CJL2', this.CJL], //期货持仓量
['ASI', this.ASI],['DC', this.DC],['DEMA', this.DEMA],["VWAP", this.VWAP],
//指南针
["ZNZ_CBAND", this.ZNZ_CBAND],["ZNZ_RPY2",this.ZNZ_RPY2],["ZNZ_RPY1", this.ZNZ_RPY1],
['飞龙四式', this.Dragon4_Main],['飞龙四式-附图', this.Dragon4_Fig],
['资金分析', this.FundsAnalysis],['融资占比',this.MarginProportion],['负面新闻', this.NewsNegative],
['涨跌趋势', this.UpDownAnalyze],['北上资金', this.HK2SHSZ],['股东人数', this.ShareHolder],
["两融余额", this.Margin2],["两融余额2", this.Margin3],
//外包指标
['放心股-操盘BS点',this.FXG_BSPoint],
['放心股-涨停多空线',this.FXG_INDEX],
['放心股-涨停吸筹区',this.FXG_INDEX2],
['放心股-量能黄金点',this.FXG_INDEX3],
//五彩K线(函数COLOR_开头)
['五彩K线-十字星',this.COLOR_KSTAR1],['五彩K线-早晨之星',this.COLOR_KSTAR2],['五彩K线-黄昏之星',this.COLOR_KSTAR3],['五彩K线-长十字',this.COLOR_SHI1],
['五彩K线-身怀六甲',this.COLOR_K220],['五彩K线-三个白武士',this.COLOR_K300],['五彩K线-三只乌鸦',this.COLOR_K310],['五彩K线-光头阳线',this.COLOR_K380],
['五彩K线-光脚阴线',this.COLOR_K390],['五彩K线-垂死十字',this.COLOR_K134],['五彩K线-早晨十字星',this.COLOR_K140],['五彩K线-黄昏十字星',this.COLOR_K150],
['五彩K线-射击之星',this.COLOR_K160],['五彩K线-倒转锤头',this.COLOR_K165],['五彩K线-锤头',this.COLOR_K170],['五彩K线-吊颈',this.COLOR_K180],
['五彩K线-穿头破脚',this.COLOR_K190],['五彩K线-出水芙蓉',this.COLOR_CSFR],['五彩K线-乌云盖顶',this.COLOR_WYGD],['五彩K线-曙光初现',this.COLOR_SGCJ],
['五彩K线-十字胎',this.COLOR_SZTAI],['五彩K线-剑',this.COLOR_SWORD],['五彩K线-平顶',this.COLOR_PINGDING],['五彩K线-平底',this.COLOR_PINGDI],
['五彩K线-大阳烛',this.COLOR_DAYANZHU],['五彩K线-大阴烛',this.COLOR_DAYINGZHU],
['五彩K线-好友反攻',this.COLOR_HYFG],['五彩K线-跳空缺口',this.COLOR_TKQK],
['五彩K线-双飞乌鸦',this.COLOR_SFWY],['五彩K线-上升三部曲',this.COLOR_SSSBQ],['五彩K线-下跌三部曲',this.COLOR_XDSBQ],['五彩K线-长下影',this.COLOR_CHXY],
['五彩K线-长上影',this.COLOR_CHSY],['五彩K线-分离',this.COLOR_FENLI],
//交易系统
['交易系统-BIAS',this.TRADE_BIAS],['交易系统-CCI',this.TRADE_CCI],['交易系统-DMI',this.TRADE_DMI],['交易系统-KD',this.TRADE_KD],
['交易系统-BOLL',this.TRADE_BOLL],['交易系统-KDJ',this.TRADE_KDJ],['交易系统-MA',this.TRADE_MA],['交易系统-MACD',this.TRADE_MACD],
['交易系统-MTM',this.TRADE_MTM],['交易系统-PSY',this.TRADE_PSY],['交易系统-ROC',this.TRADE_ROC],['交易系统-RSI',this.TRADE_RSI],
['交易系统-VR',this.TRADE_VR],['交易系统-DPSJ',this.TRADE_DPSJ],
['TEST', this.TEST] //测试用
]);
}
JSIndexScript.AddIndex=function(aryIndex) //添加自定义指标
{
for(var i in aryIndex)
{
g_CustomIndex.Add(aryIndex[i]);
}
}
//修改指标属性
JSIndexScript.ModifyAttribute=function(indexInfo, attribute)
{
if (!attribute) return;
if (attribute.Args) indexInfo.Args=attribute.Args; //外部可以设置参数
if (IFrameSplitOperator.IsNumber(attribute.FloatPrecision)) indexInfo.FloatPrecision=attribute.FloatPrecision;
if (IFrameSplitOperator.IsNumber(attribute.StringFormat)) indexInfo.StringFormat=attribute.StringFormat;
if (IFrameSplitOperator.IsBool(attribute.IsSync)) indexInfo.IsSync=attribute.IsSync;
if (IFrameSplitOperator.IsBool(attribute.IsShortTitle)) indexInfo.IsShortTitle=attribute.IsShortTitle;
if (attribute.TitleFont) indexInfo.TitleFont=attribute.TitleFont;
if (attribute.Lock) indexInfo.Lock=attribute.Lock;
if (IFrameSplitOperator.IsNumber(attribute.YSplitType)) indexInfo.YSplitType=attribute.YSplitType;
if (IFrameSplitOperator.IsBool(attribute.IsShowIndexTitle)) indexInfo.IsShowIndexTitle=attribute.IsShowIndexTitle;
if (IFrameSplitOperator.IsNumber(attribute.KLineType)) indexInfo.KLineType=attribute.KLineType;
if (attribute.YAxis)
{
var item=attribute.YAxis;
if (!indexInfo.YAxis) indexInfo.YAxis={ };
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) indexInfo.YAxis.FloatPrecision=item.FloatPrecision;
if (IFrameSplitOperator.IsNumber(item.StringFormat)) indexInfo.YAxis.StringFormat=item.StringFormat;
if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) indexInfo.YAxis.EnableRemoveZero=item.EnableRemoveZero;
if (IFrameSplitOperator.IsBool(item.ExcludeValue)) indexInfo.YAxis.ExcludeValue=item.ExcludeValue; //不参数Y轴的计算
}
}
JSIndexScript.prototype.Get=function(id)
{
var data=g_CustomIndex.Get(id);
if (data) return data;
var func=this.DataMap.get(id);
if (func)
{
var data= func();
data.ID=id;
return data;
}
return null;
}
JSIndexScript.prototype.Search=function(name)
{
var result=[];
var reg = new RegExp(name,'i');
this.DataMap.forEach(function(value,key)
{
if (key.indexOf('交易系统-')!=0 && key.indexOf('五彩K线-')!=0 && key.search(reg)>=0)
result.push(key);
});
return result;
}
JSIndexScript.prototype.MA=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} ],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" }],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);'
};
return data;
}
JSIndexScript.prototype.MA4=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20},{ Name:'M4', Value:60} ],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" } ],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);'
};
return data;
}
JSIndexScript.prototype.MA5=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} ,{ Name:'M4', Value:60} ,{ Name:'M5', Value:0}],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },{Name:'MA5',DynamicName:"MA{M5}" } ],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);'
};
return data;
}
JSIndexScript.prototype.MA6=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} , { Name:'M4', Value:60} ,
{ Name:'M5', Value:0},{ Name:'M6', Value:0}
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
{Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);'
};
return data;
}
JSIndexScript.prototype.MA7=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20}, { Name:'M4', Value:60},
{ Name:'M5', Value:0},{ Name:'M6', Value:0} ,{ Name:'M7', Value:0 }
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
{Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ,{ Name:'MA7',DynamicName:"MA{M7}" }],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);\n\
MA7:MA(CLOSE,M7);'
};
return data;
}
JSIndexScript.prototype.MA8=function()
{
let data=
{
Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20}, { Name:'M4', Value:60},
{ Name:'M5', Value:0},{ Name:'M6', Value:0} ,{ Name:'M7', Value:0 } ,{ Name:'M8', Value:0 }
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
{Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ,{ Name:'MA7',DynamicName:"MA{M7}" },{ Name:'MA8',DynamicName:"MA{M8}" }],
Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);\n\
MA7:MA(CLOSE,M7);\n\
MA8:MA(CLOSE,M8);'
};
return data;
}
JSIndexScript.prototype.EMA3=function()
{
let data=
{
Name:'EMA', Description:'指数移动平均值', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20}
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" } ],
Script: //脚本
'MA1:EMA(CLOSE,M1);\n\
MA2:EMA(CLOSE,M2);\n\
MA3:EMA(CLOSE,M3);'
};
return data;
}
JSIndexScript.prototype.EMA4=function()
{
let data=
{
Name:'EMA', Description:'指数移动平均值', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} , { Name:'M4', Value:60}
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" } ],
Script: //脚本
'MA1:EMA(CLOSE,M1);\n\
MA2:EMA(CLOSE,M2);\n\
MA3:EMA(CLOSE,M3);\n\
MA4:EMA(CLOSE,M4);'
};
return data;
}
JSIndexScript.prototype.EMA5=function()
{
let data=
{
Name:'EMA', Description:'指数移动平均值', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} , { Name:'M4', Value:60} ,
{ Name:'M5', Value:0}
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
{Name:'MA5',DynamicName:"MA{M5}" } ],
Script: //脚本
'MA1:EMA(CLOSE,M1);\n\
MA2:EMA(CLOSE,M2);\n\
MA3:EMA(CLOSE,M3);\n\
MA4:EMA(CLOSE,M4);\n\
MA5:EMA(CLOSE,M5);'
};
return data;
}
JSIndexScript.prototype.EMA6=function()
{
let data=
{
Name:'EMA', Description:'指数移动平均值', IsMainIndex:true, StringFormat:2,
Args:
[
{ Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} , { Name:'M4', Value:60} ,
{ Name:'M5', Value:0},{ Name:'M6', Value:0}
],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
{Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ],
Script: //脚本
'MA1:EMA(CLOSE,M1);\n\
MA2:EMA(CLOSE,M2);\n\
MA3:EMA(CLOSE,M3);\n\
MA4:EMA(CLOSE,M4);\n\
MA5:EMA(CLOSE,M5);\n\
MA6:EMA(CLOSE,M6);'
};
return data;
}
JSIndexScript.prototype.BOLL=function()
{
let data=
{
Name:'BOLL', Description:'布林线', IsMainIndex:true,
Args:[ { Name:'M', Value:20} ],
Script: //脚本
'BOLL:MA(CLOSE,M);\n\
UB:BOLL+2*STD(CLOSE,M);\n\
LB:BOLL-2*STD(CLOSE,M);'
};
return data;
}
JSIndexScript.prototype.BOLL2=function()
{
let data=
{
Name:'BOLL2', Description:'布林线', IsMainIndex:false, KLineType:0,
Args:[ { Name:'M', Value:20} ],
Script: //脚本
'BOLL:MA(CLOSE,M);\n\
UB:BOLL+2*STD(CLOSE,M);\n\
LB:BOLL-2*STD(CLOSE,M);'
};
return data;
}
JSIndexScript.prototype.BBI=function()
{
let data=
{
Name:'BBI', Description:'多空均线', IsMainIndex:true,
Args:[ { Name:'M1', Value:3}, { Name:'M2', Value:6}, { Name:'M3', Value:12}, { Name:'M4', Value:24} ],
Script: //脚本
'BBI:(MA(CLOSE,M1)+MA(CLOSE,M2)+MA(CLOSE,M3)+MA(CLOSE,M4))/4;'
};
return data;
}
JSIndexScript.prototype.DKX=function()
{
let data=
{
Name:'DKX', Description:'多空线', IsMainIndex:false,
Args:[ { Name:'M', Value:10} ],
Script: //脚本
'MID:=(3*CLOSE+LOW+OPEN+HIGH)/6;\n\
DKX:(20*MID+19*REF(MID,1)+18*REF(MID,2)+17*REF(MID,3)+\n\
16*REF(MID,4)+15*REF(MID,5)+14*REF(MID,6)+\n\
13*REF(MID,7)+12*REF(MID,8)+11*REF(MID,9)+\n\
10*REF(MID,10)+9*REF(MID,11)+8*REF(MID,12)+\n\
7*REF(MID,13)+6*REF(MID,14)+5*REF(MID,15)+\n\
4*REF(MID,16)+3*REF(MID,17)+2*REF(MID,18)+REF(MID,20))/210;\n\
MADKX:MA(DKX,M);'
};
return data;
}
JSIndexScript.prototype.MIKE=function()
{
let data=
{
Name:'MIKE', Description:'麦克支撑压力', IsMainIndex:true,
Args:[ { Name:'N', Value:10} ],
Script: //脚本
'HLC:=REF(MA((HIGH+LOW+CLOSE)/3,N),1);\n\
HV:=EMA(HHV(HIGH,N),3);\n\
LV:=EMA(LLV(LOW,N),3);\n\
STOR:EMA(2*HV-LV,3);\n\
MIDR:EMA(HLC+HV-LV,3);\n\
WEKR:EMA(HLC*2-LV,3);\n\
WEKS:EMA(HLC*2-HV,3);\n\
MIDS:EMA(HLC-HV+LV,3);\n\
STOS:EMA(2*LV-HV,3);'
};
return data;
}
JSIndexScript.prototype.PBX=function()
{
let data=
{
Name:'PBX', Description:'瀑布线', IsMainIndex:true,
Args:[ { Name:'M1', Value:4}, { Name:'M2', Value:6}, { Name:'M3', Value:9}, { Name:'M4', Value:13},{ Name:'M5', Value:18},{ Name:'M6', Value:24} ],
Script: //脚本
'PBX1:(EMA(CLOSE,M1)+MA(CLOSE,M1*2)+MA(CLOSE,M1*4))/3;\n\
PBX2:(EMA(CLOSE,M2)+MA(CLOSE,M2*2)+MA(CLOSE,M2*4))/3;\n\
PBX3:(EMA(CLOSE,M3)+MA(CLOSE,M3*2)+MA(CLOSE,M3*4))/3;\n\
PBX4:(EMA(CLOSE,M4)+MA(CLOSE,M4*2)+MA(CLOSE,M4*4))/3;\n\
PBX5:(EMA(CLOSE,M5)+MA(CLOSE,M5*2)+MA(CLOSE,M5*4))/3;\n\
PBX6:(EMA(CLOSE,M6)+MA(CLOSE,M6*2)+MA(CLOSE,M6*4))/3;'
};
return data;
}
JSIndexScript.prototype.ENE=function()
{
let data=
{
Name:'ENE', Description:'轨道线', IsMainIndex:true,
Args:[ { Name:'N', Value:25}, { Name:'M1', Value:6}, { Name:'M2', Value:6} ],
Script: //脚本
'UPPER:(1+M1/100)*MA(CLOSE,N);\n\
LOWER:(1-M2/100)*MA(CLOSE,N);\n\
ENE:(UPPER+LOWER)/2;'
};
return data;
}
JSIndexScript.prototype.MACD=function()
{
let data=
{
Name:'MACD', Description:'平滑异同平均', IsMainIndex:false,
Args:[ { Name:'SHORT', Value:12}, { Name:'LONG', Value:26}, { Name:'MID', Value:9} ],
Script: //脚本
'DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG);\n\
DEA:EMA(DIF,MID);\n\
MACD:(DIF-DEA)*2,COLORSTICK;'
};
return data;
}
//上下柱子
JSIndexScript.prototype.MACD2=function()
{
let data=
{
Name:'MACD', Description:'平滑异同平均', IsMainIndex:false,
Args:[ { Name:'SHORT', Value:12}, { Name:'LONG', Value:26}, { Name:'MID', Value:9} ],
Script: //脚本
'DIF2:=EMA(CLOSE,SHORT)-EMA(CLOSE,LONG);\n\
DEA2:=EMA(DIF2,MID);\n\
MACD:(DIF2-DEA2)*2,COLORSTICK,LINETHICK50;\n\
DIF:DIF2;\n\
DEA:DEA2;'
};
return data;
}
JSIndexScript.prototype.KDJ=function()
{
let data=
{
Name:'KDJ', Description:'随机指标', IsMainIndex:false,
Args:[ { Name:'N', Value:9}, { Name:'M1', Value:3}, { Name:'M2', Value:3} ],
Script: //脚本
'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
K:SMA(RSV,M1,1);\n\
D:SMA(K,M2,1);\n\
J:3*K-2*D;'
};
return data;
}
JSIndexScript.prototype.VOL=function()
{
let data=
{
Name:'VOL', Description:'成交量', IsMainIndex:false,FloatPrecision:0,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10} ],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" }],
Script: //脚本
'VOL:VOL,VOLSTICK;\n\
MA1:MA(VOL,M1);\n\
MA2:MA(VOL,M2);'
};
return data;
}
JSIndexScript.prototype.VOL2=function()
{
let data=
{
Name:'VOL', Description:'成交量', IsMainIndex:false,FloatPrecision:0,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10} ],
OutName:[ {Name:'MA1',DynamicName:"MA{M1}" }, {Name:'MA2',DynamicName:"MA{M2}" }],
Script: //脚本
'VOL:VOL,VOLSTICK,STICKTYPE(1);\n\
MA1:MA(VOL,M1);\n\
MA2:MA(VOL,M2);'
};
return data;
}
JSIndexScript.prototype.VOL_OVERLAY=function()
{
let data=
{
Name:'VOL', Description:'成交量', IsMainIndex:false,FloatPrecision:0,
Script: //脚本
'VOL:VOL,VOLSTICK,UPCOLOR(RGBA(255,0,0,0.3)),DOWNCOLOR(RGBA(0,255,0,0.3));'
};
return data;
}
JSIndexScript.prototype.VOL_TDX=function()
{
let data=
{
Name:'VOL-TDX', Description:'成交量(虚拟)', IsMainIndex:false,FloatPrecision:0,
Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10} ],
Script: //脚本
'TOTAL:=IF(PERIOD=1,5,IF(PERIOD=2,15,IF(PERIOD=3,30,IF(PERIOD=4,60,IF(PERIOD=5,TOTALFZNUM,1)))));\n\
MTIME:=MOD(FROMOPEN,TOTAL);\n\
CTIME:=IF(MTIME<0.5,TOTAL,MTIME);\n\
VVOL:IF((CURRBARSCOUNT=1 AND DYNAINFO(8)>1),VOL*(TOTAL+3)/(CTIME+3),DRAWNULL),NODRAW;\n\
STICKLINE((CURRBARSCOUNT=1 AND DYNAINFO(8)>1),VVOL,0,-1,-1),COLORYELLOW;\n\
VOLUME:VOL,VOLSTICK;\n\
MAVOL1:MA(VOLUME,M1);\n\
MAVOL2:MA(VOLUME,M2);'
};
return data;
}
JSIndexScript.prototype.RSI=function()
{
let data=
{
Name:'RSI', Description:'相对强弱指标', IsMainIndex:false,
Args:[ { Name:'N1', Value:6}, { Name:'N2', Value:12}, { Name:'N3', Value:24} ],
Script: //脚本
'LC:=REF(CLOSE,1);\n\
RSI1:SMA(MAX(CLOSE-LC,0),N1,1)/SMA(ABS(CLOSE-LC),N1,1)*100;\n\
RSI2:SMA(MAX(CLOSE-LC,0),N2,1)/SMA(ABS(CLOSE-LC),N2,1)*100;\n\
RSI3:SMA(MAX(CLOSE-LC,0),N3,1)/SMA(ABS(CLOSE-LC),N3,1)*100;'
};
return data;
}
JSIndexScript.prototype.BRAR=function()
{
let data=
{
Name:'BRAR', Description:'情绪指标', IsMainIndex:false,
Args:[ { Name:'N', Value:26} ],
Script: //脚本
'BR:SUM(MAX(0,HIGH-REF(CLOSE,1)),N)/SUM(MAX(0,REF(CLOSE,1)-LOW),N)*100;\n\
AR:SUM(HIGH-OPEN,N)/SUM(OPEN-LOW,N)*100;'
};
return data;
}
JSIndexScript.prototype.WR=function()
{
let data=
{
Name:'WR', Description:'威廉指标', IsMainIndex:false,
Args:[ { Name:'N', Value:10}, { Name:'N1', Value:6} ],
Script: //脚本
'WR1:100*(HHV(HIGH,N)-CLOSE)/(HHV(HIGH,N)-LLV(LOW,N));\n\
WR2:100*(HHV(HIGH,N1)-CLOSE)/(HHV(HIGH,N1)-LLV(LOW,N1));'
};
return data;
}
JSIndexScript.prototype.BIAS=function()
{
let data=
{
Name:'BIAS', Description:'乖离率', IsMainIndex:false,
Args:[ { Name:'N1', Value:6}, { Name:'N2', Value:12}, { Name:'N3', Value:24} ],
Script: //脚本
'BIAS1 :(CLOSE-MA(CLOSE,N1))/MA(CLOSE,N1)*100;\n\
BIAS2 :(CLOSE-MA(CLOSE,N2))/MA(CLOSE,N2)*100;\n\
BIAS3 :(CLOSE-MA(CLOSE,N3))/MA(CLOSE,N3)*100;'
};
return data;
}
JSIndexScript.prototype.OBV=function()
{
let data=
{
Name:'OBV', Description:'累积能量线', IsMainIndex:false,
Args:[ { Name:'M', Value:30} ],
Script: //脚本
'VA:=IF(CLOSE>REF(CLOSE,1),VOL,-VOL);\n\
OBV:SUM(IF(CLOSE==REF(CLOSE,1),0,VA),0);\n\
MAOBV:MA(OBV,M);'
};
return data;
}
JSIndexScript.prototype.DMI=function()
{
let data=
{
Name:'DMI', Description:'趋向指标', IsMainIndex:false,
Args:[ { Name:'N', Value:14}, { Name:'MM', Value:6} ],
Script: //脚本
'MTR:=EXPMEMA(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(REF(CLOSE,1)-LOW)),N);\n\
HD :=HIGH-REF(HIGH,1);\n\
LD :=REF(LOW,1)-LOW;\n\
DMP:=EXPMEMA(IF(HD>0&&HD>LD,HD,0),N);\n\
DMM:=EXPMEMA(IF(LD>0&&LD>HD,LD,0),N);\n\
PDI: DMP*100/MTR;\n\
MDI: DMM*100/MTR;\n\
ADX: EXPMEMA(ABS(MDI-PDI)/(MDI+PDI)*100,MM);\n\
ADXR:EXPMEMA(ADX,MM);'
};
return data;
}
JSIndexScript.prototype.CR=function()
{
let data=
{
Name:'CR', Description:'带状能量线', IsMainIndex:false,
Args:[ { Name:'N', Value:26}, { Name:'M1', Value:10},{ Name:'M2', Value:20},{ Name:'M3', Value:40},{ Name:'M4', Value:62} ],
Script: //脚本
'MID:=REF(HIGH+LOW,1)/2;\n\
CR:SUM(MAX(0,HIGH-MID),N)/SUM(MAX(0,MID-LOW),N)*100;\n\
MA1:REF(MA(CR,M1),M1/2.5+1);\n\
MA2:REF(MA(CR,M2),M2/2.5+1);\n\
MA3:REF(MA(CR,M3),M3/2.5+1);\n\
MA4:REF(MA(CR,M4),M4/2.5+1);'
};
return data;
}
JSIndexScript.prototype.PSY=function()
{
let data=
{
Name:'PSY', Description:'心理线', IsMainIndex:false,
Args:[ { Name:'N', Value:12}, { Name:'M', Value:6} ],
Script: //脚本
'PSY:COUNT(CLOSE>REF(CLOSE,1),N)/N*100;\r\
PSYMA:MA(PSY,M);'
};
return data;
}
JSIndexScript.prototype.CCI=function()
{
let data=
{
Name:'CCI', Description:'商品路径指标', IsMainIndex:false,
Args:[ { Name:'N', Value:14} ],
Script: //脚本
'TYP:=(HIGH+LOW+CLOSE)/3;\n\
CCI:(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));'
};
return data;
}
JSIndexScript.prototype.DMA=function()
{
let data=
{
Name:'DMA', Description:'平均差', IsMainIndex:false,
Args:[ { Name:'N1', Value:10},{ Name:'N2', Value:50},{ Name:'M', Value:10} ],
Script: //脚本
'DIF:MA(CLOSE,N1)-MA(CLOSE,N2);\n\
DIFMA:MA(DIF,M);'
};
return data;
}
JSIndexScript.prototype.TRIX=function()
{
let data=
{
Name:'TRIX', Description:'三重指数平均线', IsMainIndex:false,
Args:[ { Name:'N', Value:12},{ Name:'M', Value:9} ],
Script: //脚本
'MTR:=EMA(EMA(EMA(CLOSE,N),N),N);\n\
TRIX:(MTR-REF(MTR,1))/REF(MTR,1)*100;\n\
MATRIX:MA(TRIX,M) ;'
};
return data;
}
JSIndexScript.prototype.VR=function()
{
let data=
{
Name:'VR', Description:'成交量变异率', IsMainIndex:false,
Args:[ { Name:'N', Value:26},{ Name:'M', Value:6} ],
Script: //脚本
'TH:=SUM(IF(CLOSE>REF(CLOSE,1),VOL,0),N);\n\
TL:=SUM(IF(CLOSE<REF(CLOSE,1),VOL,0),N);\n\
TQ:=SUM(IF(CLOSE==REF(CLOSE,1),VOL,0),N);\n\
VR:100*(TH*2+TQ)/(TL*2+TQ);\n\
MAVR:MA(VR,M);'
};
return data;
}
JSIndexScript.prototype.EMV=function()
{
let data=
{
Name:'EMV', Description:'简易波动指标', IsMainIndex:false,
Args:[ { Name:'N', Value:14},{ Name:'M', Value:9} ],
Script: //脚本
'VOLUME:=MA(VOL,N)/VOL;\n\
MID:=100*(HIGH+LOW-REF(HIGH+LOW,1))/(HIGH+LOW);\n\
EMV:MA(MID*VOLUME*(HIGH-LOW)/MA(HIGH-LOW,N),N);\n\
MAEMV:MA(EMV,M);'
};
return data;
}
JSIndexScript.prototype.ROC=function()
{
let data=
{
Name:'ROC', Description:'变动率指标', IsMainIndex:false,
Args:[ { Name:'N', Value:12},{ Name:'M', Value:6} ],
Script: //脚本
'ROC:100*(CLOSE-REF(CLOSE,N))/REF(CLOSE,N);\n\
MAROC:MA(ROC,M);'
};
return data;
}
JSIndexScript.prototype.MTM=function()
{
let data=
{
Name:'MTM', Description:'动量线', IsMainIndex:false,
Args:[ { Name:'N', Value:12},{ Name:'M', Value:6} ],
Script: //脚本
'MTM:CLOSE-REF(CLOSE,N);\n\
MAMTM:MA(MTM,M);'
};
return data;
}
JSIndexScript.prototype.FSL=function()
{
let data=
{
Name:'FSL', Description:'分水岭', IsMainIndex:false,
Args:[ ],
Script: //脚本
'SWL:(EMA(CLOSE,5)*7+EMA(CLOSE,10)*3)/10;\n\
SWS:DMA(EMA(CLOSE,12),MAX(1,100*(SUM(VOL,5)/(3*CAPITAL))));'
};
return data;
}
JSIndexScript.prototype.CYR=function()
{
let data=
{
Name:'CYR', Description:'市场强弱', IsMainIndex:false,
Args:[ { Name:'N', Value:13},{ Name:'M', Value:5}],
Script: //脚本
'DIVE:=0.01*EMA(AMOUNT,N)/EMA(VOL,N);\n\
CYR:(DIVE/REF(DIVE,1)-1)*100;\n\
MACYR:MA(CYR,M);'
};
return data;
}
JSIndexScript.prototype.MASS=function()
{
let data=
{
Name:'MASS', Description:'市场强弱', IsMainIndex:false,
Args:[ { Name:'N1', Value:9},{ Name:'N2', Value:25}, { Name:'M', Value:6}],
Script: //脚本
'MASS:SUM(MA(HIGH-LOW,N1)/MA(MA(HIGH-LOW,N1),N1),N2);\n\
MAMASS:MA(MASS,M);'
};
return data;
}
JSIndexScript.prototype.WAD=function()
{
let data=
{
Name:'WAD', Description:'威廉多空力度线', IsMainIndex:false,
Args:[ { Name:'M', Value:30}],
Script: //脚本
'MIDA:=CLOSE-MIN(REF(CLOSE,1),LOW);\n\
MIDB:=IF(CLOSE<REF(CLOSE,1),CLOSE-MAX(REF(CLOSE,1),HIGH),0);\n\
WAD:SUM(IF(CLOSE>REF(CLOSE,1),MIDA,MIDB),0);\n\
MAWAD:MA(WAD,M);'
};
return data;
}
JSIndexScript.prototype.CHO=function()
{
let data=
{
Name:'CHO', Description:'佳庆指标', IsMainIndex:false,
Args:[ { Name:'N1', Value:10}, { Name:'N2', Value:20}, { Name:'M', Value:6}],
Script: //脚本
'MID:=SUM(VOL*(2*CLOSE-HIGH-LOW)/(HIGH+LOW),0);\n\
CHO:MA(MID,N1)-MA(MID,N2);\n\
MACHO:MA(CHO,M);'
};
return data;
}
JSIndexScript.prototype.ADTM=function()
{
let data=
{
Name:'ADTM', Description:'动态买卖气指标', IsMainIndex:false,
Args:[ { Name:'N', Value:23}, { Name:'M', Value:8}],
Script: //脚本
'DTM:=IF(OPEN<=REF(OPEN,1),0,MAX((HIGH-OPEN),(OPEN-REF(OPEN,1))));\n\
DBM:=IF(OPEN>=REF(OPEN,1),0,MAX((OPEN-LOW),(OPEN-REF(OPEN,1))));\n\
STM:=SUM(DTM,N);\n\
SBM:=SUM(DBM,N);\n\
ADTM:IF(STM>SBM,(STM-SBM)/STM,IF(STM==SBM,0,(STM-SBM)/SBM));\n\
MAADTM:MA(ADTM,M);'
};
return data;
}
JSIndexScript.prototype.HSL=function()
{
let data=
{
Name:'HSL', Description:'换手线', IsMainIndex:false,
Args:[ { Name:'N', Value:5} ],
Script: //脚本
'HSL:IF((SETCODE==0||SETCODE==1),100*VOL,VOL)/(FINANCE(7)/100);\n\
MAHSL:MA(HSL,N);'
};
return data;
}
JSIndexScript.prototype.BIAS36=function()
{
let data=
{
Name:'BIAS36', Description:'三六乖离', IsMainIndex:false,
Args:[ { Name:'M', Value:6} ],
Script: //脚本
'BIAS36:MA(CLOSE,3)-MA(CLOSE,6);\n\
BIAS612:MA(CLOSE,6)-MA(CLOSE,12);\n\
MABIAS:MA(BIAS36,M);'
};
return data;
}
JSIndexScript.prototype.BIAS_QL=function()
{
let data=
{
Name:'BIAS_QL', Description:'乖离率-传统版', IsMainIndex:false,
Args:[ { Name:'N', Value:6}, { Name:'M', Value:6} ],
Script: //脚本
'BIAS :(CLOSE-MA(CLOSE,N))/MA(CLOSE,N)*100;\n\
BIASMA :MA(BIAS,M);'
};
return data;
}
JSIndexScript.prototype.DPO=function()
{
let data=
{
Name:'DPO', Description:'区间震荡线', IsMainIndex:false,
Args:[ { Name:'N', Value:20}, { Name:'M', Value:6} ],
Script: //脚本
'DPO:CLOSE-REF(MA(CLOSE,N),N/2+1);\n\
MADPO:MA(DPO,M);'
};
return data;
}
JSIndexScript.prototype.OSC=function()
{
let data=
{
Name:'OSC', Description:'变动速率线', IsMainIndex:false,
Args:[ { Name:'N', Value:20}, { Name:'M', Value:6} ],
Script: //脚本
'OSC:100*(CLOSE-MA(CLOSE,N));\n\
MAOSC:EXPMEMA(OSC,M);'
};
return data;
}
JSIndexScript.prototype.ATR=function()
{
let data=
{
Name:'ATR', Description:'真实波幅', IsMainIndex:false,
Args:[ { Name:'N', Value:14}],
Script: //脚本
'MTR:MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));\n\
ATR:MA(MTR,N);'
};
return data;
}
JSIndexScript.prototype.NVI=function()
{
let data=
{
Name:'ATR', Description:'负成交量', IsMainIndex:false,
Args:[ { Name:'N', Value:72} ],
Script: //脚本
'NVI:100*MULAR(IF(V<REF(V,1),C/REF(C,1),1),0);\n\
MANVI:MA(NVI,N);'
};
return data;
}
JSIndexScript.prototype.PVI=function()
{
let data=
{
Name:'PVI', Description:'正成交量', IsMainIndex:false,
Args:[ { Name:'N', Value:72} ],
Script: //脚本
'NVI:100*MULAR(IF(V>REF(V,1),C/REF(C,1),1),0);\n\
MANVI:MA(NVI,N);'
};
return data;
}
JSIndexScript.prototype.UOS=function()
{
let data=
{
Name:'UOS', Description:'终极指标', IsMainIndex:false,
Args:[ { Name:'N1', Value:7} ,{ Name:'N2', Value:14},{ Name:'N3', Value:28},{ Name:'M', Value:6}],
Script: //脚本
'TH:=MAX(HIGH,REF(CLOSE,1));\n\
TL:=MIN(LOW,REF(CLOSE,1));\n\
ACC1:=SUM(CLOSE-TL,N1)/SUM(TH-TL,N1);\n\
ACC2:=SUM(CLOSE-TL,N2)/SUM(TH-TL,N2);\n\
ACC3:=SUM(CLOSE-TL,N3)/SUM(TH-TL,N3);\n\
UOS:(ACC1*N2*N3+ACC2*N1*N3+ACC3*N1*N2)*100/(N1*N2+N1*N3+N2*N3);\n\
MAUOS:EXPMEMA(UOS,M);'
};
return data;
}
JSIndexScript.prototype.CYW=function()
{
let data=
{
Name:'CYW', Description:'主力控盘', IsMainIndex:false,
Args:[ ],
Script: //脚本
'VAR1:=CLOSE-LOW;\n\
VAR2:=HIGH-LOW;\n\
VAR3:=CLOSE-HIGH;\n\
VAR4:=IF(HIGH>LOW,(VAR1/VAR2+VAR3/VAR2)*VOL,0);\n\
CYW: SUM(VAR4,10)/10000, COLORSTICK;'
};
return data;
}
JSIndexScript.prototype.LON=function()
{
let data=
{
Name:'LON', Description:'龙系长线', IsMainIndex:false,
Args:[ { Name:'N', Value:10} ],
Script: //脚本
'LC := REF(CLOSE,1);\n\
VID := SUM(VOL,2)/(((HHV(HIGH,2)-LLV(LOW,2)))*100);\n\
RC := (CLOSE-LC)*VID;\n\
LONG := SUM(RC,0);\n\
DIFF := SMA(LONG,10,1);\n\
DEA := SMA(LONG,20,1);\n\
LON : DIFF-DEA;\n\
LONMA : MA(LON,10);\n\
LONT : LON, COLORSTICK;'
};
return data;
}
JSIndexScript.prototype.NDB = function ()
{
let data =
{
Name: 'NDB', Description: '脑电波', IsMainIndex: false,
Args: [{ Name: 'P1', Value: 5 }, { Name: 'P2', Value: 10 }],
Script: //脚本
'HH:=IF(C/REF(C,1)>1.098 AND L>REF(H,1),2*C-REF(C,1)-H,2*C-H-L);\n\
V1:= BARSCOUNT(C) - 1;\n\
V2:= 2 * REF(C, V1) - REF(H, V1) - REF(L, V1);\n\
DK: SUM(HH, 0) + V2;\n\
MDK5: MA(DK, P1);\n\
MDK10: MA(DK, P2);'
};
return data;
}
JSIndexScript.prototype.SKDJ = function ()
{
let data =
{
Name: 'SKDJ', Description: '慢速随机指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 9 }, { Name: 'M', Value: 3 }],
Script: //脚本
'LOWV:=LLV(LOW,N);\n\
HIGHV:=HHV(HIGH,N);\n\
RSV:=EMA((CLOSE-LOWV)/(HIGHV-LOWV)*100,M);\n\
K:EMA(RSV,M);\n\
D:MA(K,M);'
};
return data;
}
JSIndexScript.prototype.KD = function ()
{
let data =
{
Name: 'KD', Description: '随机指标KD', IsMainIndex: false,
Args: [{ Name: 'N', Value: 9 }, { Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }],
Script: //脚本
'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
K:SMA(RSV,M1,1);\n\
D:SMA(K,M2,1);'
};
return data;
}
JSIndexScript.prototype.FKX=function()
{
let data=
{
Name:'FKX', Description:'反K线', IsMainIndex:true,
Args:[ ],
Script: //脚本
'DRAWKLINE(-LOW, -OPEN, -HIGH, -CLOSE);'
};
return data;
}
JSIndexScript.prototype.DKCOL = function ()
{
let data =
{
Name: 'DKCOL', Description: '多空能量柱(适用于分时主图)', IsMainIndex: true,
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'FF:=(C-REF(C,N))/REF(C,N);\n\
STICKLINE(FF>0,DYNAINFO(3),DYNAINFO(3)*(1+FF),0.5,0),COLORRED;\n\
STICKLINE(FF<0,DYNAINFO(3),DYNAINFO(3)*(1+FF),0.5,0),COLORGREEN;'
};
return data;
}
JSIndexScript.prototype.UDL = function ()
{
let data =
{
Name: 'UDL', Description: '引力线', IsMainIndex: false,
Args: [{ Name: 'N1', Value: 3 },{ Name: 'N2', Value: 5 },{ Name: 'N3', Value: 10 },{ Name: 'N4', Value: 20 },{ Name: 'M', Value: 6 }],
Script: //脚本
'UDL:(MA(CLOSE,N1)+MA(CLOSE,N2)+MA(CLOSE,N3)+MA(CLOSE,N4))/4;\n\
MAUDL:MA(UDL,M);'
};
return data;
}
JSIndexScript.prototype.MFI = function ()
{
let data =
{
Name: 'MFI', Description: '资金流量指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 14 },{ Name: 'N2', Value: 6 }],
Script: //脚本
'TYP := (HIGH + LOW + CLOSE)/3;\n\
V1:=SUM(IF(TYP>REF(TYP,1),TYP*VOL,0),N)/SUM(IF(TYP<REF(TYP,1),TYP*VOL,0),N);\n\
MFI:100-(100/(1+V1));'
};
return data;
}
JSIndexScript.prototype.LWR = function ()
{
let data =
{
Name: 'LWR', Description: 'LWR威廉指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }],
Script: //脚本
'RSV:= (HHV(HIGH,N)-CLOSE)/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
LWR1:SMA(RSV,M1,1);\n\
LWR2:SMA(LWR1,M2,1);'
};
return data;
}
JSIndexScript.prototype.MARSI = function ()
{
let data =
{
Name: 'MARSI', Description: '相对强弱平均线', IsMainIndex: false,
Args: [{ Name: 'M1', Value: 10 },{ Name: 'M2', Value: 6 }],
Script: //脚本
'DIF:=CLOSE-REF(CLOSE,1);\n\
VU:=IF(DIF>=0,DIF,0);\n\
VD:=IF(DIF<0,-DIF,0);\n\
MAU1:=MEMA(VU,M1);\n\
MAD1:=MEMA(VD,M1);\n\
MAU2:=MEMA(VU,M2);\n\
MAD2:=MEMA(VD,M2);\n\
RSI10:MA(100*MAU1/(MAU1+MAD1),M1);\n\
RSI6:MA(100*MAU2/(MAU2+MAD2),M2);'
};
return data;
}
JSIndexScript.prototype.CYD = function ()
{
let data =
{
Name: 'CYD', Description: '承接因子', IsMainIndex: false,
Args: [{ Name: 'N', Value: 21 }],
Script: //脚本
'CYDS:WINNER(CLOSE)/(VOL/CAPITAL);\n\
CYDN:WINNER(CLOSE)/MA(VOL/CAPITAL,N);'
};
return data;
}
JSIndexScript.prototype.CYF = function ()
{
let data =
{
Name: 'CYF', Description: '市场能量', IsMainIndex: false,
Args: [{ Name: 'N', Value: 21 }],
Script: //脚本
'CYF:100-100/(1+EMA(HSL,N));'
};
return data;
}
JSIndexScript.prototype.TAPI = function ()
{
let data =
{
Name: 'TAPI', Description: '加权指数成交值', IsMainIndex: false,
Args: [{ Name: 'M', Value: 6 }],
Script: //脚本
'TAPI:AMOUNT/INDEXC;\n\
MATAIP:MA(TAPI,M);'
};
return data;
}
JSIndexScript.prototype.VMACD = function ()
{
let data =
{
Name: 'VMACD', Description: '量平滑异同平均', IsMainIndex: false,
Args: [{ Name: 'SHORT', Value: 12 },{ Name: 'LONG', Value: 26 },{ Name: 'MID', Value: 9 }],
Script: //脚本
'DIF:EMA(VOL,SHORT)-EMA(VOL,LONG);\n\
DEA:EMA(DIF,MID);\n\
MACD:DIF-DEA,COLORSTICK;'
};
return data;
}
JSIndexScript.prototype.QACD = function ()
{
let data =
{
Name: 'QACD', Description: '快速异同平均', IsMainIndex: false,
Args: [{ Name: 'N1', Value: 12 },{ Name: 'N2', Value: 26 },{ Name: 'M', Value: 9 }],
Script: //脚本
'DIF:EMA(CLOSE,N1)-EMA(CLOSE,N2);\n\
MACD:EMA(DIF,M);\n\
DDIF:DIF-MACD;'
};
return data;
}
JSIndexScript.prototype.VPT = function ()
{
let data =
{
Name: 'VPT', Description: '量价曲线', IsMainIndex: false,
Args: [{ Name: 'N', Value: 51 },{ Name: 'M', Value: 6 }],
Script: //脚本
'VPT:SUM(VOL*(CLOSE-REF(CLOSE,1))/REF(CLOSE,1),N);\n\
MAVPT:MA(VPT,M);'
};
return data;
}
JSIndexScript.prototype.WVAD = function ()
{
let data =
{
Name: 'WVAD', Description: '威廉变异离散量', IsMainIndex: false,
Args: [{ Name: 'N', Value: 24 },{ Name: 'M', Value: 6 }],
Script: //脚本
'WVAD:SUM((CLOSE-OPEN)/(HIGH-LOW)*VOL,N)/10000;\n\
MAWVAD:MA(WVAD,M);'
};
return data;
}
JSIndexScript.prototype.DBQR = function ()
{
let data =
{
Name: 'WVAD', Description: '对比强弱', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 },{ Name: 'M1', Value: 10 },{ Name: 'M2', Value: 20 },{ Name: 'M3', Value: 60 }],
Script: //脚本
'ZS:(INDEXC-REF(INDEXC,N))/REF(INDEXC,N);\n\
GG:(CLOSE-REF(CLOSE,N))/REF(CLOSE,N);\n\
MADBQR1:MA(GG,M1);\n\
MADBQR2:MA(GG,M2);\n\
MADBQR3:MA(GG,M3);'
};
return data;
}
JSIndexScript.prototype.JS = function ()
{
let data =
{
Name: 'JS', Description: '加速线', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 },{ Name: 'M1', Value: 5 },{ Name: 'M2', Value: 10 },{ Name: 'M3', Value: 20 }],
Script: //脚本
'JS:100*(CLOSE-REF(CLOSE,N))/(N*REF(CLOSE,N));\n\
MAJS1:MA(JS,M1);\n\
MAJS2:MA(JS,M2);\n\
MAJS3:MA(JS,M3);'
};
return data;
}
JSIndexScript.prototype.CYE = function ()
{
let data =
{
Name: 'CYE', Description: '市场趋势', IsMainIndex: false,
Args: [ ],
Script: //脚本
'MAL:=MA(CLOSE,5);\n\
MAS:=MA(MA(CLOSE,20),5);\n\
CYEL:(MAL-REF(MAL,1))/REF(MAL,1)*100;\n\
CYES:(MAS-REF(MAS,1))/REF(MAS,1)*100;'
};
return data;
}
JSIndexScript.prototype.QR = function ()
{
let data =
{
Name: 'QR', Description: '强弱指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 21 } ],
Script: //脚本
'个股: (CLOSE-REF(CLOSE,N))/REF(CLOSE,N)*100; \n\
大盘: (INDEXC-REF(INDEXC,N))/REF(INDEXC,N)*100; \n\
强弱值:EMA(个股-大盘,2),COLORSTICK;'
};
return data;
}
JSIndexScript.prototype.GDX = function ()
{
let data =
{
Name: 'GDX', Description: '轨道线', IsMainIndex: false,
Args: [{ Name: 'N', Value: 30 } ,{ Name: 'M', Value: 9 }],
Script: //脚本
'AA:=ABS((2*CLOSE+HIGH+LOW)/4-MA(CLOSE,N))/MA(CLOSE,N); \n\
轨道:DMA(CLOSE,AA);\n\
压力线:(1+M/100)*轨道; \n\
支撑线:(1-M/100)*轨道;'
};
return data;
}
JSIndexScript.prototype.JLHB = function ()
{
let data =
{
Name: 'JLHB', Description: '绝路航标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 7 } ,{ Name: 'M', Value: 5 }],
Script: //脚本
'VAR1:=(CLOSE-LLV(LOW,60))/(HHV(HIGH,60)-LLV(LOW,60))*80; \n\
B:SMA(VAR1,N,1); \n\
VAR2:SMA(B,M,1); \n\
绝路航标:IF(CROSS(B,VAR2) AND B<40,50,0);'
};
return data;
}
JSIndexScript.prototype.PCNT = function ()
{
let data =
{
Name: 'PCNT', Description: '幅度比', IsMainIndex: false,
Args: [{ Name: 'M', Value: 5 }],
Script: //脚本
'PCNT:(CLOSE-REF(CLOSE,1))/CLOSE*100;\n\
MAPCNT:EXPMEMA(PCNT,M);'
};
return data;
}
JSIndexScript.prototype.BTX = function ()
{
let data =
{
Name: 'BTX', Description: '宝塔线', IsMainIndex: false,
Args: [],
Script: //脚本
'B1:=REF(C,1);\n\
B2:= REF(C, 2);\n\
SS:= IF(C > REF(C, 1) AND REF(C, 1) >= REF(C, 2), 1, IF(C < REF(C, 1) AND REF(C, 1) <= REF(C, 2), -1, IF(C > REF(C, 2) AND REF(C, 2) > REF(C, 1), 2, IF(C < REF(C, 2) AND REF(C, 2) < REF(C, 1), -2, 0))));\n\
SM:= IF(REF(SS, 1) <> 0, REF(SS, 1), IF(REF(SS, 2) <> 0, REF(SS, 2), IF(REF(SS, 3) <> 0, REF(SS, 3), IF(REF(SS, 5) <> 0, REF(SS, 5), IF(REF(SS, 6) <> 0, REF(SS, 6), IF(REF(SS, 7) <> 0, REF(SS, 7), 0))))));\n\
MC:= IF(REF(SS, 1) <> 0, B2, IF(SM > 0, MIN(B1, B2), MAX(B1, B2)));\n\
TOW1:= IF(C > REF(C, 1), C, REF(C, 1));\n\
TOW2:= IF((SS == -1 OR SS == -2) AND SM > 0, B2, TOW1);\n\
TOWER:= IF(TOW1 > TOW2, TOW1, TOW2);\n\
STICKLINE(SS == 1 OR SM >= 1 AND SS == 0, B1, C, 10, 1), COLORRED;\n\
STICKLINE(SS == -1 OR SM <= -1 AND SS == 0, B1, C, 10, 0), COLORCYAN;\n\
STICKLINE(SS == 2, B2, C, 10, 1), COLORRED;\n\
STICKLINE(SS == -2, B2, C, 10, 0), COLORCYAN;\n\
STICKLINE((SS == -1 OR SS == -2) AND SM > 0, B2, B1, 10, 1), COLORRED;\n\
STICKLINE((SS == 1 OR SS == 2) AND SM < 0, B2, B1, 10, 0), COLORCYAN;'
};
return data;
}
JSIndexScript.prototype.AMO = function ()
{
let data =
{
Name: 'AMO', Description: '成交金额', IsMainIndex: false, StringFormat:2, YAxis:{ FloatPrecision:0, StringFormat:2 },
Args: [{ Name: 'M1', Value: 5 },{ Name: 'M2', Value: 10 }],
Script: //脚本
'AMOW:AMOUNT/10000.0,VOLSTICK;\n\
AMO1:MA(AMOW,M1);\n\
AMO2:MA(AMOW,M2);'
};
return data;
}
JSIndexScript.prototype.VRSI = function ()
{
let data =
{
Name: 'VRSI', Description: '相对强弱量', IsMainIndex: false,
Args: [{ Name: 'N1', Value: 6 },{ Name: 'N2', Value: 12 },{ Name: 'N3', Value: 24 }],
Script: //脚本
'LC:=REF(VOL,1);\n\
RSI1:SMA(MAX(VOL-LC,0),N1,1)/SMA(ABS(VOL-LC),N1,1)*100;\n\
RSI2:SMA(MAX(VOL-LC,0),N2,1)/SMA(ABS(VOL-LC),N2,1)*100;\n\
RSI3:SMA(MAX(VOL-LC,0),N3,1)/SMA(ABS(VOL-LC),N3,1)*100;'
};
return data;
}
JSIndexScript.prototype.HSCOL = function ()
{
let data =
{
Name: 'HSCOL', Description: '换手柱', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'HSCOL:IF((SETCODE==0||SETCODE==1),100*VOL,VOL)/(FINANCE(7)/100),VOLSTICK;\n\
MAHSL:MA(HSCOL,N);'
};
return data;
}
JSIndexScript.prototype.DBQRV = function ()
{
let data =
{
Name: 'DBQRV', Description: '对比强弱量(需下载日线)', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'ZS:(INDEXV-REF(INDEXV,N))/REF(INDEXV,N);\n\
GG:(VOL-REF(VOL,N))/REF(VOL,N);'
};
return data;
}
JSIndexScript.prototype.DBLB = function ()
{
let data =
{
Name: 'DBLB', Description: '对比量比(需下载日线)', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 },{ Name: 'M', Value: 5 }],
Script: //脚本
'GG:=VOL/SUM(REF(VOL,1),N);\n\
ZS:=INDEXV/SUM(REF(INDEXV,1),N);\n\
DBLB:GG/ZS;\n\
MADBLB:MA(DBLB,M);'
};
return data;
}
JSIndexScript.prototype.ACD = function ()
{
let data =
{
Name: 'ACD', Description: '升降线', IsMainIndex: false,
Args: [{ Name: 'M', Value: 20 }],
Script: //脚本
'LC:=REF(CLOSE,1);\n\
DIF:=CLOSE-IF(CLOSE>LC,MIN(LOW,LC),MAX(HIGH,LC));\n\
ACD:SUM(IF(CLOSE==LC,0,DIF),0);\n\
MAACD:EXPMEMA(ACD,M);'
};
return data;
}
JSIndexScript.prototype.EXPMA = function ()
{
let data =
{
Name: 'EXPMA', Description: '指数平均线', IsMainIndex: true,
Args: [{ Name: 'M1', Value: 12 },{ Name: 'M2', Value: 50 }],
Script: //脚本
'EXP1:EMA(CLOSE,M1);\n\
EXP2:EMA(CLOSE,M2);'
};
return data;
}
JSIndexScript.prototype.EXPMA_S = function ()
{
let data =
{
Name: 'EXPMA_S', Description: '指数平均线-副图', IsMainIndex: false,
Args: [{ Name: 'M1', Value: 12 },{ Name: 'M2', Value: 50 }],
Script: //脚本
'EXP1:EMA(CLOSE,M1);\n\
EXP2:EMA(CLOSE,M2);'
};
return data;
}
JSIndexScript.prototype.HMA = function ()
{
let data =
{
Name: 'HMA', Description: '高价平均线', IsMainIndex: true,
Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }],
Script: //脚本
'HMA1:MA(HIGH,M1);\n\
HMA2:MA(HIGH,M2);\n\
HMA3:MA(HIGH,M3);\n\
HMA4:MA(HIGH,M4);\n\
HMA5:MA(HIGH,M5);'
};
return data;
}
JSIndexScript.prototype.LMA = function ()
{
let data =
{
Name: 'LMA', Description: '低价平均线', IsMainIndex: true,
Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }],
Script: //脚本
'LMA1:MA(LOW,M1);\n\
LMA2:MA(LOW,M2);\n\
LMA3:MA(LOW,M3);\n\
LMA4:MA(LOW,M4);\n\
LMA5:MA(LOW,M5);'
};
return data;
}
JSIndexScript.prototype.VMA = function ()
{
let data =
{
Name: 'VMA', Description: '变异平均线', IsMainIndex: true,
Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }],
Script: //脚本
'VV:=(HIGH+OPEN+LOW+CLOSE)/4;\n\
VMA1:MA(VV,M1);\n\
VMA2:MA(VV,M2);\n\
VMA3:MA(VV,M3);\n\
VMA4:MA(VV,M4);\n\
VMA5:MA(VV,M5);'
};
return data;
}
JSIndexScript.prototype.AMV = function ()
{
let data =
{
Name: 'AMV', Description: '成本价均线', IsMainIndex: false,
Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }],
Script: //脚本
'AMOV:=VOL*(OPEN+CLOSE)/2;\n\
AMV1:SUM(AMOV,M1)/SUM(VOL,M1);\n\
AMV2:SUM(AMOV,M2)/SUM(VOL,M2);\n\
AMV3:SUM(AMOV,M3)/SUM(VOL,M3);\n\
AMV4:SUM(AMOV,M4)/SUM(VOL,M4);'
};
return data;
}
JSIndexScript.prototype.BBIBOLL = function ()
{
let data =
{
Name: 'BBIBOLL', Description: '多空布林线', IsMainIndex: true,
Args: [{ Name: 'N', Value: 11 },{ Name: 'M', Value: 6 }],
Script: //脚本
'CV:=CLOSE;\n\
BBIBOLL:(MA(CV,3)+MA(CV,6)+MA(CV,12)+MA(CV,24))/4;\n\
UPR:BBIBOLL+M*STD(BBIBOLL,N);\n\
DWN:BBIBOLL-M*STD(BBIBOLL,N);'
};
return data;
}
JSIndexScript.prototype.ALLIGAT = function ()
{
let data =
{
Name: 'ALLIGAT', Description: '鳄鱼线', IsMainIndex: true,
Args: [],
Script: //脚本
'NN:=(H+L)/2;\n\
上唇:REF(MA(NN,5),3),COLOR40FF40;\n\
牙齿:REF(MA(NN,8),5),COLOR0000C0;\n\
下颚:REF(MA(NN,13),8),COLORFF4040;'
};
return data;
}
JSIndexScript.prototype.ZX = function ()
{
let data =
{
Name: 'ZX', Description: '重心线', IsMainIndex: false,
Args: [],
Script: //脚本
'AV:0.01*AMOUNT/VOL;'
};
return data;
}
JSIndexScript.prototype.XS = function ()
{
let data =
{
Name: 'XS', Description: '薛斯通道', IsMainIndex: true,
Args: [{ Name: 'N', Value: 13 }],
Script: //脚本
'VAR2:=CLOSE*VOL;\n\
VAR3:=EMA((EMA(VAR2,3)/EMA(VOL,3)+EMA(VAR2,6)/EMA(VOL,6)+EMA(VAR2,12)/EMA(VOL,12)+EMA(VAR2,24)/EMA(VOL,24))/4,N);\n\
SUP:1.06*VAR3;\n\
SDN:VAR3*0.94;\n\
VAR4:=EMA(CLOSE,9);\n\
LUP:EMA(VAR4*1.14,5);\n\
LDN:EMA(VAR4*0.86,5);'
};
return data;
}
JSIndexScript.prototype.XS2 = function ()
{
let data =
{
Name: 'XS2', Description: '薛斯通道II', IsMainIndex: true,
Args: [{ Name: 'N', Value: 102 },{ Name: 'M', Value: 7 }],
Script: //脚本
'AA:=MA((2*CLOSE+HIGH+LOW)/4,5); \n\
通道1:AA*N/100; \n\
通道2:AA*(200-N)/100; \n\
CC:=ABS((2*CLOSE+HIGH+LOW)/4-MA(CLOSE,20))/MA(CLOSE,20); \n\
DD:=DMA(CLOSE,CC); \n\
通道3:(1+M/100)*DD; \n\
通道4:(1-M/100)*DD;'
};
return data;
}
JSIndexScript.prototype.SG_XDT = function ()
{
let data =
{
Name: 'SG-XDT', Description: '心电图(需下载日线)', IsMainIndex: false,
Args: [{ Name: 'P1', Value: 5 },{ Name: 'P2', Value: 10 }],
Script: //脚本
'QR:CLOSE/INDEXC*1000;\n\
MQR1:MA(QR,5);\n\
MQR2:MA(QR,10);'
};
return data;
}
JSIndexScript.prototype.SG_SMX = function ()
{
let data =
{
Name: 'SG-SMX', Description: '生命线(需下载日线)', IsMainIndex: false,
Args: [{ Name: 'N', Value: 50 }],
Script: //脚本
'H1:=HHV(HIGH,N);\n\
L1:=LLV(LOW,N);\n\
H2:=HHV(INDEXH,N);\n\
L2:=LLV(INDEXL,N);\n\
ZY:=CLOSE/INDEXC*2000;\n\
ZY1:EMA(ZY,3);\n\
ZY2:EMA(ZY,17);\n\
ZY3:EMA(ZY,34);'
};
return data;
}
JSIndexScript.prototype.SG_LB = function ()
{
let data =
{
Name: 'SG-LB', Description: '量比(需下载日线)', IsMainIndex: false,
Args: [],
Script: //脚本
'ZY2:=VOL/INDEXV*1000;\n\
量比:ZY2;\n\
MA5:MA(ZY2,5);\n\
MA10:MA(ZY2,10);'
};
return data;
}
JSIndexScript.prototype.SG_PF = function ()
{
let data =
{
Name: 'SG-PF', Description: '强势股评分(需下载日线)', IsMainIndex: false,
Args: [],
Script: //脚本
'ZY1:=CLOSE/INDEXC*1000;\n\
A1:=IF(ZY1>HHV(ZY1,3),10,0);\n\
A2:=IF(ZY1>HHV(ZY1,5),15,0);\n\
A3:=IF(ZY1>HHV(ZY1,10),20,0);\n\
A4:=IF(ZY1>HHV(ZY1,2),10,0);\n\
A5:=COUNT(ZY1>REF(ZY1,1) ,9)*5;\n\
强势股评分:A1+A2+A3+A4+A5;'
};
return data;
}
JSIndexScript.prototype.RAD = function ()
{
let data =
{
Name: 'RAD', Description: '威力雷达(需下载日线)', IsMainIndex: false,
Args: [{ Name: 'D', Value: 3 },{ Name: 'S', Value: 30 },{ Name: 'M', Value: 30 }],
Script: //脚本
'SM:=(OPEN+HIGH+CLOSE+LOW)/4;\n\
SMID:=MA(SM,D);\n\
IM:=(INDEXO+INDEXH+INDEXL+INDEXC)/4;\n\
IMID:=MA(IM,D);\n\
SI1:=(SMID-REF(SMID,1))/SMID;\n\
II:=(IMID-REF(IMID,1))/IMID;\n\
RADER1:SUM((SI1-II)*2,S)*1000;\n\
RADERMA:SMA(RADER1,M,1);'
};
return data;
}
JSIndexScript.prototype.SHT = function ()
{
let data =
{
Name: 'SHT', Description: '龙系短线', IsMainIndex: false,
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'VAR1:=MA((VOL-REF(VOL,1))/REF(VOL,1),5);\n\
VAR2:=(CLOSE-MA(CLOSE,24))/MA(CLOSE,24)*100;\n\
MY: VAR2*(1+VAR1);\n\
SHT: MY, COLORSTICK;\n\
SHTMA: MA(SHT,N);'
};
return data;
}
JSIndexScript.prototype.ZLJC = function ()
{
let data =
{
Name: 'ZLJC', Description: '主力进出', IsMainIndex: false,
Args: [],
Script: //脚本
'VAR1:=(CLOSE+LOW+HIGH)/3; \n\
VAR2:=SUM(((VAR1-REF(LOW,1))-(HIGH-VAR1))*VOL/100000/(HIGH-LOW),0); \n\
VAR3:=EMA(VAR2,1); \n\
JCS:VAR3; \n\
JCM:MA(VAR3,12); \n\
JCL:MA(VAR3,26);'
};
return data;
}
JSIndexScript.prototype.ZLMM = function ()
{
let data =
{
Name: 'ZLMM', Description: '主力买卖', IsMainIndex: false,
Args: [],
Script: //脚本
'LC :=REF(CLOSE,1);\n\
RSI2:=SMA(MAX(CLOSE-LC,0),12,1)/SMA(ABS(CLOSE-LC),12,1)*100;\n\
RSI3:=SMA(MAX(CLOSE-LC,0),18,1)/SMA(ABS(CLOSE-LC),18,1)*100;\n\
MMS:MA(3*RSI2-2*SMA(MAX(CLOSE-LC,0),16,1)/SMA(ABS(CLOSE-LC),16,1)*100,3);\n\
MMM:EMA(MMS,8);\n\
MML:MA(3*RSI3-2*SMA(MAX(CLOSE-LC,0),12,1)/SMA(ABS(CLOSE-LC),12,1)*100,5);'
};
return data;
}
JSIndexScript.prototype.SLZT = function ()
{
let data =
{
Name: 'SLZT', Description: '神龙在天', IsMainIndex: false,
Args: [],
Script: //脚本
'白龙: MA(CLOSE,125);\n\
黄龙: 白龙+2*STD(CLOSE,170);\n\
紫龙: 白龙-2*STD(CLOSE,145);\n\
青龙: SAR(125,1,7), LINESTICK;\n\
VAR2:=HHV(HIGH,70);\n\
VAR3:=HHV(HIGH,20);\n\
红龙: VAR2*0.83;\n\
蓝龙: VAR3*0.91;'
};
return data;
}
JSIndexScript.prototype.ADVOL = function ()
{
let data =
{
Name: 'ADVOL', Description: '龙系离散量', IsMainIndex: false,
Args: [],
Script: //脚本
'A:=SUM(((CLOSE-LOW)-(HIGH-CLOSE))*VOL/10000/(HIGH-LOW),0);\n\
ADVOL:A;\n\
MA1:MA(A,30);\n\
MA2:MA(MA1,100);'
};
return data;
}
JSIndexScript.prototype.CYC = function ()
{
let data =
{
Name: 'CYC', Description: '成本均线', IsMainIndex: true,
Args: [{ Name: 'P1', Value: 5 },{ Name: 'P2', Value: 13 },{ Name: 'P3', Value: 34 }],
Script: //脚本
'JJJ:=IF(DYNAINFO(8)>0.01,0.01*DYNAINFO(10)/DYNAINFO(8),DYNAINFO(3));\n\
DDD:=(DYNAINFO(5)<0.01 || DYNAINFO(6)<0.01);\n\
JJJT:=IF(DDD,1,(JJJ<(DYNAINFO(5)+0.01) && JJJ>(DYNAINFO(6)-0.01)));\n\
CYC1:IF(JJJT,0.01*EMA(AMOUNT,P1)/EMA(VOL,P1),EMA((HIGH+LOW+CLOSE)/3,P1));\n\
CYC2:IF(JJJT,0.01*EMA(AMOUNT,P2)/EMA(VOL,P2),EMA((HIGH+LOW+CLOSE)/3,P2));\n\
CYC3:IF(JJJT,0.01*EMA(AMOUNT,P3)/EMA(VOL,P3),EMA((HIGH+LOW+CLOSE)/3,P3));\n\
CYC4:IF(JJJT,DMA(AMOUNT/(100*VOL),100*VOL/FINANCE(7)),EMA((HIGH+LOW+CLOSE)/3,120));'
};
return data;
}
JSIndexScript.prototype.CYS = function ()
{
let data =
{
Name: 'CYS', Description: '市场盈亏', IsMainIndex: false,
Args: [],
Script: //脚本
'CYC13:EMA(AMOUNT,13)/EMA(VOL,13);\n\
CYS:(CLOSE-CYC13)/CYC13*100;'
};
return data;
}
JSIndexScript.prototype.CYQKL = function ()
{
let data =
{
Name: 'CYQKL', Description: '博弈K线长度', IsMainIndex: false,
Args: [],
Script: //脚本
'KL:100*(WINNER(CLOSE)-WINNER(OPEN));'
};
return data;
}
JSIndexScript.prototype.SCR = function ()
{
let data =
{
Name: 'SCR', Description: '筹码集中度', IsMainIndex: false,
Args: [{ Name: 'P1', Value: 90 }],
Script: //脚本
'A:=P1+(100-P1)/2;\n\
B:=(100-P1)/2;\n\
CC:=COST(A);\n\
DD:=COST(B);\n\
SCR:(CC-DD)/(CC+DD)*100/2;'
};
return data;
}
JSIndexScript.prototype.ASR = function ()
{
let data =
{
Name: 'ASR', Description: '浮筹比例', IsMainIndex: false,
Args: [],
Script: //脚本
'ASR:(WINNER(C*1.1)-WINNER(C*0.9))/WINNER(HHV(H,0))*100;'
};
return data;
}
JSIndexScript.prototype.SAR = function ()
{
let data =
{
Name: 'SAR', Description: '抛物转向', IsMainIndex: true,
Args: [{ Name: 'P', Value: 10 },{ Name: 'STEP', Value: 2 },{ Name: 'MAXP', Value: 20 }],
Script: //脚本
'S:SAR(P,STEP,MAXP),UPDOWNDOT;'
};
return data;
}
JSIndexScript.prototype.TJCJL = function ()
{
let data =
{
Name: '太极成交量', Description: '太极成交量', IsMainIndex: true,
Args: [],
Script: //脚本
'总手:VOL,NODRAW;\n\
DRAWTEXT_FIX(ISLASTBAR,0,0,0,"说明: 红色柱为吸货量,绿色为出货量,黄色为天量,蓝色为地量"),COLORGRAY;\n\
ZZ:=IF(REF(C,1)>REF(O,1) AND O>REF(C,1)*1.014 AND C<O*1.02,1,3);\n\
V5:=MA(V,5);\n\
V12:=MA(V,12);\n\
V34:=MA(V,34);\n\
C6:=MA(C,6);\n\
STICKLINE(VOL,0,VOL,3,0),COLORLIGRAY;\n\
STICKLINE(CROSS(C,C6) AND V>V5*1.2 AND V>V12*1.2 AND ZZ>2 AND C>H*0.975,0,VOL,3,0),COLORRED;\n\
STICKLINE(CROSS(C6,C) AND V>V5*1.2 AND V>V12*1.2,0,VOL,3,0),COLORGREEN;\n\
STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND C<REF(C,1)*1.05,0,VOL,3,0),COLORYELLOW;\n\
STICKLINE(VOL<MA(VOL,5)/2 AND V<V12/2,0,VOL,3,0),COLORBLUE;\n\
STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND C<REF(C,1)*1.05 AND CROSS(C,C6) AND V>V5*1.2 AND V>V12*1.2 AND ZZ>2 AND C>H*0.975,VOL*0.5,0,3,0),COLORRED;\n\
STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND C<REF(C,1)*1.05 AND CROSS(C6,C) AND V>V5*1.2 AND V>V12*1.2,VOL*0.5,0,3,0),COLORRED;'
};
return data;
}
/*
飞龙四式-主图
*/
JSIndexScript.prototype.Dragon4_Main = function ()
{
let data =
{
Name: '飞龙四式', Description: '飞龙四式', IsMainIndex: true,
Args: [{ Name: 'N1', Value: 5 }, { Name: 'N2', Value: 10 }, { Name: 'N3', Value: 50 }, { Name: 'N4', Value: 60 }],
Script: //脚本
'蜻蜓点水:=EMA(CLOSE,N1),COLORGRAY;\n\
魔界:=EMA(CLOSE,N2),COLORGREEN;\n\
水:=EMA(CLOSE,N3),COLORRED;\n\
DRAWKLINE(HIGH,OPEN,LOW,CLOSE);\n\
生命线:MA(CLOSE,N4),COLORBLUE,LINETHICK2;\n\
DRAWBAND(魔界,\'RGB(186,225,250)\',水,\'RGB(253,194,124)\');\n\
DRAWBAND(蜻蜓点水,\'RGB(128,138,135)\',魔界,\'RGB(0,0,255)\');'
};
return data;
}
JSIndexScript.prototype.Dragon4_Fig=function()
{
let data =
{
Name: '飞龙四式', Description: '飞龙四式', IsMainIndex: false,
Args: [],
Script: //脚本
'倍:VOL>=REF(V,1)*1.90 AND C>REF(C,1),COLORYELLOW;\n\
低:VOL<REF(LLV(VOL,13),1),COLORGREEN;\n\
地:VOL<REF(LLV(VOL,100),1),COLORMAGENTA; \n\
平:=ABS(VOL-HHV(REF(VOL,1),5))/HHV(REF(VOL,1),5)<=0.03 OR ABS(VOL-REF(VOL,1))/REF(VOL,1)<=0.03,NODRAW,COLORWHITE;\n\
倍缩:VOL<=REF(V,1)*0.5,COLORFF8000;\n\
梯量:COUNT(V>REF(V,1),3)==3 AND COUNT(C>O,3)==3,COLORBROWN;\n\
缩量涨:COUNT(C>REF(C,1),2)==2 AND COUNT(V<REF(V,1),2)==2,COLORBLUE;\n\
STICKLINE(C>=REF(C,1),V,0,2,0),COLORRED;\n\
STICKLINE(C<REF(C,1),V,0,2,0),COLORGREEN;\n\
STICKLINE(倍,0,V,2,0),COLORYELLOW;\n\
STICKLINE(低,0,V,2,0),COLORGREEN;\n\
STICKLINE(地,0,V,2,0),COLORLIMAGENTA;\n\
STICKLINE(平,0,V,2,0),COLORGRAY;\n\
STICKLINE(倍缩,0,V,2,0),COLORFF8000;\n\
STICKLINE(梯量,0,V,2,0),COLORBROWN;\n\
STICKLINE(缩量涨,0,V,2,0),COLORBLUE;'
};
return data;
}
/*
能图-资金分析
M:=55;
N:=34;
LC:=REF(CLOSE,1);
RSI:=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);
FF:=EMA(CLOSE,3);
MA15:=EMA(CLOSE,21); DRAWTEXT(CROSS(85,RSI),75,'▼'),COLORGREEN;
VAR1:=IF(YEAR>=2038 AND MONTH>=1,0,1);
VAR2:=REF(LOW,1)*VAR1;
VAR3:=SMA(ABS(LOW-VAR2),3,1)/SMA(MAX(LOW-VAR2,0),3,1)*100*VAR1;
VAR4:=EMA(IF(CLOSE*1.3,VAR3*10,VAR3/10),3)*VAR1;
VAR5:=LLV(LOW,30)*VAR1;
VAR6:=HHV(VAR4,30)*VAR1;
VAR7:=IF(MA(CLOSE,58),1,0)*VAR1;
VAR8:=EMA(IF(LOW<=VAR5,(VAR4+VAR6*2)/2,0),3)/618*VAR7*VAR1;
吸筹A:IF(VAR8>100,100,VAR8)*VAR1,COLORRED;
吸筹B:STICKLINE(吸筹A>-150,0,吸筹A,8,0),COLORRED;
散户线: 100*(HHV(HIGH,M)-CLOSE)/(HHV(HIGH,M)-LLV(LOW,M)),COLORFFFF00,LINETHICK2;
RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;
K:=SMA(RSV,3,1);
D:=SMA(K,3,1);
J:=3*K-2*D;
主力线:EMA(J,5),COLORFF00FF,LINETHICK2;
DRAWICON(CROSS(主力线,散户线),主力线,1);
DRAWICON(CROSS(散户线,主力线),主力线,2);
*/
JSIndexScript.prototype.FundsAnalysis=function()
{
let data =
{
Name: '资金分析', Description: '资金分析', IsMainIndex: false,
Args: [{ Name: 'M', Value: 55 }, { Name: 'N', Value: 34 }],
Script: //脚本
'LC:=REF(CLOSE,1);\n\
RSI:=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);\n\
FF:=EMA(CLOSE,3);\n\
MA15:=EMA(CLOSE,21); DRAWTEXT(CROSS(85,RSI),75,\'▼\'),COLORGREEN;\n\
VAR1:=IF(YEAR>=2038 AND MONTH>=1,0,1);\n\
VAR2:=REF(LOW,1)*VAR1;\n\
VAR3:=SMA(ABS(LOW-VAR2),3,1)/SMA(MAX(LOW-VAR2,0),3,1)*100*VAR1;\n\
VAR4:=EMA(IF(CLOSE*1.3,VAR3*10,VAR3/10),3)*VAR1;\n\
VAR5:=LLV(LOW,30)*VAR1;\n\
VAR6:=HHV(VAR4,30)*VAR1;\n\
VAR7:=IF(MA(CLOSE,58),1,0)*VAR1;\n\
VAR8:=EMA(IF(LOW<=VAR5,(VAR4+VAR6*2)/2,0),3)/618*VAR7*VAR1;\n\
吸筹A:IF(VAR8>100,100,VAR8)*VAR1,COLORFB2F3B;\n\
{吸筹B}STICKLINE(吸筹A>-150,0,吸筹A,8,0),COLORFB2F3B;\n\
\n\
散户线: 100*(HHV(HIGH,M)-CLOSE)/(HHV(HIGH,M)-LLV(LOW,M)),COLORAA89BD,LINETHICK2;\n\
RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
K:=SMA(RSV,3,1);\n\
D:=SMA(K,3,1);\n\
J:=3*K-2*D;\n\
主力线:EMA(J,5),COLORF39800,LINETHICK2;\n\
DRAWICON(CROSS(主力线,散户线),主力线,1);\n\
DRAWICON(CROSS(散户线,主力线),主力线,2);'
};
return data;
}
JSIndexScript.prototype.MarginProportion=function()
{
let data =
{
Name: '融资占比(%)', Description: '融资占比', IsMainIndex: false,
Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] },
Args: [],
Script: //脚本
'占比:MARGIN(2);'
};
return data;
}
JSIndexScript.prototype.Margin2=function()
{
let data =
{
Name: '两融余额', Description: '融资融券余额', IsMainIndex: false,
Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] },
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'T1:MARGIN(1);\n\
T2:MA(MARGIN(1),N);'
};
return data;
}
JSIndexScript.prototype.Margin3=function()
{
let data =
{
Name: '两融余额', Description: '融资融券余额', IsMainIndex: false,
Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] },
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
'T1:=MARGIN(1);\n\
T2:=MA(MARGIN(1),N);\n\
STICKLINE(T1-T2>=0,0,T1-T2,50,T1>T2),COLORRED;\n\
STICKLINE(T1-T2<0,T1-T2,0,50,T1>T2),COLORGREEN;'
};
return data;
}
JSIndexScript.prototype.FXG_BSPoint=function()
{
let data =
{
Name: '操盘BS点', Description: '操盘BS点', IsMainIndex: true,
Args: [],
Script: //脚本
'MA5:MA(CLOSE,5);\n\
MA13:MA(CLOSE,13);\n\
MA21:MA(CLOSE,21);\n\
MA34:MA(CLOSE,34);\n\
{MA55:MA(CLOSE,55),COLOR0000FF;}\n\
{MA120:=MA(CLOSE,120),COLORFFFF00;}\n\
天使:=EMA(C,2),COLOR000000;\n\
魔鬼:=EMA(SLOPE(C,21)*20+C,42),COLOR000000;\n\
买:=CROSS(天使,魔鬼);\n\
卖:=CROSS(魔鬼,天使);\n\
DRAWICON(买,L*0.97,13);\n\
DRAWICON(卖,H*1.03,14);\n\
DRAWKLINE_IF(天使>=魔鬼,HIGH,CLOSE,LOW,OPEN),COLORRED;\n\
DRAWKLINE_IF(天使<魔鬼,HIGH,CLOSE,LOW,OPEN),COLORBLUE;\n\
DRAWKLINE_IF(CROSS(天使,魔鬼),HIGH,CLOSE,LOW,OPEN),COLORYELLOW;\n\
DRAWKLINE_IF(CROSS(魔鬼,天使),HIGH,CLOSE,LOW,OPEN),COLORBLACK;'
};
return data;
}
JSIndexScript.prototype.FXG_INDEX=function()
{
let data =
{
Name: '涨停多空线', Description: '涨停多空线', IsMainIndex: false,
Args: [],
Script: //脚本
'做多能量线: SMA((CLOSE-LLV(LOW,9))/(HHV(HIGH,9)-LLV(LOW,9))*100,5,1)-8,COLORRED,LINETHICK3;\n\
做空能量线: SMA((HHV(HIGH,36)-CLOSE)/(HHV(HIGH,36)-LLV(LOW,36))*100,2,1),COLORGREEN,LINETHICK3;\n\
20,POINTDOT,COLORF00FF0;\n\
50,POINTDOT,COLORGREEN;\n\
80,POINTDOT,COLORLIBLUE;'
};
return data;
}
JSIndexScript.prototype.FXG_INDEX2=function()
{
let data =
{
Name: '涨停吸筹区', Description: '涨停吸筹区', IsMainIndex: false,
Args: [],
Script: //脚本
'VAR0:=EMA(HHV(HIGH,500),21); \n\
VAR1:=EMA(HHV(HIGH,250),21);\n\
VAR2:=EMA(HHV(HIGH,90),21); \n\
VAR3:=EMA(LLV(LOW,500),21); \n\
VAR4:=EMA(LLV(LOW,250),21); \n\
VAR5:=EMA(LLV(LOW,90),21);\n\
\n\
VAR6:=EMA((VAR3*0.96+VAR4*0.96+VAR5*0.96+VAR0*0.558+VAR1*0.558+VAR2*0.558)/6,21); \n\
VAR7:=EMA((VAR3*1.25+VAR4*1.23+VAR5*1.2+VAR0*0.55+VAR1*0.55+VAR2*0.65)/6,21); \n\
VAR8:=EMA((VAR3*1.3+VAR4*1.3+VAR5*1.3+VAR0*0.68+VAR1*0.68+VAR2*0.68)/6,21); \n\
VAR9:=EMA((VAR6*3+VAR7*2+VAR8)/6*1.738,21); \n\
VAR10:=REF(LOW,1); \n\
VAR11:=SMA(ABS(LOW-VAR10),3,1)/SMA(MAX(LOW-VAR10,0),3,1)*100; \n\
VAR12:=EMA(IFF(CLOSE*1.35<=VAR9,VAR11*10,VAR11/10),3); \n\
VAR13:=LLV(LOW,30); \n\
VAR14:=HHV(VAR12,30); \n\
VAR15:=IFF(MA(CLOSE,58),1,0); \n\
VAR16:=EMA(IFF(LOW<=VAR13,(VAR12+VAR14*2)/2,0),3)/618*VAR15;\n\
\n\
资金入场:IFF(VAR16>0,VAR16,0),LINETHICK,LINETHICK2, COLORFF0000; \n\
\n\
A1:IFF(资金入场>0,资金入场*1.2,0),STICK,LINETHICK5, COLORFF0000;\n\
A2:IFF(资金入场>0,资金入场*0.8,0),STICK,LINETHICK5, COLORFF6600;\n\
A3:IFF(资金入场>0,资金入场*0.6,0),STICK,LINETHICK5, COLORFF9900;\n\
A4:IFF(资金入场>0,资金入场*0.4,0) ,STICK,LINETHICK5,COLORFFCC00;\n\
A5:IFF(资金入场>0,资金入场*0.2,0) ,STICK,LINETHICK5,COLORFFFF00;'
};
return data;
}
JSIndexScript.prototype.FXG_INDEX3=function()
{
let data =
{
Name: '量能黄金点', Description: '量能黄金点', IsMainIndex: false,FloatPrecision:0,
Args: [],
Script: //脚本
'A:=IFF((CLOSE>126.32),VOL,VOL); \n\
主力:=MA(A,4),COLORRED;\n\
游资:=MA(A,8),COLORYELLOW;\n\
大户:=MA(A,16),COLORF0F000;\n\
散户:=MA(A,32),COLOR00FF00;\n\
主比:=ABS(((主力)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORRED;\n\
游比:=ABS(((游资)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORYELLOW;\n\
大比:=ABS(((大户)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORF0F000;\n\
散比:=ABS(((散户)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLOR00FF00;\n\
警戒线:MA(A,180),COLORFF66FF;\n\
STICKLINE((主力 > 0),0,主力,2.5,0),COLOR1020BB;\n\
STICKLINE((主力 > 0),0,主力,0.7,0),COLORRED;\n\
STICKLINE((游资 > 0),0,游资,2.5,0),COLOR009CFF;\n\
STICKLINE((游资 > 0),0,游资,0.7,0),COLORYELLOW;\n\
STICKLINE((大户 > 0),0,大户,2.5,0),COLORFF8800;\n\
STICKLINE((大户 > 0),0,大户,0.7,0),COLORLIBLUE;\n\
STICKLINE((散户 > 0),0,散户,2.5,0),COLOR00CA00;\n\
STICKLINE((散户 > 0),0,散户,0.7,0),COLORGREEN;'
};
return data;
}
JSIndexScript.prototype.NewsNegative=function()
{
let data=
{
Name: '负面新闻', Description: '负面新闻统计', IsMainIndex: false,FloatPrecision:0,
Args: [{ Name: 'N', Value: 5 }, { Name: 'N2', Value: 10 }],
Script: //脚本
'负面:NEWS(1);\n\
MA1:MA(负面,N);\n\
MA2:MA(负面,N2);'
};
return data;
}
JSIndexScript.prototype.UpDownAnalyze=function()
{
let data=
{
Name: '涨跌趋势', Description: '涨跌趋势', IsMainIndex: false,FloatPrecision:0,
Condition: { Period:[CONDITION_PERIOD.MINUTE_ID, CONDITION_PERIOD.MULTIDAY_MINUTE_ID, CONDITION_PERIOD.KLINE_DAY_ID] },
Args: [],
Script: //脚本
"上涨家数:UPCOUNT('CNA.CI'),COLORRED;\n\
下跌家数:DOWNCOUNT('CNA.CI'),COLORGREEN;"
};
return data;
}
JSIndexScript.prototype.HK2SHSZ=function()
{
let data=
{
Name: '北上资金', Description: '北上资金', IsMainIndex: false,FloatPrecision:0,
Condition: { Period:[CONDITION_PERIOD.MINUTE_ID,CONDITION_PERIOD.MULTIDAY_MINUTE_ID,CONDITION_PERIOD.KLINE_DAY_ID] },
Args: [],
Script: //脚本
"净流入:HK2SHSZ(1),COLORSTICK;"
};
return data;
}
JSIndexScript.prototype.ShareHolder=function()
{
let data=
{
Name: '股东人数', Description: '股东人数', IsMainIndex: false,FloatPrecision:0,
Condition: { Period:[
CONDITION_PERIOD.KLINE_DAY_ID,
CONDITION_PERIOD.KLINE_MONTH_ID,
CONDITION_PERIOD.KLINE_WEEK_ID,
CONDITION_PERIOD.KLINE_YEAR_ID] },
Args: [],
Script: //脚本
"人数:FINANCE(100);"
};
return data;
}
JSIndexScript.prototype.VOLRate=function()
{
let data=
{
Name: '量比', Description: '量比', IsMainIndex: false, Condition: { Period:[CONDITION_PERIOD.MINUTE_ID, CONDITION_PERIOD.MULTIDAY_MINUTE_ID ] },
Args: [],
Script: //脚本
"LIANGBI:VOLR;"
};
return data;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//五彩K线
JSIndexScript.prototype.COLOR_KSTAR1=function()
{
let data=
{
Name: '十字星', Description: '十字星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:CLOSE==OPEN&&HIGH>LOW;'
};
return data;
}
JSIndexScript.prototype.COLOR_KSTAR2=function()
{
let data=
{
Name: '早晨之星', Description: '早晨之星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:(REF(CLOSE,2)/REF(OPEN,2)<0.95) && (REF(OPEN,1) < REF(CLOSE,2)) && (ABS(REF(OPEN,1)-REF(CLOSE,1))/REF(CLOSE,1)<0.03) && CLOSE/OPEN>1.05 && CLOSE>REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_KSTAR3=function()
{
let data=
{
Name: '黄昏之星', Description: '黄昏之星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:REF(CLOSE,2)/REF(OPEN,2)>1.05 && REF(OPEN,1)>REF(CLOSE,2) && ABS(REF(OPEN,1)-REF(CLOSE,1))/REF(CLOSE,1)<0.03 && CLOSE/OPEN<0.95 && CLOSE<REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_SHI1=function()
{
let data=
{
Name: '长十字', Description: '长十字', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:CLOSE==OPEN&&HIGH/LOW>1.03;'
};
return data;
}
JSIndexScript.prototype.COLOR_K220=function()
{
let data=
{
Name: '身怀六甲', Description: '身怀六甲', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:ABS(REF(CLOSE,1)-REF(OPEN,1))/REF(CLOSE,1)>0.04&&\n\
ABS(CLOSE-OPEN)/CLOSE<0.005&&\n\
MAX(CLOSE,OPEN)<MAX(REF(CLOSE,1),REF(OPEN,1))&&\n\
MIN(CLOSE,OPEN)>MIN(REF(CLOSE,1),REF(OPEN,1));'
};
return data;
}
JSIndexScript.prototype.COLOR_K300=function()
{
let data=
{
Name: '三个白武士', Description: '三个白武士', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:UPNDAY(CLOSE,3)&&NDAY(CLOSE,OPEN,3);'
};
return data;
}
JSIndexScript.prototype.COLOR_K310=function()
{
let data=
{
Name: '三只乌鸦', Description: '三只乌鸦', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:DOWNNDAY(CLOSE,3)&&NDAY(OPEN,CLOSE,3);'
};
return data;
}
JSIndexScript.prototype.COLOR_K380=function()
{
let data=
{
Name: '光头阳线', Description: '光头阳线', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:HIGH==CLOSE&&HIGH>LOW;'
};
return data;
}
JSIndexScript.prototype.COLOR_K390=function()
{
let data=
{
Name: '光脚阴线', Description: '光脚阴线', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:LOW==CLOSE&&HIGH>LOW;'
};
return data;
}
JSIndexScript.prototype.COLOR_K134=function()
{
let data=
{
Name: '垂死十字', Description: '垂死十字', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:CLOSE==OPEN&&CLOSE==LOW&&CLOSE<HIGH;'
};
return data;
}
JSIndexScript.prototype.COLOR_K140=function()
{
let data=
{
Name: '早晨十字星', Description: '早晨十字星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:REF(CLOSE,2)/REF(OPEN,2)<0.95&&\n\
REF(OPEN,1)<REF(CLOSE,2)&&\n\
REF(OPEN,1)==REF(CLOSE,1)&&\n\
CLOSE/OPEN>1.05&&CLOSE>REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_K150=function()
{
let data=
{
Name: '黄昏十字星', Description: '黄昏十字星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:REF(CLOSE,2)/REF(OPEN,2)>1.05&&\n\
REF(OPEN,1)>REF(CLOSE,2)&&\n\
REF(OPEN,1)=REF(CLOSE,1)&&\n\
CLOSE/OPEN<0.95&&CLOSE<REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_K160=function()
{
let data=
{
Name: '射击之星', Description: '射击之星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:MIN(OPEN,CLOSE)==LOW&&\n\
HIGH-LOW>3*(MAX(OPEN,CLOSE)-LOW)&&\n\
CLOSE>MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K165=function()
{
let data=
{
Name: '倒转锤头', Description: '倒转锤头', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:MIN(OPEN,CLOSE)==LOW&&\n\
HIGH-LOW>3*(MAX(OPEN,CLOSE)-LOW)&&\n\
CLOSE<MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K170=function()
{
let data=
{
Name: '锤头', Description: '锤头', IsMainIndex: true, InstructionType:2,
Script: //脚本
'OUT:HIGH==MAX(OPEN,CLOSE)&&\n\
HIGH-LOW>3*(HIGH-MIN(OPEN,CLOSE))&&\n\
CLOSE<MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K180=function()
{
let data=
{
Name: '吊颈', Description: '吊颈', IsMainIndex: true, InstructionType:2,
Script: //脚本
'OUT:HIGH==MAX(OPEN,CLOSE)&&\n\
HIGH-LOW>3*(HIGH-MIN(OPEN,CLOSE))&&\n\
CLOSE>MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K190=function()
{
let data=
{
Name: '穿头破脚', Description: '穿头破脚', IsMainIndex: true, InstructionType:2,
Script: //脚本
'OUT:(REF(CLOSE,1)/REF(OPEN,1)>1.03&&\n\
CLOSE/OPEN<0.96&&\n\
CLOSE<REF(OPEN,1)&&OPEN>REF(CLOSE,1))||\n\
(REF(CLOSE,1)/REF(OPEN,1)<0.97&&\n\
CLOSE/OPEN>1.04&&\n\
CLOSE>REF(OPEN,1)&&OPEN<REF(CLOSE,1));'
};
return data;
}
JSIndexScript.prototype.COLOR_SWORD=function()
{
let data=
{
Name: '剑', Description: '剑', IsMainIndex: true, InstructionType:2,
Script: //脚本
'AA:=VOL>REF(VOL,1)||VOL>(CAPITAL*0.1);\n\
BB:=OPEN>=(REF(HIGH,1))&&REF(HIGH,1)>(REF(HIGH,2)*1.06);\n\
CC:=CLOSE>(REF(CLOSE,1))-(REF(CLOSE,1)*0.01);\n\
DD:=CLOSE<(HIGH*0.965) && HIGH>(OPEN*1.05);\n\
EE:=LOW<OPEN && LOW<CLOSE&&HIGH>(REF(CLOSE,1)*1.06);\n\
FF:=(HIGH-(MAX(OPEN,CLOSE)))/2>(MIN(OPEN,CLOSE))-LOW;\n\
GG:=(ABS(OPEN-CLOSE))/2<(MIN(OPEN,CLOSE)-LOW);\n\
SWORDO:AA&&BB&&CC&&DD&&EE&&FF&&GG;'
};
return data;
}
JSIndexScript.prototype.COLOR_CSFR=function()
{
let data=
{
Name: '出水芙蓉', Description: '出水芙蓉', IsMainIndex: true, InstructionType:2,
Script: //脚本
'A:=CLOSE>OPEN;\n\
B:=A&&CLOSE>MA(CLOSE,S)&&CLOSE>MA(CLOSE,M)&&CLOSE>MA(CLOSE,LL);\n\
CC:=B&&OPEN<MA(CLOSE,M)&&OPEN<MA(CLOSE,LL);\n\
CSFRO:CC&&(CLOSE-OPEN)>0.0618*CLOSE;'
};
return data;
}
JSIndexScript.prototype.COLOR_WYGD=function()
{
let data=
{
Name: '乌云盖顶', Description: '乌云盖顶', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,1)/REF(OPEN,1)>1.03 AND \n\
CLOSE/OPEN<0.97 AND \n\
OPEN>REF(CLOSE,1) AND CLOSE<REF(CLOSE,1), 3);'
};
return data;
}
JSIndexScript.prototype.COLOR_SGCJ=function()
{
let data=
{
Name: '曙光初现', Description: '曙光初现', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,1)/REF(OPEN,1)<0.97 AND \n\
CLOSE/OPEN>1.03 AND \n\
OPEN<REF(CLOSE,1) AND CLOSE>REF(CLOSE,1), 3);'
};
return data;
}
JSIndexScript.prototype.COLOR_SZTAI=function()
{
let data=
{
Name: '十字胎', Description: '十字胎', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( ABS(REF(CLOSE,1)-REF(OPEN,1))/REF(CLOSE,1) > 0.04 AND \n\
CLOSE==OPEN AND CLOSE < MAX(REF(CLOSE,1),REF(OPEN,1)) AND \n\
CLOSE > MIN(REF(CLOSE,1),REF(OPEN,1)), 2);'
};
return data;
}
JSIndexScript.prototype.COLOR_PINGDING=function()
{
let data=
{
Name: '平顶', Description: '平顶', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET(ABS(HIGH-REF(HIGH,1))/HIGH<0.001,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_PINGDI=function()
{
let data=
{
Name: '平底', Description: '平底', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET((ABS(LOW-REF(LOW,1))/LOW<0.001 AND \n\
ABS(REF(LOW,1)-REF(LOW,2))/REF(LOW,1)<=0.001),2);'
};
return data;
}
JSIndexScript.prototype.COLOR_DAYANZHU=function()
{
let data=
{
Name: '大阳烛', Description: '大阳烛', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:CLOSE/OPEN>1.05 AND HIGH/LOW < CLOSE/OPEN+0.018;'
};
return data;
}
JSIndexScript.prototype.COLOR_DAYINGZHU=function()
{
let data=
{
Name: '大阴烛', Description: '大阴烛', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:OPEN/CLOSE > 1.05 AND HIGH/LOW < OPEN/CLOSE+0.018;'
};
return data;
}
JSIndexScript.prototype.COLOR_HYFG=function()
{
let data=
{
Name: '好友反攻', Description: '好友反攻', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( (REF(CLOSE,1)<REF(OPEN,1) AND \n\
CLOSE>OPEN AND ABS(CLOSE-REF(CLOSE,1))/CLOSE<0.002),2);'
};
return data;
}
JSIndexScript.prototype.COLOR_TKQK=function()
{
let data=
{
Name: '跳空缺口', Description: '跳空缺口', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( HIGH<REF(LOW,1) OR LOW>REF(HIGH,1),2);'
};
return data;
}
JSIndexScript.prototype.COLOR_SFWY=function()
{
let data=
{
Name: '双飞乌鸦', Description: '双飞乌鸦', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( REF(CLOSE,1)<REF(OPEN,1) AND CLOSE<OPEN AND CLOSE/OPEN<0.98,1);'
};
return data;
}
JSIndexScript.prototype.COLOR_SSSBQ=function()
{
let data=
{
Name: '上升三部曲', Description: '上升三部曲', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,4)/REF(OPEN,4)>1.03 AND \n\
REF(CLOSE,3)<REF(OPEN,3) AND \n\
REF(CLOSE,2)<REF(OPEN,2) AND \n\
REF(CLOSE,1)<REF(OPEN,1) AND \n\
REF(LOW,4)<REF(LOW,3) AND \n\
REF(LOW,4)<REF(LOW,2) AND \n\
REF(LOW,4)<REF(LOW,1) AND \n\
REF(HIGH,4)>REF(HIGH,3) AND \n\
REF(HIGH,4)>REF(HIGH,2) AND \n\
REF(HIGH,4)>REF(HIGH,1) AND \n\
CLOSE/OPEN>1.03 AND \n\
CLOSE>REF(CLOSE,4), 5);'
};
return data;
}
JSIndexScript.prototype.COLOR_XDSBQ=function()
{
let data=
{
Name: '下跌三部曲', Description: '下跌三部曲', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,4)/REF(OPEN,4)<0.97 AND \n\
REF(CLOSE,3)>REF(OPEN,3) AND \n\
REF(CLOSE,2)>REF(OPEN,2) AND \n\
REF(CLOSE,1)>REF(OPEN,1) AND \n\
REF(LOW,4)<REF(LOW,3) AND \n\
REF(LOW,4)<REF(LOW,2) AND \n\
REF(LOW,4)<REF(LOW,1) AND \n\
REF(HIGH,4)>REF(HIGH,3) AND \n\
REF(HIGH,4)>REF(HIGH,2) AND \n\
REF(HIGH,4)>REF(HIGH,1) AND \n\
CLOSE/OPEN<0.97 AND \n\
CLOSE<REF(CLOSE,4), 5);'
};
return data;
}
JSIndexScript.prototype.COLOR_CHXY=function()
{
let data=
{
Name: '长下影', Description: '长下影', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR2:(MIN(CLOSE,OPEN)-LOW)/(HIGH-LOW)>0.667;'
};
return data;
}
JSIndexScript.prototype.COLOR_CHSY=function()
{
let data=
{
Name: '长上影', Description: '长上影', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR2:(HIGH-MAX(CLOSE,OPEN))/(HIGH-LOW)>0.667,COLORBLUE;'
};
return data;
}
JSIndexScript.prototype.COLOR_FENLI=function()
{
let data=
{
Name: '分离', Description: '分离', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( OPEN==REF(OPEN,1) AND (CLOSE-OPEN)*(REF(CLOSE,1)-REF(OPEN,1))<0,2);'
};
return data;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//交易系统
JSIndexScript.prototype.TRADE_BIAS = function ()
{
let data =
{
Name: 'BIAS', Description: '乖离率专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 12 }, { Name: 'LL', Value: 6 },{ Name: 'LH', Value: 6 }],
Script: //脚本
'BIAS:=(CLOSE-MA(CLOSE,N))/MA(CLOSE,N)*100;\n\
ENTERLONG:CROSS(-LL,BIAS);\n\
EXITLONG:CROSS(BIAS,LH);'
};
return data;
}
JSIndexScript.prototype.TRADE_CCI = function ()
{
let data =
{
Name: 'CCI', Description: 'CCI专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 14 }],
Script: //脚本
'TYP:=(HIGH+LOW+CLOSE)/3;\n\
CCI:=(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));\n\
INDEX:=CCI;\n\
ENTERLONG:CROSS(INDEX,-100);\n\
EXITLONG:CROSS(100,INDEX);'
};
return data;
}
JSIndexScript.prototype.TRADE_DMI = function ()
{
let data =
{
Name: 'DMI', Description: '趋向专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 14 }],
Script: //脚本
'MTR:=SUM(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(LOW-REF(CLOSE,1))),N);\n\
HD :=HIGH-REF(HIGH,1);\n\
LD :=REF(LOW,1)-LOW;\n\
PDM:=SUM(IF(HD>0&&HD>LD,HD,0),N);\n\
MDM:=SUM(IF(LD>0&&LD>HD,LD,0),N);\n\
PDI:=PDM*100/MTR;\n\
MDI:=MDM*100/MTR;\n\
ENTERLONG:CROSS(PDI,MDI);\n\
EXITLONG:CROSS(MDI,PDI);'
};
return data;
}
JSIndexScript.prototype.TRADE_KD = function ()
{
let data =
{
Name: 'KD', Description: 'KD指标专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }],
Script: //脚本
'WRSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
WK:=SMA(WRSV,M1,1);\n\
D:=SMA(WK,M2,1);\n\
ENTERLONG:CROSS(WK,D)&&WK<20;\n\
EXITLONG:CROSS(D,WK)&&WK>80;'
};
return data;
}
JSIndexScript.prototype.TRADE_BOLL = function ()
{
let data =
{
Name: 'BOLL', Description: '布林带专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 20 }],
Script: //脚本
'MID :=MA(CLOSE,N);\n\
UPPER:=MID+2*STD(CLOSE,N);\n\
LOWER:=MID-2*STD(CLOSE,N);\n\
ENTERLONG:CROSS(CLOSE,LOWER);\n\
EXITLONG:CROSS(CLOSE,UPPER);'
};
return data;
}
JSIndexScript.prototype.TRADE_KDJ = function ()
{
let data =
{
Name: 'KDJ', Description: 'KDJ专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 }],
Script: //脚本
'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
K:=SMA(RSV,M1,1);\n\
D:=SMA(K,M1,1);\n\
J:=3*K-2*D;\n\
ENTERLONG:CROSS(J,0);\n\
EXITLONG:CROSS(100,J);'
};
return data;
}
JSIndexScript.prototype.TRADE_MA = function ()
{
let data =
{
Name: 'MA', Description: '均线专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'SHORT', Value: 5 },{ Name: 'LONG', Value: 20 }],
Script: //脚本
'ENTERLONG:CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));\n\
EXITLONG:CROSS(MA(CLOSE,LONG),MA(CLOSE,SHORT));'
};
return data;
}
JSIndexScript.prototype.TRADE_MACD = function ()
{
let data =
{
Name: 'MACD', Description: 'MACD专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'LONG', Value: 26 }, { Name: 'SHORT', Value: 12 }, { Name: 'M', Value: 9 }],
Script: //脚本
'DIFF:=EMA(CLOSE,SHORT) - EMA(CLOSE,LONG);\n\
DEA := EMA(DIFF,M);\n\
MACD := 2*(DIFF-DEA);\n\
ENTERLONG:CROSS(MACD,0);\n\
EXITLONG:CROSS(0,MACD);'
};
return data;
}
JSIndexScript.prototype.TRADE_MTM = function ()
{
let data =
{
Name: 'MTM', Description: '动力指标专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 6 }],
Script: //脚本
'WMTM:=C-REF(C,N);\n\
ENTERLONG:CROSS(WMTM,0);\n\
EXITLONG:CROSS(0,WMTM);'
};
return data;
}
JSIndexScript.prototype.TRADE_PSY = function ()
{
let data =
{
Name: 'PSY', Description: 'PSY心理线专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 12 },{ Name: 'LL', Value: 10 },{ Name: 'LH', Value: 85 }],
Script: //脚本
'MYPSY:=COUNT(CLOSE>REF(CLOSE,1),N)/N*100;\n\
ENTERLONG:CROSS(LL,MYPSY);\n\
EXITLONG:CROSS(MYPSY,LH);'
};
return data;
}
JSIndexScript.prototype.TRADE_ROC = function ()
{
let data =
{
Name: 'ROC', Description: '变动速率专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 12 },{ Name: 'M', Value: 6 }],
Script: //脚本
'WROC:=MA(100*(CLOSE-REF(CLOSE,N))/REF(CLOSE,N),M);\n\
ENTERLONG:CROSS(WROC,0);\n\
EXITLONG:CROSS(0,WROC);'
};
return data;
}
JSIndexScript.prototype.TRADE_RSI = function ()
{
let data =
{
Name: 'RSI', Description: '相对强弱专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 6 },{ Name: 'LL', Value: 20 },{ Name: 'LH', Value: 80 }],
Script: //脚本
'LC:=REF(CLOSE,1);\n\
WRSI:=SMA(MAX(CLOSE-LC,0),N,1)/SMA(ABS(CLOSE-LC),N,1)*100;\n\
ENTERLONG:CROSS(WRSI,LL);\n\
EXITLONG:CROSS(LH,WRSI);'
};
return data;
}
JSIndexScript.prototype.TRADE_VR = function ()
{
let data =
{
Name: 'VR', Description: 'VR容量比率专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N', Value: 26 },{ Name: 'LL', Value: 70 },{ Name: 'LH', Value: 250 }],
Script: //脚本
'WVR := SUM((IF(CLOSE>OPEN,VOL,0)+IF(CLOSE=OPEN,VOL/2,0)),N)/SUM((IF(CLOSE<OPEN,VOL,0)+IF(CLOSE=OPEN,VOL/2,0)),N)*100;\n\
ENTERLONG:CROSS(LL,WVR);\n\
EXITLONG:CROSS(WVR,LH);'
};
return data;
}
JSIndexScript.prototype.TRADE_DPSJ = function ()
{
let data =
{
Name: 'DPSJ', Description: '大盘随机专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N1', Value: 18 },{ Name: 'N2', Value: 12 }],
Script: //脚本
'RSV:=(INDEXC-LLV(INDEXL,N1))/(HHV(INDEXH,N1)-LLV(INDEXL,N1))*100;\n\
K:=SMA(RSV,N2,1);\n\
HSL:VOL/100/(FINANCE(7));\n\
ENTERLONG: CROSS(K,20);\n\
EXITLONG: (CROSS(HSL,5) OR CROSS(K,80));'
};
return data;
}
JSIndexScript.prototype.HeikinAshi=function()
{
let data =
{
Name: '平均K线', Description: 'Heikin-Ashi 平均K线', IsMainIndex: true, KLineType:-1,
Args: [],
Script: //脚本
"HCLOSE:(OPEN+HIGH+LOW+CLOSE)/4, NODRAW;\n\
HOPEN:(REF(OPEN,1)+REF(CLOSE,1))/2,NODRAW;\n\
HHIGH:MAX(HIGH,MAX(HOPEN,HCLOSE)),NODRAW;\n\
HLOW:MIN(LOW,MIN(HOPEN,HCLOSE)),NODRAW;\n\
DRAWKLINE(HHIGH,HOPEN,HLOW,HCLOSE);"
}
return data;
}
JSIndexScript.prototype.ADL=function()
{
let data =
{
Name: '腾落指标', Description: '腾落指标', IsMainIndex: false, StringFormat:2,
Condition:
{
Period:[CONDITION_PERIOD.KLINE_DAY_ID, CONDITION_PERIOD.KLINE_WEEK_ID, CONDITION_PERIOD.KLINE_TWOWEEK_ID,
CONDITION_PERIOD.KLINE_MONTH_ID, CONDITION_PERIOD.KLINE_QUARTER_ID ,CONDITION_PERIOD.KLINE_YEAR_ID ],
Include:["000001.SH", "000003.SH", "000016.SH", "000300.SH", "000905.SH", "399001.SZ", " 399005.SZ", "399006.SZ"]
},
Args: [ { Name: 'M', Value: 7 } ],
Script: //脚本
"ADL:SUM(ADVANCE-DECLINE,0);\n\
MAADL:MA(ADL,M);"
}
return data;
}
JSIndexScript.prototype.EMPTY = function ()
{
let data =
{
Name: '', Description: '空指标', IsMainIndex: true,
Args: [],
Script: //脚本
'VAR2:=C;'
};
return data;
}
JSIndexScript.prototype.CJL = function ()
{
let data =
{
Name: 'CJL', Description: '期货持仓量', IsMainIndex: false,
Args: [],
Script: //脚本
"成交量:VOL,VOLSTICK;\n\
持仓量:VOLINSTK,LINEOVERLAY;"
};
return data;
}
JSIndexScript.prototype.VOL_POSITION=function()
{
let data =
{
Name: '持仓量', Description: '持仓量', IsMainIndex: false,
Args: [],
Script: //脚本
"成交量:VOL,VOLSTICK;\n\
持仓量:VOLINSTK,SINGLELINE;"
};
return data;
}
JSIndexScript.prototype.ASI = function ()
{
let data =
{
Name: 'ASI', Description: '振动升降指标', IsMainIndex: false,
Args: [{ Name: 'N1', Value: 6 }],
Script: //脚本
"X_1:=REF(CLOSE,1);\n\
X_2:=ABS(HIGH-X_1);\n\
X_3:=ABS(LOW-X_1);\n\
X_4:=ABS(HIGH-REF(LOW,1));\n\
X_5:=ABS(X_1-REF(OPEN,1));\n\
X_6:=IF(X_2>X_3 AND X_2>X_4,X_2+X_3/2+X_5/4,IF(X_3>X_4 AND X_3>X_2,X_3+X_2/2+X_5/4,X_4+X_5/4));\n\
X_7:=CLOSE-X_1+(CLOSE-OPEN)/2+X_1-REF(OPEN,1);\n\
X_8:=8*X_7/X_6*MAX(X_2,X_3);\n\
ASI:SUM(X_8,0),LINETHICK2;\n\
MASI:MA(ASI,N1),LINETHICK2;"
};
return data;
}
/*
History
The Donchian Channels (DC) indicator was created by the famous commodities trader Richard Donchian. Donchian would become known as The Father of Trend Following.
Calculation
For this example, a 20 day period is used which is a very commonly used timeframe.
Upper Channel = 20 Day High
Lower Channel = 20 Day Low
Middle Channel = (20 Day High + 20 Day Low)/2
*/
JSIndexScript.prototype.DC = function ()
{
let data =
{
Name: 'DC', Description: '唐奇安通道', IsMainIndex: true,
Args: [{ Name: 'N1', Value: 20 }],
Script: //脚本
"UPPER:HHV(H,N1),COLORBLUE,LINETHICK2;\n\
LOWER:LLV(L,N1),COLORBLUE,LINETHICK2;\n\
MIDDLE:(UPPER+LOWER)/2,COLORRED,LINETHICK3;"
};
return data;
}
/*
双重指数移动均线(DEMA)由Patrick Mulloy开发并于1994年2月在"股票与商品期货的技术分析"杂志中出版。
用于平滑价格系列并被直接应用到金融证券的价格图表中。此外,它还用于平滑其他指标的价值。
DEMA的优势是在锯齿状的价格移动中清除错误信号并允许趋势强劲时保持仓位。
计算
该指标基于指数移动平均线 (EMA). 从EMA值中查看价格偏差错误:
err(i) = Price(i) - EMA(Price, N, i)
此处:
err(i) ― 当前EMA误差;
Price(i) ― 当前价格;
EMA(Price, N, i) ― 价格系列的以N为周期的EMA的当前值。
添加指数平均线错误值到价格指数移动平均数值,可以获得EDMA;
DEMA(i) = EMA(Price,N,i)+ EMA(err,N,i) = EMA(Price,N,i)+EMA(Price-EMA(Price,N,i),N,i) =
= 2*EMA(Price,N,i)-EMA(Price-EMA(Price,N,i),N,i)=2*EMA(Price,N,i)-EMA2(Price,N,i)
此处:
EMA(err, N, i) ― 误差err的指数均线的当前值;
EMA2(Price, N, i) ― 价格的二重连续平滑的当前值。
*/
JSIndexScript.prototype.DEMA = function ()
{
let data =
{
Name: 'DEMA', Description: '双重指数移动均线', IsMainIndex: true,
Args: [{ Name: 'N1', Value: 10 }],
Script: //脚本
"ERR:=C-EMA(C,N1);\n\
DEMA:EMA(C,10)+EMA(ERR,N1);"
};
return data;
}
/*
Calculation
There are five steps in calculating VWAP:
Calculate the Typical Price for the period.
[(High + Low + Close)/3)]
Multiply the Typical Price by the period Volume.
(Typical Price x Volume)
Create a Cumulative Total of Typical Price.
Cumulative(Typical Price x Volume)
Create a Cumulative Total of Volume.
Cumulative(Volume)
Divide the Cumulative Totals.
VWAP = Cumulative(Typical Price x Volume) / Cumulative(Volume)
*/
JSIndexScript.prototype.VWAP = function ()
{
let data =
{
Name: 'VWAP', Description: '成交量加权平均价', IsMainIndex: true,
Args: [{ Name: 'N1', Value: 10 }],
Script: //脚本
"PRICE:=(H+L+C)/3;\n\
T2:=VOL*PRICE;\n\
VWAP:SUM(T2,0)/SUM(VOL,0);"
};
return data;
}
JSIndexScript.prototype.SQJZ = function ()
{
let data =
{
Name: 'SQJZ', Description: '神奇九转', IsMainIndex: true,
Script: //脚本
"B:=C<REF(C,4);\n\
N:=CURRBARSCOUNT;\n\
B1:=(N=6 AND REFXV(COUNT(B,6),5)=6) OR (N=7 AND REFXV(COUNT(B,7),6)=7) OR (N=8 AND REFXV(COUNT(B,8),7)=8) OR (N>=9 AND REFXV(COUNT(B,9),8)=9);\n\
DRAWNUMBER(B1 AND REF(B,1)=0,L,1),COLORMAGENTA;\n\
B2:=(N=5 AND REFXV(COUNT(B,6),4)=6) OR (N=6 AND REFXV(COUNT(B,7),5)=7) OR (N=7 AND REFXV(COUNT(B,8),6)=8) OR (N>=8 AND REFXV(COUNT(B,9),7)=9);\n\
DRAWNUMBER(B2 AND REF(B,2)=0,L,2),COLORMAGENTA;\n\
B8:=(N=1 AND COUNT(B,8)=8) OR (N>=2 AND REFXV(COUNT(B,9),1)=9);\n\
DRAWNUMBER(B8 AND REF(B,8)=0,L,8),COLORMAGENTA;\n\
B9:=(N>=1 AND COUNT(B,9)=9);\n\
DRAWNUMBER(B9 AND REF(B,9)=0,L,9),COLORBROWN;\n\
S:=C>REF(C,4);\n\
S1:=(N=6 AND REFXV(COUNT(S,6),5)=6) OR (N=7 AND REFXV(COUNT(S,7),6)=7) OR (N=8 AND REFXV(COUNT(S,8),7)=8) OR (N>=9 AND REFXV(COUNT(S,9),8)=9);\n\
DRAWNUMBER(S1 AND REF(S,1)=0,H,1),COLORMAGENTA,DRAWABOVE;\n\
S2:=(N=5 AND REFXV(COUNT(S,6),4)=6) OR (N=6 AND REFXV(COUNT(S,7),5)=7) OR (N=7 AND REFXV(COUNT(S,8),6)=8) OR (N>=8 AND REFXV(COUNT(S,9),7)=9);\n\
DRAWNUMBER(S2 AND REF(S,2)=0,H,2),COLORMAGENTA,DRAWABOVE;\n\
S8:=(N=1 AND COUNT(S,8)=8) OR (N>=2 AND REFXV(COUNT(S,9),1)=9);\n\
DRAWNUMBER(S8 AND REF(S,8)=0,H,8),COLORMAGENTA,DRAWABOVE;\n\
S9:=(N>=1 AND COUNT(S,9)=9);\n\
DRAWNUMBER(S9 AND REF(S,9)=0,H,9),COLORGREEN,DRAWABOVE;"
};
return data;
}
JSIndexScript.prototype.XT = function ()
{
let data =
{
Name: 'XT', Description: '箱体', IsMainIndex: true,
Args: [{ Name: 'N', Value: 10 }],
Script: //脚本
"【箱顶】:PEAK(CLOSE,N,1)*0.98;\n\
【箱底】:TROUGH(CLOSE,N,1)*1.02;\n\
【箱高】:100*(【箱顶】-【箱底】)/【箱底】,NODRAW;"
};
return data;
}
JSIndexScript.prototype.CFJT = function ()
{
let data =
{
Name: 'CFJT', Description: '财富阶梯', IsMainIndex: true,
Script: //脚本
"突破:=REF(EMA(C,14),1);\n\
A1X:=(EMA(C,10)-突破)/突破*100;\n\
多方:=IF(A1X>=0,REF(EMA(C,10),BARSLAST(CROSS(A1X,0))+1),DRAWNULL);\n\
空方:=IF(A1X<0,REF(EMA(C,10),BARSLAST(CROSS(0,A1X))+1),DRAWNULL);\n\
STICKLINE(A1X>=0,多方,突破,110,0),COLORRED;\n\
STICKLINE(A1X<0,空方,突破,110,0),COLORGREEN;"
};
return data;
}
JSIndexScript.prototype.CYX = function ()
{
let data =
{
Name: 'CYX', Description: '撑压线', IsMainIndex: true,
Args: [{ Name: 'N', Value: 7 }],
Script: //脚本
"Z1:=STRCAT(HYBLOCK,' ');\n\
Z2:=STRCAT(Z1,DYBLOCK);\n\
Z3:=STRCAT(Z2,' ');\n\
DRAWTEXT_FIX(ISLASTBAR,0,0,0,STRCAT(Z3,GNBLOCK)),COLOR00C0C0;\n\
A1:=REF(H,N)=HHV(H,2*N+1);\n\
B1:=FILTER(A1,N);\n\
C1:=BACKSET(B1,N+1);\n\
D1:=FILTER(C1,N);\n\
A2:=REF(L,N)=LLV(L,2*N+1);\n\
B2:=FILTER(A2,N);\n\
C2:=BACKSET(B2,N+1);\n\
D2:=FILTER(C2,N);\n\
E1:=(REF(LLV(L,2*N),1)+REF(HHV(H,2*N),1))/2;\n\
E2:=(H+L)/2;\n\
H1:=(D1 AND NOT(D2 AND E1>=E2)) OR ISLASTBAR OR BARSCOUNT(C)=1;\n\
L1:=(D2 AND NOT(D1 AND E1<E2));\n\
H2:=D1 AND NOT(D2 AND E1>=E2);\n\
X1:=REF(BARSLAST(H1),1)+1;\n\
F1:=BACKSET(H1 AND COUNT(L1,X1)>0,LLVBARS(IF(L1,L,10000),X1));\n\
G1:=F1>REF(F1,1);\n\
I1:=BACKSET(G1,2);\n\
LD:=I1>REF(I1,1);\n\
L2:=LD OR ISLASTBAR OR BARSCOUNT(C)=1;\n\
X2:=REF(BARSLAST(L2),1)+1;\n\
F2:=BACKSET(L2 AND COUNT(H2,X2)>0,HHVBARS(IF(H2,H,0),X2));\n\
G2:=F2>REF(F2,1);\n\
I2:=BACKSET(G2,2);\n\
HD:=I2>REF(I2,1);\n\
R1:=BACKSET(ISLASTBAR,BARSLAST(HD)+1);\n\
S1:=R1>REF(R1,1);\n\
T1:=BACKSET(ISLASTBAR,BARSLAST(LD)+1);\n\
U1:=T1>REF(T1,1);\n\
R2:=BACKSET(S1,REF(BARSLAST(HD),1)+2);\n\
S2:=R2>REF(R2,1);\n\
T2:=BACKSET(U1,REF(BARSLAST(LD),1)+2);\n\
U2:=T2>REF(T2,1);\n\
DRAWLINE(S2,H,S1,H,1),LINETHICK2,COLORRED;\n\
DRAWLINE(U2,L,U1,L,1),LINETHICK2,COLORGREEN;"
};
return data;
}
JSIndexScript.prototype.WAVE = function ()
{
let data =
{
Name: 'WAVE', Description: '波浪分析', IsMainIndex: true,
Args: [{ Name: 'N', Value: 5 }],
Script: //脚本
"ZIG(3,N);"
};
return data;
}
JSIndexScript.prototype.ShareholderCount=function()
{
let data =
{
Name: '散户线', Description: '散户线', IsMainIndex: false,
Script: //脚本
"GPJYVALUE(1,1,1);"
};
return data;
}
JSIndexScript.prototype.NXTS=function()
{
let data =
{
Name: 'NXTS', Description: '牛熊天数', IsMainIndex: false,
Args: [{ Name: 'N', Value: 20 }],
Script: //脚本
"Z:=ZIG(C,N);\n\
高点:=Z>REF(Z,1) AND Z>REFX(Z,1);\n\
低点:=Z<REF(Z,1) AND Z<REFX(Z,1);\n\
NG:=BARSLAST(高点);\n\
ND:=BARSLAST(低点);\n\
D0:=DATETODAY(DATE)-DATETODAY(REF(DATE,BARSSINCE(C)));\n\
DG:=DATETODAY(DATE)-DATETODAY(REF(DATE,NG));\n\
DD:=DATETODAY(DATE)-DATETODAY(REF(DATE,ND));\n\
N1:=(NG>ND OR COUNT(高点,0)=0) AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)>(N/100);\n\
N2:=NG<ND AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)>=-(N/100);\n\
N3:=NG<ND AND NG=0;\n\
N4:=COUNT(低点 OR 高点,0)=0 AND (HHV(C,0)-REF(C,BARSSINCE(C)))/REF(C,BARSSINCE(C))>(N/100);\n\
N5:=COUNT(低点,0)=0 AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)>=-(N/100);\n\
N6:=COUNT(低点,0)=0 AND NG=0;\n\
X1:=(NG<ND OR COUNT(低点,0)=0) AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)<-(N/100);\n\
X2:=NG>ND AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)<=(N/100);\n\
X3:=NG>ND AND ND=0;\n\
X4:=COUNT(高点 OR 低点,0)=0 AND (LLV(C,0)-REF(C,BARSSINCE(C)))/REF(C,BARSSINCE(C))<-(N/100);\n\
X5:=COUNT(高点,0)=0 AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)<=(N/100);\n\
X6:=COUNT(高点,0)=0 AND ND=0;\n\
牛市天数:IF(N4 OR N5 OR N6,D0,IF(N1 OR N2 OR N3,DD,0)),COLORRED;\n\
熊市天数:IF(X4 OR X5 OR X6,D0,IF(X1 OR X2 OR X3,DG,0)),COLORGREEN;"
};
return data;
}
JSIndexScript.prototype.FKX=function()
{
let data =
{
Name: 'FKX', Description: '反K线', IsMainIndex: false,
Script: //脚本
"DRAWKLINE(-LOW, -OPEN, -HIGH, -CLOSE);"
};
return data;
}
JSIndexScript.prototype.Margin4=function()
{
let data =
{
Name: '两融资金', Description: '两融资金', IsMainIndex: false,
Script: //脚本
"TMPV:=IF(FINANCE(3)==0,REF(SCJYVALUE(1,1,1),1),REF(GPJYVALUE(3,1,1),1));\n\
TMPV1:=IF(FINANCE(3)==0,SCJYVALUE(1,1,0),GPJYVALUE(3,1,0));\n\
两融:IF(TMPV==0 OR TMPV1==0,DRAWNULL,IF(FINANCE(3)==0,(SCJYVALUE(1,1,1)-REF(SCJYVALUE(1,1,1),1))/10000-(SCJYVALUE(1,2,1)-REF(SCJYVALUE(1,2,1),1))/10000,((GPJYVALUE(3,1,1)-REF(GPJYVALUE(3,1,1),1))-((GPJYVALUE(3,2,1)*C/10000-(REF(GPJYVALUE(3,2,1),1)*REF(C,1)/10000)))))),NODRAW;\n\
STICKLINE(两融>0,0,两融,2,0),COLORRED;\n\
STICKLINE(两融<0,0,两融,2,0),COLORCYAN;"
};
return data;
}
JSIndexScript.prototype.ZSDB=function()
{
let data =
{
Name: 'ZSDB', Description: '指数对比(副图,需下载日线)', IsMainIndex: false,
Script: //脚本
"A:=REF(INDEXC,1);\n\
指数涨幅:IF(A>0,(INDEXC-A)*100/A,0),NODRAW;\n\
DRAWKLINE(INDEXH,INDEXO,INDEXL,INDEXC);"
};
return data;
}
JSIndexScript.prototype.NineTurns=function()
{
let data =
{
Name: '神奇九转', Description: '九转指标', IsMainIndex: true,
Script: //脚本
"A1:=C>REF(C,4);\n\
A2:=C<REF(C,4);\n\
T1:=A2 AND REF(A1,1);\n\
T2:=A2 AND REF(T1,1);\n\
T3:=A2 AND REF(T2,1);\n\
T4:=A2 AND REF(T3,1);\n\
T5:=A2 AND REF(T4,1);\n\
T6:=A2 AND REF(T5,1);\n\
T7:=A2 AND REF(T6,1);\n\
T8:=A2 AND REF(T7,1);\n\
T9:=A2 AND REF(T8,1);\n\
T10:=A2 AND REF(T9,1);\n\
T11:=A2 AND REF(T10,1);\n\
T12:=A2 AND REF(T11,1);\n\
T13:=A2 AND REF(T12,1);\n\
T14:=A2 AND REF(T13,1);\n\
DRAWTEXT(T1,L*0.98,'1'),COLORGREEN;\n\
DRAWTEXT(T2,L*0.98,'2'),COLORGREEN;\n\
DRAWTEXT(T3,L*0.98,'3'),COLORGREEN;\n\
DRAWTEXT(T4,L*0.98,'4'),COLORGREEN;\n\
DRAWTEXT(T5,L*0.98,'5'),COLORGREEN;\n\
DRAWTEXT(T6,L*0.98,'6'),COLORGREEN;\n\
DRAWTEXT(T7,L*0.98,'7'),COLORGREEN;\n\
DRAWTEXT(T8,L*0.98,'8'),COLORGREEN;\n\
DRAWTEXT(T9,L*0.98,'9'),COLORBLUE;\n\
B1:=C<REF(C,4);\n\
B2:=C>REF(C,4);\n\
D1:=B2 AND REF(B1,1);\n\
D2:=B2 AND REF(D1,1);\n\
D3:=B2 AND REF(D2,1);\n\
D4:=B2 AND REF(D3,1);\n\
D5:=B2 AND REF(D4,1);\n\
D6:=B2 AND REF(D5,1);\n\
D7:=B2 AND REF(D6,1);\n\
D8:=B2 AND REF(D7,1);\n\
D9:=B2 AND REF(D8,1);\n\
D10:=B2 AND REF(D9,1);\n\
D11:=B2 AND REF(D10,1);\n\
D12:=B2 AND REF(D11,1);\n\
D13:=B2 AND REF(D12,1);\n\
D14:=B2 AND REF(D13,1);\n\
DRAWTEXT(D1,H*1.010,'1'),COLORBLUE;\n\
DRAWTEXT(D2,H*1.010,'2'),COLORBLUE;\n\
DRAWTEXT(D3,H*1.010,'3'),COLORBLUE;\n\
DRAWTEXT(D4,H*1.010,'4'),COLORBLUE;\n\
DRAWTEXT(D5,H*1.010,'5'),COLORBLUE;\n\
DRAWTEXT(D6,H*1.010,'6'),COLORBLUE;\n\
DRAWTEXT(D7,H*1.010,'7'),COLORBLUE;\n\
DRAWTEXT(D8,H*1.010,'8'),COLORBLUE;\n\
DRAWTEXT(D9,H*1.010,'9'),COLORGREEN;"
};
return data;
}
JSIndexScript.prototype.ICHIMOKU=function()
{
let data =
{
Name: 'ICHIMOKU', Description: '一目均衡图', IsMainIndex: true,
Args: [{ Name: 'SHORT', Value: 7 },{ Name: 'MID', Value: 22 },{ Name: 'LONG', Value: 44 }],
Script: //脚本
"转换线:(HHV(H,SHORT)+LLV(L,SHORT))/2,COLORRED,LINETHICK2;\n\
基准线:(HHV(H,MID)+LLV(L,MID))/2,COLORFF8040,LINETHICK2;\n\
迟行带:REFXV(C,MID),COLORGRAY,LINETHICK2;\n\
A:=REF((转换线+基准线)/2,MID);\n\
B:=REF((HHV(H,LONG)+LLV(L,LONG))/2,MID);\n\
STICKLINE(A<B,A,B,2,1),COLOR339933;\n\
STICKLINE(A>=B,A,B,2,1),COLOR0033CC;\n\
先行带A:PLOYLINE(1,A),COLORBROWN;\n\
先行带B:PLOYLINE(1,B),COLORLIGREEN;"
};
return data;
}
JSIndexScript.prototype.CDP_STD=function()
{
let data =
{
Name: 'CDP-STD', Description: '逆势操作', IsMainIndex: true,
Script: //脚本
"CH:=REF(H,1);\n\
CL:=REF(L,1);\n\
CC:=REF(C,1);\n\
CDP:(CH+CL+CC)/3;\n\
AH:2*CDP+CH-2*CL;\n\
NH:CDP+CDP-CL;\n\
NL:CDP+CDP-CH;\n\
AL:2*CDP-2*CH+CL;"
};
return data;
}
JSIndexScript.prototype.TBP_STD=function()
{
let data =
{
Name: 'TBP-STD', Description: '趋势平衡点', IsMainIndex: true,
Script: //脚本
"APX:=(H+L+C)/3;\n\
TR0:=MAX(H-L,MAX(ABS(H-REF(C,1)),ABS(L-REF(C,1))));\n\
MF0:=C-REF(C,2);\n\
MF1:=REF(MF0,1);\n\
MF2:=REF(MF0,2);\n\
DIRECT1:=BARSLAST(MF0>MF1 AND MF0>MF2);\n\
DIRECT2:=BARSLAST(MF0<MF1 AND MF0<MF2);\n\
DIRECT0:=IF(DIRECT1<DIRECT2,100,-100);\n\
TBP:REF(REF(C,1)+IF(DIRECT0>50,MIN(MF0,MF1),MAX(MF0,MF1)),1);\n\
多头获利:REF(IF(DIRECT0>50,APX*2-L,DRAWNULL),1),NODRAW;\n\
多头停损:REF(IF(DIRECT0>50,APX-TR0,DRAWNULL),1),NODRAW;\n\
空头回补:REF(IF(DIRECT0<-50,APX*2-H,DRAWNULL),1),NODRAW;\n\
空头停损:REF(IF(DIRECT0<-50,APX+TR0,DRAWNULL),1),NODRAW;"
};
return data;
}
JSIndexScript.prototype.ADX = function ()
{
let data =
{
Name: 'ADX', Description: '均趋向指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 14 }],
Script: //脚本
`TR1:=SMA(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(LOW-REF(CLOSE,1))),N,1);
HD:=HIGH-REF(HIGH,1);
LD:=REF(LOW,1)-LOW;
DMP:=SMA(IF(HD>0 AND HD>LD,HD,0),N,1);
DMM:=SMA(IF(LD>0 AND LD>HD,LD,0),N,1);
PDI:DMP*100/TR1,COLORRED,DOTLINE;
MDI:DMM*100/TR1,COLORGREEN,DOTLINE;
ADX:SMA(ABS(MDI-PDI)/(MDI+PDI)*100,N,1),COLORYELLOW,LINETHICK2;
20;
40;`
};
return data;
}
JSIndexScript.prototype.ZNZ_CBAND = function()
{
let data =
{
Name: 'ZNZ_CBAND', Description: '优化成本布林带宽', IsMainIndex: false,
Args: [{ Name: 'N', Value: 20 }],
Script: //脚本
`A:=AMOUNT/(100*VOL);
BBI1:=MA(A,N);
UPR0:=BBI1+STD(A,N);
DWN0:=BBI1-STD(A,N);
UPR1:=BBI1+1.7*STD(A,N);
DWN1:=BBI1-1.7*STD(A,N);
优化成本布林带宽:100*1.7*STD(A,N);`
};
return data;
}
JSIndexScript.prototype.ZNZ_RPY2 = function()
{
let data =
{
Name: 'ZNZ_RPY2', Description: '两年相对价位', IsMainIndex: false,
Script: //脚本
`A:=REF(HHV(CLOSE,480),1);
B:=REF(LLV(CLOSE,480),1);
100*(CLOSE-B)/(A-B);`
};
return data;
}
JSIndexScript.prototype.ZNZ_RPY1 = function()
{
let data =
{
Name: 'ZNZ_RPY1', Description: '年相对价位', IsMainIndex: false,
Args: [{ Name: 'N', Value: 240 }],
Script: //脚本
`A:=REF(HHV(CLOSE,N),1);
B:=REF(LLV(CLOSE,N),1);
100*(CLOSE-B)/(A-B);`
};
return data;
}
JSIndexScript.prototype.TEST = function ()
{
let data =
{
Name: 'TEST', Description: '测试脚本', IsMainIndex: false,
Args: [{ Name: 'N', Value: 10 }],
Script: //脚本
"DRAWCHANNEL(OPEN>C,H,L, 'RGB(255,94,102)', 2 ,'5,5','RGBA(58,20,62,0.3)' );"
};
return data;
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
封装行情类图形控件 (H5版本)
*/
//日志输出类
if (!JSConsole)
{
var JSConsole=
{
Chart:{ Log:console.log, Warn:console.warn }, //图形日志
Complier:{ Log:console.log, Warn:console.warn } //编译器日志
};
}
function JSChart(divElement, bOffscreen, bCacheCanvas)
{
this.DivElement=divElement;
this.DivToolElement=null; //工具条
this.JSChartContainer; //画图控件
this.ResizeListener;
//h5 canvas
this.CanvasElement=document.createElement("canvas");
this.CanvasElement.className='jschart-drawing';
this.CanvasElement.id=Guid();
this.CanvasElement.setAttribute("tabindex",0);
if (this.CanvasElement.style)
{
this.CanvasElement.style.outline='none';
//this.CanvasElement.style.position="absolute"; //外部自己设置
}
if(divElement.hasChildNodes())
{
JSConsole.Chart.Log("[JSChart::JSChart] divElement hasChildNodes", divElement.childNodes);
}
divElement.appendChild(this.CanvasElement);
//离屏
this.OffscreenCanvasElement;
if (bOffscreen==true) this.OffscreenCanvasElement=document.createElement("canvas");
//图形缓存
this.CacheCanvasElement=null;
if (bCacheCanvas) this.CacheCanvasElement=document.createElement("canvas");
//改参数div
this.ModifyIndexDialog=new ModifyIndexDialog(divElement);
//额外的画布
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='jschart-drawing-extra';
element.id=Guid();
if (name==JSChart.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;
}
/*
{ Type: 1=K线柱子宽度不变 2=K线全部显示
Redraw:是否重绘, XYSplit:是否重新计算分割线 }
*/
this.OnSize=function(option)
{
//画布大小通过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",""));
}
if (this.ToolElement)
{
//TODO调整工具条大小
height-=this.ToolElement.style.height.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;
if (this.OffscreenCanvasElement)
{
this.OffscreenCanvasElement.height=this.CanvasElement.height;
this.OffscreenCanvasElement.width=this.CanvasElement.width;
}
if (this.CacheCanvasElement)
{
this.CacheCanvasElement.height=this.CanvasElement.height;
this.CacheCanvasElement.width=this.CanvasElement.width;
}
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(`[JSChart::OnSize] devicePixelRatio=${window.devicePixelRatio}, height=${this.CanvasElement.height}, width=${this.CanvasElement.width}`);
if (option && option.Redraw==false) return;
if (this.JSChartContainer)
{
if (option && option.XYSplit===true) this.JSChartContainer.ResetFrameXYSplit();
if (this.JSChartContainer.OnSize && option && option.Type==1) //K线宽度不变
{
this.JSChartContainer.OnSize();
}
else if (this.JSChartContainer.ShowAllKLine && option && option.Type==2)
{
this.JSChartContainer.ShowAllKLine();
}
else
{
if (this.JSChartContainer.Frame) this.JSChartContainer.Frame.SetSizeChage(true);
this.JSChartContainer.Draw();
}
}
}
//手机屏需要调整 间距
this.AdjustChartBorder=function(chart)
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
chart.Frame.ChartBorder.Left*=pixelTatio;
chart.Frame.ChartBorder.Right*=pixelTatio;
chart.Frame.ChartBorder.Top*=pixelTatio;
chart.Frame.ChartBorder.Bottom*=pixelTatio;
if (chart.Frame.AutoLeftBorder)
{
var item=chart.Frame.AutoLeftBorder;
if (IFrameSplitOperator.IsNumber(item.MinWidth)) item.MinWidth*=pixelTatio;
if (IFrameSplitOperator.IsNumber(item.Blank)) item.Blank*=pixelTatio;
}
if (chart.Frame.AutoRightBorder)
{
var item=chart.Frame.AutoRightBorder;
if (IFrameSplitOperator.IsNumber(item.MinWidth)) item.MinWidth*=pixelTatio;
if (IFrameSplitOperator.IsNumber(item.Blank)) item.Blank*=pixelTatio;
}
}
this.AdjustTitleHeight=function(chart)
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
for(var i=0;i<chart.Frame.SubFrame.length;++i)
{
chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight*=pixelTatio;
}
chart.ChartCorssCursor.TextHeight*=pixelTatio; //十字光标文本信息高度
}
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;
else option.Border.Left=chart.Frame.ChartBorder.Left;
if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
else option.Border.Right=chart.Frame.ChartBorder.Right;
if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
else option.Border.Top=chart.Frame.ChartBorder.Top;
if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom;
else option.Border.Bottom=chart.Frame.ChartBorder.Bottom;
if (item.AutoLeft)
{
chart.Frame.AutoLeftBorder={ };
if (IFrameSplitOperator.IsNumber(item.AutoLeft.Blank)) chart.Frame.AutoLeftBorder.Blank=item.AutoLeft.Blank;
if (IFrameSplitOperator.IsNumber(item.AutoLeft.MinWidth)) chart.Frame.AutoLeftBorder.MinWidth=item.AutoLeft.MinWidth;
}
if (item.AutoRight)
{
chart.Frame.AutoRightBorder={ };
if (IFrameSplitOperator.IsNumber(item.AutoRight.Blank)) chart.Frame.AutoRightBorder.Blank=item.AutoRight.Blank;
if (IFrameSplitOperator.IsNumber(item.AutoRight.MinWidth)) chart.Frame.AutoRightBorder.MinWidth=item.AutoRight.MinWidth;
}
}
this.SetEventCallback=function(chart, aryCallback)
{
if (!chart) return;
if (!IFrameSplitOperator.IsNonEmptyArray(aryCallback)) return;
for(var i=0;i<aryCallback.length;++i)
{
var item=aryCallback[i];
chart.AddEventCallback(item);
}
}
//历史K线图
this.CreateKLineChartContainer=function(option)
{
var chart=null;
if (option.Type==="历史K线图横屏") chart=new KLineChartHScreenContainer(this.CanvasElement);
else chart=new KLineChartContainer(this.CanvasElement,this.OffscreenCanvasElement,this.CacheCanvasElement);
chart.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); }
var extraElement=this.GetExtraCanvas(JSChart.CorssCursorCanvasKey);
if (extraElement) chart.SetCorssCursorElement(extraElement);
if (option.EventCallback) this.SetEventCallback(chart, option.EventCallback);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
//创建改参数div
chart.ModifyIndexDialog=this.ModifyIndexDialog;
var pixelRatio=GetDevicePixelRatio();
//右键菜单
if (IFrameSplitOperator.IsBool(option.IsShowRightMenu)) chart.IsShowRightMenu=option.IsShowRightMenu;
if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError;
if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown;
if (option.DisableMouse==true) chart.DisableMouse=option.DisableMouse;
if (option.TouchMoveMinAngle) chart.TouchMoveMinAngle=option.TouchMoveMinAngle;
if (option.EnableZoomUpDown) chart.EnableZoomUpDown=option.EnableZoomUpDown;
if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;
if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow;
if (IFrameSplitOperator.IsBool(option.IsDrawPictureXY)) chart.IsDrawPictureXY=option.IsDrawPictureXY;
if (IFrameSplitOperator.IsNumber(option.CtrlMoveStep)) chart.CtrlMoveStep=option.CtrlMoveStep;
if (IFrameSplitOperator.IsBool(option.EnableIndexChartDrag)) chart.EnableIndexChartDrag=option.EnableIndexChartDrag;
if (IFrameSplitOperator.IsBool(option.EnableVerifyRecvData)) chart.EnableVerifyRecvData=option.EnableVerifyRecvData;
if (option.GlobalOption)
{
var item=option.GlobalOption;
if (IFrameSplitOperator.IsBool(item.IsValueFullRange)) chart.GlobalOption.IsValueFullRange=item.IsValueFullRange;
if (item.SelectedBorder)
{
var subItem=item.SelectedBorder;
if (IFrameSplitOperator.IsNumber(subItem.Mode)) chart.GlobalOption.SelectedBorder.Mode=subItem.Mode;
}
}
if (option.EnableYDrag)
{
var item=option.EnableYDrag;
if (IFrameSplitOperator.IsBool(item.Left)) chart.EnableYDrag.Left=item.Left;
if (IFrameSplitOperator.IsBool(item.Right)) chart.EnableYDrag.Right=item.Right;
if (IFrameSplitOperator.IsBool(item.Wheel)) chart.EnableYDrag.Wheel=item.Wheel;
if (IFrameSplitOperator.IsNumber(item.WheelYMove)) chart.EnableYDrag.WheelYMove=item.WheelYMove;
}
if (option.KLineTooltip)
{
var item=option.KLineTooltip;
if (IFrameSplitOperator.IsBool(item.Enable)) chart.KLineTooltipConfig.Enable=item.Enable;
if (IFrameSplitOperator.IsBool(item.EnableKeyDown)) chart.KLineTooltipConfig.EnableKeyDown=item.EnableKeyDown;
}
if (option.KLine) //k线图的属性设置
{
var item=option.KLine;
if (option.KLine.DragMode>=0) chart.DragMode=option.KLine.DragMode;
if (option.KLine.Right>=0) chart.Right=option.KLine.Right;
if (option.KLine.Period>=0) chart.Period=option.KLine.Period;
if (option.KLine.MaxReqeustDataCount>0) chart.MaxRequestDataCount=option.KLine.MaxReqeustDataCount; //兼容老版本
if (option.KLine.MaxRequestDataCount>0) chart.MaxRequestDataCount=option.KLine.MaxRequestDataCount;
if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false);
if (IFrameSplitOperator.IsBool(item.IsShowTooltip)) chart.IsShowTooltip=item.IsShowTooltip;
if (option.KLine.MaxRequestMinuteDayCount>0) chart.MaxRequestMinuteDayCount=option.KLine.MaxRequestMinuteDayCount;
if (option.KLine.DrawType) chart.KLineDrawType=option.KLine.DrawType;
if (option.KLine.FirstShowDate>19910101) chart.CustomShow={ Date:option.KLine.FirstShowDate, PageSize:option.KLine.PageSize }; //!!已弃用 新的格式"CustomShow"
if (option.KLine.RightSpaceCount>0) chart.RightSpaceCount=option.KLine.RightSpaceCount;
if (option.KLine.ZoomType>0) chart.ZoomType=option.KLine.ZoomType;
if (option.KLine.DataWidth>=1) chart.KLineSize={ DataWidth:option.KLine.DataWidth };
if (IFrameSplitOperator.IsNumber(option.KLine.RightFormula)) chart.RightFormula=option.KLine.RightFormula;
}
//自定义显示位置
if (option.CustomShow && IFrameSplitOperator.IsPlusNumber(option.CustomShow.Date))
{
var item=option.CustomShow;
chart.CustomShow={ Date:item.Date };
if (IFrameSplitOperator.IsNumber(item.Time)) chart.CustomShow.Time=item.Time;
if (IFrameSplitOperator.IsPlusNumber(item.PageSize)) chart.CustomShow.PageSize=item.PageSize;
}
if (option.EnableFlowCapital)
{
var item=option.EnableFlowCapital;
if (item.BIT==true) chart.EnableFlowCapital.BIT=item.BIT;
}
if (IFrameSplitOperator.IsBool(option.EnableBorderDrag))
{
chart.EnableBorderDrag=option.EnableBorderDrag;
}
if (option.Page)
{
if (option.Page.Day && option.Page.Day.Enable==true) chart.Page.Day.Enable=true;
if (option.Page.Minute && option.Page.Minute.Enable==true) chart.Page.Minute.Enable=true;
}
if (option.DragDownload)
{
if (option.DragDownload.Day && option.DragDownload.Day.Enable==true) chart.DragDownload.Day.Enable=true;
if (option.DragDownload.Minute && option.DragDownload.Minute.Enable==true) chart.DragDownload.Minute.Enable=true;
}
if (option.ZoomDownload)
{
if (option.ZoomDownload.Day && IFrameSplitOperator.IsBool(option.ZoomDownload.Day.Enable)) chart.ZoomDownload.Day.Enable=option.ZoomDownload.Day.Enable;
if (option.ZoomDownload.Minute && IFrameSplitOperator.IsBool(option.ZoomDownload.Minute.Enable)) chart.ZoomDownload.Minute.Enable=option.ZoomDownload.Minute.Enable;
}
if (option.Language)
{
var value=g_JSChartLocalization.GetLanguageID(option.Language);
if (IFrameSplitOperator.IsNumber(value)) chart.LanguageID=value;
}
if (option.SourceDatatLimit) chart.SetSourceDatatLimit(option.SourceDatatLimit);
if (option.DrawPicture) //画图工具
{
if (option.DrawPicture.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawPicture.StorageKey);
}
if (option.DrawTool) //画图工具
{
if (option.DrawTool.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawTool.StorageKey);
}
if (IFrameSplitOperator.IsNumber(option.StepPixel)) chart.StepPixel=option.StepPixel;
if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel;
if (option.IsApiPeriod==true) chart.IsApiPeriod=option.IsApiPeriod;
//图形选中
if (option.SelectedChart)
{
var item=option.SelectedChart;
if (IFrameSplitOperator.IsBool(item.EnableSelected)) chart.SelectedChart.EnableSelected=item.EnableSelected;
if (IFrameSplitOperator.IsBool(item.EnableMoveOn)) chart.SelectedChart.EnableMoveOn=item.EnableMoveOn;
}
if (!option.Windows || option.Windows.length<=0) return null;
//K线扩展计算方法配置
if (IFrameSplitOperator.IsNonEmptyArray(option.KLineCalcOption))
{
for(var i=0;i<option.KLineCalcOption.length;++i)
{
var item=option.KLineCalcOption[i];
if (!item.ClassName || !item.Option) continue;
chart.SetKLineCalcOption(item.ClassName, item.Option);
}
}
if (chart.ClassName=="KLineChartContainer")
{
if (!option.DragSelectRect)
{
option.DragSelectRect={ Enable:true }; //默认开启区间选中画布
}
if (option.DragSelectRect)
{
var zindex=10;
var item=option.DragSelectRect;
if (IFrameSplitOperator.IsNumber(item.ZIndex)) zindex=item.ZIndex;
if (item.Enable) this.CreateExtraCanvasElement(JSChart.RectDragCanvasKey, { ZIndex:zindex }); //创建独立的区间选择画布
}
}
//创建子窗口
chart.Create(option.Windows.length, option);
this.SetChartBorder(chart, option);
this.AdjustChartBorder(chart);
if (option.KLine)
{
if (option.KLine.PageSize > 0) //一屏显示的数据个数
{
let pageSize = chart.GetMaxMinPageSize();
if (pageSize.Max>10 && pageSize.Max < option.KLine.PageSize) chart.PageSize = pageSize.Max;
else if (pageSize.Min>10 && pageSize.Min> option.KLine.PageSize) chart.PageSize=pageSize.Min;
else chart.PageSize = option.KLine.PageSize;
}
}
//取消显示十字光标刻度信息
if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine;
if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd;
if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor;
if (option.CorssCursorInfo)
{
var item=option.CorssCursorInfo;
if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left;
if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right;
if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom;
if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss;
if (IFrameSplitOperator.IsBool(item.IsShowClose)) chart.ChartCorssCursor.IsShowClose = item.IsShowClose; //Y轴显示收盘价
if (IFrameSplitOperator.IsBool(item.IsOnlyDrawKLine)) chart.ChartCorssCursor.IsOnlyDrawKLine = item.IsOnlyDrawKLine; //Y轴显示收盘价
if (option.CorssCursorInfo.PressTime) chart.PressTime=option.CorssCursorInfo.PressTime; //长按显示十字光标的时间
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.HPenType)) chart.ChartCorssCursor.HPenType=option.CorssCursorInfo.HPenType;
if (option.CorssCursorInfo.VPenType>0) chart.ChartCorssCursor.VPenType=option.CorssCursorInfo.VPenType;
if (IFrameSplitOperator.IsNumber(item.VLineType)) chart.ChartCorssCursor.VLineType=item.VLineType;
if (option.CorssCursorInfo.DateFormatType>0) chart.ChartCorssCursor.StringFormatX.DateFormatType=option.CorssCursorInfo.DateFormatType;
if (IFrameSplitOperator.IsBool(item.IsDrawXRangeBG)) chart.ChartCorssCursor.IsDrawXRangeBG=item.IsDrawXRangeBG;
if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime;
if (IFrameSplitOperator.IsNumber(item.TextHeight)) chart.ChartCorssCursor.TextHeight=item.TextHeight;
if (item.RightButton)
{
if (IFrameSplitOperator.IsBool(item.RightButton.Enable)) chart.ChartCorssCursor.RightButton.Enable=item.RightButton.Enable;
}
if (IFrameSplitOperator.IsNumber(item.PriceFormatType)) chart.ChartCorssCursor.StringFormatY.PriceFormatType=item.PriceFormatType;
if (IFrameSplitOperator.IsNumber(item.DataFormatType)) chart.ChartCorssCursor.StringFormatY.DataFormatType=item.DataFormatType;
if (IFrameSplitOperator.IsBool(item.EnableKeyboard)) chart.ChartCorssCursor.EnableKeyboard=item.EnableKeyboard;
}
//保存十字光标文字高度
option.CorssCursor={};
option.CorssCursor.TitleHeight=chart.ChartCorssCursor.TextHeight;
if (IFrameSplitOperator.IsNumber(option.SplashTitlePosition))
{
if (chart.ChartSplashPaint) chart.ChartSplashPaint.Position=option.SplashTitlePosition;
}
if (option.Frame)
{
for(var i=0;i<option.Frame.length;++i)
{
var item=option.Frame[i];
if (!chart.Frame.SubFrame[i]) continue;
var subFrame=chart.Frame.SubFrame[i].Frame;
if (IFrameSplitOperator.IsNumber(item.SplitCount)) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount;
if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat;
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision;
if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom;
if (IFrameSplitOperator.IsNumber(item.SplitType))
{
chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType=item.SplitType;
chart.Frame.SubFrame[i].Frame.YSplitOperator.DefaultSplitType=item.SplitType;
}
if (IFrameSplitOperator.IsNumber(item.FilterType)) subFrame.YSplitOperator.FilterType=item.FilterType;
if (!isNaN(item.Height)) chart.Frame.SubFrame[i].Height = item.Height;
if (item.IsShowLeftText===false || item.IsShowLeftText===true)
{
chart.Frame.SubFrame[i].Frame.IsShowYText[0]=item.IsShowLeftText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
}
if (item.IsShowRightText===false || item.IsShowRightText===true)
{
chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
if (item.TopSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.TopSpace=item.TopSpace*pixelRatio;
if (item.BottomSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.BottomSpace=item.BottomSpace*pixelRatio;
if (item.RightTextPosition>0) chart.Frame.SubFrame[i].Frame.YTextPosition[1]=item.RightTextPosition;
if (item.LeftTextPosition>0) chart.Frame.SubFrame[i].Frame.YTextPosition[0]=item.LeftTextPosition;
if (item.IsShowXLine==false) chart.Frame.SubFrame[i].Frame.IsShowXLine=item.IsShowXLine;
if (item.IsShowYLine==false) chart.Frame.SubFrame[i].Frame.IsShowYLine=item.IsShowYLine;
if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline;
if (item.YCoordinateType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=item.YCoordinateType;
if (item.IsYReverse==true) chart.Frame.SubFrame[0].Frame.CoordinateType=1; //反转坐标
if (IFrameSplitOperator.IsNumber(item.PercentageTextFormat)) subFrame.YSplitOperator.PercentageTextFormat=item.PercentageTextFormat; //百分比坐标格式
if (item.DefaultYMaxMin) chart.Frame.SubFrame[i].Frame.YSplitOperator.DefaultYMaxMin=item.DefaultYMaxMin;
if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) chart.Frame.SubFrame[i].Frame.YSplitOperator.EnableRemoveZero=item.EnableRemoveZero;
if (IFrameSplitOperator.IsPlusNumber(item.MinYDistance)) chart.Frame.SubFrame[i].Frame.MinYDistance=item.MinYDistance;
if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine;
if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) chart.Frame.SubFrame[i].Frame.IsShowIndexTitle=item.IsShowIndexTitle;
if (IFrameSplitOperator.IsBool(item.IsDrawTitleBottomLine)) subFrame.IsDrawTitleBottomLine=item.IsDrawTitleBottomLine;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) chart.Frame.SubFrame[i].Frame.IsShowNameArrow=item.IsShowNameArrow;
if (item.ClientBGColor) subFrame.ClientBGColor=item.ClientBGColor;
}
}
if (option.KLine)
{
var item=option.KLine;
var klineChart=chart.ChartPaint[0];
if (option.KLine.ShowKLine == false) klineChart.IsShow = false;
if (option.KLine.InfoPosition>0) klineChart.InfoPosition=option.KLine.InfoPosition;
if (IFrameSplitOperator.IsBool(item.IsShowMaxMinPrice)) klineChart.IsShowMaxMinPrice=item.IsShowMaxMinPrice;
if (IFrameSplitOperator.IsNumber(item.OneLimitBarType)) klineChart.OneLimitBarType=item.OneLimitBarType;
if (item.PriceGap)
{
if (IFrameSplitOperator.IsBool(item.PriceGap.Enable)) klineChart.PriceGap.Enable=item.PriceGap.Enable;
if (IFrameSplitOperator.IsNumber(item.PriceGap.Count)) klineChart.PriceGap.Count=item.PriceGap.Count;
}
}
if(option.KLineTitle)
{
var item=option.KLineTitle;
if(option.KLineTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false;
if(option.KLineTitle.IsShowSettingInfo==false) chart.TitlePaint[0].IsShowSettingInfo=false;
if(option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false;
if(IFrameSplitOperator.IsBool(item.IsTitleShowLatestData)) chart.IsTitleShowLatestData=item.IsTitleShowLatestData;
}
//叠加股票
if (option.Overlay)
{
for(var i=0;i<option.Overlay.length;++i)
{
var item=option.Overlay[i];
chart.OverlaySymbol(item.Symbol,item);
}
}
if (option.ExtendChart)
{
for(var i=0;i<option.ExtendChart.length;++i)
{
var item=option.ExtendChart[i];
chart.CreateExtendChart(item.Name, item);
}
}
//创建子窗口的指标
var scriptData = new JSIndexScript();
if (option.ColorIndex) //五彩K线
{
var item=option.ColorIndex;
let indexInfo=scriptData.Get(item.Index);
if (indexInfo)
{
indexInfo.ID=item.Index;
chart.ColorIndex=new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
}
}
if (option.TradeIndex) //交易指标
{
var item=option.TradeIndex;
let indexInfo=scriptData.Get(item.Index);
if (indexInfo)
{
indexInfo.ID=item.Index;
chart.TradeIndex=new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
}
}
for(var i=0;i<option.Windows.length;++i)
{
var item=option.Windows[i];
if (item.Script)
{
chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.JsonData)
{
chart.WindowIndex[i]=new JsonDataIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.Local && item.Local.Data)
{
chart.WindowIndex[i]=new LocalJsonDataIndex(item.Local.Name,item.Local.Args,{JsonData:item.Local.Data});
}
else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
{
var apiItem=item.API;
chart.WindowIndex[i]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
let indexItem=JSIndexMap.Get(item.Index);
if (indexItem)
{
chart.WindowIndex[i]=indexItem.Create(item.Option);
if (chart.WindowIndex[i].SetArgs) chart.WindowIndex[i].SetArgs(item.Args);
chart.CreateWindowIndex(i);
}
else
{
var scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(item.Index);
if (!indexInfo) continue;
JSIndexScript.ModifyAttribute(indexInfo, item);
indexInfo.ID=item.Index;
chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
if (item.StringFormat>0) chart.WindowIndex[i].StringFormat=item.StringFormat;
if (item.FloatPrecision>=0) chart.WindowIndex[i].FloatPrecision=item.FloatPrecision;
}
}
var frame=chart.Frame.SubFrame[i].Frame;
if (IFrameSplitOperator.IsBool(item.Modify)) frame.ModifyIndex=item.Modify;
if (IFrameSplitOperator.IsBool(item.Change)) frame.ChangeIndex=item.Change;
if (IFrameSplitOperator.IsBool(item.Close)) frame.CloseIndex=item.Close;
if (IFrameSplitOperator.IsBool(item.Overlay)) frame.OverlayIndex=item.Overlay;
if (IFrameSplitOperator.IsBool(item.Export)) frame.ExportData=item.Export;
if (IFrameSplitOperator.IsBool(item.MaxMin)) chart.Frame.SubFrame[i].Frame.MaxMinWindow=item.MaxMin;
if (IFrameSplitOperator.IsBool(item.TitleWindow)) chart.Frame.SubFrame[i].Frame.TitleWindow=item.TitleWindow;
if (item.IsDrawTitleBG==true) chart.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) chart.Frame.SubFrame[i].Frame.IsShowNameArrow=item.IsShowNameArrow;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
else item.TitleHeight=chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight;
if (IFrameSplitOperator.IsBool(item.IsShowTitleArrow)) frame.IsShowTitleArrow=item.IsShowTitleArrow;
if (IFrameSplitOperator.IsNumber(item.TitleArrowType)) frame.TitleArrowType=item.TitleArrowType;
if (item.IsShowIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowIndexName=false;
if (item.IsShowOverlayIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowOverlayIndexName=false;
if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) chart.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) chart.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
if (!IFrameSplitOperator.IsUndefined(item.HorizontalReserved)) frame.HorizontalReserved=item.HorizontalReserved;
if (item.OverlayIndexType)
{
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) chart.Frame.SubFrame[i].Frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) chart.Frame.SubFrame[i].Frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
}
}
//叠加指标宽度
if (option.OverlayIndexFrameWidth>40) chart.Frame.FixedRightWidth.Overlay=option.OverlayIndexFrameWidth;
//叠加指标
if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
{
for(var i=0;i<option.OverlayIndex.length;++i)
{
var item=option.OverlayIndex[i];
if (item.Windows>=chart.Frame.SubFrame.length) continue;
var itemString = JSON.stringify(item);
var obj = JSON.parse(itemString);
if (item.Index) obj.IndexName=item.Index;
if (item.Windows>=0) obj.WindowIndex=item.Windows;
chart.CreateOverlayWindowsIndex(obj);
}
}
this.AdjustTitleHeight(chart);
return chart;
}
//自定义指数历史K线图
this.CreateCustomKLineChartContainer=function(option)
{
var chart=new CustomKLineChartContainer(this.CanvasElement);
//创建改参数div
chart.ModifyIndexDialog=this.ModifyIndexDialog;
//右键菜单
if (IFrameSplitOperator.IsBool(option.IsShowRightMenu)) chart.IsShowRightMenu=option.IsShowRightMenu;
if (option.KLine) //k线图的属性设置
{
if (option.KLine.DragMode>=0) chart.DragMode=option.KLine.DragMode;
if (option.KLine.Right>=0) chart.Right=option.KLine.Right;
if (option.KLine.Period>=0) chart.Period=option.KLine.Period;
if (option.KLine.MaxRequestDataCount>0) chart.MaxRequestDataCount=option.KLine.MaxRequestDataCount;
if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false);
if (option.KLine.PageSize>0) chart.PageSize=option.KLine.PageSize;
if (option.KLine.IsShowTooltip==false) chart.IsShowTooltip=false;
}
if (option.CustomStock) chart.CustomStock=option.CustomStock;
if (option.QueryDate) chart.QueryDate=option.QueryDate;
if (!option.Windows || option.Windows.length<=0) return null;
//创建子窗口
chart.Create(option.Windows.length);
if (option.Border)
{
if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left;
if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
}
if (option.IsShowCorssCursorInfo==false) //取消显示十字光标刻度信息
{
chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo;
}
if (option.Frame)
{
for(var i=0;i<option.Frame.length;++i)
{
var item=option.Frame[i];
if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount;
if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat;
}
}
if(option.KLineTitle)
{
if(option.KLineTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false;
if(option.KLineTitle.IsShowSettingInfo==false) chart.TitlePaint[0].IsShowSettingInfo=false;
}
//创建子窗口的指标
let scriptData = new JSIndexScript();
for(var i=0;i<option.Windows.length;++i)
{
var item=option.Windows[i];
if (item.Script)
{
chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else
{
let indexItem=JSIndexMap.Get(item.Index);
if (indexItem)
{
chart.WindowIndex[i]=indexItem.Create();
chart.CreateWindowIndex(i);
}
else
{
let indexInfo = scriptData.Get(item.Index);
if (!indexInfo) continue;
if (item.Lock) indexInfo.Lock=item.Lock;
chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
}
}
if (item.Modify!=null)
chart.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify;
if (item.Change!=null)
chart.Frame.SubFrame[i].Frame.ChangeIndex=item.Change;
if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
}
return chart;
}
//分钟走势图
this.CreateMinuteChartContainer=function(option)
{
var chart=null;
if (option.Type==="分钟走势图横屏") chart=new MinuteChartHScreenContainer(this.CanvasElement);
else chart=new MinuteChartContainer(this.CanvasElement, this.OffscreenCanvasElement, this.CacheCanvasElement);
chart.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); }
if (option.EventCallback) this.SetEventCallback(chart, option.EventCallback);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
chart.ModifyIndexDialog=this.ModifyIndexDialog;
var pixelRatio=GetDevicePixelRatio();
var windowsCount=2;
if (option.Windows && option.Windows.length>0) windowsCount+=option.Windows.length; //指标窗口从第3个窗口开始
if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown;
if (option.DisableMouse==true) chart.DisableMouse=option.DisableMouse;
if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError; //指标执行错误回调
if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;
if (IFrameSplitOperator.IsBool(option.EnableSelectRect)) chart.EnableSelectRect=option.EnableSelectRect; //是否启用区间选择
if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow;
if (IFrameSplitOperator.IsBool(option.IsDrawPictureXY)) chart.IsDrawPictureXY=option.IsDrawPictureXY;
if (IFrameSplitOperator.IsBool(option.EnableNewIndex)) chart.EnableNewIndex=option.EnableNewIndex;
if (IFrameSplitOperator.IsBool(option.EnableIndexChartDrag)) chart.EnableIndexChartDrag=option.EnableIndexChartDrag;
if (IFrameSplitOperator.IsBool(option.EnableVerifyRecvData)) chart.EnableVerifyRecvData=option.EnableVerifyRecvData;
if (IFrameSplitOperator.IsBool(option.EnableNightDayBG)) chart.EnableNightDayBG=option.EnableNightDayBG;
if (option.GlobalOption)
{
var item=option.GlobalOption;
if (IFrameSplitOperator.IsBool(item.IsValueFullRange)) chart.GlobalOption.IsValueFullRange=item.IsValueFullRange;
if (IFrameSplitOperator.IsNumber(item.XDateFormat)) chart.GlobalOption.XDateFormat=item.XDateFormat;
}
if (option.DisplayLatest)
{
var item=option.DisplayLatest;
if (IFrameSplitOperator.IsBool(item.Enable)) chart.DisplayLatestOption.Enable=item.Enable;
if (IFrameSplitOperator.IsNumber(item.DelayTime)) chart.DisplayLatestOption.DelayTime=item.DelayTime;
}
if (option.DrawDynamicInfo)
{
var item=option.DrawDynamicInfo;
if (IFrameSplitOperator.IsBool(item.Enable)) chart.DrawDynamicInfoOption.Enable=item.Enable;
if (IFrameSplitOperator.IsNumber(item.DelayTime)) chart.DrawDynamicInfoOption.DelayTime=item.DelayTime;
}
if (option.Minute) //分钟走势图属性设置
{
if (option.Minute.IsShowTooltip==false) chart.IsShowTooltip=false;
if (option.Minute.DragMode>=0) chart.DragMode=option.Minute.DragMode;
}
if (option.Language)
{
var value=g_JSChartLocalization.GetLanguageID(option.Language);
if (IFrameSplitOperator.IsNumber(value)) chart.LanguageID=value;
}
if (option.Info && option.Info.length>0) chart.SetMinuteInfo(option.Info,false);
if (option.DrawTool) //画图工具
{
if (option.DrawTool.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawTool.StorageKey);
}
if (option.BeforeOpen) //集合竞价
{
var item=option.BeforeOpen;
if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowBeforeData=item.IsShow;
if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Left=item.Width;
if (IFrameSplitOperator.IsBool(item.IsShowMultiDay)) chart.IsShowMultiDayBeforeData=item.IsShowMultiDay;
if (IFrameSplitOperator.IsNumber(item.MulitiDayWidth)) chart.MultiDayExtendWidth.Left=item.MulitiDayWidth;
}
if (option.AfterClose) //收盘集合竞价
{
var item=option.AfterClose;
if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowAfterData=item.IsShow;
if (IFrameSplitOperator.IsNumber(item.ShareVol)) chart.ShareAfterVol=item.ShareVol;
if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Right=item.Width;
if (IFrameSplitOperator.IsBool(item.IsShowMultiDay)) chart.IsShowMultiDayAfterData=item.IsShowMultiDay;
if (IFrameSplitOperator.IsNumber(item.MulitiDayWidth)) chart.MultiDayExtendWidth.Right=item.MulitiDayWidth;
}
//图形选中
if (option.SelectedChart)
{
var item=option.SelectedChart;
if (IFrameSplitOperator.IsBool(item.EnableSelected)) chart.SelectedChart.EnableSelected=item.EnableSelected;
if (IFrameSplitOperator.IsBool(item.EnableMoveOn)) chart.SelectedChart.EnableMoveOn=item.EnableMoveOn;
}
if (chart.ClassName=="MinuteChartContainer")
{
if (!option.DragSelectRect)
{
option.DragSelectRect={ Enable:true }; //默认开启区间选中画布
}
if (option.DragSelectRect)
{
var item=option.DragSelectRect;
var zindex=10;
if (IFrameSplitOperator.IsNumber(item.ZIndex)) zindex=item.ZIndex;
if (item.Enable) this.CreateExtraCanvasElement(JSChart.RectDragCanvasKey, { ZIndex:zindex }); //创建独立的区间选择画布
}
}
//分页
if (option.PageInfo) chart.SetPageInfo(option.PageInfo);
chart.Create(windowsCount,option); //创建子窗口
if (option.CorssCursorInfo)
{
var item=option.CorssCursorInfo;
if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left;
if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right;
if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom;
if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss;
if (option.CorssCursorInfo.RightTextFormat>0) chart.ChartCorssCursor.TextFormat.Right=option.CorssCursorInfo.RightTextFormat;
if (option.CorssCursorInfo.IsOnlyDrawMinute == true) chart.ChartCorssCursor.IsOnlyDrawMinute = option.CorssCursorInfo.IsOnlyDrawMinute; //Y轴显示收盘价
if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime;
if (item.RightButton)
{
if (IFrameSplitOperator.IsBool(item.RightButton.Enable)) chart.ChartCorssCursor.RightButton.Enable=item.RightButton.Enable;
}
if (IFrameSplitOperator.IsNumber(item.PriceFormatType)) chart.ChartCorssCursor.StringFormatY.PriceFormatType=item.PriceFormatType;
if (IFrameSplitOperator.IsNumber(item.DataFormatType)) chart.ChartCorssCursor.StringFormatY.DataFormatType=item.DataFormatType;
if (IFrameSplitOperator.IsNumber(item.HPenType)) chart.ChartCorssCursor.HPenType=item.HPenType;
if (IFrameSplitOperator.IsNumber(item.VPenType)) chart.ChartCorssCursor.VPenType=item.VPenType;
if (IFrameSplitOperator.IsBool(item.EnableKeyboard)) chart.ChartCorssCursor.EnableKeyboard=item.EnableKeyboard;
}
if (option.MinuteInfo) chart.CreateMinuteInfo(option.MinuteInfo);
if (IFrameSplitOperator.IsBool(option.IsShowRightMenu)) chart.IsShowRightMenu=option.IsShowRightMenu;
if (IFrameSplitOperator.IsNumber(option.DayCount)) chart.DayCount=option.DayCount;
this.SetChartBorder(chart, option);
if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle;
if (IFrameSplitOperator.IsBool(option.EnableBorderDrag))
{
chart.EnableBorderDrag=option.EnableBorderDrag;
}
this.AdjustChartBorder(chart);
if (option.Frame)
{
for(var i=0;i<option.Frame.length;++i)
{
var item=option.Frame[i];
if (!chart.Frame.SubFrame[i]) continue;
var subFrame=chart.Frame.SubFrame[i].Frame;
if (IFrameSplitOperator.IsNumber(item.SplitCount)) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount;
if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat;
if (IFrameSplitOperator.IsNumber(item.SplitType))
{
chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType=item.SplitType;
chart.Frame.SubFrame[i].Frame.YSplitOperator.DefaultSplitType=item.SplitType;
}
if (IFrameSplitOperator.IsNumber(item.FilterType)) subFrame.YSplitOperator.FilterType=item.FilterType;
if (item.IsShowLeftText==false)
{
chart.Frame.SubFrame[i].Frame.IsShowYText[0]=item.IsShowLeftText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
}
if (item.IsShowRightText==false)
{
chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
if (item.Height>=0) chart.Frame.SubFrame[i].Height = item.Height;
if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom;
if (item.RightTextFormat>0) chart.Frame.SubFrame[i].Frame.YSplitOperator.RightTextFormat=item.RightTextFormat;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine;
if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) chart.Frame.SubFrame[i].Frame.YSplitOperator.EnableRemoveZero=item.EnableRemoveZero;
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision;
if (IFrameSplitOperator.IsBool(item.IsShowXLine)) chart.Frame.SubFrame[i].Frame.IsShowXLine=item.IsShowXLine;
if (IFrameSplitOperator.IsBool(item.IsShowYLine)) chart.Frame.SubFrame[i].Frame.IsShowYLine=item.IsShowYLine;
if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline;
if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) chart.Frame.SubFrame[i].Frame.IsShowIndexTitle=item.IsShowIndexTitle;
if (item.TopSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.TopSpace=item.TopSpace*pixelRatio;
if (item.BottomSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.BottomSpace=item.BottomSpace*pixelRatio;
//是否显示关闭集合竞价按钮
if (IFrameSplitOperator.IsNumber(item.CloseBeforeButton)) chart.Frame.SubFrame[i].Frame.IsShowCloseButton=item.CloseBeforeButton;
if (item.ClientBGColor) subFrame.ClientBGColor=item.ClientBGColor;
if (!IFrameSplitOperator.IsUndefined(item.HorizontalReserved)) subFrame.HorizontalReserved=item.HorizontalReserved;
}
chart.UpdateXShowText();
}
if (option.ExtendChart)
{
for(var i=0;i<option.ExtendChart.length;++i)
{
var item=option.ExtendChart[i];
chart.CreateExtendChart(item.Name, item);
}
}
//叠加股票
if (option.Overlay)
{
for(var i=0;i<option.Overlay.length;++i)
{
var item=option.Overlay[i];
chart.OverlaySymbol(item.Symbol,item);
}
}
if (option.MinuteLine)
{
if (option.MinuteLine.IsDrawAreaPrice==false) chart.ChartPaint[0].IsDrawArea=false;
if (option.MinuteLine.IsShowLead==false) chart.IsShowLead=false;
if (option.MinuteLine.IsShowAveragePrice==false)
{
chart.ChartPaint[1].IsShow=false;
chart.TitlePaint[0].IsShowAveragePrice=false; //标题栏均线也不显示
for(var i=0;i<chart.ExtendChartPaint.length;++i)
{
var item=chart.ExtendChartPaint[i];
if (item.ClassName=="MinuteTooltipPaint")
item.IsShowAveragePrice=false;
}
}
if (option.MinuteLine.SplitType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType;
}
if (option.MinuteVol)
{
var item=option.MinuteVol;
if (IFrameSplitOperator.IsNumber(item.BarColorType)) chart.ChartPaint[2].BarColorType=item.BarColorType;
}
if(option.MinuteTitle)
{
var item=option.MinuteTitle;
if(IFrameSplitOperator.IsBool(item.IsShowName)) chart.TitlePaint[0].IsShowName=item.IsShowName;
if(IFrameSplitOperator.IsBool(item.IsShowDate)) chart.TitlePaint[0].IsShowDate=item.IsShowDate;
if(IFrameSplitOperator.IsBool(item.IsShowTime)) chart.TitlePaint[0].IsShowTime=item.IsShowTime;
if(IFrameSplitOperator.IsBool(item.IsTitleShowLatestData)) chart.IsTitleShowLatestData=item.IsTitleShowLatestData;
if(IFrameSplitOperator.IsBool(item.IsAlwaysShowLastData)) chart.TitlePaint[0].IsAlwaysShowLastData=item.IsAlwaysShowLastData;
if(IFrameSplitOperator.IsNumber(item.ShowLastDataFormat)) chart.TitlePaint[0].ShowLastDataFormat=item.ShowLastDataFormat;
if (IFrameSplitOperator.IsNumber(item.TitleBaseLine)) chart.TitlePaint[0].TitleBaseLine=item.TitleBaseLine;
if (item.TimeFormat) chart.TitlePaint[0].TimeFormat=item.TimeFormat;
}
if (IFrameSplitOperator.IsBool(option.CorssCursorTouchEnd)) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd;
if (IFrameSplitOperator.IsBool(option.IsClickShowCorssCursor)) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor;
if (option.IsShowBeforeData===true) chart.IsShowBeforeData=option.IsShowBeforeData;
//分钟数据指标从第3个指标窗口设置
if (IFrameSplitOperator.IsNonEmptyArray(option.Windows))
{
let scriptData = new JSIndexScript();
for(var i=0;i<option.Windows.length;++i)
{
var index=2+i;
var item=option.Windows[i];
if (item.Script)
{
chart.WindowIndex[index]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
{
var apiItem=item.API;
chart.WindowIndex[index]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var indexItem=JSIndexMap.Get(item.Index);
if (indexItem)
{
chart.WindowIndex[index]=indexItem.Create(); //创建子窗口的指标
chart.CreateWindowIndex(index);
}
else
{
let indexInfo = scriptData.Get(item.Index);
if (!indexInfo) continue;
JSIndexScript.ModifyAttribute(indexInfo, item);
indexInfo.ID=item.Index;
chart.WindowIndex[index] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
if (item.StringFormat>0) chart.WindowIndex[index].StringFormat=item.StringFormat;
if (item.FloatPrecision>=0) chart.WindowIndex[index].FloatPrecision=item.FloatPrecision;
}
}
var frame=chart.Frame.SubFrame[index].Frame;
if (IFrameSplitOperator.IsBool(item.Modify)) frame.ModifyIndex=item.Modify;
if (IFrameSplitOperator.IsBool(item.Change)) frame.ChangeIndex=item.Change;
if (IFrameSplitOperator.IsBool(item.Close)) frame.CloseIndex=item.Close;
if (IFrameSplitOperator.IsBool(item.Overlay)) frame.OverlayIndex=item.Overlay;
if (IFrameSplitOperator.IsBool(item.Export)) frame.ExportData=item.Export;
if (IFrameSplitOperator.IsBool(item.MaxMin)) frame.MaxMinWindow=item.MaxMin;
if (IFrameSplitOperator.IsBool(item.TitleWindow)) frame.TitleWindow=item.TitleWindow;
if (IFrameSplitOperator.IsNumber(item.YSplitType)) chart.Frame.SubFrame[index].Frame.YSplitOperator.SplitType=item.YSplitType;
if (IFrameSplitOperator.IsNumber(item.FilterType)) chart.Frame.SubFrame[index].Frame.YSplitOperator.FilterType=item.FilterType;
if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[index].Frame.ChartBorder.TitleHeight=item.TitleHeight;
if (IFrameSplitOperator.IsBool(item.IsDrawTitleBG)) chart.Frame.SubFrame[index].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) chart.Frame.SubFrame[index].Frame.IsShowNameArrow=item.IsShowNameArrow;
if (IFrameSplitOperator.IsBool(item.IsShowTitleArrow)) frame.IsShowTitleArrow=item.IsShowTitleArrow;
if (IFrameSplitOperator.IsNumber(item.TitleArrowType)) frame.TitleArrowType=item.TitleArrowType;
if (item.IsShowIndexName==false) chart.Frame.SubFrame[index].Frame.IsShowIndexName=false;
if (item.IsShowOverlayIndexName==false) chart.Frame.SubFrame[index].Frame.IsShowOverlayIndexName=false;
if (!IFrameSplitOperator.IsUndefined(item.HorizontalReserved)) frame.HorizontalReserved=item.HorizontalReserved;
}
}
this.AdjustTitleHeight(chart);
//叠加指标
if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
{
for(var i=0;i<option.OverlayIndex.length;++i)
{
var item=option.OverlayIndex[i];
if (item.Windows>=chart.Frame.SubFrame.length) continue;
var itemString = JSON.stringify(item);
var obj = JSON.parse(itemString);
if (item.Index) obj.IndexName=item.Index;
if (item.Windows>=0) obj.WindowIndex=item.Windows;
chart.CreateOverlayWindowsIndex(obj);
}
}
return chart;
}
this.CreateMinMinuteChartContainer=function(option)
{
var chart=null;
if (option.Type==="迷你分钟走势图横屏") chart=new MinuteChartHScreenContainer(this.CanvasElement);
else chart=new MinuteChartContainer(this.CanvasElement);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
var windowsCount=2;
if (option.BeforeOpen) //集合竞价
{
var item=option.BeforeOpen;
if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowBeforeData=item.IsShow;
if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Left=item.Width;
if (IFrameSplitOperator.IsBool(item.IsShowMultiDay)) chart.IsShowMultiDayBeforeData=item.IsShowMultiDay;
if (IFrameSplitOperator.IsNumber(item.MulitiDayWidth)) chart.MultiDayExtendWidth.Left=item.MulitiDayWidth;
}
if (option.AfterClose) //收盘集合竞价
{
var item=option.AfterClose;
if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowAfterData=item.IsShow;
if (IFrameSplitOperator.IsNumber(item.ShareVol)) chart.ShareAfterVol=item.ShareVol;
if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Right=item.Width;
if (IFrameSplitOperator.IsBool(item.IsShowMultiDay)) chart.IsShowMultiDayAfterData=item.IsShowMultiDay;
if (IFrameSplitOperator.IsNumber(item.MulitiDayWidth)) chart.MultiDayExtendWidth.Right=item.MulitiDayWidth;
}
if (!option.Listener) option.Listener={ KeyDown:false, Wheel:false };
chart.Create(windowsCount,option.Listener); //创建子窗口
if (option.CorssCursorInfo)
{
var item=option.CorssCursorInfo;
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left;
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right;
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom;
if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss;
if (option.CorssCursorInfo.RightTextFormat>0) chart.ChartCorssCursor.TextFormat.Right=option.CorssCursorInfo.RightTextFormat;
if (option.CorssCursorInfo.IsOnlyDrawMinute == true) chart.ChartCorssCursor.IsOnlyDrawMinute = option.CorssCursorInfo.IsOnlyDrawMinute; //Y轴显示收盘价
if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime;
if (item.RightButton)
{
if (IFrameSplitOperator.IsBool(item.RightButton.Enable)) chart.ChartCorssCursor.RightButton.Enable=item.RightButton.Enable;
}
if (IFrameSplitOperator.IsNumber(item.PriceFormatType)) chart.ChartCorssCursor.StringFormatY.PriceFormatType=item.PriceFormatType;
if (IFrameSplitOperator.IsNumber(item.DataFormatType)) chart.ChartCorssCursor.StringFormatY.DataFormatType=item.DataFormatType;
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.HPenType)) chart.ChartCorssCursor.HPenType=option.CorssCursorInfo.HPenType;
if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.VPenType)) chart.ChartCorssCursor.VPenType=option.CorssCursorInfo.VPenType;
}
if (IFrameSplitOperator.IsNumber(option.DayCount)) chart.DayCount=option.DayCount;
this.SetChartBorder(chart, option);
if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle;
if (IFrameSplitOperator.IsBool(option.EnableVerifyRecvData)) chart.EnableVerifyRecvData=option.EnableVerifyRecvData;
chart.TitlePaint[0].IsShow=false;
//主窗口 隐藏刻度
var mainFrame=chart.Frame.SubFrame[0];
mainFrame.Frame.IsShowYText[0]=false;
mainFrame.Frame.IsShowYText[1]=false;
mainFrame.Frame.IsShowXLine=false;
mainFrame.Frame.IsShowYLine=false;
mainFrame.Frame.BorderLine=0;
chart.Frame.SubFrame[1].Height=0; //隐藏成交量
chart.EnableBorderDrag=false;
if (option.Frame)
{
for(var i=0;i<option.Frame.length;++i)
{
var item=option.Frame[i];
if (!chart.Frame.SubFrame[i]) continue;
if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount;
if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat;
if (IFrameSplitOperator.IsNumber(item.SplitType))
{
chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType=item.SplitType;
chart.Frame.SubFrame[i].Frame.YSplitOperator.DefaultSplitType=item.SplitType;
}
if (IFrameSplitOperator.IsBool(item.IsShowLeftText))
{
chart.Frame.SubFrame[i].Frame.IsShowYText[0]=item.IsShowLeftText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
}
if (IFrameSplitOperator.IsBool(item.IsShowRightText))
{
chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText;
chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
if (item.Height>=0) chart.Frame.SubFrame[i].Height = item.Height;
if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom;
if (item.RightTextFormat>0) chart.Frame.SubFrame[i].Frame.YSplitOperator.RightTextFormat=item.RightTextFormat;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine;
if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) chart.Frame.SubFrame[i].Frame.YSplitOperator.EnableRemoveZero=item.EnableRemoveZero;
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision;
if (IFrameSplitOperator.IsBool(item.IsShowXLine)) chart.Frame.SubFrame[i].Frame.IsShowXLine=item.IsShowXLine;
if (IFrameSplitOperator.IsBool(item.IsShowYLine)) chart.Frame.SubFrame[i].Frame.IsShowYLine=item.IsShowYLine;
if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline;
}
}
chart.UpdateXShowText();
if (option.MinuteLine)
{
if (option.MinuteLine.IsDrawAreaPrice==false) chart.ChartPaint[0].IsDrawArea=false;
if (option.MinuteLine.IsShowLead==false) chart.IsShowLead=false;
if (option.MinuteLine.IsShowAveragePrice==false)
{
chart.ChartPaint[1].IsShow=false;
chart.TitlePaint[0].IsShowAveragePrice=false; //标题栏均线也不显示
for(var i=0;i<chart.ExtendChartPaint.length;++i)
{
var item=chart.ExtendChartPaint[i];
if (item.ClassName=="MinuteTooltipPaint")
item.IsShowAveragePrice=false;
}
}
if (option.MinuteLine.SplitType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType;
}
this.AdjustTitleHeight(chart);
if (option.DisableMouseEvent===true)
{
//取消鼠标事件
this.CanvasElement.onmousemove=(e)=>{ }
this.CanvasElement.oncontextmenu=(e)=> { }
this.CanvasElement.ondblclick=(e)=>{ }
this.CanvasElement.onmousedown=(e)=> { }
this.CanvasElement.onmouseout=(e)=>{ }
this.CanvasElement.onmouseleave=(e)=>{ }
}
if (option.ExtendChart)
{
for(var i=0;i<option.ExtendChart.length;++i)
{
var item=option.ExtendChart[i];
chart.CreateExtendChart(item.Name, item);
}
}
return chart;
}
/*废弃
//统一全部使用 MinuteChartContainer
//历史分钟走势图
this.CreateHistoryMinuteChartContainer=function(option)
{
var chart=new HistoryMinuteChartContainer(this.CanvasElement);
var windowsCount=2;
if (option.Windows && option.Windows.length>0) windowsCount+=option.Windows.length; //指标窗口从第3个窗口开始
chart.Create(windowsCount); //创建子窗口
if (option.IsShowCorssCursorInfo==false) //取消显示十字光标刻度信息
{
chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo;
}
if (option.Border)
{
if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left;
if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom;
}
let scriptData = new JSIndexScript();
if (option.Windows)
{
for(var i=0;i<option.Windows.length;++i)
{
var item=option.Windows[i];
if (item.Script)
{
chart.WindowIndex[2+parseInt(i)]=new ScriptIndex(item.Name,item.Script,item.Args); //脚本执行
}
else
{
var indexItem=JSIndexMap.Get(item.Index);
if (indexItem)
{
chart.WindowIndex[2+parseInt(i)]=indexItem.Create(); //创建子窗口的指标
chart.CreateWindowIndex(2+parseInt(i));
}
else
{
let indexInfo = scriptData.Get(item.Index);
if (!indexInfo) continue;
chart.WindowIndex[2+parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args); //脚本执行
}
}
if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2+parseInt(i)].Frame.ChartBorder.TitleHeight=item.TitleHeight;
}
}
chart.TradeDate=20181009;
if (option.HistoryMinute.TradeDate) chart.TradeDate=option.HistoryMinute.TradeDate;
if (option.HistoryMinute.IsShowName!=null) chart.TitlePaint[0].IsShowName=option.HistoryMinute.IsShowName; //动态标题是否显示股票名称
if (option.HistoryMinute.IsShowDate!=null) chart.TitlePaint[0].IsShowDate=option.HistoryMinute.IsShowDate; //动态标题是否显示日期
return chart;
}
*/
this.CreateKLineTrainChartContainer=function(option)
{
var isSimpleTrain=false;
if (option.Type=="简单K线训练" || option.Type=="简单K线训练横屏")
{
var bHScreen=(option.Type=='简单K线训练横屏'? true:false);
var chart=new KLineTrainSimpleChartContainer(this.CanvasElement,bHScreen);
isSimpleTrain=true;
}
else
{
var bHScreen=(option.Type=='K线训练横屏'? true:false);
var chart=new KLineTrainChartContainer(this.CanvasElement,bHScreen);
}
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
if (option.IsApiPeriod==true) chart.IsApiPeriod=option.IsApiPeriod;
//创建改参数div
chart.ModifyIndexDialog=this.ModifyIndexDialog;
if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError;
if (option.KLine) //k线图的属性设置
{
if (option.KLine.Right>=0) chart.Right=option.KLine.Right;
if (option.KLine.Period>=0) chart.Period=option.KLine.Period;
if (option.KLine.MaxRequestDataCount>0) chart.MaxRequestDataCount=option.KLine.MaxRequestDataCount;
if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false);
if (option.KLine.PageSize>0) chart.PageSize=option.KLine.PageSize;
if (option.KLine.IsShowTooltip==false) chart.IsShowTooltip=false;
if (option.KLine.MaxRequestMinuteDayCount>0) chart.MaxRequestMinuteDayCount=option.KLine.MaxRequestMinuteDayCount;
if (option.KLine.DrawType) chart.KLineDrawType=option.KLine.DrawType;
if (IFrameSplitOperator.IsNumber(option.KLine.RightSpaceCount) && !isSimpleTrain) chart.RightSpaceCount=option.KLine.RightSpaceCount;
}
if (option.Train)
{
if (option.Train.DataCount) chart.TrainDataCount=option.Train.DataCount;
if (option.Train.Callback) chart.TrainCallback=option.Train.Callback;
if (option.Train.StartDate) chart.TrainStartDate=option.Train.StartDate;
}
if (!option.Windows || option.Windows.length<=0) return null;
//创建子窗口
chart.Create(option.Windows.length);
this.SetChartBorder(chart, option);
this.AdjustChartBorder(chart);
if (option.IsShowCorssCursorInfo==false) chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo; //取消显示十字光标刻度信息
if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine;
if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd;
if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor;
if (option.CorssCursorInfo)
{
if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left;
if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right;
if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom;
if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss;
if (option.CorssCursorInfo.IsShowClose == true) chart.ChartCorssCursor.IsShowClose = option.CorssCursorInfo.IsShowClose; //Y轴显示收盘价
if (option.CorssCursorInfo.PressTime) chart.PressTime=option.CorssCursorInfo.PressTime; //长按显示十字光标的时间
if (option.CorssCursorInfo.HPenType>0) chart.ChartCorssCursor.HPenType=option.CorssCursorInfo.HPenType;
if (option.CorssCursorInfo.VPenType>0) chart.ChartCorssCursor.VPenType=option.CorssCursorInfo.VPenType;
}
//保存十字光标文字高度
option.CorssCursor={};
option.CorssCursor.TitleHeight=chart.ChartCorssCursor.TextHeight;
if (option.Frame)
{
for(var i=0;i<option.Frame.length;++i)
{
var item=option.Frame[i];
if (!chart.Frame.SubFrame[i]) continue;
if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount;
if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat;
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision;
if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom;
if (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType=item.SplitType;
if (item.Height>0) chart.Frame.SubFrame[i].Height = item.Height;
if (item.IsShowLeftText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
if (item.IsShowRightText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
}
if (option.KLine)
{
if (option.KLine.ShowKLine == false) chart.ChartPaint[0].IsShow = false;
if (option.KLine.InfoPosition>0) chart.ChartPaint[0].InfoPosition=option.KLine.InfoPosition;
if (option.KLine.IsShowMaxMinPrice == false) chart.ChartPaint[0].IsShowMaxMinPrice=option.KLine.IsShowMaxMinPrice;
}
if(option.KLineTitle) //股票名称 日期 周期
{
if(option.KLineTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false;
if(option.KLineTitle.IsShowSettingInfo==false) chart.TitlePaint[0].IsShowSettingInfo=false;
if(option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false;
}
if (IFrameSplitOperator.IsNonEmptyArray(option.Overlay)) //叠加股票
{
for(var i=0;i<option.Overlay.length;++i)
{
var item=option.Overlay[i];
chart.OverlaySymbol(item.Symbol,item);
}
}
if (option.ExtendChart)
{
for(var i=0;i<option.ExtendChart.length;++i)
{
var item=option.ExtendChart[i];
chart.CreateExtendChart(item.Name, item);
}
}
if (IFrameSplitOperator.IsNonEmptyArray(option.Windows))
{
//创建子窗口的指标
for(var i=0;i<option.Windows.length;++i)
{
var item=option.Windows[i];
if (item.Script)
{
chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else
{
let indexItem=JSIndexMap.Get(item.Index);
if (indexItem)
{
chart.WindowIndex[i]=indexItem.Create();
chart.CreateWindowIndex(i);
}
else
{
var scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(item.Index);
if (!indexInfo) continue;
if (item.Lock) indexInfo.Lock=item.Lock;
chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
}
}
if (item.Modify!=null) chart.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify;
if (item.Change!=null) chart.Frame.SubFrame[i].Frame.ChangeIndex=item.Change;
if (item.Close!=null) chart.Frame.SubFrame[i].Frame.CloseIndex=item.Close;
if (item.Overlay!=null) frame.OverlayIndex=item.Overlay;
if (IFrameSplitOperator.IsBool(item.Export)) frame.ExportData=item.Export;
if (IFrameSplitOperator.IsBool(item.MaxMin)) chart.Frame.SubFrame[i].Frame.MaxMinWindow=item.MaxMin;
if (IFrameSplitOperator.IsBool(item.TitleWindow)) chart.Frame.SubFrame[i].Frame.TitleWindow=item.TitleWindow;
if (IFrameSplitOperator.IsBool(item.IsDrawTitleBG)) chart.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) chart.Frame.SubFrame[i].Frame.IsShowNameArrow=item.IsShowNameArrow;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
if (IFrameSplitOperator.IsBool(item.IsShowTitleArrow)) chart.Frame.SubFrame[i].Frame.IsShowTitleArrow=item.IsShowTitleArrow;
if (item.IsShowIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowIndexName=false;
if (item.IsShowOverlayIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowOverlayIndexName=false;
if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) chart.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) chart.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
}
}
this.AdjustTitleHeight(chart);
return chart;
}
//深度图
this.CreateDepthChartContainer=function(option)
{
var chart=null;
chart=new DepthChartContainer(this.CanvasElement);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown;
if (IFrameSplitOperator.IsPlusNumber(option.MaxVolRate)) chart.MaxVolRate=option.MaxVolRate;
if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel;
if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;
if (IFrameSplitOperator.IsBool(option.EnableVerifyRecvData)) chart.EnableVerifyRecvData=option.EnableVerifyRecvData;
if (option.Language)
{
var value=g_JSChartLocalization.GetLanguageID(option.Language);
if (IFrameSplitOperator.IsNumber(value)) chart.LanguageID=value;
}
chart.Create(option.Listener);
if (option.Border)
{
if (IFrameSplitOperator.IsNumber(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left;
else option.Border.Left=chart.Frame.ChartBorder.Left;
if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
else option.Border.Right=chart.Frame.ChartBorder.Right;
if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
else option.Border.Top=chart.Frame.ChartBorder.Top;
if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom;
else option.Border.Bottom=chart.Frame.ChartBorder.Bottom;
}
this.AdjustChartBorder(chart);
if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd;
if (option.CorssCursorInfo)
{
var item=option.CorssCursorInfo;
if (IFrameSplitOperator.IsNumber(item.HPenType)) chart.ChartCorssCursor.HPenType=item.HPenType;
if (IFrameSplitOperator.IsNumber(item.VPenType)) chart.ChartCorssCursor.VPenType=item.VPenType;
if (IFrameSplitOperator.IsBool(item.IsShowTooltip)) chart.ChartCorssCursor.IsShowTooltip=item.IsShowTooltip;
}
if (option.Frame)
{
var item=option.Frame
if (item.SplitCount) chart.Frame.YSplitOperator.SplitCount=item.SplitCount;
if (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.YSplitOperator.SplitType=item.SplitType;
if (IFrameSplitOperator.IsNumber(item.Height)) chart.Frame.Height = item.Height;
if (IFrameSplitOperator.IsNumber(item.YLineType)) chart.Frame.YSplitOperator.LineType=item.YLineType;
if (IFrameSplitOperator.IsNumber(item.XLineType)) chart.Frame.XSplitOperator.LineType=item.XLineType;
if (Array.isArray(item.IgnoreYValue)) chart.Frame.YSplitOperator.IgnoreYValue=item.IgnoreYValue;
if (item.IsShowLeftText===false || item.IsShowLeftText===true)
{
chart.Frame.IsShowYText[0]=item.IsShowLeftText;
chart.Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
}
if (item.IsShowRightText===false || item.IsShowRightText===true)
{
chart.Frame.IsShowYText[1]=item.IsShowRightText;
chart.Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
if (item.IsShowXLine==false) chart.Frame.IsShowXLine=item.IsShowXLine;
if (item.IsShowYLine==false) chart.Frame.IsShowYLine=item.IsShowYLine;
if (IFrameSplitOperator.IsNumber(item.XSplitCount)) chart.Frame.XSplitOperator.SplitCount=item.XSplitCount; //X轴刻度个数 半边的
}
return chart;
}
//根据option内容绘制图形
this.SetOption=function(option)
{
//toolbar按钮风格
if (IFrameSplitOperator.IsNumber(option.ToolbarButtonStyle)) g_JSChartResource.ToolbarButtonStyle=option.ToolbarButtonStyle;
var chart=null;
switch(option.Type)
{
case "历史K线图":
case '历史K线图横屏':
chart=this.CreateKLineChartContainer(option);
break;
case "自定义指数历史K线图":
chart=this.CreateCustomKLineChartContainer(option);
break;
case "分钟走势图":
case "分钟走势图横屏":
chart=this.CreateMinuteChartContainer(option);
break;
case "迷你分钟走势图":
chart=this.CreateMinMinuteChartContainer(option);
break;
case 'K线训练':
case 'K线训练横屏':
case "简单K线训练":
case "简单K线训练横屏":
chart=this.CreateKLineTrainChartContainer(option);
break;
case "深度图":
chart=this.CreateDepthChartContainer(option);
break;
default:
return false;
}
if (!chart) return false;
this.JSChartContainer=chart;
chart.DivElement=this.DivElement;
if (option.EnableResize==true) this.CreateResizeListener();
if (option.DefaultCursor) chart.DefaultCursor=option.DefaultCursor;
if (option.OnCreatedCallback) option.OnCreatedCallback(chart);
//是否自动更新
if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate;
if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency;
//内置菜单
if (option.EnablePopMenuV2===true) chart.InitalPopMenu();
//画图工具
if (option.EnableDrawToolDialogV2===true) chart.InitalDrawToolDialog();
if (option.EnableModifyDrawDialogV2===true) chart.InitalModifyDrawDialog();
//K线tooltip
if (option.TooltipDialog && option.TooltipDialog.Enable)
chart.InitalTooltipDialog(option.TooltipDialog);
if (option.FloatTooltip && option.FloatTooltip.Enable)
chart.InitalFloatTooltip(option.FloatTooltip);
if (option.SelectRectDialog && option.SelectRectDialog.Enable)
chart.InitalSelectRectDialog(option.SelectRectDialog);
if (option.SearchIndexDialog && option.SearchIndexDialog.Enable)
chart.InitalSearchIndexDialog(option.SearchIndexDialog);
//注册事件
if (option.EventCallback)
{
for(var i=0;i<option.EventCallback.length;++i)
{
var item=option.EventCallback[i];
chart.AddEventCallback(item);
}
}
//设置股票代码
if (!option.Symbol)
{
chart.DrawEmpty();
this.JSChartContainer=chart;
this.DivElement.JSChart=this; //div中保存一份
}
else
{
chart.Draw();
chart.ChangeSymbol(option.Symbol);
this.JSChartContainer=chart;
this.DivElement.JSChart=this; //div中保存一份
this.JSChartContainer.Draw();
}
}
this.CreateResizeListener=function()
{
this.ResizeListener = new ResizeObserver((entries)=>{ this.OnDivResize(entries); });
this.ResizeListener.observe(this.DivElement);
}
this.OnDivResize=function(entries)
{
JSConsole.Chart.Log("[JSChart::OnDivResize] entries=", entries);
this.OnSize( {Type:1} );
}
//创建工具条
this.CreateToolbar=function(option)
{
}
//创建设置div窗口
this.CreateSettingDiv=function(option)
{
}
this.Focus=function()
{
if (this.CanvasElement) this.CanvasElement.focus();
}
//切换股票代码接口
this.ChangeSymbol=function(symbol, option)
{
if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol,option);
}
//K线切换指标
this.ChangeIndex=function(windowIndex,indexName,option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndex)=='function')
this.JSChartContainer.ChangeIndex(windowIndex,indexName,option);
}
//切换一个窗口指标,包含叠加指标,以及这个窗口的属性
this.ChangeIndexWindow=function(windowIndex, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexWindow)=='function')
this.JSChartContainer.ChangeIndexWindow(windowIndex, option);
}
this.AddIndexWindow=function(indexName,option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.AddIndexWindow)=='function')
this.JSChartContainer.AddIndexWindow(indexName,option);
}
this.AddScriptIndexWindow=function(indexInfo, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.AddScriptIndexWindow)=='function')
this.JSChartContainer.AddScriptIndexWindow(indexInfo,option);
}
this.AddAPIIndexWindow=function(indexData, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.AddAPIIndexWindow)=='function')
this.JSChartContainer.AddAPIIndexWindow(indexData,option);
}
this.RemoveIndexWindow=function(id)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.RemoveIndexWindow)=='function')
this.JSChartContainer.RemoveIndexWindow(id);
}
this.ChangeScriptIndex=function(windowIndex,indexData,option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeScriptIndex)=='function')
this.JSChartContainer.ChangeScriptIndex(windowIndex,indexData,option);
}
this.ChangePyScriptIndex=function(windowIndex, indexData) //切换py指标
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePyScriptIndex)=='function')
this.JSChartContainer.ChangePyScriptIndex(windowIndex,indexData);
}
this.GetIndexInfo=function()
{
if (this.JSChartContainer && typeof(this.JSChartContainer.GetIndexInfo)=='function')
return this.JSChartContainer.GetIndexInfo();
else
return [];
}
this.ChangeInstructionIndex=function(indexName, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeInstructionIndex)=='function')
this.JSChartContainer.ChangeInstructionIndex(indexName, option);
}
this.ChangeInstructionScriptIndex=function(indexData)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeInstructionIndex)=='function')
this.JSChartContainer.ChangeInstructionScriptIndex(indexData);
}
this.CancelInstructionIndex=function()
{
if (this.JSChartContainer && typeof(this.JSChartContainer.CancelInstructionIndex)=='function')
this.JSChartContainer.CancelInstructionIndex();
}
//K线周期切换
this.ChangePeriod=function(period, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePeriod)=='function')
this.JSChartContainer.ChangePeriod(period, option);
}
//K线复权切换
this.ChangeRight=function(right)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeRight)=='function')
this.JSChartContainer.ChangeRight(right);
}
//叠加股票
this.OverlaySymbol=function(symbol,option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.OverlaySymbol)=='function')
this.JSChartContainer.OverlaySymbol(symbol,option);
}
//删除一个叠加股票
this.DeleteOverlaySymbol=function(symbol)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlaySymbol)=='function')
this.JSChartContainer.DeleteOverlaySymbol(symbol);
}
//设置当前屏的起始日期 { Date:起始日期(必填), Time:起始时间(分钟K线必填) PageSize:一屏显示的数据个数(可选)}
this.SetFirstShowDate=function(obj)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.SetFirstShowDate)=='function')
this.JSChartContainer.SetFirstShowDate(obj);
}
//K线切换类型 0=实心K线 1=收盘价线 2=美国线 3=空心K线 4=面积图 5=订单流
this.ChangeKLineDrawType=function(drawType, isDraw, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeKLineDrawType)=='function')
this.JSChartContainer.ChangeKLineDrawType(drawType,isDraw, option);
}
//指标窗口个数
this.ChangeIndexWindowCount = function(count, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexWindowCount) == 'function')
{
this.JSChartContainer.ChangeIndexWindowCount(count,option);
}
}
//取消叠加
this.ClearOverlaySymbol = function(){
if(this.JSChartContainer && typeof(this.JSChartContainer.ClearOverlaySymbol) == 'function'){
this.JSChartContainer.ClearOverlaySymbol();
}
}
this.DeleteKLineInfo=function(infoName)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.DeleteKLineInfo) == 'function')
{
this.JSChartContainer.DeleteKLineInfo(infoName);
}
}
this.ClearKLineInfo=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ClearKLineInfo) == 'function')
{
this.JSChartContainer.ClearKLineInfo();
}
}
this.AddKLineInfo=function(infoName, bUpdate)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddKLineInfo) == 'function')
{
this.JSChartContainer.AddKLineInfo(infoName,bUpdate);
}
}
this.AddOverlayIndex=function(obj) //{WindowIndex:窗口ID, IndexName:指标ID, Identify:叠加指标ID(可选), API}
{
if (this.JSChartContainer && typeof(this.JSChartContainer.AddOverlayIndex)=='function')
this.JSChartContainer.AddOverlayIndex(obj);
}
this.MoveOverlayIndex=function(src, dest, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.MoveOverlayIndex)=='function')
this.JSChartContainer.MoveOverlayIndex(src, dest, option);
}
this.MoveOverlayIndexToNewWindow=function(src, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.MoveOverlayIndexToNewWindow)=='function')
this.JSChartContainer.MoveOverlayIndexToNewWindow(src, option);
}
this.DeleteOverlayWindowsIndex=function(identify)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlayWindowsIndex)=='function')
this.JSChartContainer.DeleteOverlayWindowsIndex(identify);
}
this.StopAutoUpdate=function()
{
if (this.JSChartContainer && typeof(this.JSChartContainer.StopAutoUpdate)=='function')
this.JSChartContainer.StopAutoUpdate();
}
this.ChartDestroy=function()
{
if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestroy) == 'function')
{
this.JSChartContainer.ChartDestroy();
}
}
this.ChartDestory=this.ChartDestroy; //版本写错了,继续使用
//设置深度图数据 depthData=[ {ID:深度图ID, Data:数据},] option={ Draw: true/false }
this.SetDepthMapData=function(depthData, option)
{
if (this.JSChartContainer && typeof(this.JSChartContainer.SetDepthMapData)=='function')
this.JSChartContainer.SetDepthMapData(depthData, option);
}
//设置强制横屏
this.ForceLandscape=function(bForceLandscape)
{
if (this.JSChartContainer)
{
JSConsole.Chart.Log("[JSChart::ForceLandscape] bForceLandscape="+bForceLandscape);
this.JSChartContainer.IsForceLandscape=bForceLandscape;
}
}
//锁指标
this.LockIndex=function(lockData)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.LockIndex)=='function')
{
JSConsole.Chart.Log('[JSChart:LockIndex] lockData', lockData);
this.JSChartContainer.LockIndex(lockData);
}
}
//历史分钟数据 更改日期
this.ChangeTradeDate=function(tradeDate)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeTradeDate)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeTradeDate] date', tradeDate);
this.JSChartContainer.ChangeTradeDate(tradeDate);
}
}
//多日走势图
this.ChangeDayCount=function(count, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeDayCount)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeDayCount] count', count);
this.JSChartContainer.ChangeDayCount(count,option);
}
}
//集合竞价显示/隐藏
this.ShowCallAuctionData=function(obj, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ShowCallAuctionData)=='function')
{
JSConsole.Chart.Log('[JSChart:ShowCallAuctionData] obj, option ', obj, option);
this.JSChartContainer.ShowCallAuctionData(obj, option);
}
}
//返回弹幕数据类
this.StartAnimation=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.StartAnimation)=='function')
{
JSConsole.Chart.Log('[JSChart:StartAnimation] start.');
return this.JSChartContainer.StartAnimation(option);
}
}
this.StopAnimation=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.StopAnimation)=='function')
{
JSConsole.Chart.Log('[JSChart:StopAnimation] start.');
return this.JSChartContainer.StopAnimation();
}
}
this.SaveToImage = function (format,colorGB) //format=保存的文件格式, colorGB=背景色
{
if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImage) == 'function')
return this.JSChartContainer.SaveToImage(format,colorGB);
}
this.SaveToImageUrl=function(obj, callback)
{
if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImageUrl) == 'function')
return this.JSChartContainer.SaveToImageUrl(obj, callback);
}
//事件回调
this.AddEventCallback=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function')
{
JSConsole.Chart.Log('[JSChart:AddEventCallback] ', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//设置语言 'EN', 'CN'
this.SetLanguage=function(language)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.SetLanguage)=='function')
{
JSConsole.Chart.Log('[JSChart:SetLanguage] ', language);
this.JSChartContainer.SetLanguage(language);
}
}
//切换指标模板
this.ChangeIndexTemplate=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexTemplate)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeIndexTemplate] ', option);
this.JSChartContainer.ChangeIndexTemplate(option);
}
}
//画图工具
this.SetChartDrawOption=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.SetChartDrawOption)=='function')
{
JSConsole.Chart.Log('[JSChart:SetChartDrawOption] ', option);
this.JSChartContainer.SetChartDrawOption(option);
}
}
this.CreateChartDrawPicture=function(name,option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.CreateChartDrawPicture)=='function')
{
JSConsole.Chart.Log('[JSChart:CreateChartDrawPicture] ', name);
this.JSChartContainer.CreateChartDrawPicture(name,option);
}
}
this.AddChartDrawPicture=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddChartDrawPicture)=='function')
{
JSConsole.Chart.Log('[JSChart:AddChartDrawPicture] ', obj);
return this.JSChartContainer.AddChartDrawPicture(obj);
}
}
//删除画图工具
this.ClearChartDrawPicture=function(drawPicture, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ClearChartDrawPicture)=='function')
{
//JSConsole.Chart.Log('[JSChart:ClearChartDrawPicture] ', drawPicture);
this.JSChartContainer.ClearChartDrawPicture(drawPicture, option);
}
}
//复制一个画图
this.PasteChartDrawPicture=function(data, frameID, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.PasteChartDrawPicture)=='function')
{
JSConsole.Chart.Log('[JSChart:PasteChartDrawPicture] ', data, frameID, option);
return this.JSChartContainer.PasteChartDrawPicture(data, frameID, option);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSChart:ReloadResource] ');
this.JSChartContainer.ReloadResource(option);
}
}
this.EnableSplashScreen=function(enable, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.EnableSplashScreen)=='function')
{
JSConsole.Chart.Log('[JSChart:EnableSplashScreen] ');
this.JSChartContainer.EnableSplashScreen(enable, option);
}
}
this.Draw=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function')
{
JSConsole.Chart.Log('[JSChart:Draw] ');
this.JSChartContainer.Draw();
}
}
this.SetFocus=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.SetFocus)=='function')
{
JSConsole.Chart.Log('[JSChart:SetFocus] ');
this.JSChartContainer.SetFocus();
}
}
//数据导出, option={ Start:{ Date, Time:可选}, End:{Date: Time:可选} }
this.ExportData=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ExportData)=='function')
{
JSConsole.Chart.Log('[JSChart:ExportData] ');
return this.JSChartContainer.ExportData(option);
}
}
this.ChangePriceGap=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangePriceGap)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangePriceGap] ');
return this.JSChartContainer.ChangePriceGap(option);
}
}
this.PopupMenuByTab=function(menuData, rtTab)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.PopupMenuByTab)=='function')
{
JSConsole.Chart.Log('[JSChart:PopupMenuByTab] ');
return this.JSChartContainer.PopupMenuByTab(menuData, rtTab);
}
}
this.PopupMenuByDrapdown=function(menuData, rtButton)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.PopupMenuByDrapdown)=='function')
{
JSConsole.Chart.Log('[JSChart:PopupMenuByDrapdown] ');
return this.JSChartContainer.PopupMenuByDrapdown(menuData, rtButton);
}
}
}
JSChart.LastVersion=null; //最新的版本号
JSChart.EnableCanvasWillReadFrequently=false; //https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently
JSChart.CorssCursorCanvasKey="hqchart_corsscursor";
JSChart.TooltipCursorCanvasKey="hqchart_tooltip";
JSChart.RectDragCanvasKey="hqchart_drag_rect";
//初始化
JSChart.Init=function(divElement,bScreen,bCacheCanvas)
{
var jsChartControl=new JSChart(divElement,bScreen,bCacheCanvas);
jsChartControl.OnSize();
return jsChartControl;
}
JSChart.SetDomain=function(domain,cacheDomain)
{
if (domain) g_JSChartResource.Domain=domain;
if (cacheDomain) g_JSChartResource.CacheDomain=cacheDomain;
}
JSChart.SetPyIndexDomain=function(domain) //设置py指标计算api域名
{
if (domain) g_JSChartResource.PyIndexDomain=domain;
}
//自定义风格
JSChart.SetStyle=function(option)
{
if (option) g_JSChartResource.SetStyle(option);
}
//value { EN:'', CH:'' }
JSChart.SetTextResource=function(key,value)
{
g_JSChartLocalization.SetTextResource(key,value);
}
//获取本地化资源
JSChart.GetLocalization=function()
{
return g_JSChartLocalization;
}
//获取设备分辨率比
JSChart.GetDevicePixelRatio=function()
{
return GetDevicePixelRatio();
}
JSChart.CreateGuid=function()
{
return Guid();
}
JSChart.GetResource=function() //获取颜色配置 (设置配必须啊在JSChart.Init()之前)
{
return g_JSChartResource;
}
JSChart.GetMinuteTimeStringData=function()
{
return g_MinuteTimeStringData;
}
JSChart.GetMinuteCoordinateData=function()
{
return g_MinuteCoordinateData;
}
JSChart.GetKLineZoom=function() //K线缩放配置
{
return ZOOM_SEED;
}
JSChart.SetKLineZoom=function(aryZoom) //设置K线缩放比例
{
ZOOM_SEED=aryZoom;
}
JSChart.GetDivTooltipDataFormat=function() //div tooltip数据格式化
{
return g_DivTooltipDataForamt;
}
JSChart.GetKLineCustomCalulate=function() //K线额外计算
{
return g_KLineCustomCalulate;
}
JSChart.SetUSATimeType=function(type) //设置 0=标准时间 1=夏令时间 3=美国时间
{
g_NYMEXTimeData.TimeType=type;
g_COMEXTimeData.TimeType=type;
g_NYBOTTimeData.TimeType=type;
g_CBOTTimeData.TimeType=type;
}
JSChart.GetChinaFuturesTimeData=function() //获取国内期货交易时间配置
{
return g_FuturesTimeData;
}
JSChart.AddPeriodCallback=function(obj) //添加自定义周期方法 { Period:周期ID, Callback:回调 }
{
g_DataPlus.AddPeriodCallback(obj);
}
JSChart.RemovePeriodCallback=function(obj) //添加自定义周期方法 { Period:周期ID, }
{
g_DataPlus.RemovePeriodCallback(obj);
}
//注册一个新的画图工具 {Name:中文名字, ClassName:类名, Create:function()}
JSChart.RegisterDrawPicture=function(obj)
{
return IChartDrawPicture.RegisterDrawPicture(obj);
}
//注册一个新图标 {Name:, Text: , Color:, Family:}
JSChart.RegisterDrawPictureIonFont=function(obj)
{
return IChartDrawPicture.RegisterIonFont(obj);
}
JSChart.GetInternalTimeData=function(name) //内置品种交易时间
{
switch(name)
{
case "NYMEXTimeData":
return g_NYMEXTimeData;
case "COMEXTimeData":
return g_COMEXTimeData;
case "NYBOTTimeData":
return g_NYBOTTimeData;
case "CBOTTimeData":
return g_CBOTTimeData;
case "LMETimeData":
return g_LMETimeData;
case "FuturesTimeData":
return g_FuturesTimeData;
case "TOCOMTimeData": //东京商品交易所(TOCOM
return g_TOCOMTimeData;
case "IPETimeData":
return g_IPETimeData; //美国洲际交易所
default:
return null;
}
}
//注册外部扩展图形
//option:{ Create:创建类方法 }
JSChart.RegisterExtendChartClass=function(name, option)
{
return g_ExtendChartPaintFactory.Add(name,option);
}
JSChart.AddExtendCallbackDraw=function(className)
{
return g_ExtendChartPaintFactory.AddCallbackDrawClassName(className);
}
//注册外部图形类
//option:{ Create:创建类方法 }
JSChart.RegisterChartPaintClass=function(name, option)
{
return g_ChartPaintFactory.Add(name, option);
}
//注册外部指标图形
JSChart.RegisterScriptIndexChart=function(name, option)
{
return g_ScriptIndexChartFactory.Add(name, option);
}
//注册设置对话框类
//option:{ Create:创建类方法 }
JSChart.RegisterDialogClass=function(name, option)
{
return g_DialogFactory.Add(name, option);
}
//注册框架类
JSChart.RegisterChartFrameClass=function(name, option)
{
return g_ChartFrameFactory.Add(name, option);
}
//一些公共函数
JSChart.ToFixedPoint=function(value)
{
return ToFixedPoint(value);
}
JSChart.ToFixedPoint2=function(width, value)
{
return ToFixedPoint2(width, value);
}
JSChart.ToFixedRect=function(value)
{
return ToFixedRect(value);
}
JSChart.GetScrollPosition=function()
{
return GetScrollPosition();
}
//品种小数位数
JSChart.GetfloatPrecision=function(symbol)
{
return GetfloatPrecision(symbol);
}
var JSCHART_EVENT_ID=
{
//RECV_KLINE_MATCH:1, //接收到形态匹配
RECV_INDEX_DATA:2, //接收指标数据
RECV_HISTROY_DATA:3,//接收到历史数据
RECV_TRAIN_MOVE_STEP:4, //接收K线训练,移动一次K线
CHART_STATUS:5, //每次Draw() 以后会调用
BARRAGE_PLAY_END:6, //单个弹幕播放完成
RECV_OVERLAY_INDEX_DATA:7,//接收叠加指标数据
DBCLICK_KLINE:8, //双击K线图
RECV_START_AUTOUPDATE:9, //开始自动更新
RECV_STOP_AUTOUPDATE:10, //停止自动更新
ON_CONTEXT_MENU:11, //右键菜单事件
ON_TITLE_DRAW:12, //标题信息绘制事件
ON_SELECT_RECT:13, //区间选择事件通知
RECV_MINUTE_DATA:14, //分时图数据到达
ON_CLICK_INDEXTITLE:15, //点击指标标题事件
RECV_KLINE_UPDATE_DATA:16, //K线日,分钟更新数据到达
ON_CLICK_DRAWPICTURE:17, //点击画图工具
ON_FINISH_DRAWPICTURE:18, //完成画图工具
ON_INDEXTITLE_DRAW:19, //指标标题重绘事件
ON_CUSTOM_VERTICAL_DRAW:20, //自定义X轴绘制事件
RECV_KLINE_MANUAL_UPDATE_DATA:21, //手动更新K线事件
ON_ENABLE_SPLASH_DRAW:22, //开启/关闭过场动画事件
ON_CLICK_CHART_PAINT:23, //点击图形
ON_DRAW_MINUTE_LAST_POINT:24, //分时图绘制回调事件, 返回最后一个点的坐标
ON_DRAW_DEPTH_TOOLTIP:25, //绘制深度图tooltip事件
ON_CLICK:26, //点击事件
ON_PHONE_TOUCH:27, //手势点击事件 包含 TouchStart 和 TouchEnd
ON_CLICKUP_CHART_PAINT:28, //点击图形鼠标抬起
ON_SPLIT_YCOORDINATE:29, //分割Y轴及格式化刻度文字
ON_DBCLICK:30,
ON_SPLIT_XCOORDINATE:31, //分割X轴及格式化刻度文字
ON_KEYDOWN_SELECT_RECT:32, //键盘空格区间选择完成事件
ON_DRAG_SELECT_RECT:33, //区间选择区域变动
ON_DRAG_SELECT_RECT_MOUSEUP:34, //区间选择区域变动鼠标松开
ON_DRAW_KLINE_LAST_POINT:35, //K线图绘制回调事件,返回最后一个点的坐标
ON_CLICK_CROSSCURSOR_RIGHT:36, //十字光标右边按钮
ON_PLAY_SOUND:37, //播放声音 { Name:, Data: }
ON_CALCULATE_INDEX_OX:38, //创建OX指标回调
ON_LOAD_DRAWPICTURE:39, //加载画图工具
//ON_SAVE_DRAWPICTURE:40 //画图工具存盘
ON_DRAW_COUNTDOWN:41, //倒计时回调
ON_BIND_DRAWICON:42, //小程序用到,h5无效
ON_DRAW_DEAL_VOL_COLOR:43, //成交明细 成交量颜色
ON_DRAW_DEAL_TEXT:44, //成交明细 自定义字段
ON_FILTER_DEAL_DATA:45, //成交明细 数据过滤回调
ON_FILTER_REPORT_DATA:46, //报价列表 数据过滤回调
ON_CLICK_REPORT_ROW:47, //点击报价列表
ON_REPORT_MARKET_STATUS:48, //报价列表交易状态
ON_DBCLICK_REPORT_ROW:49, //双击报价列表
ON_RCLICK_REPORT_ROW:50, //右键点击列表
ON_CLICK_REPORT_HEADER:51, //单击表头
ON_RCLICK_REPORT_HEADER:52, //右键点击表头
ON_REPORT_LOCAL_SORT:53, //报价列表本地排序
ON_DRAW_REPORT_NAME_COLOR:54, //报价列表股票名称列颜色
ON_DRAW_CUSTOM_TEXT:55, //报价列表自定义列
ON_CLICK_REPORT_TAB:56, //报价列表标签点击
ON_CLICK_REPORT_TABMENU:57, //报价列表标签菜单点击
ON_DRAW_REPORT_FIXEDROW_TEXT:58, //报价列表固定行绘制
ON_CLICK_REPORT_FIXEDROW:59, //点击报价列表点击固定行
ON_RCLICK_REPORT_FIXEDROW:60, //点击报价列表右键点击固定行
ON_KEYDOWN_SELECT_RECT_FIRST:61, //区间选择第1个位置事件
ON_CLICK_FRAME_TOOLBAR:62, //指标标题工具栏
ON_REPORT_DRAG_ROW:63, //自选股行拖拽
ON_MOUSE_MOVE:64, //鼠标移动
ON_MINUTE_PAGE_CHANGED:65, //分时图翻页事件
ON_DRAG_SUB_SELECT_RECT:66, //拖拽区间选择子区域
ON_DRAG_SUB_SELECT_RECT_MOUSEUP:67, //拖拽区间选择子区域鼠标松开
ON_KEYBOARD_SELECTED:68, //键盘精灵选中回车
ON_KEYBOARD_MOUSEUP:69,
ON_CLICK_DRAWPICTURE_BUTTON:70, //画图工具按钮
ON_FINISH_MOVE_DRAWPICTURE:71, //画图工具移动完成
ON_CLICK_EXTENDCHART_BUTTON:72,
ON_SCROLLBAR_SLIDER_CHANGED:73, //滚动条拖动
ON_DISPLAY_LATEST:74, //显示最新数据
ON_FORMAT_CORSSCURSOR_Y_TEXT:75, //格式化十字光标Y轴文字
ON_FORMAT_INDEX_OUT_TEXT:76, //格式化指标标题文字
ON_FORMAT_CORSSCURSOR_X_TEXT:77, //格式化十字光标X轴文字
ON_REPORT_MOUSE_MOVE:78, //鼠标移动 { x,y, Cell:单元格}
ON_REPORT_DRAG_HEADER_TOOLTIP:88, //表头拖动提示信息
ON_REPORT_DRAW_CUSTOM_ICON:89, //表格自定义图标
ON_REPORT_DRAW_KLINE:90, //表格绘制K线
ON_DBCLICK_REPORT_DRAG_COLUMN_WIDTH:91, //双击表头拖动宽度
ON_REPORT_FORMAT_DRAW_INFO:92, //单元格输出信息
ON_FORMAT_INDEX_Y_LABEL:93, //格式化指标右侧Y轴刻度输出
ON_FORMAT_OVERLAY_INDEX_Y_LABEL:94, //格式化叠加指标右侧Y轴刻度输出
ON_CUSTOM_UNCHANGE_KLINE_COLOR:95, //定制平盘K线颜色
ON_CLICK_TITLE_BUTTON:96, //指标标题按钮
ON_CUSTOM_LEFT_TOOLBAR:97,
ON_CUSTOM_RIGHT_TOOLBAR:98,
ON_REPORT_DRAG_COLUMN_WIDTH:99, //拖动列宽
ON_CUSTOM_UNCHANGE_KLINE_TITLE_COLOR:100, //定制平盘K线标题颜色
ON_CHANGE_KLINE_PERIOD:101, //切换周期
ON_MINUTE_TOUCH_ZOOM:102, //分时图手势缩放
ON_RELOAD_INDEX_CHART_RESOURCE:103, //加载指标图形额外资源
ON_RELOAD_OVERLAY_INDEX_CHART_RESOURCE:104, //加载叠加指标图形额外资源
ON_CREATE_FRAME:105,
ON_DELETE_FRAME:106,
ON_SIZE_FRAME:107,
ON_TOUCH_SCROLL_UP_DOWN:108, //页面上下滚动 手机端
ON_RECV_REALTIME_DATA:109, //实时数据
ON_CUSTOM_OVERLAY_TOOLBAR:110, //自定义叠加指标按钮
//绘图之前的事件
ON_BEFORE_DRAW:111,
ON_BEFORE_DRAW_DYNAMIC_INFO:112,
//自定义图形拖拽
ON_CUSTOM_DRAG_MOUSE_DOWN:113,
ON_CUSTOM_DRAG_DOC_MOUSE_MOVE:114,
ON_CUSTOM_DRAG_DOC_MOUSE_UP:115,
ON_CUSTOM_DRAG_MOUSE_MOVE:116,
ON_KEYDOWN:117,
ON_CREATE_OVERLAY_FRAME:118, //创建叠加框架回调
ON_CREATE_CUSTOM_Y_COORDINATE:119, //自定义Y轴刻度
ON_BEFORE_DRAW_SPLASH_SCREEN:120,
//T型报价
ON_TREPORT_MARKET_STATUS:121, //T型报价列表交易状态
ON_DBCLICK_TREPORT_ROW:122, //双击T型报报价列表
ON_RCLICK_TREPORT_ROW:123, //右键点击T型报价列表
ON_CLICK_TREPORT_HEADER:124, //单击T型报价表头
ON_RCLICK_TREPORT_HEADER:125, //右键点击T型报价表头
ON_TREPORT_LOCAL_SORT:126, //T型报价列表本地排序
ON_CLICK_TREPORT_ROW:127, //左键点击点击T型报价列表
ON_MOVE_SELECTED_TREPORT_ROW:128, //选中行变动
ON_DRAW_REPORT_ROW_BG:140, //报价列表整行背景
ON_CLICK_REPORT_CHECKBOX:141, //报价列表checkbox
ON_CLICK_REPORT_BUTTON:142, //报价列表按钮
ON_CLICK_REPORT_LINK:143, //报价列表 链接
ON_CREATE_REPORT_HEADER_MENU:144, //报价列表 表头菜单
ON_CHANGE_INDEX:150, //切换指标
ON_MENU_COMMAND:151, //菜单事件回调
ON_CREATE_RIGHT_MENU:152, //创建右键菜单
ON_FORMAT_CALL_AUCTION_INDEX_TITLE:153, //集合竞价指标窗口标题内容
ON_FORMAT_KLINE_HIGH_LOW_TITLE:154, //K线最高最低价格式化内容
ON_CUSTOM_CORSSCURSOR_POSITION:155, //自定义十字光标X轴的输出的位置
ON_CUSTOM_MINUTE_NIGHT_DAY_X_INDEX:156, //日盘夜盘的分界线
ON_CUSTOM_MINUTE_BG:157, //自定义分时图背景颜色
ON_CLICK_HORIZONTAL_LABEL:158, //点击Y轴刻度标签
ON_FORMAT_DIALOG_TOOLTIP:159, //格式化Tooltip对话框显示文字
ON_CHANGE_KLINE_RIGHT:160, //切换复权
ON_FORMAT_KLINE_FLOAT_TOOLTIP:161, //格式化k线浮动框显示文字
ON_FORMAT_KLINE_INFO_FLOAT_TOOLTIP:162, //格式化信息地雷显示文字
}
var JSCHART_OPERATOR_ID=
{
OP_SCROLL_LEFT:1, //往左移动
OP_SCROLL_RIGHT:2, //往右移动
OP_ZOOM_OUT:3, //缩小
OP_ZOOM_IN:4, //放大
OP_GOTO_HOME:5, //最新一天数据
OP_GOTO_END:6, //第1天的数据
OP_LEFT_ZOOM_OUT:7, //左边缩小
OP_LEFT_ZOOM_IN:8, //左右放大
OP_RIGHT_ZOOM_OUT:9, //右边缩小
OP_RIGHT_ZOOM_IN:10, //右边放大
OP_SCROLL_GOTO:11, //滚动条移动到某一个位置
OP_SET_SELECTRECT:12, //区间选择
OP_SET_SUB_SELECTRECT:13, //区间选择子区域
OP_CORSSCURSOR_GOTO:14, //十字光标移动某一个时刻点
OP_SCROOLBAR_SLIDER_CHANGED:15, //滑块变动
OP_GOTO:16, //移动到某一个天或某一个分钟
OP_GOTO_BY_DATAINDEX:17, //的移动到某一个数据起始位置
}
var JSCHART_DRAG_ID=
{
DISABLE_DRAG_ID:0,
CLICK_TOUCH_MODE_ID:3 //长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
}
var JSCHART_BUTTON_ID=
{
CLOSE_BEFOREOPEN_ID:1, //关闭集合竞价
CLOSE_OVERLAY_INDEX:2, //关闭叠加指标
MODIFY_INDEX_PARAM:3, //改指标参数
CHANGE_INDEX:4, //换指标
CLOSE_INDEX_WINDOW:5, //关闭指标窗口
OVERLAY_INDEX:6, //叠加指标
MODIFY_OVERLAY_INDEX_PARAM:7, //改叠加指标参数
CHIP_DEFULT:8,
CHIP_LONG:9,
CHIP_RECENT:10,
MAX_MIN_WINDOW:11, //指标窗口最大最小化
TITLE_WINDOW:12, //指标窗口只显示标题
//画图工具
DRAW_PICTURE_DELETE:13,
DRAW_PICTURE_SETTING:14,
EXTEND_CHART_BUTTON_ID:15, //扩展画法按钮事件
EXPORT_DATA:16,
//画图工具 按钮预留18个
DRAW_PICTURE_BUTTON_1:17,
DRAW_PICTURE_BUTTON_2:18,
DRAW_PICTURE_BUTTON_3:19,
DRAW_PICTURE_BUTTON_4:20,
DRAW_PICTURE_BUTTON_5:21,
DRAW_PICTURE_BUTTON_6:22,
DRAW_PICTURE_BUTTON_7:23,
DRAW_PICTURE_BUTTON_8:24,
DRAW_PICTURE_BUTTON_9:25,
DRAW_PICTURE_BUTTON_10:26,
DRAW_PICTURE_BUTTON_11:27,
DRAW_PICTURE_BUTTON_12:28,
DRAW_PICTURE_BUTTON_13:29,
DRAW_PICTURE_BUTTON_14:30,
DRAW_PICTURE_BUTTON_15:31,
DRAW_PICTURE_BUTTON_16:32,
DRAW_PICTURE_BUTTON_17:33,
DRAW_PICTURE_BUTTON_18:34,
//弹出菜单
POP_MENU_1:40,
POP_MENU_2:41,
POP_MENU_3:42,
INDEX_NAME_BUTTON:43
}
var JSCHART_DATA_FIELD_ID=
{
KLINE_ORDERFLOW:99,
MINUTE_MULTI_DAY_EXTENDDATA:21, //多日分时图扩展数据序号
MINUTE_DAY_EXTENDDATA:21,
MINUTE_BEFOREOPEN_EXTENDDATA:21,
MINUTE_AFTERCLOSE_EXTENDDATA:21,
KLINE_COLOR_DATA:66, //K线自定义颜色数据
KLINE_DAY_EXTENDDATA:25,
KLINE_MINUTE_EXTENDDATA:25,
//OrderBook Heatmap
KLINE_HEATMAP:67,
}
var JSCHART_WORKER_MESSAGE_ID=
{
EXECUTE_SCRIPT:1, //工作线程执行脚本
FINISH_EXECUTE_SCRIPT:2, //脚本执行完成
ERROR_EXECUTE_SCRIPT:3,
}
var JSCHART_MENU_ID=
{
CMD_CHANGE_PERIOD_ID:1, //切换周期
CMD_CHANGE_WINDOW_COUNT_ID:2, //窗口个数
CMD_CHANGE_RIGHT_ID:3, //复权
CMD_CHANGE_INDEX_ID:4, //切换指标
CMD_CHANGE_COLOR_INDEX_ID:5, //五彩K线指标
CMD_CHANGE_TRADE_INDEX_ID:6, //专家系统(交易指标)
CMD_DELETE_COLOR_INDEX_ID:7, //删除五彩K线指标
CMD_DELETE_TRADE_INDEX_ID:8, //删除专家系统(交易指标)
CMD_CHANGE_KLINE_TYPE_ID:9, //切换K线类型
CMD_CHANGE_PRICE_GAP_ID:10, //缺口提示
CMD_OVERLAY_SYMBOL_ID:11, //叠加品种
CMD_DELETE_ALL_OVERLAY_SYMBOL_ID:12, //删除所有叠加品种
CMD_CHANGE_COORDINATETYPE_ID:13, //切换坐标类型
CMD_CHANGE_KLINE_INFO_ID:14, //切换信息地雷
CMD_DELETE_ALL_KLINE_INFO_ID:15, //清空信息地雷
CMD_CHANGE_DRAG_MODE_ID:16, //切换拖动模式
CMD_CHANGE_BG_SPLIT_ID:17, //背景分割
CMD_SHOW_DRAWTOOL_ID:18, //画图工具
CMD_HIDE_DRAWTOOL_ID:19,
CMD_SHOW_STOCKCHIP_ID:20, //筹码分布
CMD_HIDE_STOCKCHIP_ID:21,
CMD_ENABLE_SELECT_RECT_ID:22, //启动区间选择
CMD_CHANGE_DAY_COUNT_ID:23, //切换天数
CMD_SHOW_BEFORE_DATA_ID:24, //显示|隐藏集合竞价
CMD_SELECTED_ZOOM_ID:25, //选中放大
CMD_SELECTED_SUMMARY_ID:26, //区间统计
CMD_SHOW_INDEX_ID:27, //显示隐藏指标
CMD_SHOW_OVERLAY_INDEX_ID:28, //显示隐藏叠加指标
CMD_DELETE_OVERLAY_INDEX_ID:29, //删除叠加指标
CMD_SHOW_OVERLAY_Y_AXIS_ID:30, //显示隐藏Y轴叠加指标
CMD_ENABLE_OVERLAY_SHARE_Y_ID:31, //和主图指标共享Y轴坐标
CMD_CHANGE_DEFAULTCURSOR_ID:32, //修改鼠标形状
CMD_CHANGE_API_INDEX_ID:33, //切换后台接口指标
CMD_CHANGE_SCRIPT_INDEX_ID:34, //切换成自定义的脚本指标
CMD_CHANGE_BASELINE_ID:35, //分时图切换基准线
CMD_ADD_OVERLAY_INDEX_ID:36, //添加叠加指标
CMD_CHANGE_LANGUAGE_ID:37, //语言切换
CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID:38,
CMD_SHOW_CORSS_LINE_ID:39, //显示十字光标线
CMD_ENABLE_POP_MINUTE_CHART_ID:40, //双击弹分时图
CMD_CHANGE_INFO_POSITION_ID:41, //修改信息地雷位置
CMD_REPORT_CHANGE_BLOCK_ID:60, //报价列表 切换板块ID
CMD_REPORT_COLUMN_SORT_ID:61, //报价列表 表头排序 Arg[列序号, 排序方向]
CMD_REPORT_COLUMN_DEL_ID:62, //报价列表 删除列
CMD_REPORT_COLUMN_MOVE_ID:63, //报价列表 列移动
CMD_REPORT_COLUMN_FILTER_ID:64, //报价列表 筛选
CMD_DIALOG_TOOLTIP_ATTRIBUTE:65, //修改K线信息框属性 Ary:[{ Enable:, Style:}, ]
CMD_KLINE_TOOLTIP_ATTRIBUTE:66, //修改K线提示框属性 Ary:[{ Enable:true/false, EnableKeyDown:true/false}]
}
function PhoneDBClick()
{
this.Start=[];
this.Clear=function()
{
this.Start=[];
}
this.AddTouchStart=function(x, y, time)
{
if (this.Start.length>0)
{
var item=this.Start[this.Start.length-1];
var spanTime=time-item.Time;
if (spanTime>0 && spanTime<300)
{
this.Start.push({ X:x, Y:y, Time:time });
}
else
{
this.Start=[];
}
}
else
{
this.Start.push({ X:x, Y:y, Time:time });
}
}
this.IsVaildDBClick=function()
{
if (this.Start.length==2) return true;
return false;
}
this.AddTouchEnd=function(time)
{
if (this.Start.length<=0) return;
var item=this.Start[this.Start.length-1];
var spanTime=time-item.Time;
if (spanTime>=0 && spanTime<150)
{
}
else
{
this.Start=[];
}
}
}
/*
图形控件
*/
function JSChartContainer(uielement, OffscreenElement, cacheElement)
{
this.ClassName='JSChartContainer';
var _self = this;
this.Frame; //框架画法
this.ChartPaint=new Array(); //图形画法
this.ChartPaintEx=[]; //图形扩展画法
this.ChartInfo=new Array(); //K线|走势图上信息地雷
this.ChartInfoPaint; //信息地理
this.ExtendChartPaint=new Array(); //扩展画法
this.TitlePaint=new Array(); //标题画法
this.OverlayChartPaint=new Array(); //叠加信息画法
this.ChartDrawPicture=new Array(); //画图工具
this.ChartDrawStorage; //画图工具保存
this.ChartDrawOption={ IsLockScreen:false, Zoom:1, Magnet:null }; //画图工具设置 { IsLockScreen://是否锁住屏幕, Zoom: //线段|点放大倍数, Magnet:磁吸 {Enable:, Type, Distance,} }
this.CurrentChartDrawPicture=null; //当前的画图工具
this.SelectChartDrawPicture=null; //当前选中的画图
this.MoveOnChartDrawPicture=null; //鼠标在画图上
this.EnableEraseChartDrawPicture=false; //擦除画图
this.IsDrawPictureXY=false; //选中的画图工具是否显示X,Y轴对应数值
this.EnableShowCorssCursor={ DrawPicture:true }; //DrawPicture=画图是否显示十字光标
this.ChartPictureMenu; //画图工具 单个图形设置菜单
this.ChartCorssCursor; //十字光标
this.ChartDragSelectRect; //选择区间选中
this.IsClickShowCorssCursor=false; //手势点击显示十字光标
this.ChartSplashPaint=null; //等待提示
this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息
this.DefaultCursor="default"; //crosshair , default 默认手型
//绘图缓存
this.CacheCanvas=null;
this.CacheElement=null;
if (cacheElement)
{
this.CacheElement=cacheElement;
this.CacheCanvas=cacheElement.getContext("2d");
}
if (OffscreenElement)
{
this.Canvas=OffscreenElement.getContext("2d");
this.OffscreenCanvasElement=OffscreenElement;
this.ShowCanvas=uielement.getContext("2d");
}
else
{
if (JSChart.EnableCanvasWillReadFrequently===true)
{
let contextAttr={ willReadFrequently:true };
this.Canvas=uielement.getContext("2d",contextAttr); //画布
}
else
{
this.Canvas=uielement.getContext("2d"); //画布
}
this.ShowCanvas=null;
}
//十字光标层
this.CorssCursorElement;
this.CorssCursorCanvas;
this.UIElement=uielement;
this.MouseDrag;
this.PhoneTouchInfo; //手机手势信息
this.DragMode=1; //拖拽模式 0 禁止拖拽 1 数据拖拽 2 区间选择 3(CLICK_TOUCH_MODE_ID)=长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
this.EnableBorderDrag=true; //是否可以拖拽边框调整指标框高度
this.BorderDrag; //{ Index:, }
this.YDrag; //{Index: } //y轴拖拽放大缩小
this.TouchStatus={ CorssCursorShow:false }, //十字光标是否显示
this.DragTimer;
this.EnableScrollUpDown=false; //是否可以上下滚动图形(手机端才有)
this.ClickChartTimer=null; //点击图形定时器,解决双击和单击K线事件
this.CursorIndex=0; //十字光标X轴索引
this.LastPoint=new Point(); //鼠标位置
this.IsForceLandscape=false; //是否强制横屏
this.CorssCursorTouchEnd = false; //手离开屏幕自动隐藏十字光标
this.IsTitleShowLatestData=false; //十字/手势不在K线图上,标题显示最新一个数据
this.StepPixel=4; //移动一个数据需要的像素 0=自动模式(根据K线宽度+间距)
this.ZoomStepPixel=5; //放大缩小手势需要的最小像素
this.TouchMoveMinAngle=70; //左右移动最小角度
this.EnableAnimation=false; //是否开启动画
//tooltip提示信息
this.Tooltip=document.createElement("div");
this.Tooltip.className='jschart-tooltip';
this.Tooltip.style.background=g_JSChartResource.TooltipBGColor;
this.Tooltip.style.opacity=g_JSChartResource.TooltipAlpha;
this.Tooltip.style["pointer-events"]="none";
this.Tooltip.id=Guid();
uielement.parentNode.appendChild(this.Tooltip);
this.IsShowTooltip=true; //是否显示K线tooltip
this.KLineTooltipConfig={ EnableKeyDown:true, Enable:true }; //K线鼠标移动上去提示信息配置
this.TooltipCache={ Type:null, IsShow:false, X:null, Y:null, Data:null, InnerHTML:null }; //缓存tooltip数据
//坐标轴风格方法 double-更加数值型分割 price-更加股票价格分割
this.FrameSplitData=new Map();
this.FrameSplitData.set("double",new SplitData());
this.FrameSplitData.set("price",new PriceSplitData());
//事件回调
this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,}
this.PhonePinch=null; //手机双指操作信息
this.IsOnTouch = false; //是否再操作数据
this.TouchDrawCount = 0; //手势绘制次数
this.DisableMouse=false; //禁止鼠标事件
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.PressTime=500;
this.IsPress=false; //是否长按
this.NetworkFilter; //网络请求回调 function(data, callback);
this.LastMouseStatus={ MouseOnToolbar:null }; // MouseOnToolbar={ Rect:{}, Title: }
this.ClickDownPoint; //鼠标点击坐标 {X, Y}, 鼠标放开以后清空为null
this.IsDestroy=false; //是否已经销毁了
this.EnableYDrag=
{
Left:false, Right:false, //是否可以拖拽缩放Y轴最大最小值
Wheel:false, WheelYMove:5 //是否可以滚轴缩放Y轴最大最小值
};
this.EnableZoomIndexWindow=false; //是否支持双击缩放附图窗口
this.EnableVerifyRecvData=false; //是否检测接收到的数据
this.PhoneDBClick=new PhoneDBClick();
this.SelectedChart={ EnableSelected:false, EnableMoveOn:false, Selected:{ Identify:null }, MoveOn:{ Identify:null } }; //选中图形
this.IndexChartDrag; //拖拽指标图形
this.EnableIndexChartDrag=false;
this.GlobalOption=
{
IsValueFullRange:false ,
IsDisplayLatest:false,
SelectedBorder:{ Mode:0, SelFrame:0 }, //边框选中模式 Mode:0=禁用 1=右侧标记选中 2=指标窗口标记选中
SelectedXBorder: { Mode:0, Date:null } //X边框选中模式 Mode:0=禁用 分时图图有效
//XDateFormat (多日分时图x轴底部日期格式)
};
this.VerticalDrag; //通过X轴左右拖动数据(手势才有)
this.EnableVerticalDrag=false;
//十字光标长留(手势才有)
this.ClickModel={ IsShowCorssCursor:false };
this.EnableClickModel=false;
//标题栏显示最新数据
this.DisplayLatestOption={ Timer:null, Enable: false, DelayTime:60*1000*3, LastPoint:null };
this.DrawDynamicInfoOption={ Timer:null, Enable:false , DelayTime:10 };
this.CustomChartDrag; //自定义图形的拖拽操作 { Type:, Data: }
this.StockCache={ Data:null }; //扩展数据缓存数据
this.JSPopMenu; //内置菜单
this.IsShowRightMenu=true; //显示右键菜单
this.DialogDrawTool; //画图工具
this.DialogModifyDraw; //画图修改
this.DialogTooltip; //tooltip信息
this.DialogSelectRect; //区间统计
this.FloatTooltip; //浮动tooltip信息
this.DialogSearchIndex; //指标搜索
this.ClearStockCache=function()
{
this.StockCache.Data=null;
}
this.InitalPopMenu=function() //初始化弹出窗口
{
if (this.JSPopMenu) return;
this.JSPopMenu=new JSPopMenu(); //内置菜单
this.JSPopMenu.Inital();
}
this.InitalDrawToolDialog=function()
{
if (this.DialogDrawTool) return;
this.DialogDrawTool=new JSDialogDrawTool();
this.DialogDrawTool.Inital(this);
this.DialogDrawTool.Create();
}
this.InitalTooltipDialog=function(option)
{
if (this.DialogTooltip) return;
this.DialogTooltip=new JSDialogTooltip();
this.DialogTooltip.Inital(this, option);
this.DialogTooltip.Create();
}
this.InitalFloatTooltip=function(option)
{
if (this.FloatTooltip) return;
this.FloatTooltip=new JSFloatTooltip();
this.FloatTooltip.Inital(this, option);
this.FloatTooltip.Create();
}
this.InitalModifyDrawDialog=function()
{
if ( this.DialogModifyDraw) return;
this.DialogModifyDraw=new JSDialogModifyDraw();
this.DialogModifyDraw.Inital(this);
this.DialogModifyDraw.Create();
}
this.InitalSelectRectDialog=function(option)
{
if (this.DialogSelectRect) return;
this.DialogSelectRect=new JSDialogSelectRect();
this.DialogSelectRect.Inital(this, option);
this.DialogSelectRect.Create();
}
this.InitalSearchIndexDialog=function(option)
{
if (this.DialogSearchIndex) return;
this.DialogSearchIndex=new JSDialogSearchIndex();
this.DialogSearchIndex.Inital(this, option);
this.DialogSearchIndex.Create();
}
this.ShowChangeIndexDialog=function(data)
{
if (!data) return;
if (!this.DialogSearchIndex) return;
data.Title=`切换指标 [窗口${data.WindowIndex+1}]`;
this.DialogSearchIndex.SetOpData(data);
this.DialogSearchIndex.Show();
}
this.ShowAddOverlayIndexDialog=function(data)
{
if (!data) return;
if (!this.DialogSearchIndex) return;
data.Title=`添加叠加指标 [窗口${data.WindowIndex+1}]`;
this.DialogSearchIndex.SetOpData(data);
this.DialogSearchIndex.Show();
}
this.DrawSelectRectDialog=function()
{
}
this.IsShowSelectRectDialog=function()
{
if (!this.DialogSelectRect) return false;
return this.DialogSelectRect.IsShow();
}
this.ShowDrawToolDialog=function(x,y)
{
if (!this.DialogDrawTool) return;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var top=this.UIElement.offsetTop+15;
var left=this.UIElement.offsetWidth-this.DialogDrawTool.DivDialog.offsetWidth-15;
left+=rtClient.left+rtScroll.Left;
top+=rtClient.top+rtScroll.Top;
this.DialogDrawTool.Show(left,top);
}
this.IsShowDrawToolDialog=function()
{
if (!this.DialogDrawTool) return false;
return this.DialogDrawTool.IsShow();
}
this.ShowModifyDrawDialog=function(chart, x,y)
{
if (!this.DialogModifyDraw) return;
this.DialogModifyDraw.SetChartPicture(chart);
if (this.DialogModifyDraw.IsShow()) return;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var top=this.UIElement.offsetTop+15;
var left=(this.UIElement.offsetWidth-this.DialogModifyDraw.DivDialog.offsetWidth)/2;
left+=rtClient.left+rtScroll.Left;
top+=rtClient.top+rtScroll.Top;
this.DialogModifyDraw.Show(left, top);
}
this.CloseModifyDrawDialog=function()
{
if (!this.DialogModifyDraw) return;
this.DialogModifyDraw.Close();
}
this.IsShowTooltipDialog=function()
{
if (!this.DialogTooltip) return false;
return this.DialogTooltip.IsShow();
}
this.CloseTooltipDialog=function()
{
if (!this.DialogTooltip) return;
this.DialogTooltip.Close();
}
this.HideFloatTooltip=function()
{
if (!this.FloatTooltip) return;
this.FloatTooltip.Hide();
}
this.DestroyTooltipDialog=function()
{
if (!this.DialogTooltip) return;
this.DialogTooltip.Destroy();
this.DialogTooltip=null;
}
this.DestroyFloatTooltip=function()
{
if (!this.FloatTooltip) return;
this.FloatTooltip.Destroy();
this.FloatTooltip=null;
}
this.DestroySearchIndexDialog=function()
{
if (!this.DialogSearchIndex) return;
this.DialogSearchIndex.Destroy();
this.DialogSearchIndex=null;
}
//obj={ Element:, Canvas: }
this.SetCorssCursorElement=function(obj)
{
if (!obj || !obj.Element || !obj.Canvas) return;
this.CorssCursorElement=obj.Element;
this.CorssCursorCanvas=obj.Canvas;
}
this.StopDisplayLatest=function()
{
this.GlobalOption.IsDisplayLatest=false;
if (this.DisplayLatestOption.Timer)
{
clearTimeout(this.DisplayLatestOption.Timer);
this.DisplayLatestOption.Timer=null;
}
}
this.StartStopDisplayLatest=function()
{
this.StopDisplayLatest();
if (!this.DisplayLatestOption.Enable) return;
this.DisplayLatestOption.Timer=setTimeout(()=>
{
if (this.DisplayLatest)
{
JSConsole.Chart.Log('[JSChartContainer:StartStopDisplayLatest] call this.DisplayLatest()');
this.DisplayLatest();
}
},this.DisplayLatestOption.DelayTime);
}
this.StopDrawDynamicInfo=function()
{
if (this.DrawDynamicInfoOption.Timer)
{
clearTimeout(this.DrawDynamicInfoOption.Timer);
this.DrawDynamicInfoOption.Timer=null;
}
}
this.ChartDestroy=function() //销毁
{
this.IsDestroy=true;
this.StopAutoUpdate();
this.DestroyTooltipDialog();
this.DestroyFloatTooltip();
this.DestroySearchIndexDialog();
}
this.ChartDestory=this.ChartDestroy; //老版本写错了,需要兼容下
//设置焦点
this.SetFocus=function()
{
if (this.UIElement) this.UIElement.focus();
}
//设置事件回调
//{event:事件id, callback:回调函数}
this.AddEventCallback=function(object)
{
if (!object || !object.event || !object.callback) return;
var data={Callback:object.callback, Source:object};
this.mapEvent.set(object.event,data);
}
this.RemoveEventCallback=function(eventid)
{
if (!this.mapEvent.has(eventid)) return;
this.mapEvent.delete(eventid);
}
this.GetEventCallback=function(id) //获取事件回调
{
if (!this.mapEvent.has(id)) return null;
var item=this.mapEvent.get(id);
return item;
}
//接收指标数据
this.GetIndexEvent=function()
{
return this.GetEventCallback(JSCHART_EVENT_ID.RECV_INDEX_DATA);
}
this.GetOverlayIndexEvent=function()
{
return this.GetEventCallback(JSCHART_EVENT_ID.RECV_OVERLAY_INDEX_DATA);
}
//鼠标事件绑定
uielement.onmousemove=(e)=>{ this.UIOnMouseMove(e);}
uielement.oncontextmenu=(e)=> { return this.UIOnContextMenu(e); }
uielement.ondblclick=(e)=>{ this.UIOnDblClick(e); }
uielement.onmousedown=(e)=> { this.UIOnMouseDown(e); }
uielement.onmouseout=(e)=>{ this.UIOnMounseOut(e); }
uielement.onmouseleave=(e)=>{ this.UIOnMouseleave(e); }
this.UIOnMouseMove=function(e)
{
//JSConsole.Chart.Log('[JSChartContainer.UIOnMouseMove] e.clientX, e.clientY, left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top);
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
this.StopDisplayLatest();
//加载数据中,禁用鼠标事件
this.MoveOnChartDrawPicture=null;
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
if (this.DisableMouse==true) return;
if (this.BorderDrag) return;
if (this.YDrag) return;
if (this.IndexChartDrag) return;
if (this.CustomChartDrag) return;
//if (this.RectSelectDrag) return;
/*
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.PointCount<=2) return;
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseMove] Status", drawPicture.Status);
}
*/
//鼠标离开
if (e && e.type=="mouseout" && e.buttons==0)
{
x=y=-1;
}
//保存最后一次鼠标移动信息
var MoveStatus={ X:x, Y:y, IsInClient: this.IsMouseOnClient(x,y) };
this.LastMouseStatus.OnMouseMove=MoveStatus;
this.LastMouseStatus.MoveOnPoint={X:x, Y:y}; //鼠标移动的位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MOUSE_MOVE);
var titleChart=this.TitlePaint[0];
if (event && titleChart) titleChart.OnMouseMoveEvent=event;
this.MoveOnPoint={X:x, Y:y};
this.OnMouseMove(x,y,e);
//this.LastMouseStatus.MoveOnPoint=null;
if (titleChart) titleChart.OnMouseMoveEvent=null;
this.StartStopDisplayLatest();
}
this.IsMouseOnClient=function(x,y)
{
var rect={ Left:this.Frame.ChartBorder.GetLeft(), Top:this.Frame.ChartBorder.GetTop(), Width:this.Frame.ChartBorder.GetWidth(), Height:this.Frame.ChartBorder.GetHeight() };
rect.Right=rect.Left+rect.Width;
rect.Bottom=rect.Top+rect.Height;
if (x>=rect.Left && x<=rect.Right && y>=rect.Top && y<=rect.Bottom) return true;
return false;
}
this.UIOnContextMenu=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
if (!this.IsShowRightMenu) return;
var x = e.clientX-this.UIElement.getBoundingClientRect().left;
var y = e.clientY-this.UIElement.getBoundingClientRect().top;
if(typeof(this.OnRightMenu)=='function') this.OnRightMenu(x,y,e); //右键菜单事件
return false;
}
this.UIOnDblClick=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
this.OnDoubleClick(x,y,e);
}
//是否在拖拽Y轴上
this.TryYDrag=function(x,y)
{
if (!this.EnableYDrag) return null;
if (!this.EnableYDrag.Left && !this.EnableYDrag.Right) return null;
if (!this.Frame || !this.Frame.PtInFrameY) return null;
var dragY=this.Frame.PtInFrameY(x,y);
if (!dragY || dragY.Index<0 ) return null;
if (dragY.IsOverlay===true)
{
if (!dragY.Right || !this.EnableYDrag.Right) return null;
if (this.Frame.IsEnableOverlayDragY(dragY.Index, dragY.OverlayIndex)) return dragY;
return null;
}
if (dragY.Left && this.EnableYDrag.Left && this.Frame.IsEnableDragY(dragY.Index))
{
return dragY;
}
if (dragY.Right && this.EnableYDrag.Right && this.Frame.IsEnableDragY(dragY.Index))
{
return dragY;
}
return null;
}
//是否可以上下拖拽
this.TryUpDownDrag=function(x,y)
{
var windowIndex=this.Frame.PtInFrame(x,y);
if (windowIndex<0) return null;
var item=this.Frame.SubFrame[windowIndex];
if (!item || !item.Frame) return null;
var frame=item.Frame;
if (!frame.YSplitOperator || !frame.YSplitOperator.FixedYMaxMin) return null;
return { Index:windowIndex, X:x, Y:y };
}
this.TryRectSelectDrag=function(x,y)
{
var paint=this.GetRectSelectPaint();
if (!paint) return null;
if (paint.GetPointCount()<=0) return null;
var item=paint.PtInPaint(x,y);
return { Item:item, X:x, Y:y };
}
this.TryClickCrossCursor=function(x,y,e)
{
if (!this.ChartCorssCursor) return;
var button=this.ChartCorssCursor.PtInButton(x,y);
if (!button) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_CROSSCURSOR_RIGHT);
if (event && event.Callback)
{
var sendData={ Button:button, e };
event.Callback(event,sendData,this);
}
return true;
}
this.TryClickButton=function(x, y, e)
{
var button=this.Frame.PtInButtons(x,y);
if (button && this.ClickFrameButton)
{
this.ClickFrameButton(button, e);
return true;
}
button=this.PtInExtendChartButtons(x,y);
if (button && this.ClickExtendChartButton)
{
this.ClickExtendChartButton(button, e);
return true;
}
button=this.PtInDrawPictureButtons(x,y);
if (button && this.ClickDrawPictureButton)
{
this.ClickDrawPictureButton(button, e);
return true;
}
button=this.PtInTitleButtons(x,y);
if (button && this.ClickTitleButton)
{
this.ClickTitleButton(button, e);
return true;
}
var label=this.Frame.PtInHorizontalLabel(x,y);
if (label && this.ClickHorizontalLabel)
{
this.ClickHorizontalLabel(label, e);
return true;
}
return false;
}
this.TryMouseMove_CustomChartDrag=function(sendData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_DRAG_MOUSE_MOVE);
if (!event || !event.Callback) return false;
return event.Callback(event, sendData, this);
}
this.TryClick_CustomChartDrag=function(sendData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_DRAG_MOUSE_DOWN);
if (!event || !event.Callback) return false;
sendData.ChartDrag=null;
sendData.Cusrsor=null;
event.Callback(event, sendData, this);
this.CustomChartDrag=sendData.ChartDrag;
this.SetCursor(sendData);
}
this.TryDragMove_CustomChartDrag=function(sendData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_DRAG_DOC_MOUSE_MOVE);
if (!event || !event.Callback) return;
var e=sendData.e;
var drag=sendData.Drag;
if(Math.abs(drag.LastMove.Y-e.clientY)<2 && Math.abs(drag.LastMove.X-e.clientX)<2) return;
if (event.Callback(event, sendData, this))
{
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
}
this.TryMouseUp_CustomChartDrag=function(sendData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_DRAG_DOC_MOUSE_UP);
if (!event || !event.Callback) return;
event.Callback(event, sendData, this);
}
this.UIOnMouseDown=function(e)
{
this.MoveOnChartDrawPicture=null;
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.ClickDownPoint={ X:e.clientX, Y:e.clientY };
this.IsOnTouch=true;
this.BorderDrag=null;
this.YDrag=null;
this.UpDownDrag=null;
this.RectSelectDrag=null;
this.IndexChartDrag=null;
this.CustomChartDrag=null;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.TryClickButton(x,y,e))
{
this.IsOnTouch=false;
return;
}
var bDrawDynamicInfo=false;
if (this.GlobalOption.SelectedBorder && this.GlobalOption.SelectedBorder.Mode>=1)
{
var item=this.GlobalOption.SelectedBorder;
var frameId=this.Frame.PtInFrame(x,y);
if (frameId>=0 && frameId!=item.SelFrame)
{
item.SelFrame=frameId;
bDrawDynamicInfo=true;
}
}
var bRedraw=false;
if (this.GlobalOption.SelectedXBorder && this.GlobalOption.SelectedXBorder.Mode>=1)
{
if (this.PtInMulitDayMinute)
{
var item=this.GlobalOption.SelectedXBorder;
var selectedDate=this.PtInMulitDayMinute(x,y);
if (item.Date!=selectedDate)
{
item.Date=selectedDate
bRedraw=true;
}
}
}
if (this.TryClickCrossCursor(x,y, e))
{
this.IsOnTouch=false;
return;
}
if (this.TryClickChartTooltipData && this.TryClickChartTooltipData(x,y,e)) //预留给外部点击图标什么用的
{
this.IsOnTouch=false;
return;
}
if (this.TryClickLock)
{
//JSConsole.Chart.Log('[uielement.onmousedown] left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top);
if (this.TryClickLock(x,y)) return;
}
this.HideSelectRect();
this.ClearDragSelectRect();
if (this.ChartPictureMenu) this.ChartPictureMenu.Hide();
var paint=this.GetRectSelectPaint();
if (paint && paint.GetPointCount()>0)
{
var item=paint.PtInPaint(x,y);
if (item)
{
if (item.Type==4)
{
//this.UIElement.style.cursor="pointer";
this.SetCursor({Cursor:"pointer"});
var obj={ X:e.clientX };
if (this.GetXDataIndex(obj))
{
this.RectSelectDrag={ DataIndex:obj.DataIndex, Type:item.Type, X:e.clientX };
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] drag sub rect select ", obj);
}
}
else
{
//this.UIElement.style.cursor="ew-resize";
this.SetCursor({Cursor:"ew-resize"});
this.RectSelectDrag={ Index:item.PointIndex, Type:item.Type };
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] drag rect select ",item);
}
}
}
if (!this.IsShowSelectRectDialog()) //区间统计框存在,不清空区间背景色
{
if (!this.RectSelectDrag && this.ClearRectSelect(false)) this.Draw();
}
if (this.EnableBorderDrag && this.Frame)
{
var dragBorder=this.Frame.PtInFrameBorder(x,y);
if (dragBorder && dragBorder.Index>=0)
{
//this.UIElement.style.cursor="n-resize";
this.SetCursor({Cursor:"n-resize"});
this.BorderDrag={ Index:dragBorder.Index };
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] DragBorder ",dragBorder);
}
}
//拖拽Y轴缩放
if (!this.BorderDrag)
{
var dragY=this.TryYDrag(x,y);
if (dragY)
{
//this.UIElement.style.cursor=dragY.Position==0 ? "n-resize":"row-resize";
var cursor=dragY.Position==0 ? "n-resize":"row-resize";
this.SetCursor({Cursor:cursor});
this.YDrag=dragY;
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] dragY ",dragY);
}
else
{
var dragUpDown=this.TryUpDownDrag(x,y);
if (dragUpDown)
{
//this.UIElement.style.cursor="pointer";
this.SetCursor({Cursor:"pointer"});
this.UpDownDrag=dragUpDown;
JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] dragUpDown ",dragUpDown);
}
}
}
var sendData={ X:x, Y:y, e:e };
if (this.TryClick_CustomChartDrag(sendData))
{
}
if(this.DragMode==0) return;
var drag=
{
"Click":{},
"LastMove":{}, //最后移动的位置
CurrentMove:{}, //当前的移动
};
drag.Click.X=e.clientX;
drag.Click.Y=e.clientY;
drag.Click.IsInFrameBottom=this.Frame.PtInFrameBottom(x,y); //是否点击在X轴上
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
this.MouseDrag=drag;
var drawPictureActive=this.GetActiveDrawPicture(); //上一次选中的
var selectedChart={ Chart:this.SelectedChart.Selected.Chart, Identify:this.SelectedChart.Selected.Identify }; //上一次选中的图形
this.SelectChartDrawPicture=null;
if (this.BorderDrag)
{
}
else if (this.YDrag || this.RectSelectDrag || this.CustomChartDrag)
{
}
else if (this.CurrentChartDrawPicture) //画图工具模式
{
this.UpDownDrag=null; //画图优先
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint())
{
if (drawPicture.IsDrawMain) this.Draw();
else this.DrawDynamicInfo();
}
}
if (drawPictureActive.Select.Guid && ( !this.CurrentChartDrawPicture ||drawPictureActive.Select.Guid!=this.CurrentChartDrawPicture.Guid))
{
if (drawPictureActive.Select.Chart.IsDrawMain) this.Draw();
}
}
else //是否在画图工具上
{
var drawPictrueData={};
drawPictrueData.X=(e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
drawPictrueData.Y=(e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
if (this.EnableEraseChartDrawPicture) //擦掉画线
{
this.CurrentChartDrawPicture=null;
this.SelectChartDrawPicture=null;
this.ClearChartDrawPicture(drawPictrueData.ChartDrawPicture);
}
else
{
this.UpDownDrag=null; //画图优先
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
//当前已有选中的,需要刷下
var bDraw=false;
if (drawPictureActive.Select.Guid && drawPictureActive.Select.Chart && drawPictureActive.Select.Chart.IsDrawMain) bDraw=true;
else if (drawPictrueData.ChartDrawPicture.IsDrawMain) bDraw=true;
if (bDraw) this.Draw();
if (drawPictrueData.ChartDrawPicture.EnableMove==true)
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
//this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
//this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture.DragInfo={Click:{X:e.clientX,Y:e.clientY}};
}
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
var sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
else
{
this.OnSelectChartPicture(drawPictrueData.ChartDrawPicture); //选中画图工具事件
}
}
else
{
if (this.ClickChartTimer!=null)
{
clearTimeout(this.ClickChartTimer);
this.ClickChartTimer=null;
}
var self=this;
var ptClick={ X:this.ClickDownPoint.X, Y:this.ClickDownPoint.Y };
this.ClickChartTimer = setTimeout(function()
{
self.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICK_CHART_PAINT,ptClick,e);
}, 250);
var bSelectedChartChanged=false;
if (this.SelectedChart.EnableSelected)
{
var selectChart=this.PtInChart(x,y);
if (selectChart)
{
if (this.SelectedChart.Selected.Identify!=selectChart.Identify)
{
this.SelectedChart.Selected.Identify=selectChart.Identify;
this.SelectedChart.Selected.Chart=selectChart.Chart;
bSelectedChartChanged=true;
}
if (this.EnableIndexChartDrag)
{
this.IndexChartDrag={ SelectedChart:selectChart, LastMove:{X:x, Y:y}, Click:{X:x, Y:y } };
this.IndexChartDrag.Info=this.GetSelectedChartInfo(selectChart);
if (this.IndexChartDrag.Info) this.IndexChartDrag.Info.FrameID=this.Frame.PtInFrame(x,y);
}
}
else
{
if (this.SelectedChart.Selected.Identify)
{
this.SelectedChart.Selected.Identify=null;
this.SelectedChart.Selected.Chart=null;
bSelectedChartChanged=true;
}
}
}
else
{
if (this.SelectedChart.Selected.Identify)
{
this.SelectedChart.Selected.Identify=null;
bSelectedChartChanged=true;
}
}
if ((drawPictureActive.Select.Guid!=null && this.SelectChartDrawPicture==null) || bSelectedChartChanged)
{
var drawType=0;
if (drawPictureActive.Select.Guid && drawPictureActive.Select.Chart && drawPictureActive.Select.Chart.IsDrawMain)
drawType=1;
if (bSelectedChartChanged)
{
var chart=selectedChart.Chart;
if (chart && chart.SetSelectedStatus)
{
chart.SetSelectedStatus(0);
drawType=1;
}
chart=this.SelectedChart.Selected.Chart;
if (chart &&chart.SetSelectedStatus)
{
chart.SetSelectedStatus(1);
drawType=1;
}
}
if (drawType==1)
this.Draw();
else
this.DrawDynamicInfo();
}
else if (bRedraw)
{
this.Draw();
}
else if (bDrawDynamicInfo)
{
this.DrawDynamicInfo();
}
}
}
if (!this.SelectChartDrawPicture) this.CloseModifyDrawDialog(); //当前没有选中画图 隐藏画图修改框
document.onmousemove=(e)=>{ this.DocOnMouseMove(e); }
document.onmouseup=(e)=> { this.DocOnMouseUp(e); }
}
this.DocOnMouseMove=function(e)
{
//加载数据中,禁用鼠标事件
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return;
var drag=this.MouseDrag;
if (!drag) return;
var moveSetp=Math.abs(drag.LastMove.X-e.clientX);
var moveSetpY=Math.abs(drag.LastMove.Y-e.clientY);
var isDragSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Index>=0);
var isDragSubSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Type==4);
if (drag.CurrentMove)
{
drag.CurrentMove.X=e.clientX;
drag.CurrentMove.Y=e.clientY;
}
if (this.BorderDrag && this.BorderDrag.Index>=0) //边框拖动
{
if(Math.abs(drag.LastMove.Y-e.clientY)<5) return;
var yMove=e.clientY-drag.LastMove.Y;
this.OnMoveFromeBorder(this.BorderDrag.Index, yMove);
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.YDrag && this.YDrag.Index>=0) //Y轴缩放
{
if(moveSetpY<5) return;
var yMove=e.clientY-drag.LastMove.Y;
//this.UIElement.style.cursor="n-resize";
JSConsole.Chart.Log("[JSChartContainer::DocOnMouseMove] YDrag ",this.YDrag,yMove);
this.OnZoomUpDownFrameY(this.YDrag, yMove);
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.IndexChartDrag && this.IndexChartDrag.SelectedChart)
{
if(Math.abs(drag.LastMove.Y-e.clientY)<2 && Math.abs(drag.LastMove.X-e.clientX)<2) return;
var chartMove=this.GetExtendChartByClassName("DragMovePaint");
if (chartMove && chartMove.Chart)
{
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
chartMove.Chart.Point={X:x, Y:y};
chartMove.Chart.IsShow=true;
chartMove.Chart.Info=this.IndexChartDrag.Info;
this.DrawDynamicInfo();
}
this.IndexChartDrag.LastMove.X=x;
this.IndexChartDrag.LastMove.Y=y;
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.CustomChartDrag)
{
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
var sendData={X:x, Y:y, e:e, ChartDrag:this.CustomChartDrag, Drag:drag };
this.TryDragMove_CustomChartDrag(sendData);
}
else if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.EnableMove===true)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<5) return;
if(this.SetChartDrawPictureSecondPoint(e.clientX,e.clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(e.clientX,e.clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<1) return;
if (this.SelectChartDrawPicture)
{
if (this.SelectChartDrawPicture.EnableCtrlMove)
{
if (!e.ctrlKey) return;
}
}
if (this.SelectChartDrawPicture && this.SelectChartDrawPicture.DragInfo)
this.SelectChartDrawPicture.DragInfo.Move={X:e.clientX, Y:e.client};
if(this.MoveChartDrawPicture(e.clientX-drag.LastMove.X,e.clientY-drag.LastMove.Y,false,drag))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.DragMode==1 || isDragSelectRect || isDragSubSelectRect) //数据上下左右拖拽
{
this.OnDragMode_One({X:moveSetp, Y:moveSetpY}, e);
}
else if (this.DragMode==2) //区间选择
{
var yMoveSetp=Math.abs(drag.LastMove.Y-e.clientY);
if (moveSetp<5 && yMoveSetp<5) return;
this.SetCursor({Cursor:"default"});
var ptStart=this.PointAbsoluteToRelative(drag.Click.X, drag.Click.Y);
var ptEnd=this.PointAbsoluteToRelative(e.clientX, e.clientY);
this.ShowDragSelectRect(ptStart, ptEnd);
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
}
this.OnDragMode_One=function(moveData, e)
{
var moveSetp=moveData.X;
var moveSetpY=moveData.Y;
var drag=this.MouseDrag;
if (moveSetp<5 && moveSetpY<5) return;
var bNeedDraw=false;
var bUpDownY=false;
if (moveSetpY>=5)
{
if (this.UpDownDrag && this.UpDownDrag.Index>=0)
{
var yMove=e.clientY-drag.LastMove.Y;
JSConsole.Chart.Log("[JSChartContainer::OnDragMode_One] UpDownDrag ",this.UpDownDrag,yMove);
//this.UIElement.style.cursor="pointer";
this.SetCursor({Cursor:"pointer"});
if (this.OnUpDonwFrameY(this.UpDownDrag, yMove))
{
bNeedDraw=true;
bUpDownY=true;
}
drag.LastMove.Y=e.clientY;
}
}
if (moveSetp>=5)
{
if (this.RectSelectDrag)
{
if (this.RectSelectDrag.Index>=0)
{
var obj={ X:e.clientX, Y:e.clientY, PointIndex:this.RectSelectDrag.Index, Name:"MoveRectSelectLine" };
if (this.MoveRectSelectPoint(obj)) bNeedDraw=true;
}
else if (this.RectSelectDrag.Type===4)
{
var obj={ X:e.clientX };
if (!this.GetXDataIndex(obj)) return;
if (obj.DataIndex==this.RectSelectDrag.DataIndex) return;
var step=obj.DataIndex-this.RectSelectDrag.DataIndex;
var isLeft=true;
if (step>0) isLeft=false;
if (!this.MoveSubRectSelect({ Step:Math.abs(step), IsLeft:isLeft, X:e.clientX, Y:e.clientY })) return;
this.RectSelectDrag.DataIndex=obj.DataIndex;
this.RectSelectDrag.X=e.clientX;
bNeedDraw=true;
}
}
else
{
var isLeft=true;
if (drag.LastMove.X<e.clientX) isLeft=false;//右移数据
var cursorStatus="pointer";
if (drag.Click.IsInFrameBottom) cursorStatus="ew-resize";
var oneStepWidth=this.GetMoveOneStepWidth();
if (moveSetp<oneStepWidth)
{
//this.UIElement.style.cursor=cursorStatus;
this.SetCursor({Cursor:cursorStatus});
if (bNeedDraw) this.Draw();
return;
}
else
{
if (drag.Click && drag.Click.IsInFrameBottom)
{
if (this.XCoordinateZoom(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
bNeedDraw=true;
}
}
else if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
//this.UpdatePointByCursorIndex(); //推拽数据的时候不需要把鼠标位置更新到K线上
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
bNeedDraw=true;
}
else if (!bUpDownY)
{
if (this.DragDownloadData)
{
this.DragDownloadData();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return;
}
}
}
//this.UIElement.style.cursor=cursorStatus;
this.SetCursor({Cursor:cursorStatus});
}
drag.LastMove.X=e.clientX;
}
if (bNeedDraw)
{
this.Draw();
this.OnKLinePageChange("datamove");
}
}
this.GetXDataIndex=function(obj)
{
if (!this.ChartPaint[0] || !this.ChartPaint[0].Data) return false;
var kData=this.ChartPaint[0].Data;
if (!this.Frame.SubFrame[0]) return false;
var subFrame=this.Frame.SubFrame[0].Frame;
if (!subFrame) false;
var pixelTatio = GetDevicePixelRatio();
var x=(obj.X-uielement.getBoundingClientRect().left)*pixelTatio;
var index=subFrame.GetXData(x);
index=parseInt(index.toFixed(0));
var dataIndex=index+kData.DataOffset;
if (dataIndex>=kData.Data.length) dataIndex=kData.Data.length-1;
var item = kData.Data[dataIndex];
obj.DataIndex=dataIndex;
obj.Item=item;
//JSConsole.Chart.Log("[JSChartContainer::GetXDataIndex] point, item", obj.PointIndex, item);
return true;
}
this.DocOnMouseUp=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
var IsMinuteChart=(this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") ? true:false;
var isDragSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Index>=0);
var isDragSubSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Type==4);
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
else if (this.IndexChartDrag && this.IndexChartDrag.SelectedChart)
{
var chartMove=this.GetExtendChartByClassName("DragMovePaint");
if (chartMove && chartMove.Chart) chartMove.Chart.Clear();
if (!this.OnDragChart(this.IndexChartDrag)) this.DrawDynamicInfo();
//this.UIElement.style.cursor="default";
this.SetCursor({Cursor:"default"});
}
else if (this.CustomChartDrag)
{
var sendData={ e:e, ChartDrag:this.CustomChartDrag, Drag:this.MouseDrag };
this.TryMouseUp_CustomChartDrag(sendData);
}
else if (isDragSelectRect) //区间选择拖动范围
{
if (this.OnDragSelectRectMouseUp) this.OnDragSelectRectMouseUp(e);
}
else if (isDragSubSelectRect)
{
if (this.OnDragSubSelectRectMouseUp) this.OnDragSubSelectRectMouseUp(e);
}
else if (IsMinuteChart)
{
if (this.OnMinuteSelectRectMouseUp) this.OnMinuteSelectRectMouseUp(e);
}
else if (this.DragMode==2) //区间选择
{
var drag=this.MouseDrag;
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
var selectData=new SelectRectData();
var pixelTatio = GetDevicePixelRatio();
//区间起始位置 结束位子
selectData.XStart=(drag.Click.X-uielement.getBoundingClientRect().left)*pixelTatio;
selectData.YStart=(drag.Click.Y-uielement.getBoundingClientRect().top)*pixelTatio;
selectData.XEnd=(drag.LastMove.X-uielement.getBoundingClientRect().left)*pixelTatio;
selectData.YEnd=(drag.LastMove.Y-uielement.getBoundingClientRect().top)*pixelTatio;
selectData.JSChartContainer=this;
selectData.Stock={Symbol:this.Symbol, Name:this.Name};
if (this.ChartDragSelectRect.Enable && !this.BorderDrag && this.GetSelectRectData(selectData))
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SELECT_RECT);
var paint=this.GetRectSelectPaint();
var isShowMenu=true;
if (event && event.Callback)
{
var data=
{
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
IsShowMenu:true,
e,e
};
event.Callback(event,data,this);
isShowMenu=data.IsShowMenu;
}
if (IsMinuteChart) //分时图直接显示显示区间选择
{
this.HideSelectRect();
this.UpdateSelectRect(selectData.Start,selectData.End);
}
else
{
if (isShowMenu)
{
var data=
{
Chart:this,
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
e.data=data;
this.PopupSelectRectMenuV2(data, e);
}
}
}
else
{
this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
}
}
else
{
this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
this.ClickEvent(e);
}
//清空数据
JSConsole.Chart.Log('[KLineChartContainer::document.onmouseup]',e);
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.DragInfo=null;
//this.UIElement.style.cursor="default";
this.SetCursor({Cursor:"default"});
this.MouseDrag=null;
this.ClickDownPoint=null;
this.IsOnTouch=false;
if (this.EnableEraseChartDrawPicture==true)
{
this.EnableEraseChartDrawPicture=false;
//更改画图工具对话框橡皮状态
if (this.DialogDrawTool && this.DialogDrawTool.SetEraseChartButtonStatus) this.DialogDrawTool.SetEraseChartButtonStatus(false);
}
if (this.BorderDrag && this.BorderDrag.Index>=0) this.Frame.SaveSubFrameHeightRate(); //拖拽指标窗口高度以后保存
this.BorderDrag=null;
this.YDrag=null;
this.UpDownDrag=null;
this.RectSelectDrag=null;
this.IndexChartDrag=null;
this.CustomChartDrag=null;
if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
}
this.UIOnMounseOut=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer::UIOnMounseOut]',e);
this.UIOnMouseMove(e);
}
this.UIOnMouseleave=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer::UIOnMouseleave]',e);
//this.UIOnMouseMove(e);
}
this.OnDragChart=function(drag)
{
if (!drag) return false;
var info=drag.Info;
var lastMove=drag.LastMove;
var startFrameID=info.FrameID;
var endFrameID=this.Frame.PtInFrame(lastMove.X,lastMove.Y);
if (endFrameID<0)
{
if (endFrameID==-3) //底部 移动到新的窗口
return this.MoveIndexToNewWindow({ WindowIndex:startFrameID, IndexID:info.IndexID }, { Operator:0 });
return false;
}
if (startFrameID==endFrameID) return false;
//移动指标
return this.MoveIndex({ WindowIndex:startFrameID, IndexID:info.IndexID }, { WindowIndex:endFrameID, }, { Operator:0 });
}
//获取选中图形信息
this.GetSelectedChartInfo=function(selectedChart)
{
if (!selectedChart) return null;
var result={ Type:0 };
var id=selectedChart.Identify;
if (id=="Main-KLine")
{
result.Name=this.Name;
result.Symbol=this.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.MAIN_KLINE;
}
else if (id.indexOf("Overlay-KLine-")==0)
{
result.Name=selectedChart.Chart.Title;
result.Symbol=selectedChart.Chart.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.OVERLAY_KLINE;
}
else if (id.indexOf("Overlay-Minute-")==0)
{
result.Name=selectedChart.Chart.Title;
result.Symbol=selectedChart.Chart.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.OVERLAY_MINUTE;
}
else if (id=="Minute-Line")
{
result.Name=this.Name;
result.Symbol=this.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.MAIN_MINUTE;
}
else if (id=="Minute-Average-Line")
{
result.Name=this.Name;
result.Symbol=this.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.MAIN_AVERAGE_MINUTE;
}
else if (id=="Minute-Vol-Bar")
{
result.Name=this.Name;
result.Symbol=this.Symbol;
result.Type=JSCHART_DRAGCHART_TYPE_ID.MAIN_MINUTE_VOL;
}
else if (id.indexOf("guid")==0)
{
for(var i=0;i<this.TitlePaint.length;++i)
{
var titleItem=this.TitlePaint[i];
if (titleItem.ClassName!="DynamicChartTitlePainting") continue;
if (titleItem.Identify==id)
{
result.IndexName=titleItem.Title;
result.IndexID=id;
result.Type=JSCHART_DRAGCHART_TYPE_ID.MAIN_INDEX;
break;
}
for(var item of titleItem.OverlayIndex)
{
if (item[0]==id)
{
result.IndexName=item[1].Title;
result.IndexID=id;
result.Type=JSCHART_DRAGCHART_TYPE_ID.OVERLAY_INDEX;
break;
}
}
if (result.Type>0) break;
}
}
return result;
}
//点击事件
this.ClickEvent=function(e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK);
if (!event || !event.Callback) return false;
if (this.ClickDownPoint.X!=e.clientX || this.ClickDownPoint.Y!=e.clientY) return false;
var pixelTatio = GetDevicePixelRatio();
var x=(e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
var y=(e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;
var data= { X:e.clientX, Y:e.clientY, FrameID:-1 };
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)
{
var yValueExtend={};
var yValue=this.Frame.GetYData(y,yValueExtend);
if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
{
var xValue=this.Frame.GetXData(x);
data.FrameID=yValueExtend.FrameID;
data.Data={ X:xValue, Y:yValue } ;
}
}
event.Callback(event, data, this);
return true;
}
//双击事件
this.DBClickEvent=function(dbClickInfo, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DBCLICK);
if (!event || !event.Callback) return false;
var pixelTatio = GetDevicePixelRatio();
var x=(e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
var y=(e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;
var data= { X:e.clientX, Y:e.clientY, FrameID:-1 , ClientPos:-1 };
var clientPos=this.PtInClient(x,y);
data.ClientPos=clientPos;
if (clientPos>0)
{
var yValueExtend={};
var yValue=this.Frame.GetYData(y,yValueExtend);
if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
{
var xValue=this.Frame.GetXData(x);
data.FrameID=yValueExtend.FrameID;
data.Data={ X:xValue, Y:yValue } ;
if (this.GetDataItem) data.Data.Item=this.GetDataItem({ClientPos:clientPos, Index:xValue, Point:{ X:x, Y:y } });
}
}
//选中图形
if (dbClickInfo && dbClickInfo.SelectedChart)
{
data.SelectedChart=this.GetSelectedChartInfo(dbClickInfo.SelectedChart);
}
event.Callback(event, data, this);
return true;
}
this.PtInChartPaintTooltip=function(x,y, toolTip)
{
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (item.GetTooltipData(x,y,toolTip))
return item;
}
return null;
}
//叠加指标提示信息
this.PtInOverlayIndexTooltip=function(x, y, tooltip)
{
var windowIndex=this.Frame.PtInFrame(x,y);
if (windowIndex<0) return null;
if (!this.Frame.SubFrame[windowIndex]) return null;
var aryOverlay=this.Frame.SubFrame[windowIndex].OverlayIndex;
if (!IFrameSplitOperator.IsNonEmptyArray(aryOverlay)) return null;
for(var i=0; i<aryOverlay.length; ++i)
{
var overlayItem=aryOverlay[i];
if (!IFrameSplitOperator.IsNonEmptyArray(overlayItem.ChartPaint)) continue;
for(var j=0;j<overlayItem.ChartPaint.length;++j)
{
var item=overlayItem.ChartPaint[j];
if (!item.IsShow) continue;
if (item.IsHideScriptIndex()) continue;
if (item.GetTooltipData(x,y,tooltip))
{
tooltip.OverlayIndex={ WindowIndex:windowIndex , Identify:overlayItem.Identify };
if (overlayItem.Script)
{
tooltip.OverlayIndex.IndexName=overlayItem.Script.Name;
tooltip.OverlayIndex.IndexID=overlayItem.Script.ID;
}
return item;
}
}
}
return null;
}
this.PtInOverlayChartPaintTooltip=function(x,y,toolTip)
{
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (item.GetTooltipData(x,y,toolTip))
return item;
}
return null;
}
//扩展图形支持tooltip外部接口
this.PtInExtendChartPaintTooltip=function(x,y,tooltip)
{
return null;
}
this.TryClickPaintEvent=function(eventID, ptClick, e)
{
var event=this.GetEventCallback(eventID);
if (event && event.Callback)
{
if (ptClick.X==e.clientX && ptClick.Y==e.clientY)
{
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;
var toolTip=new TooltipData();
var stock=null;
//主数据
var paint=this.PtInChartPaintTooltip(x,y, toolTip);
if (paint) stock={ Symbol:this.Symbol, Name:this.Name };
if (!paint) //叠加数据
{
paint=this.PtInOverlayChartPaintTooltip(x,y, toolTip);
if (paint) stock={ Symbol:toolTip.ChartPaint.Symbol, Name:toolTip.ChartPaint.Title };
}
if (toolTip.Data)
{
var data= { X:e.clientX, Y:e.clientY, Stock: stock, Tooltip:toolTip };
event.Callback(event, data, this);
return true;
}
}
}
return false;
}
//判断是单个手指
this.IsPhoneDragging=function(e)
{
// JSConsole.Chart.Log(e);
var changed=e.changedTouches.length;
var touching=e.touches.length;
return changed==1 && touching==1;
}
//是否是2个手指操所
this.IsPhonePinching=function(e)
{
var changed=e.changedTouches.length;
var touching=e.touches.length;
return (changed==1 || changed==2) && touching==2;
}
this.PreventTouchEvent=function(e)
{
if (e.cancelable) e.preventDefault();
e.stopPropagation();
}
this.GetToucheData=function(e, isForceLandscape)
{
var touches=new Array();
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
for(var i=0; i<e.touches.length; ++i)
{
var item=e.touches[i];
if (isForceLandscape)
{
touches.push(
{
clientX:item.clientY*pixelTatio, clientY:item.clientX*pixelTatio,
pageX:item.pageY*pixelTatio, pageY:item.pageX*pixelTatio
});
}
else
{
touches.push(
{
clientX:item.clientX*pixelTatio, clientY:item.clientY*pixelTatio,
pageX:item.pageX*pixelTatio, pageY:item.pageY*pixelTatio
});
}
}
return touches;
}
this.IsSingleTouch=function(e) //是否是单点触屏
{
var touchCount=e.touches.length;
return touchCount==1;
}
this.StopDragTimer=function()
{
if (IFrameSplitOperator.IsNumber(this.DragTimer))
{
clearTimeout(this.DragTimer);
this.DragTimer=null;
this.IsPress=false;
}
}
this.GetMoveAngle=function(pt,pt2) //计算角度
{
var xMove=Math.abs(pt.X-pt2.X);
var yMove=Math.abs(pt.Y-pt2.Y);
var angle=Math.atan(xMove/yMove)*180/Math.PI;
return angle;
}
//手机拖拽
uielement.ontouchstart=(e)=> { this.OnTouchStart(e); }
uielement.ontouchmove=(e)=> {this.OnTouchMove(e); }
uielement.ontouchend=(e)=> {this.OnTouchEnd(e); }
this.AddPhoneDBClickInfo=function(x,y,time)
{
var item={ X:x, Y:y, Time:time };
this.PhoneDBClickInfo.Start.push(item);
}
this.ClearPhoneDBClickInfo=function()
{
this.PhoneDBClickInfo.Start=[];
}
this.IsShortPhoneClick=function(x,y,time)
{
}
this.OnTouchStart=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.IsPress=false;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.PhonePinch=null;
this.StopDragTimer();
var isSingleTouch=this.IsSingleTouch(e);
if (this.EnableScrollUpDown==false || !isSingleTouch || //多点触屏
(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true)) //十字光标显示,不能滚动页面
{
if (e.cancelable) e.preventDefault();
}
if (this.IsPhoneDragging(e))
{
var touches = this.GetToucheData(e, this.IsForceLandscape);
var pt=this.PointAbsoluteToRelative(touches[0].clientX, touches[0].clientY, true);
if (this.TryClickLock || this.TryClickIndexTitle) //指标枷锁区域 , 指标标题点击
{
var x = pt.X;
var y = pt.Y;
if (this.TryClickLock && this.TryClickLock(x, y)) return;
if (this.TryClickIndexTitle && this.TryClickIndexTitle(x,y)) return;
}
if (this.ClickFrameButton)
{
var button=this.Frame.PtInButtons(pt.X,pt.Y);
if (button)
{
this.ClickFrameButton(button, e);
return;
}
}
if (this.EnableVerticalDrag )
{
this.VerticalDrag={ IsDrag:false };
if (this.Frame.PtInFrameVertical(pt.X, pt.Y))
this.VerticalDrag.IsDrag=true;
}
var bStartTimer=true;
if (this.ChartDrawOption.IsLockScreen)
{
bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
bStartTimer=false;
}
else
{
if (!isSingleTouch) bStartTimer=false;
}
if (this.VerticalDrag) bStartTimer=false;
if (this.EnableClickModel && this.ClickModel.IsShowCorssCursor==true) bStartTimer=false;
var drag=
{
"Click":{},
"LastMove":{} //最后移动的位置
};
//var touches=this.GetToucheData(e,this.IsForceLandscape);
drag.Click.X=touches[0].clientX;
drag.Click.Y=touches[0].clientY;
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
this.MouseDrag=drag;
var drawPictureActive=this.GetActiveDrawPicture(); //上一次选中的
var selectedChart={ Chart:this.SelectedChart.Selected.Chart, Identify:this.SelectedChart.Selected.Identify }; //上一次选中的图形
this.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } };
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
var isDrawPictrue=false;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y,true);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint())
{
if (drawPicture.IsDrawMain) this.Draw();
else this.DrawDynamicInfo( {Corss:false, Tooltip:false} );
}
}
if (e.cancelable) e.preventDefault();
return;
}
else
{
var pt=this.PointAbsoluteToRelative(touches[0].clientX,touches[0].clientY, true);
var drawPictrueData={ X:pt.X, Y:pt.Y };
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
if (drawPictrueData.ChartDrawPicture.EnableMove==true)
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
drawPictrueData.ChartDrawPicture.IsSelected=true;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
var drawType=0;
if (drawPictrueData.ChartDrawPicture.IsDrawMain) drawType=1;
else if (drawPictureActive.Select.Guid && drawPictureActive.Select.Chart && drawPictureActive.Select.Chart.IsDrawMain) drawType=1;
if (drawType==1) this.Draw();
if (e.cancelable) e.preventDefault();
return;
}
}
if (bStartTimer)
{
//长按2秒,十字光标
var self=this;
this.DragTimer=setTimeout(function()
{
self.IsPress=true;
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
if (self.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID) self.TouchStatus.CorssCursorShow=true; //十字显示
if (self.EnableClickModel===true) self.ClickModel.IsShowCorssCursor=true;
self.MoveCorssCursor(drag.Click,e);//移动十字光标
}
}, self.PressTime);
}
if (this.EnableZoomIndexWindow)
{
this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now());
JSConsole.Chart.Log("[JSChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick);
}
if (this.ChartDrawOption.IsLockScreen)
{
this.MouseDrag=null;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e);
}
else if (this.EnableClickModel)
{
//if (this.ClickModel.IsShowCorssCursor===true) this.MoveCorssCursor(drag.Click,e)
}
else if (this.VerticalDrag)
{
if (!this.VerticalDrag.IsDrag) this.MoveCorssCursor(drag.Click,e); //没有点击X轴, 就显示十字光标
}
else if (this.IsClickShowCorssCursor)
{
this.MoveCorssCursor(drag.Click,e);
}
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, e);
var drawType=0;
if (drawPictureActive.Select.Guid!=null)
{
if (drawPictureActive.Select.Guid && drawPictureActive.Select.Chart) drawType=1;
}
if (drawType==1) this.Draw();
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.GetToucheData(e,this.IsForceLandscape);
phonePinch.Start={X:touches[0].pageX, Y:touches[0].pageY, X2:touches[1].pageX, Y2:touches[1].pageY};
phonePinch.Last={X:touches[0].pageX, Y:touches[0].pageY, X2:touches[1].pageX, Y2:touches[1].pageY};
this.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
}
}
this.OnTouchMove=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var touches=this.GetToucheData(e,this.IsForceLandscape);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
if (this.IsForceLandscape) y=uielement.getBoundingClientRect().width-touches[0].clientY; //强制横屏Y计算
if (!this.ChartDrawOption.IsLockScreen) this.MoveCorssCursor({X:touches[0].clientX, Y:touches[0].clientY},e);
}
else
{
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveSetp=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
moveSetp=parseInt(moveSetp);
var isMoveCorssCursor=(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true); //是否移动十字光标
if (this.VerticalDrag)
{
if (this.VerticalDrag.IsDrag===true) isMoveCorssCursor=false;
else isMoveCorssCursor=true;
}
if (this.EnableClickModel)
{
if (this.ClickModel.IsShowCorssCursor===true) isMoveCorssCursor=true;
else isMoveCorssCursor=false;
}
//JSConsole.Chart.Log(`[JSChartContainer::OnTouchMove] moveAngle=${moveAngle} , moveUpDown=${moveUpDown}, moveSetp=${moveSetp}`);
if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.EnableMove===true)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.SetChartDrawPictureSecondPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.MoveChartDrawPicture(touches[0].clientX-drag.LastMove.X,touches[0].clientY-drag.LastMove.Y,true))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
else if (isMoveCorssCursor) //点击模式下 十字光标显示 左右移动十字光标
{
var mouseDrag=this.MouseDrag;
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e); //移动十字光标
}
else if (this.DragMode==1 || isMoveCorssCursor==false) //数据左右拖拽
{
if ( ((moveUpDown>0 && moveSetp<=3) || moveAngle<=this.TouchMoveMinAngle) && this.EnableScrollUpDown==true )
{
this.StopDragTimer();
return;
}
if (moveSetp<5 || moveAngle<=this.TouchMoveMinAngle)
{
this.PreventTouchEvent(e);
return;
}
if (this.EnableVerticalDrag)
{
if (!this.VerticalDrag) return;
if (!this.VerticalDrag.IsDrag) return;
}
var isLeft=true;
if (drag.LastMove.X<touches[0].clientX) isLeft=false;//右移数据
var oneStepWidth=this.GetMoveOneStepWidth();
if (moveSetp<oneStepWidth) return;
if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
this.OnKLinePageChange("OnTouchMove");
}
else
{
if (this.DragDownloadData) this.DragDownloadData();
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
}
if (this.PhoneTouchInfo)
{
this.PhoneTouchInfo.End.X=touches[0].clientX;
this.PhoneTouchInfo.End.Y=touches[0].clientY;
}
}
else if (this.IsPhonePinching(e))
{
if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID) return;
this.PreventTouchEvent(e);
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
phonePinch.Operator=null;
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) return;
var yHeight=Math.abs(touches[0].pageY-touches[1].pageY);
var yLastHeight=Math.abs(phonePinch.Last.Y-phonePinch.Last.Y2);
var yStep=yHeight-yLastHeight;
var xHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var xLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var xStep=xHeight-xLastHeight;
var minStep=this.ZoomStepPixel;
if (Math.abs(yStep)<minStep && Math.abs(xStep)<minStep) return;
var step=yStep;
if (Math.abs(yStep)<minStep) step=xStep;
if (step>0) //放大
{
var cursorIndex={ IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomUp(cursorIndex)) return;
phonePinch.Operator="ZoomUp";
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
//this.ResetFrameXSplit();
this.Draw();
this.ShowTooltipByKeyDown();
this.StopDragTimer();
}
else //缩小
{
var cursorIndex={ IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomDown(cursorIndex)) return;
phonePinch.Operator="ZoomDown";
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
//this.ResetFrameXSplit();
this.Draw();
this.ShowTooltipByKeyDown();
this.StopDragTimer();
}
phonePinch.Last={ X:touches[0].pageX, Y:touches[0].pageY, X2:touches[1].pageX, Y2:touches[1].pageY };
}
this.PreventTouchEvent(e);
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer:OnTouchEnd]',e);
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
if (this.EnableZoomIndexWindow)
{
var time=Date.now();
this.PhoneDBClick.AddTouchEnd(time);
if (this.PhoneDBClick.IsVaildDBClick())
{
this.OnTouchDBClick(this.PhoneDBClick.Start);
this.PhoneDBClick.Clear();
}
}
this.IsOnTouch = false;
this.VerticalDrag=null;
if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
this.StopDragTimer();
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e);
this.OnTouchFinished();
this.TouchDrawCount=0;
this.PhonePinch=null;
}
this.OnTouchDBClick=function(points)
{
var pt=this.PointAbsoluteToRelative(points[0].X, points[0].Y, true);
var x=pt.X, y=pt.Y;
JSConsole.Chart.Log(`[KLineChartContainer:OnTouchDBClick] Phone dbclick absolute [${x},${y}], soruce [${points[0].X},${points[0].Y}]`);
var frameId=this.Frame.PtInFrame(x,y);
JSConsole.Chart.Log("[KLineChartContainer::OnTouchDBClick] frameId",frameId);
if (frameId>=this.Frame.ZoomStartWindowIndex)
{
if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
{
this.Frame.SetSizeChage(true);
this.Draw();
return true;
}
}
}
//手势事件
this.TouchEvent=function(obj,e)
{
var eventID=obj.EventID;
var event=this.GetEventCallback(eventID);
if (!event || !event.Callback) return false;
var drag=this.PhoneTouchInfo
if (!drag || !drag.Start || !drag.End ) return false;
var pixelTatio = GetDevicePixelRatio();
var clientX=drag.End.X/pixelTatio;
var clientY=drag.End.Y/pixelTatio;
var x=drag.End.X-this.UIElement.getBoundingClientRect().left*pixelTatio;
var y=drag.End.Y-this.UIElement.getBoundingClientRect().top*pixelTatio;
var data=
{
X:clientX, Y:clientY, FrameID:-1, FunctionName:obj.FunctionName,
Drag:
{
Start:{ X:drag.Start.X/pixelTatio, Y:drag.Start.Y/pixelTatio },
End:{ X:drag.End.X/pixelTatio, Y:drag.End.Y/pixelTatio }
}
};
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)
{
if (this.Frame && this.Frame.IsHScreen)
{
var yValueExtend={};
var yValue=this.Frame.GetYData(x,yValueExtend);
if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
{
var xValue=this.Frame.GetXData(y);
data.FrameID=yValueExtend.FrameID;
data.Data={ X:xValue, Y:yValue } ;
}
}
else
{
var yValueExtend={};
var yValue=this.Frame.GetYData(y,yValueExtend);
if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
{
var xValue=this.Frame.GetXData(x);
data.FrameID=yValueExtend.FrameID;
data.Data={ X:xValue, Y:yValue } ;
}
}
}
event.Callback(event, data, this);
return true;
}
this.MoveCorssCursor=function(point,e)
{
var pixelTatio = GetDevicePixelRatio();
var x = point.X-this.UIElement.getBoundingClientRect().left*pixelTatio;
var y = point.Y-this.UIElement.getBoundingClientRect().top*pixelTatio;
if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID) this.TouchStatus.CorssCursorShow=true; //十字显示
this.OnMouseMove(x,y,e,true);
}
this.DrawEmpty=function()
{
if (this.UIElement.width<=0 || this.UIElement.height<=0) return;
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
if (this.Frame)
{
this.Frame.ScreenImageData=null;
this.Frame.Draw();
}
}
this.PtInChart=function(x,y)
{
var result=null;
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (!item.PtInChart) continue;
if (item.IsHideScriptIndex()) continue;
result=item.PtInChart(x,y);
if (result) return result;
}
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (!item.PtInChart) continue;
result=item.PtInChart(x,y);
if (result) return result;
}
if (this.Frame.PtInOveralyChart)
{
result=this.Frame.PtInOveralyChart(x,y);
if (result) return result;
}
return null;
}
//绘制选中图形的状态
this.DrawSelectedStatus=function()
{
if (!this.SelectedChart.MoveOn.Identify && !this.SelectedChart.Selected.Identify) return;
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (!item.Identify) continue;
if (item.Identify!=this.SelectedChart.MoveOn.Identify && item.Identify!=this.SelectedChart.Selected.Identify) continue;
if (item.DrawSelectedStatus) item.DrawSelectedStatus();
}
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Identify) continue;
if (item.Identify!=this.SelectedChart.MoveOn.Identify && item.Identify!=this.SelectedChart.Selected.Identify) continue;
if (item.DrawSelectedStatus) item.DrawSelectedStatus();
}
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Identify) continue;
if (item.Identify!=this.SelectedChart.MoveOn.Identify && item.Identify!=this.SelectedChart.Selected.Identify) continue;
if (item.DrawSelectedStatus) item.DrawSelectedStatus();
}
if (this.Frame.DrawOveralySelectedStatus) this.Frame.DrawOveralySelectedStatus(this.SelectedChart);
}
this.SetCanvas=function(canvas)
{
if (this.Frame)
{
var subFrame=this.Frame.SubFrame;
for(var i=0; i<subFrame.length; ++i)
{
var item=subFrame[i];
item.Frame.Canvas=canvas; //框架
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.Canvas=canvas; //子框架
for(var k=0;k<overlayItem.ChartPaint.length;++k)
{
var chartItem=overlayItem.ChartPaint[k];
chartItem.Canvas=canvas; //叠加图形
}
}
}
}
//画图工具
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
item.Canvas=canvas;
}
//图形
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
item.Canvas=canvas;
}
//扩展图形
for(var i=0;i<this.ChartPaintEx.length;++i)
{
var item=this.ChartPaintEx[i];
item.Canvas=canvas;
}
//叠加股票
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
item.Canvas=canvas;
}
//扩展画法
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
item.Canvas=canvas;
}
}
//清空画布
this.ClearCanvas=function(canvas)
{
if (!canvas) return;
if (!this.UIElement) return;
canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
}
this.Draw=function()
{
if (this.ChartCorssCursor) this.ChartCorssCursor.Status=0;
if (this.UIElement.width<=0 || this.UIElement.height<=0) return;
this.StopDrawDynamicInfo();
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_BEFORE_DRAW);
if (event && event.Callback)
{
var sendData={ };
event.Callback(event,sendData,this);
}
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
if (this.CacheCanvas) this.CacheCanvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash)
{
var data=this.InvokeBeforeDrawSplashScreenCallback();
if (data && data.PreventDefault===true) return;
this.Frame.ClearCoordinateText();
this.Frame.Draw( { IsEnableSplash:this.ChartSplashPaint.IsEnableSplash} );
this.ChartSplashPaint.Draw();
return;
}
if (this.CacheCanvas) this.SetCanvas(this.CacheCanvas);
//框架
if (this.Frame.SetBeforeDrawXYCallback)
{
this.Frame.SetBeforeDrawXYCallback((frame)=>
{
this.BeforeDrawXYCoordinate(frame);
});
}
this.Frame.Draw();
if (this.Frame.DrawCustomVertical)
{
var eventCVericalDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_VERTICAL_DRAW);
this.Frame.DrawCustomVertical(eventCVericalDraw);
}
this.Frame.CalculateLock();
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (!item.IsDrawMain) continue;
if (item.IsDrawMain()) item.MainDraw();
}
//框架内图形
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (item.IsDrawFirst)
item.Draw();
}
if (this.Frame.DrawOveraly)
this.Frame.DrawOveraly(true); //画叠加指标
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.ChartPaintEx.length;++i)
{
var item=this.ChartPaintEx[i];
item.Draw();
}
//叠加股票
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
item.Draw();
}
if (this.Frame.DrawOveraly)
this.Frame.DrawOveraly(false); //画叠加指标
//固定扩展图形
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.DrawAfterPicture) continue;
if (!item.IsDynamic && item.IsAnimation==false) item.Draw();
}
if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal();
this.KLineIncreaseCustomHorizontal();
if (this.Frame.DrawCustomHorizontal) this.Frame.DrawCustomHorizontal(); //Y轴自定义坐标
if (this.Frame.DrawEx) this.Frame.DrawEx( {Symbol:this.Symbol} );
if (this.ChartInfoPaint) this.ChartInfoPaint.Draw();
this.Frame.DrawLock();
this.Frame.DrawLogo();
//图形缓存
if (this.CacheCanvas)
{
this.Canvas.drawImage(this.CacheElement,0,0);
this.SetCanvas(this.Canvas);
}
else
{
this.Frame.Snapshot();
}
if (this.Frame.DrawToolbar) this.Frame.DrawToolbar(this.LastMouseStatus);
this.DrawSelectedStatus();
this.DrawSelectedBorder();
if (this.DrawSelectedXBorder) this.DrawSelectedXBorder();
var moveonPoint=null;
if (this.LastMouseStatus && this.LastMouseStatus.MoveOnPoint) moveonPoint=this.LastMouseStatus.MoveOnPoint;
for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.DrawAfterPicture) continue;
if (item.IsDynamic && item.DrawAfterTitle===false)
{
item.Draw();
if (item.DrawToolbar) item.DrawToolbar(moveonPoint);
}
}
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (item.IsDrawFirst) item.Draw();
}
this.DrawDrawPictureXYCoordinate(); //绘制画图工具 X,Y轴刻度信息
var bDrawDialogTooltip=false;
var ptPosition=null; //鼠标位置 null 无效 -1 在外面 >=0 对应的指标窗口中ID
if (this.LastPoint.X!=null || this.LastPoint.Y!=null)
{
if (this.ChartCorssCursor)
{
this.ChartCorssCursor.LastPoint=this.LastPoint;
this.ChartCorssCursor.CursorIndex=this.CursorIndex;
if (this.EnableNewIndex)
{
this.ChartCorssCursor.CorssCursorIndex=this.CorssCursorIndex;
this.ChartCorssCursor.EnableNewIndex=this.EnableNewIndex;
}
var bRestoreCanvas=false;
if (this.CorssCursorCanvas) //独立的十字光标层
{
this.ChartCorssCursor.Canvas=this.CorssCursorCanvas;
this.ChartCorssCursor.Canvas.clearRect(0,0,this.CorssCursorElement.width,this.CorssCursorElement.height)
bRestoreCanvas=true;
}
var button=this.PtInButton(this.LastPoint.X,this.LastPoint.Y);
if (button) //鼠标在按钮上 不显示十字光标
{
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{ //点击手势模式下
if (this.TouchStatus.CorssCursorShow==true) this.ChartCorssCursor.Draw();
}
else if (this.EnableClickModel)
{
if (this.ClickModel.IsShowCorssCursor===true) this.ChartCorssCursor.Draw();
}
else if (!(this.CorssCursorTouchEnd===true && this.MouseDrag) && !(this.CorssCursorTouchEnd==true && this.IsOnTouch==false))
{ //移动端 拖拽数据的时候 不显示十字光标, 没有按屏的时候也不显示十字光标
this.ChartCorssCursor.Draw();
}
if (bRestoreCanvas)
{
this.ChartCorssCursor.Canvas=this.Canvas;
}
bDrawDialogTooltip=true;
}
ptPosition=this.Frame.PtInFrame(this.LastPoint.X, this.LastPoint.Y);
}
var drawStatus=this.GetDrawStatus();
drawStatus.DrawName="Draw";
var eventTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_TITLE_DRAW);
var eventIndexTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
for(var i=0;i<this.TitlePaint.length;++i)
{
var item=this.TitlePaint[i];
if (!item.IsDynamic) continue;
item.CursorIndex=this.CursorIndex;
item.LastPoint=this.LastPoint;
if (item.ClassName=='DynamicChartTitlePainting') item.OnDrawEvent=eventIndexTitleDraw
else item.OnDrawEvent=eventTitleDraw;
if (item.OnDrawEvent)
{
item.OnDrawEvent.FunctionName='Draw';
item.OnDrawEvent.PointPosition=ptPosition;
}
item.DrawStatus=drawStatus;
item.Draw(moveonPoint, this.LastMouseStatus);
}
for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.DrawAfterPicture) continue;
if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw();
}
if (this.EnableAnimation)
{
for(var i=0;i<this.ExtendChartPaint.length;++i) //动画
{
var item=this.ExtendChartPaint[i];
if (item.IsAnimation===true) item.Draw();
}
}
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (item.IsDrawFirst) continue;
if (item.IsDrawMain && item.IsDrawMain()) continue;
if (this.SelectChartDrawPicture && this.SelectChartDrawPicture.Guid==item.Guid) continue; //当前选中在最后画
item.Draw();
}
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.Draw();
if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10)
{
this.CurrentChartDrawPicture.Draw();
}
for(var i=0;i<this.ExtendChartPaint.length;++i) //画图工具绘制完成以后 动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.DrawAfterPicture)
item.Draw();
}
this.OffscreenToShowCanvas();
//更新滚动条
if (typeof(this.UpdateScrollBar)=='function') this.UpdateScrollBar();
if (this.LastMouseStatus.MouseOnToolbar) //工具栏按钮提示信息
{
var frame=this.LastMouseStatus.MouseOnToolbar.Frame;
if (frame && frame.DrawToolbarTooltip) frame.DrawToolbarTooltip(this.LastMouseStatus.MouseOnToolbar);
}
if (bDrawDialogTooltip) this.DrawTooltipDialog();
//发送图形状态给外部
if (this.mapEvent.has(JSCHART_EVENT_ID.CHART_STATUS))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.CHART_STATUS);
var data={ };
if (typeof(this.GetChartStatus)=='function') data=this.GetChartStatus();
event.Callback(event,data,this);
}
++this.TouchDrawCount;
}
this.PtInButton=function(x, y)
{
var button=this.Frame.PtInButtons(x,y);
if (button)
return { Name:"FrameButton", Button:button };
button=this.PtInExtendChartButtons(x,y);
if (button)
return { Name:"ExtendChartButton", Button:button };
button=this.PtInDrawPictureButtons(x,y);
if (button)
return { Name:"DrawPictureButton", Button:button };
button=this.PtInTitleButtons(x,y);
if (button)
return { Name:"TitleButton", Button:button };
return null;
}
this.DrawDrawPictureXYCoordinate=function()
{
var actionDrawPicture=null; //当前激活的画图
if (this.CurrentChartDrawPicture) actionDrawPicture=this.CurrentChartDrawPicture;
else if (this.SelectChartDrawPicture) actionDrawPicture=this.SelectChartDrawPicture;
//画图工具显示点在Y轴的刻度
var option= { Symbol:this.Symbol, Period:this.Period }
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (!item) continue;
if (this.IsDrawPictureXY && actionDrawPicture&& (actionDrawPicture==item || actionDrawPicture.Guid==item.Guid) )
{
if (this.Frame.DrawPictureCoordinate(actionDrawPicture,option)) continue;
}
if (item.IsShowYCoordinate)
{
if (item.Frame) item.Frame.DrawPicturePointYCoordinate(item, option);
}
}
}
this.BeforeDrawXYCoordinate=function(frame)
{
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw)
{
if (["KLineYAxisBGPaint","DepthMapPaint","BackgroundPaint","MinuteBackgroundPaint", "SessionBreaksPaint"].includes(item.ClassName))
{
if (item.FrameID==frame.Identify) item.Draw();
}
else if (g_ExtendChartPaintFactory.IsCallbackDraw(item.ClassName))
{
if (item.FrameID==frame.Identify) item.Draw();
}
}
}
}
this.DrawSelectedBorder=function()
{
if (!this.GlobalOption.SelectedBorder) return;
var item=this.GlobalOption.SelectedBorder;
if (!IFrameSplitOperator.IsPlusNumber(item.Mode)) return;
if (!IFrameSplitOperator.IsNumber(item.SelFrame) && item.SelFrame<0) return;
var subFrame=this.Frame.SubFrame[item.SelFrame];
if (!subFrame) return;
if (subFrame.Frame.DrawSelectedBorder) subFrame.Frame.DrawSelectedBorder(item);
}
//当前屏K线涨幅Y轴刻度
this.KLineIncreaseCustomHorizontal=function()
{
if (!this.Frame || !this.Frame.SubFrame) return;
var frame=this.Frame.SubFrame[0].Frame;
if (!frame) return;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
var isPercentage=false; //是否是百分比坐标
if (frame.YSplitOperator && frame.YSplitOperator.CoordinateType==1) isPercentage=true;
var isOverlayCoordinate=false; //是否包含叠加股票刻度
for(var i=0;i<frame.CustomHorizontalInfo.length;++i)
{
var info=frame.CustomHorizontalInfo[i];
if (info.Type==4) isOverlayCoordinate=true;
if ((isPercentage && info.Type==3) || info.Type==2)
{
var item=this.ChartPaint[0];
if (!item) continue;
var data=item.Data;
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) continue;
if (!IFrameSplitOperator.IsNumber(item.DrawKRange.Start) || !IFrameSplitOperator.IsNumber(item.DrawKRange.End)) continue;
var startKLine=data.Data[item.DrawKRange.Start];
var endKLine=data.Data[item.DrawKRange.End];
var value=(endKLine.Close-startKLine.Close)/startKLine.Close*100;
info.Value=endKLine.Close;
if (info.Type==2)
{
info.Message[1]=endKLine.Close.toFixed(defaultfloatPrecision);
if (endKLine.Close>endKLine.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
else if (endKLine.Close<endKLine.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;
}
else
{
info.Message[1]=value.toFixed(2)+"%";
}
if (this.Name) info.Title=this.Name;
}
}
if (isOverlayCoordinate)
{
//叠加股票自定义刻度需要移除重新添加
var newCustomHorizontalInfo= frame.CustomHorizontalInfo.filter(function(value, index, ary)
{
return value.Type!=4
});
frame.CustomHorizontalInfo=newCustomHorizontalInfo;
}
//叠加股票右侧名称+涨幅
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item) continue;
if (item.YInfoType!=4) continue;
var data=item.Data;
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) continue;
if (!IFrameSplitOperator.IsNumber(item.DrawKRange.Start) || !IFrameSplitOperator.IsNumber(item.DrawKRange.End)) continue;
var startKLine=null;
for(var j=item.DrawKRange.Start; j<=item.DrawKRange.End;++j)
{
var kItem=data.Data[j];
if (IFrameSplitOperator.IsNumber(kItem.Close))
{
startKLine=kItem;
break;
}
}
if (!startKLine) continue;
var endKLine=data.Data[item.DrawKRange.End];
var value=(endKLine.Close-startKLine.Close)/startKLine.Close*100;
var info=new CoordinateInfo();
info.Value=endKLine.Close/item.ShowRange.FirstOverlayOpen*item.ShowRange.FirstOpen;
info.Message[1]=value.toFixed(2)+"%";
info.LineType=-1;
info.Type=item.YInfoType; //叠加股票
info.LineColor=item.Color;
info.TextColor=g_JSChartResource.FrameLatestPrice.OverlayTextColor;
if (item.Title) info.Title=item.Title;
frame.CustomHorizontalInfo.push(info);
}
}
this.OffscreenToShowCanvas=function()
{
if (!this.ShowCanvas) return;
this.ShowCanvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
this.ShowCanvas.drawImage(this.OffscreenCanvasElement,0,0);
}
this.GetDrawStatus=function()
{
var status=
{
Point:{ X:this.LastPoint.X, Y:this.LastPoint.Y },
IsOnTouch:this.IsOnTouch,
CorssCursorTouchEnd:this.CorssCursorTouchEnd,
IsTitleShowLatestData:this.IsTitleShowLatestData,
IsMinuteChart:(this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") ? true:false
};
status.FrameID=this.Frame.PtInFrame(this.LastPoint.X, this.LastPoint.Y);
return status;
}
this.InvokeBeforeDrawSplashScreenCallback=function()
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_BEFORE_DRAW_SPLASH_SCREEN);
if (!event || !event.Callback) return null;
var data={ PreventDefault:false };
event.Callback(event,data,this);
return data;
}
this.DrawSplashScreen=function(option)
{
var data=this.InvokeBeforeDrawSplashScreenCallback();
if (data && data.PreventDefault===true) return;
if (this.Frame.ScreenImageData==null && !this.CacheCanvas) return;
if (this.Frame.ScreenImageData)
{
this.Canvas.putImageData(this.Frame.ScreenImageData,0,0);
}
else if (this.CacheCanvas)
{
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height)
this.Canvas.drawImage(this.CacheElement,0,0);
}
var bgColor=g_JSChartResource.SplashScreen.BGColor;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(0,0,this.UIElement.width,this.UIElement.height)
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash)
{
var title=g_JSChartResource.SplashScreen.Title;
if (option && option.Title) title=option.Title;
this.ChartSplashPaint.SetTitle(title);
this.ChartSplashPaint.Draw();
}
}
//画动态信息
this.DrawDynamicInfo=function(option)
{
this.LastMouseStatus.MouseOnToolbar=null; //鼠标在工具栏按钮上
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_BEFORE_DRAW_DYNAMIC_INFO);
if (event && event.Callback)
{
var sendData={ };
event.Callback(event,sendData,this);
}
if (this.Frame.ScreenImageData==null && !this.CacheCanvas) return;
var isErase=false;
if (this.ChartCorssCursor)
{
if (this.ChartCorssCursor.PointX!=null || this.ChartCorssCursor.PointY!=null)
isErase=true;
}
isErase=true; //每次都擦除背景
if (isErase==false)
{
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.IsDynamic && item.IsEraseBG)
{
isErase=true;
break;
}
}
}
if (isErase)
{
if (this.Frame.ScreenImageData)
{
this.Canvas.putImageData(this.Frame.ScreenImageData,0,0);
}
else if (this.CacheCanvas)
{
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height)
this.Canvas.drawImage(this.CacheElement,0,0);
}
}
if (this.Frame.DrawToolbar) this.Frame.DrawToolbar(this.LastMouseStatus);
this.DrawSelectedStatus();
this.DrawSelectedBorder();
if (this.DrawSelectedXBorder) this.DrawSelectedXBorder();
var moveonPoint=null;
if (this.LastMouseStatus && this.LastMouseStatus.MoveOnPoint) moveonPoint=this.LastMouseStatus.MoveOnPoint;
for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.DrawAfterPicture) continue;
if (item.IsDynamic && item.DrawAfterTitle===false && item.IsAnimation==false)
{
item.Draw();
if (item.DrawToolbar) item.DrawToolbar(moveonPoint, this.LastMouseStatus);
}
}
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (item.IsDrawFirst) item.Draw();
}
this.DrawDrawPictureXYCoordinate();
var bDrawDialogTooltip=false;
if (this.ChartCorssCursor)
{
this.ChartCorssCursor.LastPoint=this.LastPoint;
this.ChartCorssCursor.CursorIndex=this.CursorIndex;
if (this.EnableNewIndex)
{
this.ChartCorssCursor.CorssCursorIndex=this.CorssCursorIndex;
this.ChartCorssCursor.EnableNewIndex=this.EnableNewIndex;
}
var bRestoreCanvas=false;
if (this.CorssCursorCanvas) //独立的十字光标层
{
this.ChartCorssCursor.Canvas=this.CorssCursorCanvas;
this.ChartCorssCursor.Canvas.clearRect(0,0,this.CorssCursorElement.width,this.CorssCursorElement.height)
bRestoreCanvas=true;
}
if (option && option.Corss==false)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) this.ChartCorssCursor.Draw();
}
else if (this.IsOnTouch===false && this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.IsShowCorssCursor===true) //开始绘图
{
this.ChartCorssCursor.Draw();
}
else if ( !(this.IsOnTouch===false && this.CorssCursorTouchEnd===true) && !this.CurrentChartDrawPicture)
{
this.ChartCorssCursor.Draw();
}
else if (this.IsOnTouch===true && (this.CurrentChartDrawPicture && this.EnableShowCorssCursor && this.EnableShowCorssCursor.DrawPicture==true))
{
this.ChartCorssCursor.Draw();
}
if (bRestoreCanvas)
{
this.ChartCorssCursor.Canvas=this.Canvas;
}
bDrawDialogTooltip=true;
}
var ptPosition=null; //鼠标位置 null 无效 -1 在外面 >=0 对应的指标窗口中ID
if (option && option.Point && (option.ParentFunction=='OnMouseMove' || option.ParentFunction=='MoveCorssCursorIndex'))
{
ptPosition=this.Frame.PtInFrame(option.Point.X, option.Point.Y);
}
var drawStatus=this.GetDrawStatus();
drawStatus.DrawName="DrawDynamicInfo";
for(var i=0;i<this.TitlePaint.length;++i)
{
var item=this.TitlePaint[i];
if (!item.IsDynamic) continue;
item.CursorIndex=this.CursorIndex;
item.LastPoint=this.LastPoint;
if (item.OnDrawEvent)
{
item.OnDrawEvent.FunctionName='DrawDynamicInfo';
item.OnDrawEvent.PointPosition=ptPosition;
}
item.DrawStatus=drawStatus;
var pointInfo=null;
if (option && IFrameSplitOperator.IsNumber(option.ClientPos) && option.Point) //当前鼠标所在位置的详细信息 包含盘前盘后
pointInfo={ ClientPos:option.ClientPos, Point:{ X:option.Point.X, Y:option.Point.Y }};
item.PointInfo=pointInfo;
item.Draw(moveonPoint, this.LastMouseStatus);
}
for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形 在动态标题以后画
{
var item=this.ExtendChartPaint[i];
if (item.IsCallbackDraw) continue;
if (item.DrawAfterPicture) continue;
if (item.ClassName=='KLineTooltipPaint' && option)
{
if (option.Tooltip==false) continue;
if (option.Point) item.LatestPoint=option.Point;
}
else if (item.ClassName=="MinuteTooltipPaint" && option)
{
if (option.Point) item.LatestPoint=option.Point;
}
if (item.IsDynamic && item.DrawAfterTitle===true) item.Draw(moveonPoint, this.LastMouseStatus);
}
if (this.EnableAnimation)
{
for(var i=0;i<this.ExtendChartPaint.length;++i) //动画
{
var item=this.ExtendChartPaint[i];
if (item.IsAnimation===true) item.Draw();
}
}
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (item.IsDrawFirst) continue;
if (item.IsDrawMain && item.IsDrawMain()) continue;
if (this.SelectChartDrawPicture &&item.Guid==this.SelectChartDrawPicture.Guid) continue; //选中画图最后画 确保显示在最外面
item.Draw(moveonPoint, this.LastMouseStatus);
}
if (this.SelectChartDrawPicture)
{
this.SelectChartDrawPicture.Draw(moveonPoint, this.LastMouseStatus);
}
if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10)
{
this.CurrentChartDrawPicture.Draw();
}
for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.DrawAfterPicture)
item.Draw();
}
if (this.LastMouseStatus.MouseOnToolbar) //工具栏按钮提示信息
{
var frame=this.LastMouseStatus.MouseOnToolbar.Frame;
if (frame && frame.DrawToolbarTooltip) frame.DrawToolbarTooltip(this.LastMouseStatus.MouseOnToolbar);
}
this.OffscreenToShowCanvas();
if (bDrawDialogTooltip) this.DrawTooltipDialog();
++this.TouchDrawCount;
}
this.DrawAnimation=function() //绘制动画 如弹幕
{
if (!this.EnableAnimation) return;
if (this.Frame.ScreenImageData && !this.IsOnTouch)
{
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.IsAnimation===true) item.IsMoveStep=true; //移动弹幕
}
this.DrawDynamicInfo();
}
var self=this;
window.requestAnimationFrame(function() { self.DrawAnimation(); });
}
this.StartAnimation=function(option)
{
var bCreated=false; //是否已经创建了弹幕画法
var barrageData=null;
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName==='BarragePaint')
{
bCreated=true;
barrageData=item.BarrageList;
break;
}
}
if (!bCreated)
{
var chart=new BarragePaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
barrageData=chart.BarrageList;
}
this.EnableAnimation=true;
var self=this;
window.requestAnimationFrame(function() { self.DrawAnimation(); });
return barrageData;
}
this.StopAnimation=function()
{
this.EnableAnimation=false;
this.DrawDynamicInfo();
}
this.GetChartTooltipData=function(x,y,option)
{
var toolTip=new TooltipData();
if (this.ChartInfoPaint)
{
if (this.ChartInfoPaint.GetTooltipData(x,y,toolTip))
return toolTip;
}
if (this.PtInChartPaintTooltip(x,y, toolTip))
return toolTip;
if (IFrameSplitOperator.IsNonEmptyArray(this.Frame.SubFrame))
{
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var subFrame=this.Frame.SubFrame[i];
for(var j=0;j<subFrame.OverlayIndex.length;++j)
{
var overlayItem=subFrame.OverlayIndex[j];
for(var k=0;k<overlayItem.ChartPaint.length;++k)
{
var item=overlayItem.ChartPaint[k];
if (item.GetTooltipData(x,y,toolTip))
return toolTip;
}
}
}
}
if (this.PtInOverlayChartPaintTooltip(x,y,toolTip))
return toolTip;
if (this.PtInExtendChartPaintTooltip(x,y,toolTip))
return toolTip;
return null;
}
this.PtInExtendChartButtons=function(x,y)
{
for(var i=0;i<this.ExtendChartPaint.length; ++i)
{
var item=this.ExtendChartPaint[i];
if (item.PtInButtons)
{
var button=item.PtInButtons(x,y);
if (button)
{
button.Chart=item;
return button;
}
}
}
return null;
}
this.ClickExtendChartButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_EXTENDCHART_BUTTON);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
}
this.PtInDrawPictureButtons=function(x,y)
{
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (!item.PtInButtons) continue;
var button=item.PtInButtons(x,y);
if (button)
{
button.Chart=item;
return button;
}
}
return null;
}
this.ClickDrawPictureButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE_BUTTON);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
if (button.ID==JSCHART_BUTTON_ID.DRAW_PICTURE_DELETE)
{
JSConsole.Chart.Log(button,"ClickDrawPictureButton");
this.ClearChartDrawPicture(button.Chart); //删除画图工具
}
else if (button.ID==JSCHART_BUTTON_ID.DRAW_PICTURE_SETTING)
{
}
}
this.PtInTitleButtons=function(x,y)
{
for(var i=0;i<this.TitlePaint.length;++i)
{
var item=this.TitlePaint[i];
if (!item.PtInButtons) continue;
var button=item.PtInButtons(x,y);
if (button)
{
button.Chart=item;
return button;
}
}
return null;
}
this.OnMouseMove=function(x,y,e, isPhone)
{
this.StopDrawDynamicInfo();
this.LastPoint.X=x;
this.LastPoint.Y=y;
var mouseStatus=null; //鼠标状态
var button=null; //当前鼠标所在按钮
var frameID=this.Frame.PtInFrame(x,y);
if (IFrameSplitOperator.IsNumber(frameID) && frameID>=0) //在K线内部移动,调整K线索引
this.CursorIndex=this.Frame.GetXData(x);
if (this.EnableBorderDrag && this.Frame && !this.CurrentChartDrawPicture)
{
var dragBorder=this.Frame.PtInFrameBorder(x,y);
if (dragBorder && dragBorder.Index>=0)
{
mouseStatus={ Cursor:"n-resize", Name:"DragBorder"};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag border ",dragBorder);
}
}
if (this.EnableYDrag && this.Frame && !this.CurrentChartDrawPicture)
{
var dragY=this.TryYDrag(x,y);
if (dragY)
{
mouseStatus={ Cursor:dragY.Position==0 ? "n-resize":"row-resize", Name:"DragY"};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag y ",dragY);
}
}
if (!this.CurrentChartDrawPicture)
{
button=this.PtInButton(x,y);
if (button)
{
mouseStatus={ Cursor:"pointer", Name:button.Name};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] frame button ", button);
}
}
if (this.ChartCorssCursor)
{
var crossButton=this.ChartCorssCursor.PtInButton(x,y);
if (crossButton)
{
mouseStatus={ Cursor:"pointer", Name:"CorssCursorButton"};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] cross cursor button ", crossButton);
}
}
if (this.ClassName=="KLineChartContainer" && this.Frame.PtInFrameBottom(x,y))
{
mouseStatus={ Cursor:"ew-resize", Name:"FrameButtom"};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] frame bottom ");
}
if (this.Frame.PtInHorizontalLabel && this.Frame.PtInHorizontalLabel(x,y))
{
mouseStatus={ Cursor:"pointer", Name:"HorizontalLabel"};
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] frame Horizontal Label ");
}
if (this.SelectedChart.EnableMoveOn && this.PtInChart && !this.CurrentChartDrawPicture)
{
var chartInfo=this.PtInChart(x,y);
if (chartInfo && chartInfo.Identify)
{
mouseStatus={ Cursor:"pointer", Name:"PtInChart"};
this.SelectedChart.MoveOn.Identify=chartInfo.Identify;
this.SelectedChart.MoveOn.Identify=null;
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] Point in chart ", chartInfo);
}
else
{
this.SelectedChart.MoveOn.Identify=null;
}
}
else
{
this.SelectedChart.MoveOn.Identify=null;
}
//区间选择
var paint=this.GetRectSelectPaint();
if (paint && paint.GetPointCount()>0)
{
var item=paint.PtInPaint(x,y);
if (item)
{
if (item.Type==4) mouseStatus={ Cursor:"pointer", Name:"DragRectSelect"}; //子区域选中
else mouseStatus={ Cursor:"ew-resize", Name:"DragRectSelect" };
JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag rect select ",item);
}
}
var sendData={ MouseStatus:null, X:x, Y:y, FrameID:frameID, e:e };
if (this.TryMouseMove_CustomChartDrag(sendData))
{
if (sendData.MouseStatus)
mouseStatus=sendData.MouseStatus;
}
var bDrawPicture=false; //是否正在画图
if (this.CurrentChartDrawPicture)
{
var index=this.Frame.PtInChartFrame(x,y);
if (this.CurrentChartDrawPicture.Status!=20)
{
var bDrawValid=false; //是否在有效绘图区域里面
if (IFrameSplitOperator.IsNumber(this.CurrentChartDrawPicture.LimitFrameID))
{
if (index>=0 && index==this.CurrentChartDrawPicture.LimitFrameID) bDrawValid=true;
}
else
{
if (index>=0) bDrawValid=true;
}
mouseStatus={ Cursor:bDrawValid ? "crosshair":"not-allowed", Name:"CurrentChartDrawPicture"};
}
if (this.CurrentChartDrawPicture.SetLastPoint) this.CurrentChartDrawPicture.SetLastPoint({X:x,Y:y});
bDrawPicture=true;
}
else
{
var drawPictrueData={};
drawPictrueData.X=x;
drawPictrueData.Y=y;
if (this.GetChartDrawPictureByPoint(drawPictrueData) && drawPictrueData.ChartDrawPicture)
{
if (this.EnableEraseChartDrawPicture)
{
this.SetCursor({Cursor:"grabbing"});
}
else
{
if (drawPictrueData.ChartDrawPicture.EnableMove==true)
{
if (drawPictrueData.PointIndex===100)
{
if (drawPictrueData.Cursor) this.SetCursor(drawPictrueData); //this.UIElement.style.cursor=drawPictrueData.Cursor;
else this.SetCursor({Cursor:"move"}); //this.UIElement.style.cursor="move";
}
else
{
if (drawPictrueData.Cursor) this.SetCursor(drawPictrueData); //this.UIElement.style.cursor=drawPictrueData.Cursor
else this.SetCursor({Cursor:"pointer"}); //this.UIElement.style.cursor="pointer";
}
bDrawPicture=true;
}
}
this.MoveOnChartDrawPicture=drawPictrueData.ChartDrawPicture;
}
else
{
if (!this.MouseDrag)
this.SetCursor({Cursor:"default"}); //this.UIElement.style.cursor="default";
}
}
var clientPos=this.PtInClient(x,y);
var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true, ClientPos:clientPos };
if ((e && (e.type=="mouseout" || e.type=="mouseleave")) || button) option.Corss=false; //鼠标移开,在按钮上,不显示十字光标
if (this.SetCorssCursorIndex) this.SetCorssCursorIndex(option);
if (this.DrawDynamicInfoOption.Enable)
{
this.DrawDynamicInfoOption.Timer=setTimeout(()=>
{
this.DrawDynamicInfo(option);
},this.DrawDynamicInfoOption.DelayTime);
}
else
{
this.DrawDynamicInfo(option);
}
this.SetCursor(mouseStatus);
if (this.IsShowTooltip && bDrawPicture==false)
{
var toolTip=this.GetChartTooltipData(x,y);
if (toolTip && toolTip.Data)
{
if (isPhone===true)
{
var touche=e.touches[0];
var xTooltip = touche.clientX-this.UIElement.getBoundingClientRect().left;
var yTooltip = touche.clientY-this.UIElement.getBoundingClientRect().top;
}
else
{
var xTooltip = e.clientX-this.UIElement.getBoundingClientRect().left;
var yTooltip = e.clientY-this.UIElement.getBoundingClientRect().top;
}
this.ShowTooltip(xTooltip,yTooltip,toolTip);
}
else
{
this.HideTooltip();
}
}
}
//设置鼠标形状 {Cursor:鼠标形状 }
this.SetCursor=function(obj)
{
if (!obj || !obj.Cursor) return;
if (obj.Cursor=="default")
this.UIElement.style.cursor=this.DefaultCursor;
else
this.UIElement.style.cursor=obj.Cursor;
}
this.OnKeyDown=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
//回调事件
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN);
if (event && event.Callback)
{
var sendData={ e:e, PreventDefault:false };
event.Callback(event, sendData, this);
if (sendData.PreventDefault) return;
}
var keyID = e.keyCode ? e.keyCode :e.which;
var draw=false;
if (this.ChartCorssCursor && this.ChartCorssCursor.OnKeyDown) //十字光标 隐藏显示
{
var sendData={ e:e, KeyID:keyID, Draw:false, PreventDefault:false };
this.ChartCorssCursor.OnKeyDown(sendData);
draw=sendData.Draw;
}
switch(keyID)
{
case 37: //left
if (e.ctrlKey && this.OnCustomKeyDown)
{
if (this.OnCustomKeyDown(keyID, e))
break;
}
if (this.CursorIndex<=0.99999)
{
if (!this.DataMoveLeft())
{ //左移数据到头了 触发下载新数据
if (this.DragDownloadData) this.DragDownloadData();
break;
}
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
}
else
{
--this.CursorIndex;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
this.ShowTooltipByKeyDown();
}
break;
case 39: //right
if (e.ctrlKey && this.OnCustomKeyDown)
{
if (this.OnCustomKeyDown(keyID, e))
break;
}
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (this.CursorIndex+1>=xPointcount)
{
if (!this.DataMoveRight()) break;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
}
else
{
//判断是否在最后一个数据上
var data=null;
if (this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) break;
if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break;
++this.CursorIndex;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
this.ShowTooltipByKeyDown();
}
break;
case 38: //up
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Keyboard===false) break;
var cursorIndex={ ZoomType:this.ZoomType, IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomUp(cursorIndex)) break;
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
break;
case 40: //down
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Keyboard===false) break;
var cursorIndex={ ZoomType:this.ZoomType ,IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomDown(cursorIndex, { ZoomDownloadDataCallback:(requestData)=>{ this.ZoomDownloadData(requestData) } })) break;
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true)
{
}
else
{
this.Draw();
}
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
break;
case 46: //del
if (this.SelectChartDrawPicture)
{
var drawPicture=this.SelectChartDrawPicture;
JSConsole.Chart.Log("[JSChartContainer::OnKeyDown] delete draw picture.");
this.SelectChartDrawPicture=null;
if (this.ChartPictureMenu) this.ChartPictureMenu.Hide();
this.ClearChartDrawPicture(drawPicture); //删除选中的画图工具
this.CloseModifyDrawDialog();
}
else if (this.SelectedChart && this.SelectedChart.Selected.Identify)
{
var selectedInfo=this.GetSelectedChartInfo(this.SelectedChart.Selected);
if (selectedInfo)
{
if (selectedInfo.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_INDEX)
this.DeleteOverlayWindowsIndex(selectedInfo.IndexID);
else if (selectedInfo.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_KLINE)
this.DeleteOverlaySymbol(selectedInfo.Symbol);
}
}
break;
case 32: //space
this.OnMarkRectSelect(e);
break;
case 27: //ESCAPE 取消画布工具
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status!=20) //画布移动的时候不能取消
this.CurrentChartDrawPicture=null;
}
break;
default:
return;
}
if (draw) this.DrawDynamicInfo();
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnDoubleClick=function(x,y,e)
{
//JSConsole.Chart.Log(e);
}
this.ZoomIndexWindow=function(frameID, option) //最大化/最小化指标窗口
{
if (frameID<0 || frameID>=this.Frame.SubFrame.length) return false;
return this.Frame.ZoomIndexWindow(frameID, option);
}
this.ShowIndexTitleOnly=function(frameID, option) //只显示指标的标题
{
if (frameID<0 || frameID>=this.Frame.SubFrame.length) return false;
return this.Frame.ShowIndexTitleOnly(frameID, option);
}
this.RemoveMinSizeWindows=function() //清空最小化窗口
{
if (!this.Frame.ZoomWindowsInfo) return;
var aryDeleteIndex=[], aryIndex=[]; //删除的索引, 保留的索引
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
item.Frame.ClearToolbar();
if (item.Frame.IsMinSize)
aryDeleteIndex.push(i);
else
aryIndex.push(i);
}
this.Frame.ZoomWindowsInfo=null;
if (aryDeleteIndex.length<=0) return;
for(var i=0;i<aryDeleteIndex.length;++i)
{
this.DeleteIndexPaint(aryDeleteIndex[i]);
}
var newSubFrame=[];
var newWindowIndex=[];
var newTitlePaint=[this.TitlePaint[0]];
for(var i=0;i<aryIndex.length;++i)
{
var id=aryIndex[i];
newSubFrame[i]=this.Frame.SubFrame[id];
newWindowIndex[i]=this.WindowIndex[id];
newTitlePaint[i+1]=this.TitlePaint[id+1];
}
this.Frame.SubFrame=newSubFrame;
this.WindowIndex=newWindowIndex;
this.TitlePaint=newTitlePaint;
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
item.Identify=i;
}
if (IFrameSplitOperator.IsNonEmptyArray(this.ChartDrawPicture))
{
var aryDrawPicture=[];
for(var i=0; i<this.ChartDrawPicture.length; ++i)
{
var item=this.ChartDrawPicture[i];
for(var j=0; j<this.Frame.SubFrame.length; ++j)
{
if (item.Frame==this.Frame.SubFrame[j].Frame)
{
aryDrawPicture.push(item);
break;
}
}
}
this.ChartDrawPicture=aryDrawPicture;
}
}
this.PtInClient=function(x,y)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
var border=this.Frame.ChartBorder.GetHScreenBorder();
if (border.DayBorder) //多日分时+多日集合竞价
{
var width=border.Right-border.Left;
for(var i=0;i<border.DayBorder.length;++i)
{
var client=border.DayBorder[i];
this.Canvas.beginPath();
this.Canvas.rect(border.Left,client.TopEx,width,client.BottomEx-client.TopEx);
if (this.Canvas.isPointInPath(x,y))
return 1;
//盘前
this.Canvas.beginPath();
this.Canvas.rect(border.Left,client.Top,width,client.TopEx-client.Top);
if (this.Canvas.isPointInPath(x,y))
return 200+parseInt(i);
//盘后
this.Canvas.beginPath();
this.Canvas.rect(border.Left,client.BottomEx,width,client.Bottom-client.BottomEx);
if (this.Canvas.isPointInPath(x,y))
return 300+parseInt(i);
}
return -1;
}
this.Canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
}
else
{
var border=this.Frame.ChartBorder.GetBorder();
if (border.DayBorder) //多日分时+多日集合竞价
{
for(var i=0;i<border.DayBorder.length;++i)
{
var client=border.DayBorder[i];
//盘前
this.Canvas.beginPath();
this.Canvas.rect(client.Left,border.TopEx,client.LeftEx-client.Left,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y))
return 200+parseInt(i);
//盘中
this.Canvas.beginPath();
this.Canvas.rect(client.LeftEx,border.TopEx,client.RightEx-client.LeftEx,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y)) return 1;
//盘后
this.Canvas.beginPath();
this.Canvas.rect(client.RightEx,border.TopEx,client.Right-client.RightEx,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y))
return 300+parseInt(i);
}
return -1;
}
this.Canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 1;
if (this.Frame.ChartBorder.LeftExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
}
else
{
this.Canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 2;
}
if (this.Frame.ChartBorder.RightExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
}
else
{
this.Canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 3;
}
return -1;
}
this.OnMoveFromeBorder=function(index, yMove)
{
if (!this.Frame) return;
if (!this.Frame.OnMoveFromeBorder(index,yMove)) return ;
//this.Frame.SetSizeChage(true);
this.Frame.SetFrameBorderSizeChange();
this.Frame.ReDrawToolbar();
this.Draw();
}
this.OnZoomUpDownFrameY=function(obj, yMove)
{
if (!this.Frame) return;
if (!this.Frame.OnZoomUpDownFrameY(obj,yMove)) return ;
this.Frame.SetSizeChage(true);
this.Draw();
}
this.OnUpDonwFrameY=function(obj, yMove)
{
if (!this.Frame) return false;
if (!this.Frame.OnUpDonwFrameY(obj,yMove)) return false;
this.Frame.SetSizeChage(true);
return true;
}
this.CancelZoomUpDownFrameY=function(obj)
{
if (!this.Frame) return;
if (!this.Frame.CancelZoomUpDownFrameY(obj)) return ;
this.UpdateFrameMaxMin();
this.Frame.SetSizeChage(true);
this.Draw();
}
this.IsKLineContainer=function()
{
if (this.ClassName=='KLineChartContainer' || this.ClassName=='KLineChartHScreenContainer' ||
this.ClassName=="KLineTrainChartContainer" || this.ClassName=="CustomKLineChartContainer" ) return true;
return false;
}
this.IsMinuteContainer=function()
{
if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") return true;
return false;
}
this.UpdatePointByCursorIndex=function(type) //type 1=根据十字光标更新 2=强制取消十字光标
{
var pt={X:null, Y:null};
pt.X=this.Frame.GetXFromIndex(this.CursorIndex);
var index=Math.abs(this.CursorIndex-0.5);
if (this.IsKLineContainer()) index=this.CursorIndex;
var data=this.Frame.Data;
if (data.DataOffset+index<data.Data.length)
{
var close=data.Data[data.DataOffset+index].Close;
pt.Y=this.Frame.GetYFromData(close);
}
if (type==1 && this.ChartCorssCursor)
{
if (this.ChartCorssCursor.Status==1) //十字光标显示中, 不调整位置
{
}
else
{
this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex);
var index=Math.abs(this.CursorIndex-0.5);
index=parseInt(index.toFixed(0));
if (this.IsKLineContainer()) index=this.CursorIndex;
this.LastPoint.Y=null;
}
}
else if (type==2 && this.ChartCorssCursor) //取消鼠标位置,十字光标就不显示了
{
this.LastPoint.Y=null;
this.LastPoint.X=null;
}
else
{
this.LastPoint.X=pt.X;
this.LastPoint.Y=pt.Y;
}
}
this.ShowTooltipByKeyDown=function()
{
if (!this.KLineTooltipConfig.Enable || !this.KLineTooltipConfig.EnableKeyDown) return;
var index=Math.abs(this.CursorIndex-0.5);
index=parseInt(index.toFixed(0));
if (this.ClassName=='KLineChartContainer' || this.ClassName=='KLineTrainChartContainer') index=this.CursorIndex;
var data=this.Frame.Data;
var toolTip=new TooltipData();
toolTip.Data=data.Data[data.DataOffset+index];
toolTip.ChartPaint=this.ChartPaint[0];
var pixelTatio = GetDevicePixelRatio();
if (pixelTatio===0) pixelTatio=1; //div 缩放还是使用原始坐标
this.ShowTooltip(this.LastPoint.X/pixelTatio,this.LastPoint.Y/pixelTatio,toolTip);
}
this.DrawTooltipDialog=function()
{
}
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,
Symbol:this.Symbol,
Name:this.Name,
DataType:1,
};
this.FloatTooltip.Update(sendData);
}
//更新实时行情到浮动tooltip
this.UpdateHQFloatTooltip=function(item)
{
}
this.ShowTooltip=function(x,y,toolTip)
{
if (!this.IsShowTooltip) return;
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var xMove=15/pixelTatio; //顶部坐标偏移位置
this.TooltipCache.Type=toolTip.Type;
this.TooltipCache.Data=null;
this.TooltipCache.X=x;
this.TooltipCache.Y=y;
var bHideFloatToolip=true;
if (toolTip.Type===0) //K线信息
{
if (!this.KLineTooltipConfig.Enable) return;
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var scrollPos=GetScrollPosition();
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('HistoryDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
format.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (!format.Operator()) return;
var textHeight=format.LineCount*25; //每行的行高25
if (format.Height>0) textHeight=format.Height; //新版本高度有格式化类计算完成
var width=format.Width;
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =textHeight+"px";
//JSConsole.Chart.Log(`[JSChartContainer::ShowTooltip] left=${left} top=${top} xMove=${xMove}` );
//if (toolTip.ChartPaint.Name=="Overlay-KLine") this.Tooltip.style.height =220+"px";
this.Tooltip.style.position = "absolute";
//JSConsole.Chart.Log('[JSChartContainer::ShowTooltip] getBoundingClientRect() ',this.UIElement.getBoundingClientRect())
if (left+width>this.UIElement.getBoundingClientRect().width)
this.Tooltip.style.left = (left-width) + "px";
else
this.Tooltip.style.left = left + "px";
if (top+xMove+textHeight>this.UIElement.getBoundingClientRect().height-5)
this.Tooltip.style.top = (top-textHeight)+ "px";
else this.Tooltip.style.top = (top + xMove)+ "px";
this.Tooltip.className='jschart-tooltip';
this.Tooltip.innerHTML=format.Text;
this.Tooltip.style.display = "block";
this.TooltipCache.IsShow=true;
this.TooltipCache.Data={ Date:toolTip.Data.Date, Time:toolTip.Data.Time };
this.TooltipCache.InnerHTML=format.Text;
}
else if (toolTip.Type===1) //信息地雷提示信息
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var scrollPos=GetScrollPosition();
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('KLineInfoDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-klineinfo-tooltip';
this.Tooltip.style.position = "absolute";
if(left+width>this.UIElement.getBoundingClientRect().width){
this.Tooltip.style.left = (left-width) + "px";
}else{
this.Tooltip.style.left = left + "px";
}
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==2) //指标信息
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('KLineTradeDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-klinetrade-tooltip';
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==3) //分时图异动信息
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('MinuteInfoDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-minuteinfo-tooltip'; //分时图异动
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==4) //ChartMultiSVGIconV2 图标信息
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('IconDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-iconinfo-tooltip'; //图标信息
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==5)
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('ChartOXDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.Period=this.Period;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-chartox-tooltip'; //OX指标数据
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==6) //散点图
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('ScatterPlotDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.Period=this.Period;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-charscatterplot-tooltip'; //OX指标数据
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==7) //ChartDrawSVG
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
var left = x;
var top = y;
var format=g_DivTooltipDataForamt.Create('ChartDrawSVGDataStringFormat');
format.Value=toolTip;
format.Symbol=this.Symbol;
format.Period=this.Period;
format.LanguageID=this.LanguageID;
if (!format.Operator()) return;
var width=format.Width;
this.Tooltip.className='jchart-chartdrawsvg-tooltip'; //ChartDrawSVG指标数据
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = left + "px";
this.Tooltip.style.top = (top +xMove)+ "px";
this.Tooltip.style.width = width+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=format.Text;
this.Tooltip.style.display = "block";
}
else if (toolTip.Type==8) //ChartDrawSVG 新版本
{
if (this.FloatTooltip)
{
this.DrawFloatTooltip({X:x, Y:y, YMove:20/pixelTatio}, toolTip);
bHideFloatToolip=false;
return;
}
}
if (bHideFloatToolip) this.HideFloatTooltip();
}
this.UpdateDOMTooltip=function(toolTipType, data)
{
if (!this.TooltipCache.IsShow) return ;
if (this.TooltipCache.Type!=toolTipType) return;
if (!this.TooltipCache.Data) return;
if (this.TooltipCache.Type===0)
{
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
var lastItem=data.Data[data.Data.length-1];
if (lastItem.Date!=this.TooltipCache.Data.Date) return;
if (IFrameSplitOperator.IsNumber(lastItem.Time) && lastItem.Time!=this.TooltipCache.Data.Time) return;
var klinePaint=this.ChartPaint[0];
var format=g_DivTooltipDataForamt.Create('HistoryDataStringFormat');
format.Value={ Data:lastItem, ChartPaint:klinePaint, Type:this.TooltipCache.Type };
format.Symbol=this.Symbol;
format.LanguageID=this.LanguageID;
format.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (!format.Operator()) return;
if (format.Text==this.TooltipCache.InnerHTML) return;
this.Tooltip.innerHTML=format.Text;
this.TooltipCache.InnerHTML=format.Text;
}
}
this.HideTooltip=function()
{
this.TooltipCache.IsShow=false;
this.TooltipCache.Type=null;
this.TooltipCache.InnerHTML=null;
this.TooltipCache.Data=null;
if (this.Tooltip.style.display!="none") this.Tooltip.style.display = "none";
this.HideFloatTooltip();
}
this.UpdateSelectRect=function(start,end)
{
if (!this.ChartPaint[0].Data) return;
var paint=this.GetRectSelectPaint();
if (!paint) return;
var data=this.ChartPaint[0].Data;
var count=data.Data.length;
if (end>=count) end=count-1;
var startItem=data.Data[start];
var endItem=data.Data[end];
JSConsole.Chart.Log('[JSChartContainer::UpdateSelectRect]',startItem,endItem);
paint.SetPoint(startItem, { Index:0, DataIndex:start });
paint.SetPoint(endItem, { Index:1, DataIndex:end });
this.Draw();
}
this.HideSelectRect=function()
{
this.ClearDragSelectRect();
}
this.ResetFrameXYSplit=function()
{
if (typeof(this.Frame.ResetXYSplit)=='function')
this.Frame.ResetXYSplit();
}
this.ResetFrameXSplit=function()
{
if (typeof(this.Frame.ResetXSplit)=='function')
this.Frame.ResetXSplit();
}
this.ResetFrameYCustomSplit=function(windowIndex)
{
if (typeof(this.Frame.ResetYCustomSplit)=='function')
this.Frame.ResetYCustomSplit(windowIndex);
}
this.UpdateFrameMaxMinV2=function()
{
var mapFrame=new Map(); //key=frameid, value:{ ChartPaint:[] }
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var subItem=this.Frame.SubFrame[i];
if (!subItem || !subItem.Frame) continue;
var frame=subItem.Frame;
//自定义刻度每次都调用
frame.YCustomSplit=true;
var key=frame.Identify;
var item=
{
ID:key, Frame:frame, ChartPaint:[] , Max:null, Min:null,
OverlayFrame:[], //共享坐标
SingleOverlay:[], //独立坐标
MainOverlayFrame:[null, null], //叠加坐标在主坐标显示[0]=left [1]=right
};
for(var j=0;j<subItem.OverlayIndex.length;++j)
{
var overlayItem=subItem.OverlayIndex[j];
var overlayFrame=overlayItem.Frame;
if (overlayFrame.IsShowMainFrame===1) item.MainOverlayFrame[0]= overlayFrame;
else if (overlayFrame.IsShowMainFrame===2) item.MainOverlayFrame[1]= overlayFrame;
if (overlayFrame.IsShareY)
{
if (!overlayFrame.MainFrame) continue;
if (overlayFrame.IsCalculateYMaxMin===false) continue; //叠加坐标Y轴不调整
item.OverlayFrame.push(overlayFrame);
for(var k=0; k<overlayItem.ChartPaint.length; ++k)
{
var chart=overlayItem.ChartPaint[k];
item.ChartPaint.push(chart);
}
}
else
{
item.SingleOverlay.push(overlayItem);
}
}
mapFrame.set(key, item);
}
for(var i=0;i<this.ChartPaint.length;++i)
{
var chart=this.ChartPaint[i];
var key=chart.ChartFrame.Identify;
if (!mapFrame.has(key)) continue;
var finder=mapFrame.get(key);
finder.ChartPaint.push(chart);
}
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var chart=this.OverlayChartPaint[i];
if (!chart.ChartFrame) continue;
var key=chart.ChartFrame.Identify;
if (!mapFrame.has(key)) continue;
var finder=mapFrame.get(key);
finder.ChartPaint.push(chart);
}
for(var mapItem of mapFrame)
{
var item=mapItem[1];
var frame=item.Frame;
//计算主框架最大最小
for(var i=0;i<item.ChartPaint.length;++i)
{
var chart=item.ChartPaint[i];
if (chart.IsShow==false) continue; //隐藏的图形不计算
if (chart.NotSupportMessage) continue;
if (!chart.ChartFrame) continue;
if (chart.IsExcludeYValue===true) continue;
var range=chart.GetMaxMin();
if (range==null || range.Max==null || range.Min==null) continue;
if (item.Max==null || item.Max<range.Max) item.Max=range.Max;
if (item.Min==null || item.Min>range.Min) item.Min=range.Min;
}
if (item.Frame.YSpecificMaxMin) //固定坐标
{
item.Min=item.Frame.YSpecificMaxMin.Max;
item.Max=item.Frame.YSpecificMaxMin.Min;
}
if (!IFrameSplitOperator.IsNumber(frame.YMaxMin.Max) || frame.YMaxMin.Max!=item.Max)
{
frame.YMaxMin.Max=item.Max;
frame.XYSplit=true;
}
if (!IFrameSplitOperator.IsNumber(frame.YMaxMin.Min) || frame.YMaxMin.Min!=item.Min)
{
frame.YMaxMin.Min=item.Min
frame.XYSplit=true;
}
if (frame.XYSplit)
{
var max=10, min=0;
if (item.Max!=null) max=item.Max;
if (item.Min!=null) min=item.Min;
frame.HorizontalMax=max;
frame.HorizontalMin=min;
}
else
{
frame.XSplit=true;
}
//共享Y轴叠加指标同步下坐标
for(var j=0;j<item.OverlayFrame.length;++j)
{
item.OverlayFrame[j].XYSplit=true;
}
//叠加坐标显示在主图坐标 需要同步
for(var i=0;i<item.MainOverlayFrame.length;++i)
{
var subItem=item.MainOverlayFrame[i];
if (subItem) subItem.XYSplit=true;
}
//独立坐标叠加指标
for(var i=0;i<item.SingleOverlay.length;++i)
{
var overlayItem=item.SingleOverlay[i];
overlayItem.UpdateFrameMaxMin();
}
}
}
this.UpdateFrameMaxMin=function()
{
this.UpdateFrameMaxMinV2();
return;
var frameMaxMinData=new Array();
var chartPaint=new Array();
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (item.IsShow==false) continue; //隐藏的图形不计算
chartPaint.push(this.ChartPaint[i]);
}
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
chartPaint.push(this.OverlayChartPaint[i]);
}
var aryNotSupport=[];
for(var i=0;i<chartPaint.length;++i)
{
var paint=chartPaint[i];
if (paint.NotSupportMessage)
{
aryNotSupport.push(paint);
continue;
}
var range=paint.GetMaxMin();
if (range==null || range.Max==null || range.Min==null) continue;
var frameItem=null;
for(var j=0; j<frameMaxMinData.length; ++j)
{
if (frameMaxMinData[j].Frame==paint.ChartFrame)
{
frameItem=frameMaxMinData[j];
break;
}
}
if (frameItem)
{
if (frameItem.Range.Max<range.Max) frameItem.Range.Max=range.Max;
if (frameItem.Range.Min>range.Min) frameItem.Range.Min=range.Min;
}
else
{
frameItem={ OverlayFrame:[] };
frameItem.Frame=paint.ChartFrame;
frameItem.Range=range;
frameMaxMinData.push(frameItem);
}
}
//当前计算
for(var i=0;i<aryNotSupport.length;++i)
{
var paint=aryNotSupport[i];
var range={Max:10, Min:1 };
var frameItem=null;
for(var j=0; j<frameMaxMinData.length; ++j)
{
if (frameMaxMinData[j].Frame==paint.ChartFrame)
{
frameItem=frameMaxMinData[j];
break;
}
}
if (frameItem) continue;
frameItem={ OverlayFrame:[] };
frameItem.Frame=paint.ChartFrame;
frameItem.Range=range;
frameMaxMinData.push(frameItem);
}
var mapFrame=new Map();
for(var i=0;i<frameMaxMinData.length;++i)
{
var item=frameMaxMinData[i];
mapFrame.set(item.Frame.Identify,item);
}
//叠加坐标Y轴使用主图指标, 最大最小值
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var subFrame=this.Frame.SubFrame[i];
for(var j=0;j<subFrame.OverlayIndex.length;++j)
{
var overlayItem=subFrame.OverlayIndex[j];
var overlayFrame=overlayItem.Frame;
if (overlayFrame.IsShareY!=true) continue;
if (!overlayFrame.MainFrame) continue;
if (!mapFrame.has(overlayFrame.MainFrame.Identify)) continue;
var frameItem=mapFrame.get(overlayFrame.MainFrame.Identify);
if (!frameItem) continue;
frameItem.OverlayFrame.push(overlayFrame);
if (overlayFrame.IsCalculateYMaxMin===false) continue; //叠加坐标Y轴不调整
for(var k=0; k<overlayItem.ChartPaint.length; ++k)
{
var paint=overlayItem.ChartPaint[k];
if (paint.IsShow==false)
continue; //隐藏的图形不计算
var range=paint.GetMaxMin();
if (range==null || range.Max==null || range.Min==null) continue;
if (frameItem.Range.Max<range.Max) frameItem.Range.Max=range.Max;
if (frameItem.Range.Min>range.Min) frameItem.Range.Min=range.Min;
}
}
}
for(var i=0;i<frameMaxMinData.length;++i)
{
var item=frameMaxMinData[i];
if (!item.Frame || !item.Range) continue;
if (item.Range.Max==null || item.Range.Min==null) continue;
if (item.Frame.YSpecificMaxMin)
{
item.Frame.HorizontalMax=item.Frame.YSpecificMaxMin.Max;
item.Frame.HorizontalMin=item.Frame.YSpecificMaxMin.Min;
}
else
{
item.Frame.HorizontalMax=item.Range.Max;
item.Frame.HorizontalMin=item.Range.Min;
}
item.Frame.XYSplit=true;
for(var j in item.OverlayFrame)
{
item.OverlayFrame[j].XYSplit=true;
}
}
//更新独立子坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var subFrame=this.Frame.SubFrame[i];
for(var j=0;j<subFrame.OverlayIndex.length;++j)
{
var overlayItem=subFrame.OverlayIndex[j];
if (overlayItem.Frame.IsShareY===true) continue;
overlayItem.UpdateFrameMaxMin();
}
}
}
this.DataMoveLeft=function()
{
var data=null;
if (!this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
if (data.DataOffset<=0) return false;
--data.DataOffset;
return true;
}
this.DataMoveRight=function()
{
var data=null;
if (!this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (!xPointcount) return false;
if (xPointcount+data.DataOffset>=data.Data.length) return false;
++data.DataOffset;
return true;
}
this.UpdataDataoffset=function()
{
var data=null;
if (this.Frame.Data)
data=this.Frame.Data;
else
data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return;
for(var i in this.ChartPaint)
{
var item =this.ChartPaint[i];
if (!item.Data) continue;
item.Data.DataOffset=data.DataOffset;
}
for(var i in this.OverlayChartPaint)
{
var item =this.OverlayChartPaint[i];
if (!item.Data) continue;
item.Data.DataOffset=data.DataOffset;
}
//叠加指标当前显示的数据偏移
for (var i in this.Frame.SubFrame)
{
var subFrame=this.Frame.SubFrame[i];
for(var j in subFrame.OverlayIndex)
{
var overlayItem=subFrame.OverlayIndex[j];
for(var k in overlayItem.ChartPaint)
{
var item=overlayItem.ChartPaint[k];
if (!item.Data) continue;
item.Data.DataOffset=data.DataOffset;
}
}
}
}
this.GetMoveOneStepWidth=function()
{
if (IFrameSplitOperator.IsPlusNumber(this.StepPixel)) return this.StepPixel;
var pixelRatio=GetDevicePixelRatio();
var mainFrame=this.Frame.SubFrame[0].Frame;
var dataWidth=mainFrame.DataWidth;
var distanceWidth=mainFrame.DistanceWidth;
var oneStepWidth=this.StepPixel;
var oneStepWidth=(dataWidth+distanceWidth)/pixelRatio;
if (oneStepWidth<1) oneStepWidth=1;
return oneStepWidth;
}
this.DataMove=function(step,isLeft)
{
var oneStepWidth=this.GetMoveOneStepWidth();
var moveStep=step;
step=parseInt(step/oneStepWidth); //除以4个像素
if (step<=0) return false;
var data=null;
if (!this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (!xPointcount) return false;
if (this.Frame.SubFrame && this.Frame.SubFrame.length>0 && this.Frame.SubFrame[0].Frame)
{
var fristFrame=this.Frame.SubFrame[0].Frame;
if (fristFrame.DataWidth<=1 || fristFrame.DistanceWidth<=1) //K线在缩放很小的时候 移动加速
{
if (IFrameSplitOperator.IsPlusNumber(this.StepPixel))
step=parseInt(moveStep)*this.StepPixel;
}
}
if (isLeft) //-->
{
if (this.RightSpaceCount>0)
{
if (xPointcount+data.DataOffset>=data.Data.length+this.RightSpaceCount) return false;
data.DataOffset+=step;
if (data.DataOffset+xPointcount>=data.Data.length+this.RightSpaceCount)
data.DataOffset=data.Data.length-(xPointcount-this.RightSpaceCount);
}
else
{
if (xPointcount+data.DataOffset>=data.Data.length) return false;
data.DataOffset+=step;
if (data.DataOffset+xPointcount>=data.Data.length)
data.DataOffset=data.Data.length-xPointcount;
}
return true;
}
else //<--
{
if (data.DataOffset<=0) return false;
data.DataOffset-=step;
if (data.DataOffset<0) data.DataOffset=0;
return true;
}
}
this.XCoordinateZoom=function(step, isMoveLeft)
{
var oneStepWidth=this.GetMoveOneStepWidth();
var moveStep=step;
step=parseInt(step/oneStepWidth); //除以4个像素
if (step<=0) return false;
return this.Frame.XCoordinateZoom(isMoveLeft);
}
//获取鼠标在当前子窗口id
this.GetSubFrameIndex=function(x,y)
{
if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return -1;
for(var i in this.Frame.SubFrame)
{
var frame=this.Frame.SubFrame[i].Frame;
var left=frame.ChartBorder.GetLeft();
var top=frame.ChartBorder.GetTop();
var height=frame.ChartBorder.GetHeight();
var width=frame.ChartBorder.GetWidth();
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
if (this.Canvas.isPointInPath(x,y)) return parseInt(i);
}
return 0;
}
//根据X坐标获取数据索引
this.GetDataIndexByPoint=function(x)
{
var frame=this.Frame;
if (this.Frame.SubFrame && this.Frame.SubFrame.length>0) frame=this.Frame.SubFrame[0].Frame;
var data=null;
if (this.Frame.Data)
data=this.Frame.Data;
else
data=this.Frame.SubFrame[0].Frame.Data;
if (!data || !frame) return;
var index=parseInt(frame.GetXData(x));
//JSConsole.Chart.Log('x='+ x +' date='+data.Data[data.DataOffset+index].Date);
return data.DataOffset+index;
}
//获取主数据
this.GetSelectRectData=function(selectData)
{
if (Math.abs(selectData.XStart-selectData.XEnd)<5) return false;
var startClientPos=this.PtInClient(selectData.XStart, selectData.YStart);
var endClientPos=this.PtInClient(selectData.XEnd, selectData.YEnd);
var data=null;
if (this.Frame.Data)
data=this.Frame.Data;
else
data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
var start=this.GetDataIndexByPoint(selectData.XStart);
var end=this.GetDataIndexByPoint(selectData.XEnd);
if (Math.abs(start-end)<2) return false;
selectData.Data=data;
if (start>end)
{
selectData.Start=end;
selectData.End=start;
}
else
{
selectData.Start=start;
selectData.End=end;
}
return true;
}
//获取当前的点对应的 画图工具的图形
//data.X data.Y 鼠标位置 返回 data.ChartDrawPicture 数据在画图工具 data.PointIndex 在画图工具对应点索引
this.GetChartDrawPictureByPoint=function(data)
{
for(var i=0;i<this.ChartDrawPicture.length; ++i)
{
var item =this.ChartDrawPicture[i];
var pointIndex=item.IsPointIn(data.X, data.Y, this.ChartDrawOption);
if (pointIndex===false) continue;
if (pointIndex>=0)
{
data.ChartDrawPicture=item;
data.PointIndex=pointIndex;
if (item.GetCursorType) data.Cursor=item.GetCursorType(pointIndex); //鼠标形状
return true;
}
}
return false;
}
// 保存图片
this.SaveToImage = function (format,colorGB)
{
if (this.UIElement.width<=0 || this.UIElement.height<=0) return null;
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return null; // 数据加载中不能保存
JSConsole.Chart.Log('[JSChartContainer::SaveToImage]', this.UIElement);
var clrBG='rgb(255,255,255)';
if (colorGB) clrBG=colorGB;
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
this.Canvas.fillStyle=clrBG;
this.Canvas.fillRect(0,0,this.UIElement.width,this.UIElement.height); //画一个背景色, 不然是一个黑的背景
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度
this.Frame.Draw(); //框架
for (var i in this.ChartPaint) //框架内图形
{
var item=this.ChartPaint[i];
if (item.IsDrawFirst)
item.Draw();
}
for(var i in this.ChartPaint)
{
var item=this.ChartPaint[i];
if (!item.IsDrawFirst)
item.Draw();
}
for(var i in this.ChartPaintEx)
{
var item=this.ChartPaintEx[i];
item.Draw();
}
for(var i in this.OverlayChartPaint) //叠加股票
{
var item=this.OverlayChartPaint[i];
item.Draw();
}
for(var i in this.ExtendChartPaint) //固定扩展图形
{
var item=this.ExtendChartPaint[i];
if (!item.IsDynamic && item.IsAnimation==false) item.Draw();
}
if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal();
this.Frame.DrawLock();
for(var i in this.ExtendChartPaint) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw();
}
if (this.LastPoint.X!=null || this.LastPoint.Y!=null)
{
if (this.ChartCorssCursor) //十字光标不画
{
this.ChartCorssCursor.LastPoint=this.LastPoint;
this.ChartCorssCursor.CursorIndex=this.CursorIndex;
}
}
for(var i in this.TitlePaint)
{
var item=this.TitlePaint[i];
if (!item.IsDynamic) continue;
item.CursorIndex=this.CursorIndex;
item.Draw();
}
for(var i in this.ExtendChartPaint) //动态扩展图形
{
var item=this.ExtendChartPaint[i];
if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw();
}
if (this.EnableAnimation)
{
for(var i in this.ExtendChartPaint) //动画
{
var item=this.ExtendChartPaint[i];
if (item.IsAnimation===true) item.Draw();
}
}
for(var i in this.ChartDrawPicture)
{
var item=this.ChartDrawPicture[i];
item.Draw();
}
if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10)
{
this.CurrentChartDrawPicture.Draw();
}
var dataURL=this.UIElement.toDataURL(format ? format:'image/png', 1.0);
JSConsole.Chart.Log('[JSChartContainer::SaveToImage] data= ', dataURL);
return dataURL;
}
this.SaveToImageUrl=function(obj,callback) //obj:{Format: 图片格式, ColorGB: 背景色}, callback:function(bSuccess,obj)
{
if (!obj) obj={Format:'image/png', ColorGB:'rgb(255,255,255)'};
var imageData=this.SaveToImage(obj.Format, obj.ColorGB);
var postData={"Base64":imageData, "BucketName":"downloadcache", "Path":"hqchart/hq_snapshot"};
var url=g_JSChartResource.Domain+'/API/FileUploadForBase64';
JSNetwork.HttpRequest({
url: url,
method: "POST",
dataType: "json",
data: postData,
success: function (data)
{
JSConsole.Chart.Log('[JSChartContainer::SaveToImageUrl] recv data', data);
var result={Path:data.relativeurl, Domain:'http://127.0.0.1:8087'};
result.Url=`${result.Domain}/${result.Path}`;
if (callback) callback(true,result,'');
},
error: function (request)
{
JSConsole.Chart.Log('[JSChartContainer::SaveToImageUrl] error ', request);
if (callback) callback(false,null,'upload failed');
}
});
}
this.ExportDataToCSV=function(data)
{
var strCSV="";
var strRow="";
var rowCount=0;
//标题
for(var i=0;i<data.length;++i)
{
var item=data[i];
strRow+=`"${item.Name}"`;
if (i==data.length-1) strRow+="\r\n";
else strRow+=",";
if (IFrameSplitOperator.IsNonEmptyArray(item.Data))
rowCount=Math.max(rowCount,item.Data.length);
}
strCSV+=strRow;
for(var i=0, j=0;i<rowCount;++i)
{
strRow="";
for(j=0;j<data.length;++j)
{
var item=data[j];
var value=null;
if (item.Data && i<item.Data.length)
value=item.Data[i];
strRow+=`"${value}"`;
if (j==data.length-1) strRow+="\r\n";
else strRow+=",";
}
strCSV+=strRow;
}
strCSV = "\uFEFF" + strCSV;
return strCSV;
}
this.SetLanguage=function(language)
{
var languageID=g_JSChartLocalization.GetLanguageID(language);
if (!IFrameSplitOperator.IsNumber(languageID))
{
console.warn(`[JSChartContainer::SetLanguage] language=${language} error`);
return;
}
if (this.LanguageID==languageID) return;
this.LanguageID=languageID;
if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY) this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
for(var i=0; i<this.TitlePaint.length; ++i) //标题
{
var item=this.TitlePaint[i];
if (item) item.LanguageID=this.LanguageID;
}
for(var i=0;i<this.ExtendChartPaint.length;++i) //tooltip 等扩展图形
{
var item=this.ExtendChartPaint[i];
if (item) item.LanguageID=this.LanguageID;
}
if (this.Frame && this.Frame.SetLanguage) this.Frame.SetLanguage(this.LanguageID);
//this.Frame.ClearYCoordinateMaxMin();
this.ResetFrameXYSplit();
this.Frame.SetSizeChage(true);
this.Draw();
if (this.PopMinuteChart) this.PopMinuteChart.SetLanguage(language);
}
this.ReloadTiltePaintResource=function(resource) //重新加载配置
{
for(var i in this.TitlePaint)
{
var item=this.TitlePaint[i];
if (item.ReloadResource) item.ReloadResource(resource);
}
}
this.ReloadExtendChartPaintResource=function(resource) //扩展画法重新加载配置
{
for(var i=0;i<this.ExtendChartPaint.length; ++i)
{
var item=this.ExtendChartPaint[i];
if (item.ReloadResource) item.ReloadResource(resource);
}
if (this.ChartDragSelectRect && this.ChartDragSelectRect.ReloadResource) this.ChartDragSelectRect.ReloadResource(resource);
}
this.ReloadChartDrawPictureResource=function(resource)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.ChartDrawPicture)) return;
for(var i=0;i<this.ChartDrawPicture.length;++i)
{
var item=this.ChartDrawPicture[i];
if (item.ReloadResource) item.ReloadResource(resource);
}
}
this.ReloadResource=function(option)
{
this.ReloadBorder(option);
this.ReloadTiltePaintResource(option.Resource);
this.ReloadChartPaint(option.Resource);
this.ReloadFrame(option.Resource);
this.ReloadExtendChartPaintResource(option.Resource);
this.ReloadChartCorssCursor(option,option.Resource);
this.ReloadChartDrawPictureResource(option.Resource);
if (option.Update && this.Update) this.Update( {UpdateCursorIndexType:2} ); //是否立即更新并重绘
else if (option.Draw==true) this.Draw(); //是否立即重绘
if (this.PopMinuteChart) this.PopMinuteChart.ReloadResource(option);
if (this.DialogTooltip) this.DialogTooltip.ReloadResource(option);
if (this.FloatTooltip) this.FloatTooltip.ReloadResource(option);
if (this.DialogSelectRect) this.DialogSelectRect.ReloadResource(option);
if (this.DialogSearchIndex) this.DialogSearchIndex.ReloadResource(option);
}
this.ReloadBorder=function(option) //根据页面缩放调整对应边框的尺长
{
if (!option) return;
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
if (option.Border)
{
var item=option.Border;
if (IFrameSplitOperator.IsNumber(item.Left)) this.Frame.ChartBorder.Left=item.Left*pixelTatio;
if (IFrameSplitOperator.IsNumber(item.Right)) this.Frame.ChartBorder.Right=item.Right*pixelTatio;
if (IFrameSplitOperator.IsNumber(item.Top)) this.Frame.ChartBorder.Top=item.Top*pixelTatio;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.Frame.ChartBorder.Bottom=item.Bottom*pixelTatio;
}
for(var i in option.Windows)
{
var item=option.Windows[i];
if (i>=this.Frame.SubFrame.length) continue;
var subFrame=this.Frame.SubFrame[i];
var border=subFrame.Frame.ChartBorder;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) border.TitleHeight=item.TitleHeight*pixelTatio;
}
for(var i in option.Frame)
{
var item=option.Frame[i];
if (i>=this.Frame.SubFrame.length) continue;
var subFrame=this.Frame.SubFrame[i];
var border=subFrame.Frame.ChartBorder;
if (item.TopSpace>=0) border.TopSpace=item.TopSpace*pixelTatio;
if (item.BottomSpace>=0) border.BottomSpace=item.BottomSpace*pixelTatio;
}
}
this.ReloadFrame=function(resource)
{
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
var subFrame=item.Frame;
if (subFrame && subFrame.ReloadResource) subFrame.ReloadResource(resource);
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Frame && overlayItem.Frame.ReloadResource) overlayItem.Frame.ReloadResource(resource);
}
}
}
this.ReloadChartPaint=function(resource)
{
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (item && item.ReloadResource) item.ReloadResource(resource);
}
}
this.ReloadChartCorssCursor=function(option, resource)
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
if (option && option.CorssCursor)
{
var item=option.CorssCursor;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) this.ChartCorssCursor.TextHeight=item.TitleHeight*pixelTatio; //十字光标文本信息高度
}
if (this.ChartCorssCursor.ReloadResource) this.ChartCorssCursor.ReloadResource(resource);
}
this.SetDepthMapData=function(depthData, option)
{
for(var i=0;i<depthData.length; ++i)
{
var item=depthData[i];
for(var j=0;j<this.ExtendChartPaint.length; ++j)
{
var chart=this.ExtendChartPaint[j];
if (chart.ID==item.ID)
{
chart.Data=item.Data;
break;
}
}
}
if (option)
{
if (option.Draw==true) this.Draw();
}
}
//画图工具
//把X, Y绝对位置转成的相对位置的点
this.PointAbsoluteToRelative=function(x, y, isPhone)
{
var pt={ X:x, Y:y };
var pixelTatio = GetDevicePixelRatio(); //x,y是原始坐标 需要乘以放大倍速
var uiRect=this.UIElement.getBoundingClientRect(); //dom返回的是没有放大倍数的值
if (isPhone)
{
pt.X=x-uiRect.left*pixelTatio; //手机端 dom返回的是没有放大倍数的值
pt.Y=y-uiRect.top*pixelTatio;
}
else
{
pt.X=(x-uiRect.left)*pixelTatio;
pt.Y=(y-uiRect.top)*pixelTatio;
}
return pt;
}
this.SetChartDrawPictureFirstPoint=function(x,y, isPhone)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return false;
//相对坐标
var pt=this.PointAbsoluteToRelative(x, y, isPhone);
var xFixed=pt.X;
var yFixed=pt.Y;
for(var i=0;i<this.Frame.SubFrame.length; ++i)
{
var frame=this.Frame.SubFrame[i].Frame;
var left=frame.ChartBorder.GetLeft();
var top=frame.ChartBorder.GetTopEx();
var bottom=frame.ChartBorder.GetBottomEx();
var height=bottom-top;
var width=frame.ChartBorder.GetWidth();
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
//this.Canvas.fillStyle='rgb(255,0,0)';
//this.Canvas.fill();
if (this.Canvas.isPointInPath(xFixed,yFixed))
{
if (IFrameSplitOperator.IsNumber(drawPicture.LimitFrameID))
{
if (i!=drawPicture.LimitFrameID) return false;
}
drawPicture.Frame=frame;
break;
}
}
if (!drawPicture.Frame) return false;
drawPicture.Point[0]=new Point();
drawPicture.Point[0].X=xFixed;
drawPicture.Point[0].Y=yFixed;
drawPicture.Status=1; //第1个点完成
drawPicture.PointMagnetKLine();
return true;
}
this.SetChartDrawPictureSecondPoint=function(x,y,isPhone)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
//相对坐标
var pt=this.PointAbsoluteToRelative(x, y, isPhone);
drawPicture.Point[1]=new Point();
drawPicture.Point[1].X=pt.X;
drawPicture.Point[1].Y=pt.Y;
drawPicture.Status=2; //设置第2个点
return true;
}
//设置第3个点
this.SetChartDrawPictureThirdPoint=function(x,y,isPhone)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
//相对坐标
var pt=this.PointAbsoluteToRelative(x, y, isPhone);
drawPicture.Point[2]=new Point();
drawPicture.Point[2].X=pt.X;
drawPicture.Point[2].Y=pt.Y;
drawPicture.Status=3; //设置第3个点
return true;
}
//xStep,yStep 移动的偏移量
this.MoveChartDrawPicture=function(x,y,isPhone,drag)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
if (isPhone) pixelTatio=1;
var xStep=x*pixelTatio;
var yStep=y*pixelTatio;
//JSConsole.Chart.Log("xStep="+xStep+" yStep="+yStep);
drawPicture.Move(xStep,yStep,drag);
return true;
}
this.FinishChartDrawPicturePoint=function()
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
if (drawPicture.PointCount!=drawPicture.Point.length) return false;
if (drawPicture.ClassName=="ChartDrawRuler") //尺子不用保存的
{
if (drawPicture.FinishedCallback) drawPicture.FinishedCallback(drawPicture);
this.CurrentChartDrawPicture=null;
return true;
}
drawPicture.PointMagnetKLine();
drawPicture.Status=10; //完成
drawPicture.PointToValue();
this.ChartDrawPicture.push(drawPicture);
this.CurrentChartDrawPicture=null;
//通知上层画好了
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FINISH_DRAWPICTURE); //完成画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPicture };
event.Callback(event,sendData,this);
}
//单个回调
if (drawPicture.FinishedCallback) drawPicture.FinishedCallback(drawPicture);
if (drawPicture.OnFinish) drawPicture.OnFinish();
if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture);
return true;
}
//选中画图工具 出现单个图形设置菜单
this.OnSelectChartPicture=function(chart)
{
JSConsole.Chart.Log('[JSChartContainer::OnSelectChartPicture]',chart);
if (!this.DialogModifyDraw) return;
if (chart.ClassName=="ChartDrawPictureText" || chart.ClassName=='ChartDrawVolProfile')
{
this.CloseModifyDrawDialog();
if (!this.ChartPictureMenu) this.ChartPictureMenu=g_DialogFactory.Create('ChartPictureSettingMenu', this.UIElement.parentNode);
if (!this.ChartPictureMenu) return;
var event={ data: { ChartPicture:chart, HQChart:this}};
this.ChartPictureMenu.DoModal(event);
}
else
{
this.ShowModifyDrawDialog(chart);
}
}
this.FinishMoveChartDrawPicture=function()
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
if (drawPicture.PointCount!=drawPicture.Point.length) return false;
drawPicture.PointMagnetKLine();
drawPicture.Status=10; //完成
drawPicture.PointToValue();
if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture);
this.CurrentChartDrawPicture=null;
if (this.SelectChartDrawPicture && this.SelectChartDrawPicture.DragInfo) //图形移动了回调调用移动完成函数
{
var dargInfo=this.SelectChartDrawPicture.DragInfo;
if (dargInfo.Click && dargInfo.Move)
{
if (dargInfo.Click.X!=dargInfo.Move.X || dargInfo.Click.Y!=dargInfo.Move.Y)
{
//通知上层画好了
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FINISH_MOVE_DRAWPICTURE); //完成画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPicture };
event.Callback(event,sendData,this);
}
if (drawPicture.OnMoveFinish) drawPicture.OnMoveFinish();
}
}
}
return true;
}
//清空所有的画线工具 option={ Draw:false/true }
this.ClearChartDrawPicture=function(drawPicture, option)
{
var bDraw=true;
if (!drawPicture)
{
this.ChartDrawPicture=[];
if (this.ChartDrawStorage) this.ChartDrawStorage.Clear();
this.SelectChartDrawPicture=null;
if (option && option.Draw==false) bDraw=false;
if (bDraw) this.Draw();
}
else
{
for(var i=0; i<this.ChartDrawPicture.length; ++i)
{
var item=this.ChartDrawPicture[i];
if (item.Guid==drawPicture.Guid || item==drawPicture)
{
if (this.ChartDrawStorage) this.ChartDrawStorage.DeleteDrawData(drawPicture);
this.ChartDrawPicture.splice(i,1);
if (this.SelectChartDrawPicture) //去掉选中
{
if (this.SelectChartDrawPicture.Guid==drawPicture.Guid || this.SelectChartDrawPicture==drawPicture)
this.SelectChartDrawPicture=null;
}
if (option && option.Draw==false) bDraw=false;
if (bDraw) this.Draw();
}
}
}
}
//获取画图工具当前选中图形的Guid
this.GetActiveDrawPicture=function()
{
var result={ Move: { Guid:null }, Select:{ Guid:null }, MoveOn: {Guid:null} };
if (this.CurrentChartDrawPicture)
result.Move={ Guid: this.CurrentChartDrawPicture.Guid };
if (this.SelectChartDrawPicture)
result.Select={ Guid:this.SelectChartDrawPicture.Guid, Chart:this.SelectChartDrawPicture };
if (this.MoveOnChartDrawPicture)
result.MoveOn={ Guid:this.MoveOnChartDrawPicture.Guid };
return result;
}
this.SetChartDrawOption=function(option)
{
if (IFrameSplitOperator.IsBool(option.IsLockScreen)) this.ChartDrawOption.IsLockScreen=option.IsLockScreen;
if (IFrameSplitOperator.IsNumber(option.Zoom) && option.Zoom>=0) this.ChartDrawOption.Zoom=option.Zoom;
if (option.Magnet)
{
var item=option.Magnet;
if (!this.ChartDrawOption.Magnet) this.ChartDrawOption.Magnet={ Type:0, Distance:20*GetDevicePixelRatio(), Enable:false };
if (IFrameSplitOperator.IsBool(item.Enable)) this.ChartDrawOption.Magnet.Enable=item.Enable;
if (IFrameSplitOperator.IsNumber(item.Type)) this.ChartDrawOption.Magnet.Type=item.Type;
if (IFrameSplitOperator.IsNumber(item.Distance)) this.ChartDrawOption.Magnet.Distance=item.Distance;
}
}
//是否显示十字光标的十字线
this.EnableShowCorssCursorLine=function(bShow)
{
if (!this.ChartCorssCursor) return;
this.ChartCorssCursor.IsShowCorss=bShow;
}
//获取扩展画法
this.GetExtendChartByClassName=function(name)
{
for(var i=0; i<this.ExtendChartPaint.length; ++i)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName==name) return { Index:i, Chart:item };
}
return null
}
//获取多个扩展画法
this.GetExtendChartByClassNameV2=function(name)
{
var aryChart=[];
for(var i=0; i<this.ExtendChartPaint.length; ++i)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName==name)
{
aryChart.push({ Index:i, Chart:item });
}
}
if (aryChart.length<=0) return null;
return aryChart;
}
this.GetExtendChartRightWidth=function() //扩展画法右边宽度
{
var width=0;
for(var i=0; i<this.ExtendChartPaint.length; ++i)
{
var item=this.ExtendChartPaint[i];
if (!item) continue;
if (item.ClassName=="StockChip")
{
if (IFrameSplitOperator.IsNumber(item.Width))
width+=item.Width;
}
}
return width;
}
//删除扩展画法
this.DeleteExtendChart=function(data)
{
if (data.Index>=this.ExtendChartPaint.length) return;
if (this.ExtendChartPaint[data.Index]!=data.Chart) return;
if (typeof(data.Chart.Clear)=='function') data.Chart.Clear();
this.ExtendChartPaint.splice(data.Index,1);
}
//删除扩展画法
this.DeleteExtendChartByID=function(id)
{
for(var i=0;i<this.ExtendChartPaint.length;++i)
{
var item=this.ExtendChartPaint[i];
if (item.ID==id)
{
this.ExtendChartPaint.splice(i, 1);
return true;
}
}
return false;
}
//全屏提示信息 { Title:提示信息, Draw:false/true 是否立即重绘, }
this.EnableSplashScreen=function(enable, option)
{
if (!this.ChartSplashPaint) return;
this.ChartSplashPaint.EnableSplash(enable);
if (option && option.Draw===false) return;
if (enable) this.DrawSplashScreen(option);
else this.Draw();
}
//设置指标窗口属性 windowItem=SetOption.Windows[i], frameItem=SetOption.Frames[i];
this.SetSubFrameAttribute=function(subFrame, windowItem, frameItem)
{
if (!subFrame || !subFrame.Frame) return;
var frame=subFrame.Frame;
if (windowItem)
{
if (IFrameSplitOperator.IsBool(windowItem.Modify)) frame.ModifyIndex=windowItem.Modify;
if (IFrameSplitOperator.IsBool(windowItem.Change)) frame.ChangeIndex=windowItem.Change;
if (IFrameSplitOperator.IsBool(windowItem.Close)) frame.CloseIndex=windowItem.Close;
if (IFrameSplitOperator.IsBool(windowItem.Overlay)) frame.OverlayIndex=windowItem.Overlay;
if (IFrameSplitOperator.IsBool(windowItem.IsDrawTitleBG)) frame.IsDrawTitleBG=windowItem.IsDrawTitleBG;
if (IFrameSplitOperator.IsNumber(windowItem.TitleHeight)) frame.ChartBorder.TitleHeight=windowItem.TitleHeight;
else windowItem.TitleHeight=frame.ChartBorder.TitleHeight;
if (IFrameSplitOperator.IsBool(windowItem.IsShowTitleArrow)) frame.IsShowTitleArrow=windowItem.IsShowTitleArrow;
if (IFrameSplitOperator.IsNumber(windowItem.TitleArrowType)) frame.TitleArrowType=windowItem.TitleArrowType;
if (IFrameSplitOperator.IsBool(windowItem.IsShowIndexName)) frame.IsShowIndexName=windowItem.IsShowIndexName;
if (IFrameSplitOperator.IsNumber(windowItem.IndexParamSpace)) frame.IndexParamSpace=windowItem.IndexParamSpace;
if (IFrameSplitOperator.IsNumber(windowItem.IndexTitleSpace)) frame.IndexTitleSpace=windowItem.IndexTitleSpace;
if (!IFrameSplitOperator.IsUndefined(windowItem.HorizontalReserved)) frame.HorizontalReserved=windowItem.HorizontalReserved; //Y轴上下预留
}
if (frameItem)
{
if (frameItem.SplitCount) frame.YSplitOperator.SplitCount=frameItem.SplitCount;
if (IFrameSplitOperator.IsNumber(frameItem.SplitType))
{
frame.YSplitOperator.SplitType=frameItem.SplitType;
frame.YSplitOperator.DefaultSplitType=frameItem.SplitType;
}
if (IFrameSplitOperator.IsBool(frameItem.IsShowXLine)) frame.IsShowXLine=frameItem.IsShowXLine;
if (IFrameSplitOperator.IsBool(frameItem.IsShowYLine)) frame.IsShowYLine=frameItem.IsShowYLine;
if (IFrameSplitOperator.IsBool(frameItem.IsShowLeftText))
{
frame.IsShowYText[0]=frameItem.IsShowLeftText;
frame.YSplitOperator.IsShowLeftText=frameItem.IsShowLeftText; //显示左边刻度
}
if (IFrameSplitOperator.IsBool(frameItem.IsShowRightText))
{
frame.IsShowYText[1]=frameItem.IsShowRightText;
frame.YSplitOperator.IsShowRightText=frameItem.IsShowRightText; //显示右边刻度
}
if (IFrameSplitOperator.IsNumber(frameItem.Height) && frameItem.Height>=0) subFrame.Height = frameItem.Height;
}
}
this.SetSubFrameOption=function(subFrame, option)
{
if (!option) return;
var frame=subFrame.Frame;
if (option.Window)
{
var item=option.Window;
if (IFrameSplitOperator.IsBool(item.Modify)) frame.ModifyIndex=item.Modify;
if (IFrameSplitOperator.IsBool(item.Change)) frame.ChangeIndex=item.Change;
if (IFrameSplitOperator.IsBool(item.Close)) frame.CloseIndex=item.Close;
if (IFrameSplitOperator.IsBool(item.Overlay)) frame.OverlayIndex=item.Overlay;
if (IFrameSplitOperator.IsBool(item.Export)) frame.ExportData=item.Export;
if (IFrameSplitOperator.IsBool(item.MaxMin)) frame.MaxMinWindow=item.MaxMin;
if (IFrameSplitOperator.IsBool(item.TitleWindow)) frame.TitleWindow=item.TitleWindow;
if (IFrameSplitOperator.IsBool(item.IsDrawTitleBG)) frame.IsDrawTitleBG=item.IsDrawTitleBG;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) frame.IsShowNameArrow=item.IsShowNameArrow;
if (item.OverlayIndexType)
{
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
}
if (IFrameSplitOperator.IsNonEmptyArray(item.CustomToolbar)) //自定义工具按钮
{
frame.CustomToolbar=item.CustomToolbar.slice();
}
}
if (IFrameSplitOperator.IsNumber(option.SplitCount)) subFrame.Frame.YSplitOperator.SplitCount=option.SplitCount;
if (IFrameSplitOperator.IsNumber(option.TitleHeight)) subFrame.Frame.ChartBorder.TitleHeight=option.TitleHeight;
if (IFrameSplitOperator.IsBool(option.IsShowTitleArrow)) subFrame.Frame.IsShowTitleArrow=option.IsShowTitleArrow;
if (IFrameSplitOperator.IsNumber(option.TitleArrowType)) subFrame.Frame.TitleArrowType=option.TitleArrowType;
if (IFrameSplitOperator.IsBool(option.IsShowIndexName)) subFrame.Frame.IsShowIndexName=option.IsShowIndexName;
if (IFrameSplitOperator.IsBool(option.IsShowOverlayIndexName)) subFrame.Frame.IsShowOverlayIndexName=option.IsShowOverlayIndexName;
if (IFrameSplitOperator.IsNumber(option.IndexParamSpace)) subFrame.Frame.IndexParamSpace=option.IndexParamSpace;
if (IFrameSplitOperator.IsBool(option.IsShowXLine)) subFrame.Frame.IsShowXLine=option.IsShowXLine;
if (IFrameSplitOperator.IsBool(option.IsShowYLine)) subFrame.Frame.IsShowYLine=option.IsShowYLine;
if (IFrameSplitOperator.IsBool(option.IsShowIndexTitle)) subFrame.Frame.IsShowIndexTitle=option.IsShowIndexTitle;
if (IFrameSplitOperator.IsBool(option.IsShowLeftText))
{
subFrame.Frame.IsShowYText[0]=option.IsShowLeftText;
subFrame.Frame.YSplitOperator.IsShowLeftText=option.IsShowLeftText; //显示左边刻度
}
if (IFrameSplitOperator.IsBool(option.IsShowRightText))
{
subFrame.Frame.IsShowYText[1]=option.IsShowRightText;
subFrame.Frame.YSplitOperator.IsShowRightText=option.IsShowRightText; //显示右边刻度
}
}
this.AddNewSubFrame=function(option)
{
var index=this.Frame.SubFrame.length;
var subFrame=this.CreateSubFrameItem(index);
var pixelRatio=GetDevicePixelRatio();
subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
this.Frame.SubFrame[index]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[index].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.TitlePaint[index+1]=titlePaint;
this.SetSubFrameOption(subFrame,option);
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
this.Frame.SetSizeChage(true);
if (this.UpdateXShowText) this.UpdateXShowText();
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
return index;
}
//增加一个指标窗口
this.AddIndexWindow=function(indexName,option)
{
//查找系统指标
let scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(indexName);
if (!indexInfo) return;
this.RemoveMinSizeWindows(); //清空隐藏的指标
var index=this.AddNewSubFrame(option);
JSIndexScript.ModifyAttribute(indexInfo, option);
this.WindowIndex[index] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer")
var bindData=this.SourceData;
else
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(index,bindData); //执行脚本
}
this.AddAPIIndexWindow=function(indexData, option)
{
if (!indexData.API) return;
this.RemoveMinSizeWindows(); //清空隐藏的指标
var index=this.AddNewSubFrame(option);
//使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
var apiItem=indexData.API;
this.WindowIndex[index]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,indexData);
if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer")
var bindData=this.SourceData;
else
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(index,bindData); //执行脚本
}
//增加一个自定义指标窗口
this.AddScriptIndexWindow=function(indexInfo, option)
{
if (!indexInfo || !indexInfo.Script || !indexInfo.Name) return;
this.RemoveMinSizeWindows(); //清空隐藏的指标
var index=this.AddNewSubFrame(option);
var indexData =
{
Name:indexInfo.Name, Script:indexInfo.Script, Args: indexInfo.Args, ID:indexInfo.Name ,
//扩展属性 可以是空
KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale,
FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition,StringFormat:indexInfo.StringFormat,
OutName:indexInfo.OutName
};
if (indexInfo.ID) indexData.ID=indexInfo.ID;
this.WindowIndex[index] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args,indexData); //脚本执行
if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer")
var bindData=this.SourceData;
else
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(index,bindData); //执行脚本
}
//区间选择
this.GetRectSelectPaint=function()
{
var finder=this.GetExtendChartByClassName("RectSelectPaint");
if (!finder) return null;
return finder.Chart;
}
//鼠标拖动区域
this.GetRectDragPaint=function()
{
var finder=this.GetExtendChartByClassName("RectDragPaint");
if (!finder) return null;
return finder.Chart;
}
this.SetRectSelectData=function(kItem, index)
{
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (paint.GetPointCount()==2)
{
if (!paint.SpaceReselected)
return false;
var oldPreventClose=paint.PreventClose; //备份下
paint.PreventClose=false;
paint.ClearPoint();
paint.PreventClose=oldPreventClose; //还原
}
return paint.SetPoint(kItem, { DataIndex:index} );
}
this.MoveRectSelectPoint=function(obj)
{
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (!this.ChartPaint[0] || !this.ChartPaint[0].Data) return false;
var kData=this.ChartPaint[0].Data;
if (!this.Frame.SubFrame[0]) return false;
var subFrame=this.Frame.SubFrame[0].Frame;
if (!subFrame) false;
var pixelTatio = GetDevicePixelRatio();
var x=(obj.X-uielement.getBoundingClientRect().left)*pixelTatio;
var index=subFrame.GetXData(x);
index=parseInt(index.toFixed(0));
var dataIndex=index+kData.DataOffset;
if (dataIndex>=kData.Data.length) dataIndex=kData.Data.length-1;
var item = kData.Data[dataIndex];
JSConsole.Chart.Log("[KLineChartContainer::MoveRectSelectPoint] point, item", obj.PointIndex, item);
if (!paint.SetPoint(item,{ Index: obj.PointIndex, DataIndex:dataIndex })) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT);
if (event)
{
var selectData=paint.GetSelectRectData();
var data={ X:obj.X, Y:obj.Y, SelectData:selectData, RectSelectPaint:paint };
event.Callback(event,data,this);
}
if (this.IsShowSelectRectDialog()) //区间统计
{
var selectData=paint.GetSelectRectData();
var data=
{
Chart:this, X:obj.X, Y:obj.Y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
var e={ data:data }
this.DrawSelectRectDialog(e);
}
return true;
}
this.MoveSubRectSelect=function(obj)
{
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (!paint.MoveSubRect(obj.Step, obj.IsLeft)) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SUB_SELECT_RECT);
if (event)
{
var subRectData={Start:paint.SubClient.FirstPoint, End: paint.SubClient.SecondPoint }
var data={ X:obj.X, Y:obj.Y, SubRectSelectData: subRectData, RectSelectPaint:paint };
event.Callback(event,data,this);
}
return true;
}
this.ClearRectSelect=function(bEnforce)
{
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (bEnforce) paint.PreventClose=false;
return paint.ClearPoint();
}
//删除指定窗口的所有叠加指标
this.DeleteWindowsOverlayIndex=function(windowIndex)
{
if (!IFrameSplitOperator.IsNumber(windowIndex)) return;
if (windowIndex<0 || windowIndex>=this.Frame.SubFrame.length) return;
var subFrame=this.Frame.SubFrame[windowIndex];
if (!IFrameSplitOperator.IsNonEmptyArray(subFrame.OverlayIndex)) return;
var aryIndexID=[];
for(var i=0; i<subFrame.OverlayIndex.length; ++i)
{
var overlayItem=subFrame.OverlayIndex[i];
aryIndexID.push(overlayItem.Identify);
for(var j=0;j<overlayItem.ChartPaint.length;++j) //图形销毁事件
{
var overlayChart=overlayItem.ChartPaint[j];
if (overlayChart && overlayChart.OnDestroy) overlayChart.OnDestroy();
}
overlayItem.ChartPaint=[];
}
subFrame.OverlayIndex=[];
var titlePaint=this.TitlePaint[windowIndex+1];
for(var i=0;i<aryIndexID.length;++i)
{
var identify=aryIndexID[i];
if (titlePaint.OverlayIndex.has(identify))
titlePaint.OverlayIndex.delete(identify);
if (titlePaint.OverlayDynamicTitle.has(identify))
titlePaint.OverlayDynamicTitle.delete(identify);
}
}
//删除叠加指标, 没有重绘
this.DeleteOverlayIndex=function(identify, windowIndex)
{
var findIndex=null;
if (IFrameSplitOperator.IsNumber(windowIndex))
{
if (windowIndex>=0 && windowIndex<this.Frame.SubFrame.length)
{
var item=this.Frame.SubFrame[windowIndex];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Identify===identify)
{
for(var k=0;k<overlayItem.ChartPaint.length;++k) //图形销毁事件
{
var overlayChart=overlayItem.ChartPaint[k];
if (overlayChart && overlayChart.OnDestroy) overlayChart.OnDestroy();
}
item.OverlayIndex.splice(j, 1);
findIndex=windowIndex
break;
}
}
}
}
else
{
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Identify===identify)
{
for(var k=0;k<overlayItem.ChartPaint.length;++k) //图形销毁事件
{
var overlayChart=overlayItem.ChartPaint[k];
if (overlayChart && overlayChart.OnDestroy) overlayChart.OnDestroy();
}
item.OverlayIndex.splice(j, 1);
findIndex=i;
break;
}
}
}
}
if (findIndex==null)
{
console.warn(`[JSChartContainer::DeleteOverlayIndex] can't find overlay index. [identify=${identify}]`);
return false;
}
var windowsIndex=findIndex+1;
var titlePaint=this.TitlePaint[windowsIndex];
if (titlePaint.OverlayIndex.has(identify))
titlePaint.OverlayIndex.delete(identify);
if (titlePaint.OverlayDynamicTitle.has(identify))
titlePaint.OverlayDynamicTitle.delete(identify);
return true;
}
this.FindScriptIndex=function(guid, windowsIndex)
{
if (IFrameSplitOperator.IsNumber(windowsIndex) && windowsIndex>=0)
{
if (windowsIndex>=this.Frame.SubFrame.length) return null;
var item=this.WindowIndex[windowsIndex];
if (item && item.Guid==guid)
return { Type:0, Data:item, WindowIndex:windowsIndex };
var item=this.Frame.SubFrame[windowsIndex];
for(var i=0; i<item.OverlayIndex.length; ++i)
{
var overlayItem=item.OverlayIndex[i];
if (overlayItem.Identify===guid)
return { Type:1, Data:overlayItem, WindowIndex:windowsIndex, OverlayIndex:i };
}
}
else
{
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.WindowIndex[i];
if (item && item.Guid==guid)
return { Type:0, Data:item, WindowIndex:i };
var item=this.Frame.SubFrame[i];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Identify===guid)
return { Type:1, Data:overlayItem, WindowIndex:i, OverlayIndex:j };
}
}
}
return null;
}
//移动指标 src={ WindowIndex:指标窗口索引,IndexID:指标ID } dest={ WindowIndex:指标窗口索引 } , option={ Operator: 0=移动, 1=复制 }
this.MoveIndex=function(src, dest, option)
{
if (!src || !dest || !option) return false;
if ( !IFrameSplitOperator.IsNumber(src.WindowIndex) || src.WindowIndex<0 || src.WindowIndex>=this.Frame.SubFrame.length ) return false;
if ( !IFrameSplitOperator.IsNumber(dest.WindowIndex) || dest.WindowIndex<0 || dest.WindowIndex>=this.Frame.SubFrame.length ) return false;
var find=this.FindScriptIndex(src.IndexID,src.WindowIndex);
if (!find) return false;
var findItem=null,findOverlayItem=null;
if (find.Type==0) findItem=find.Data;
else if (find.Type==1) findOverlayItem=find.Data;
if (!findOverlayItem && !findItem) return false;
//固定窗口
var fixedWindowCount=0;
var isMinuteChart=(this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") ? true:false;
if (isMinuteChart) fixedWindowCount=2; //走势图固定2个窗口
if (dest.WindowIndex>=fixedWindowCount && this.WindowIndex[dest.WindowIndex]==null) //主指标是空的,移动到主指标上
{
if (findItem) this.WindowIndex[dest.WindowIndex] = this.CreateMainScript(findItem);
else if (findOverlayItem) this.WindowIndex[dest.WindowIndex] = this.CreateMainScript(findOverlayItem.Script);
if (option.Operator==0) //移动模式, 删除原来的
{
if (findOverlayItem)
this.DeleteOverlayIndex(findOverlayItem.Identify, src.WindowIndex);
else if (findItem)
this.DeleteMainIndex(findItem.Guid,src.WindowIndex);
}
var bindData=this.GetMainData();
this.BindIndexData(dest.WindowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
else
{
var subFrame=this.Frame.SubFrame[dest.WindowIndex];
var overlayFrame=new OverlayIndexItem();
var frame=this.CreateOverlayFrame();
frame.Canvas=this.Canvas;
frame.MainFrame=subFrame.Frame;
frame.ChartBorder=subFrame.Frame.ChartBorder;
if (findOverlayItem) frame.IsShow=findOverlayItem.Frame.IsShow;
//if (obj.IsShareY===true) frame.IsShareY=true;
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=frame.ChartBorder;
frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount;
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
overlayFrame.Frame=frame;
var scriptIndex;
if (findItem)
{
scriptIndex=this.CreateOverlayScript(findItem);
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:dest.WindowIndex, Frame:overlayFrame }; //叠加指标信息
}
else if (findOverlayItem)
{
scriptIndex=this.CreateOverlayScript(findOverlayItem.Script);
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:dest.WindowIndex, Frame:overlayFrame }; //叠加指标信息
}
overlayFrame.Script=scriptIndex;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_OVERLAY_FRAME);
if (event && event.Callback)
{
var sendData={ OverlayFrame:overlayFrame, WindowIndex:dest.WindowIndex, SubFrame:subFrame };
event.Callback(event, sendData, this);
}
subFrame.OverlayIndex.push(overlayFrame);
var updateWindowIndex=dest.WindowIndex;
if (option.Operator==0) //移动模式, 删除原来的
{
if (findOverlayItem)
this.DeleteOverlayIndex(findOverlayItem.Identify, src.WindowIndex);
else if (findItem)
{
this.DeleteMainIndex(findItem.Guid,src.WindowIndex);
var find=this.FindScriptIndex(overlayFrame.Identify);
if (find) updateWindowIndex=find.WindowIndex;
}
}
var bindData=this.GetMainData();
this.BindOverlayIndexData(overlayFrame,updateWindowIndex,bindData);
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
}
//移动指标到新的指标窗口 src={ WindowIndex:指标窗口索引,IndexID:指标ID } , option={ Operator: 0=移动, 1=复制 }
this.MoveIndexToNewWindow=function(src, option)
{
if (!src || !option) return false;
if (!IFrameSplitOperator.IsNumber(src.WindowIndex) || src.WindowIndex<0 || src.WindowIndex>=this.Frame.SubFrame.length) return false;
var find=this.FindScriptIndex(src.IndexID,src.WindowIndex);
if (!find) return false;
var findItem=null,findOverlayItem=null;
if (find.Type==0) findItem=find.Data;
else if (find.Type==1) findOverlayItem=find.Data;
if (!findOverlayItem && !findItem) return false;
if (src.WindowIndex==this.Frame.SubFrame.length-1 && this.Frame.SubFrame[src.WindowIndex].OverlayIndex<=0) return false; //指标在最后一个窗口不需要移动
this.RemoveMinSizeWindows(); //清空隐藏的指标
var index=this.Frame.SubFrame.length;
var subFrame=this.CreateSubFrameItem(index);
var pixelRatio=GetDevicePixelRatio();
subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
this.Frame.SubFrame[index]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[index].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.SelectedChart=this.SelectedChart;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.TitlePaint[index+1]=titlePaint;
this.SetSubFrameOption(subFrame, option);
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
if (option.Operator==0) //移动模式, 删除原来的
{
if (findOverlayItem)
this.DeleteOverlayIndex(findOverlayItem.Identify, src.WindowIndex);
else if (findItem)
this.DeleteMainIndex(findItem.Guid,src.WindowIndex);
}
this.UpdataDataoffset(); //更新数据偏移
this.Frame.SetSizeChage(true);
if (this.UpdateXShowText) this.UpdateXShowText();
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
var index=this.Frame.SubFrame.length-1;
if (findItem) this.WindowIndex[index] = this.CreateMainScript(findItem);
else if (findOverlayItem) this.WindowIndex[index] = this.CreateMainScript(findOverlayItem.Script);
var bindData=this.GetMainData();
this.BindIndexData(index,bindData); //执行脚本
}
//创建一个叠加指标
this.CreateOverlayScript=function(src)
{
var scriptIndex=null;
switch(src.ClassName)
{
case "ScriptIndex":
scriptIndex=new OverlayScriptIndex();
break;
case "APIScriptIndex":
scriptIndex=new APIScriptIndex(null, null, null,null, true);
break;
case "OverlayScriptIndex":
scriptIndex=new OverlayScriptIndex();
break;
}
src.CopyTo(scriptIndex);
return scriptIndex;
}
//创建主指标
this.CreateMainScript=function(src)
{
var scriptIndex=null;
switch(src.ClassName)
{
case "ScriptIndex":
case "OverlayScriptIndex":
scriptIndex=new ScriptIndex();
break;
case "APIScriptIndex":
scriptIndex=new APIScriptIndex();
break;
}
src.CopyTo(scriptIndex);
return scriptIndex;
}
//删除主指标, 如果有叠加指标,移动第1个叠加指标为主指标, 没有叠加指标,删除指标窗口
this.DeleteMainIndex=function(identify, windowIndex)
{
var mainIndex=this.WindowIndex[windowIndex];
if (!mainIndex) return false;
var subFrame=this.Frame.SubFrame[windowIndex];
if (!subFrame) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(subFrame.OverlayIndex))
{
this.RemoveIndexWindow(windowIndex, { DeleteMainIndex:true });
}
else
{
var overlayItem=subFrame.OverlayIndex[0];
this.DeleteOverlayIndex(overlayItem.Identify, windowIndex);
this.WindowIndex[windowIndex] = this.CreateMainScript(overlayItem.Script);
var bindData=this.GetMainData();
this.BindIndexData(windowIndex,bindData); //执行脚本
}
}
this.GetMainData=function()
{
switch(this.ClassName)
{
case "MinuteChartContainer":
case "MinuteChartHScreenContainer":
return this.SourceData;
case "KLineChartContainer":
case "KLineChartHScreenContainer":
return this.ChartPaint[0].Data;
}
}
this.CreateOverlayFrame=function()
{
switch(this.ClassName)
{
case "KLineChartContainer":
return new OverlayKLineFrame();
case "KLineChartHScreenContainer":
return new OverlayKLineHScreenFrame();
case "MinuteChartContainer":
return new OverlayMinuteFrame();
case "MinuteChartHScreenContainer":
return new OverlayMinuteHScreenFrame();
}
}
//数据导出
this.ExportData=function(option)
{
if (!this.ExportMainData) return null;
if (!this.ChartPaint[0]) return null;
var mainData=this.GetMainData();
if (!mainData || !IFrameSplitOperator.IsNonEmptyArray(mainData.Data)) return null;
var range=null;
var aryKData=mainData.Data; //K线/分时数据
if (option.Start && option.End) range=mainData.GetDataRange(option.Start, option.End);
var aryData=this.ExportMainData(mainData, range); //导出K线/分时
if (!aryData) return null;
//主图+附图指标
for(var i=1;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (!item || !item.ExportData) continue;
var data=item.ExportData(aryKData, range);
if (data && IFrameSplitOperator.IsNonEmptyArray(data))
{
for(var j=0;j<data.length;++j)
{
var subItem=data[j];
if (item.IndexName) aryData.push({Name:`${subItem.Name}(${item.IndexName})`, Data:subItem.Data});
else aryData.push(subItem);
}
}
}
//叠加股票
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Data || !IFrameSplitOperator.IsNonEmptyArray(chart.Data.Data)) continue;
var data=this.ExportMainData(item.Data, { IsOverlay:true });
if (data && IFrameSplitOperator.IsNonEmptyArray(data))
{
for(var j=0;j<data.length;++j)
{
var subItem=data[j];
aryData.push({ Name:`${subItem.Name}(${item.Symbol})`, Data:subItem.Data} );
}
}
}
//叠加指标
for(var i=0, j=0, k=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (IFrameSplitOperator.IsNonEmptyArray(overlayItem.ChartPaint))
{
for(k=0;k<overlayItem.ChartPaint.length;++k)
{
var chart=overlayItem.ChartPaint[k];
if (!chart || !chart.ExportData) continue;
var data=chart.ExportData(aryKData, range);
if (data && IFrameSplitOperator.IsNonEmptyArray(data))
{
for(var index=0;index<data.length;++index)
{
var subItem=data[index];
if (chart.IndexName) aryData.push({Name:`${subItem.Name}(${chart.IndexName})`, Data:subItem.Data});
else aryData.push(subItem);
}
}
}
}
}
}
if (option && option.Type=="CSV")
{
return this.ExportDataToCSV(aryData);
}
return aryData;
}
//重置指标计数器
this.ClearIndexRunCount=function()
{
//主图指标
for(var i=0;i<this.WindowIndex.length;++i)
{
var item=this.WindowIndex[i];
if (!item) continue;
item.RunCount=0;
}
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Script) overlayItem.Script.RunCount=0;
}
}
}
//获取当前的显示的指标 包含叠加指标
this.GetIndexInfo=function()
{
var aryIndex=[];
for(var i=0, j=0; i<this.WindowIndex.length; ++i)
{
var item=this.WindowIndex[i];
if (!item) continue;
var info={ Name:item.Name, WindowIndex:i, IsOverlay:false };
if (item.ID) info.ID=item.ID;
if (IFrameSplitOperator.IsNonEmptyArray(item.Arguments)) //参数
{
info.Args=[];
for(j=0;j<item.Arguments.length;++j)
{
var argItem=item.Arguments[j];
info.Args.push( { Name:argItem.Name, Value:argItem.Value} );
}
}
aryIndex.push(info);
}
this.GetOverlayIndexInfo(aryIndex); //叠加指标
return aryIndex;
}
//叠加指标
this.GetOverlayIndexInfo=function(aryIndex)
{
for(var i=0, j=0, k=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
if (!IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex)) continue;
for(j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (!overlayItem.Script) continue;
var indexData=overlayItem.Script;
var info={ Name:indexData.Name, ID:indexData.ID, WindowIndex:i, IsOverlay:true, Identify:overlayItem.Identify };
if (IFrameSplitOperator.IsNonEmptyArray(indexData.Arguments)) //参数
{
info.Args=[];
for(k=0;k<indexData.Arguments.length;++k)
{
var argItem=indexData.Arguments[k];
info.Args.push( { Name:argItem.Name, Value:argItem.Value} );
}
}
aryIndex.push(info);
}
}
}
//点tab弹菜单
this.PopupMenuByTab=function(menuData, rtTab)
{
if (!this.JSPopMenu) return;
var pixelRatio=GetDevicePixelRatio();
var rtCell={ Left:rtTab.Left/pixelRatio, Right:rtTab.Right/pixelRatio, Bottom:rtTab.Bottom/pixelRatio, Top:rtTab.Top/pixelRatio };
rtCell.Width=rtCell.Right-rtCell.Left;
rtCell.Height=rtCell.Bottom-rtCell.Top;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var offsetLeft=rtClient.left+rtScroll.Left;
var offsetTop=rtClient.top+rtScroll.Top;
rtCell.Left+=offsetLeft;
rtCell.Right+=offsetLeft;
rtCell.Top+=offsetTop;
rtCell.Bottom+=offsetTop;
this.JSPopMenu.CreatePopMenu(menuData);
this.JSPopMenu.PopupMenuByTab(rtCell);
}
//下拉菜单
this.PopupMenuByDrapdown=function(menuData, rtButton)
{
if (!this.JSPopMenu) return;
var pixelRatio=GetDevicePixelRatio();
var rtCell={ Left:rtButton.Left/pixelRatio, Right:rtButton.Right/pixelRatio, Bottom:rtButton.Bottom/pixelRatio, Top:rtButton.Top/pixelRatio };
rtCell.Width=rtCell.Right-rtCell.Left;
rtCell.Height=rtCell.Bottom-rtCell.Top;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var offsetLeft=rtClient.left+rtScroll.Left;
var offsetTop=rtClient.top+rtScroll.Top;
rtCell.Left+=offsetLeft;
rtCell.Right+=offsetLeft;
rtCell.Top+=offsetTop;
rtCell.Bottom+=offsetTop;
this.JSPopMenu.CreatePopMenu(menuData);
this.JSPopMenu.PopupMenuByDrapdown(rtCell);
}
//右键菜单
this.PopupMenuByRClick=function(menuData, x, y)
{
if (!this.JSPopMenu) return;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
x+=rtClient.left+rtScroll.Left;
y+=rtClient.top+rtScroll.Top;
this.JSPopMenu.CreatePopMenu(menuData);
this.JSPopMenu.PopupMenuByRight(x,y);
}
//菜单命令
this.ExecuteMenuCommand=function(cmdID, aryArgs)
{
JSConsole.Chart.Log('[JSChartContainer::ExecuteMenuCommand] cmdID=, aryArgs=', cmdID,aryArgs);
var param=null, srcParam=null; //原始值
if (IFrameSplitOperator.IsNonEmptyArray(aryArgs))
{
srcParam=aryArgs[0];
if (IFrameSplitOperator.IsNumber(aryArgs[0])) param=aryArgs[0];
}
switch(cmdID)
{
case JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID:
if (this.ChangePeriod && param!=null)
this.ChangePeriod(param);
break;
case JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID:
if (this.ChangeIndexWindowCount && param!=null)
this.ChangeIndexWindowCount(param);
break;
case JSCHART_MENU_ID.CMD_CHANGE_RIGHT_ID:
if (this.ChangeRight && param!=null)
this.ChangeRight(param);
break;
case JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID:
if (this.ChangeIndex && param!=null && aryArgs[1])
this.ChangeIndex(param,aryArgs[1]);
break;
case JSCHART_MENU_ID.CMD_CHANGE_API_INDEX_ID:
if (this.ChangeAPIIndex && param!=null && aryArgs[1])
this.ChangeAPIIndex(param, aryArgs[1]);
break;
case JSCHART_MENU_ID.CMD_CHANGE_SCRIPT_INDEX_ID:
if (this.ChangeScriptIndex && param!=null && aryArgs[1])
this.ChangeScriptIndex(param,aryArgs[1],aryArgs[2]);
break;
case JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID:
case JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID:
if (this.ChangeInstructionIndex && aryArgs[0])
this.ChangeInstructionIndex(aryArgs[0]);
break;
case JSCHART_MENU_ID.CMD_DELETE_COLOR_INDEX_ID: //删除五彩K线指标
case JSCHART_MENU_ID.CMD_DELETE_TRADE_INDEX_ID: //删除专家系统(交易指标)
if (this.CancelInstructionIndex) this.CancelInstructionIndex();
break;
case JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID: //切换K线类型
if (this.ChangeKLineDrawType && param!=null)
this.ChangeKLineDrawType(param,aryArgs[1],aryArgs[2]);
break;
case JSCHART_MENU_ID.CMD_CHANGE_PRICE_GAP_ID: //缺口提示
if (this.ChangePriceGap && IFrameSplitOperator.IsBool(aryArgs[0]))
{
if (aryArgs[0]==false)
{
this.ChangePriceGap({ Enable:aryArgs[0] });
}
else
{
if (IFrameSplitOperator.IsNumber(aryArgs[1]))
this.ChangePriceGap({ Enable:aryArgs[0], Count:aryArgs[1] });
}
}
break;
case JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID:
if (aryArgs[1]===true)
{
if (this.OverlaySymbol && aryArgs[0]) this.OverlaySymbol(aryArgs[0]);
}
else if (aryArgs[1]===false)
{
if (this.DeleteOverlaySymbol && aryArgs[0]) this.DeleteOverlaySymbol(aryArgs[0]);
}
break;
case JSCHART_MENU_ID.CMD_DELETE_ALL_OVERLAY_SYMBOL_ID:
if (this.ClearOverlaySymbol) this.ClearOverlaySymbol();
break;
case JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID:
if (this.ChangeCoordinateType && aryArgs[0]) this.ChangeCoordinateType(aryArgs[0]);
break;
case JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID:
if (aryArgs[0] && IFrameSplitOperator.IsBool(aryArgs[1]))
{
if (aryArgs[1]==true && this.AddKLineInfo) this.AddKLineInfo(aryArgs[0],true);
else if (aryArgs[1]==false && this.DeleteKLineInfo) this.DeleteKLineInfo(aryArgs[0]);
}
break;
case JSCHART_MENU_ID.CMD_DELETE_ALL_KLINE_INFO_ID:
if (this.ClearKLineInfo) this.ClearKLineInfo();
break;
case JSCHART_MENU_ID.CMD_CHANGE_DRAG_MODE_ID:
if (param!=null) this.DragMode=param;
break;
case JSCHART_MENU_ID.CMD_CHANGE_BG_SPLIT_ID:
if (IFrameSplitOperator.IsBool(srcParam))
{
if (srcParam)
{
this.CreateExtendChart("SessionBreaksPaint", { });
this.Draw();
}
else
{
var finder=this.GetExtendChartByClassName("SessionBreaksPaint");
if (finder)
{
this.DeleteExtendChartByID(finder.Chart.ID);
this.Draw();
}
}
}
break;
case JSCHART_MENU_ID.CMD_SHOW_DRAWTOOL_ID:
if (!this.IsShowDrawToolDialog())
this.ShowDrawToolDialog();
break;
case JSCHART_MENU_ID.CMD_SHOW_STOCKCHIP_ID:
var option={Name:'筹码分布', ShowType:1, Width:230 };
var extendChart=this.CreateExtendChart(option.Name, option); //创建扩展图形
this.SetSizeChange(true);
this.Draw();
break;
case JSCHART_MENU_ID.CMD_HIDE_STOCKCHIP_ID:
var StockChip=this.GetExtendChartByClassName('StockChip');
if (StockChip)
{
var chipWidth=StockChip.Chart.Width;
this.DeleteExtendChart(StockChip);
this.Frame.ChartBorder.Right-=chipWidth;
this.SetSizeChange(true);
this.Draw();
}
break;
case JSCHART_MENU_ID.CMD_ENABLE_SELECT_RECT_ID:
if (IFrameSplitOperator.IsBool(srcParam))
this.EnableSelectRect=srcParam;
break;
case JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID:
if (this.ChangeDayCount && param!=null)
this.ChangeDayCount(param);
break;
case JSCHART_MENU_ID.CMD_SHOW_BEFORE_DATA_ID:
if (this.ShowCallAuctionData && IFrameSplitOperator.IsBool(srcParam))
this.ShowCallAuctionData({ Left:srcParam, MultiDay:{ Left:srcParam }});
break;
case JSCHART_MENU_ID.CMD_CHANGE_BASELINE_ID:
if (this.ChangeBaselineType && IFrameSplitOperator.IsNumber(param))
this.ChangeBaselineType(param);
break;
case JSCHART_MENU_ID.CMD_SELECTED_ZOOM_ID:
if (this.ShowSelectData && srcParam) this.ShowSelectData(srcParam);
break;
case JSCHART_MENU_ID.CMD_SELECTED_SUMMARY_ID:
if (this.DialogSelectRect && srcParam) this.DrawSelectRectDialog(srcParam);
break;
case JSCHART_MENU_ID.CMD_SHOW_INDEX_ID: //显示隐藏指标 [0]=windowIndex [1]=0=自动 1=隐藏 2=显示
if (param==null || !IFrameSplitOperator.IsNumber(aryArgs[1])) return false;
var windowIndex=param, showType=aryArgs[1];
var script=this.WindowIndex[windowIndex];
if (!script) return false;
if (showType==1) script.IsShow=false;
else if (showType==2) script.IsShow=true;
else script.IsShow=!script.IsShow;
this.UpdateWindowIndex(windowIndex);
break;
case JSCHART_MENU_ID.CMD_SHOW_OVERLAY_INDEX_ID: //显示隐藏叠加指标 [0]=indexGuid [1]=0=自动 1=隐藏 2=显示
if (!srcParam || !IFrameSplitOperator.IsNumber(aryArgs[1])) return false;
var indexGuid=srcParam,showType=aryArgs[1];
var overlay=this.GetOverlayIndexByIdentify(indexGuid);
if (!overlay || !overlay.OverlayItem || !overlay.OverlayItem.Script) return false;
var script=overlay.OverlayItem.Script;
if (showType==1) script.IsShow=false;
else if (showType==2) script.IsShow==true;
else script.IsShow=!script.IsShow;
this.UpdateOverlayIndex(indexGuid);
break;
case JSCHART_MENU_ID.CMD_DELETE_OVERLAY_INDEX_ID:
if (srcParam && this.DeleteOverlayWindowsIndex)
this.DeleteOverlayWindowsIndex(srcParam);
break;
case JSCHART_MENU_ID.CMD_SHOW_OVERLAY_Y_AXIS_ID:
if (!srcParam || !IFrameSplitOperator.IsNumber(aryArgs[1])) return false;
if (!this.GetOverlayIndexByIdentify) return false;
var indexGuid=srcParam,showType=aryArgs[1];
var finder=this.GetOverlayIndexByIdentify(indexGuid);
if (!finder || !finder.OverlayItem) return false;
var frame=finder.OverlayItem.Frame;
if (showType==1) frame.IsShow=false;
else if (showType==2) frame.IsShow==true;
else frame.IsShow=!frame.IsShow;
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
break;
case JSCHART_MENU_ID.CMD_ENABLE_OVERLAY_SHARE_Y_ID:
if (!srcParam || !IFrameSplitOperator.IsNumber(aryArgs[1])) return false;
if (!this.GetOverlayIndexByIdentify) return false;
var indexGuid=srcParam,showType=aryArgs[1];
var finder=this.GetOverlayIndexByIdentify(indexGuid);
if (!finder || !finder.OverlayItem) return false;
var frame=finder.OverlayItem.Frame;
if (showType==1) frame.IsShareY=false;
else if (showType==2) frame.IsShareY==true;
else frame.IsShareY=!frame.IsShareY;
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
break;
case JSCHART_MENU_ID.CMD_CHANGE_DEFAULTCURSOR_ID:
if (!IFrameSplitOperator.IsString(srcParam)) return;
this.DefaultCursor=srcParam;
this.UIElement.style.cursor=this.DefaultCursor;
break;
case JSCHART_MENU_ID.CMD_ADD_OVERLAY_INDEX_ID: //叠加指标 0=windowIndex, 1=indexinfo
if (param==null || !aryArgs[1]) return false;
var obj=aryArgs[1];
obj.WindowIndex=param;
this.AddOverlayIndex(obj);
break;
case JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID:
if (srcParam) this.SetLanguage(srcParam);
break;
case JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID:
if (param!=null)
{
if (this.ChartDragSelectRect) this.ChartDragSelectRect.ShowMode=param;
}
break;
case JSCHART_MENU_ID.CMD_SHOW_CORSS_LINE_ID:
if (IFrameSplitOperator.IsBool(srcParam))
{
if (this.ChartCorssCursor) this.ChartCorssCursor.IsShowCorss=srcParam;
}
break;
case JSCHART_MENU_ID.CMD_ENABLE_POP_MINUTE_CHART_ID://双击弹分时图
if (IFrameSplitOperator.IsBool(srcParam))
{
if (srcParam)
{
this.DestroyPopMinuteChart();
this.InitalPopMinuteChart( {KLine:{KLineDoubleClick:true}} );
}
else
{
this.DestroyPopMinuteChart();
}
}
break;
case JSCHART_MENU_ID.CMD_CHANGE_INFO_POSITION_ID:
if (param==null) return false;
var klineChart=this.ChartPaint[0];
if (!klineChart) return false;
klineChart.InfoPosition=param;
this.Draw();
break;
case JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE:
if (!aryArgs[0]) return false;
var option=aryArgs[0];
if (!IFrameSplitOperator.IsBool(option.Enable)) return false;
if (option.Enable===false)
{
this.DestroyTooltipDialog();
}
else
{
this.DestroyTooltipDialog();
this.InitalTooltipDialog(option);
}
break;
case JSCHART_MENU_ID.CMD_KLINE_TOOLTIP_ATTRIBUTE:
if (!aryArgs[0]) return false;
var option=aryArgs[0];
if (IFrameSplitOperator.IsBool(option.Enable)) this.KLineTooltipConfig.Enable=option.Enable;
if (IFrameSplitOperator.IsBool(option.EnableKeyDown)) this.KLineTooltipConfig.EnableKeyDown=option.EnableKeyDown;
break;
}
}
this.GetShowIndexMenuData=function(windowIndex, showType)
{
var script=this.WindowIndex[windowIndex];
if (!script) return null;
var data= { Name:script.IsShow?"隐藏指标":"显示指标", Data:{ ID: JSCHART_MENU_ID.CMD_SHOW_INDEX_ID, Args:[windowIndex, 0] } };
return data;
}
this.GetShowOverlayIndexMenuData=function(indexGuid, showType)
{
var overlay=this.GetOverlayIndexByIdentify(indexGuid);
if (!overlay || !overlay.OverlayItem || !overlay.OverlayItem.Script) return null;
var script=overlay.OverlayItem.Script;
var data= { Name:script.IsShow?"隐藏指标":"显示指标", Data:{ ID: JSCHART_MENU_ID.CMD_SHOW_OVERLAY_INDEX_ID, Args:[indexGuid, 0] } };
return data;
}
this.GetShowOverlayIndexYAxisMenuData=function(indexGuid, showType)
{
var overlay=this.GetOverlayIndexByIdentify(indexGuid);
if (!overlay || !overlay.OverlayItem || !overlay.OverlayItem.Script) return null;
var frame=overlay.OverlayItem.Frame;
var data= { Name:frame.IsShow?"隐藏Y轴":"显示Y轴", Data:{ ID: JSCHART_MENU_ID.CMD_SHOW_OVERLAY_Y_AXIS_ID, Args:[indexGuid, 0] } };
return data;
}
this.GetOverlayIndexShareYMenuData=function(indexGuid, showType)
{
var overlay=this.GetOverlayIndexByIdentify(indexGuid);
if (!overlay || !overlay.OverlayItem || !overlay.OverlayItem.Script) return null;
var frame=overlay.OverlayItem.Frame;
var data= { Name:"公用窗口Y轴", Data:{ ID: JSCHART_MENU_ID.CMD_ENABLE_OVERLAY_SHARE_Y_ID, Args:[indexGuid, 0] } , Checked:frame.IsShareY };
return data;
}
//点击右键菜单
this.OnClickRightMenu=function(data)
{
JSConsole.Chart.Log('[JSChartContainer::OnClickRightMenu] ',data);
if (!data || !data.Data) return;
var cmdID=data.Data.ID; //命令ID
var aryArgs=data.Data.Args; //参数
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MENU_COMMAND); //回调通知外部
if (event && event.Callback)
{
var data={ PreventDefault:false, CommandID:cmdID, Args:aryArgs, SrcData:data };
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
this.ExecuteMenuCommand(cmdID, aryArgs);
}
this.PopupRightMenuV2=function(data,e)
{
if (!this.JSPopMenu) return;
var x=data.X, y=data.Y;
var frameID=data.FrameID;
var menuData={ Menu:this.GetRightMenuData(frameID), Position:JSPopMenu.POSITION_ID.RIGHT_MENU_ID };
menuData.ClickCallback=(data)=>{ this.OnClickRightMenu(data); }
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_RIGHT_MENU);
if (event && event.Callback)
{
var sendData={ MenuData:menuData, FrameID:frameID };
event.Callback(event, sendData, this);
}
this.PopupMenuByRClick(menuData, x, y);
}
//指标窗口扩展图形
this.CreateChartPaintExtend=function(chart, windowIndex)
{
if (windowIndex<0) return false;
var subFrame=this.Frame.SubFrame[windowIndex];
if (!subFrame || !subFrame.Frame) return false;
var frame=subFrame.Frame;
chart.Canvas=this.Canvas;
chart.ChartBorder=frame.ChartBorder;
chart.ChartFrame=frame;
this.ChartPaintEx.push(chart);
return true;
}
//删除指标窗口扩展图形 option={ ChartID:图形ID, WindowIndex:窗口 }
this.DeleteChartPaintExtend=function(option, bCallDestroy)
{
if (!option) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.ChartPaintEx)) return;
if (IFrameSplitOperator.IsNumber(option.WindowIndex))
{
var windowIndex=option.WindowIndex;
if (!this.Frame.SubFrame[windowIndex]) return;
var subFrame=this.Frame.SubFrame[windowIndex].Frame;
if (!subFrame) return;
var paint=[]; //踢出当前窗口的指标画法
var deleteCount=0;
for(var i=0;i<this.ChartPaintEx.length; ++i)
{
var item=this.ChartPaintEx[i];
var bFind=(item.ChartFrame.Guid==subFrame.Guid || item.ChartFrame==subFrame);
if (!bFind)
{
paint.push(item);
}
else
{
++deleteCount;
if (bCallDestroy===true)
{
if (item && item.OnDestroy) item.OnDestroy(); //图形销毁
}
}
}
if (deleteCount>0) this.ChartPaintEx=paint;
}
}
this.ClearCurrnetDrawPicture=function()
{
this.CurrentChartDrawPicture=null;
}
this.CreateDragSelectRect=function(option)
{
var chart=g_ExtendChartPaintFactory.Create("RectDragPaint",option);
if (!chart) return null;
if (option && option.Enable===true) chart.Enable=true;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ChartDragSelectRect=chart;
}
this.ClearDragSelectRect=function()
{
if (!this.ChartDragSelectRect) return;
this.ChartDragSelectRect.ClearPoint();
}
this.ShowDragSelectRect=function(ptStart, ptEnd)
{
if (!this.ChartDragSelectRect) return;
this.ChartDragSelectRect.SetFirstPoint(ptStart.X, ptStart.Y);
this.ChartDragSelectRect.SetSecondPoint(ptEnd.X, ptEnd.Y);
this.ChartDragSelectRect.Draw();
}
//切换窗口指标 option={ Window:{}, OverlayIndex:[], Frame:{ }}
this.ChangeIndexWindow=function(windowIndex, option)
{
JSConsole.Chart.Log('[KLineChartContainer::ChangeIndexWindow] windowIndex, option', windowIndex, option);
if (windowIndex<0 || windowIndex>=this.Frame.SubFrame.length) return false;
if (!option) return false;
var frame=this.Frame.SubFrame[windowIndex];
if (option.Delete)
{
var item=option.Delete;
if (item.Window===true) this.DeleteIndexPaint(windowIndex); //删除主指标
if (item.Overlay===true) this.DeleteWindowsOverlayIndex(windowIndex); //清空叠加指标
}
//清空标题栏
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
if (option.Window) //主指标
{
this.DeleteIndexPaint(windowIndex); //删除主指标
var item=option.Window;
if (item.Script) //自定义指标脚本
{
this.WindowIndex[windowIndex]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API) //后台指标
{
var apiItem=item.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var indexID=item.Index;
var indexItem=JSIndexMap.Get(indexID);
if (indexItem)
{
this.WindowIndex[windowIndex]=indexItem.Create();
this.CreateWindowIndex(windowIndex);
}
else
{
var systemScript = new JSIndexScript();
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo,item);
this.WindowIndex[windowIndex]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
}
}
}
this.SetSubFrameAttribute(frame, item, option.Frame);
}
//叠加指标
var aryOverlayIndex=[];
if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
{
this.DeleteWindowsOverlayIndex(windowIndex); //清空叠加指标
for(var i=0;i<option.OverlayIndex.length;++i)
{
var item=option.OverlayIndex[i];
if (item.Index) item.IndexName=item.Index;
item.WindowIndex=windowIndex;
if (item.Windows>=0) item.WindowIndex=item.Windows;
var overlay=this.CreateOverlayWindowsIndex(item);
if (!overlay) continue;
aryOverlayIndex.push({ WindowsIndex:item.WindowIndex, Overlay:overlay });
}
}
//刷新指标
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //请求主指标
for(var i=0;i<aryOverlayIndex.length;++i) //请求叠加指标
{
var item=aryOverlayIndex[i];
this.BindOverlayIndexData(item.Overlay,item.WindowsIndex,bindData);
}
this.UpdataDataoffset(); //更新数据偏移
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ClickHorizontalLabel=function(lable, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_HORIZONTAL_LABEL);
if (event && event.Callback)
{
var data={ Info:lable, PreventDefault:false }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
}
this.ResetOverlaySymbolStatus=function()
{
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
}
}
//十字光标状态变动
this.OnChangeCorssCursorStatus=function(data, obj)
{
if (data.Type==1)
{
if (!data.IsShowCorss) //十字光标隐藏
{
this.HideTooltip();
this.CloseTooltipDialog();
}
}
}
this.UpdateWindowIndexV2=function(aryIndex)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryIndex)) return false;
var aryID=[];
for(var i=0;i<this.WindowIndex.length;++i)
{
var item=this.WindowIndex[i];
if (!item) continue;
if (!item.ID) continue;
if (aryIndex.find((element)=>{ return element.ID==item.ID;} ))
{
aryID.push(i);
}
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryID)) return false;
if (this.IsKLineContainer()) //K线
{
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (this.IsApiPeriod)
{
}
else
{
if (bindData.Right>0) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
}
}
else if (this.IsMinuteContainer()) //分时图
{
var bindData=this.SourceData;
}
else
{
return;
}
for(var i=0;i<aryID.length;++i)
{
this.BindIndexData(aryID[i],bindData)
}
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
}
function GetDevicePixelRatio()
{
if (typeof(window) =='undefined') return 1;
return window.devicePixelRatio || 1;
}
function GetFontHeight(context, font, word)
{
if (!context) return null;
if (font) context.font=font;
var text='擎';
if (IFrameSplitOperator.IsString(word)) text=word;
var fontInfo=context.measureText(text);
var textHeight=fontInfo.fontBoundingBoxAscent + fontInfo.fontBoundingBoxDescent;
if (!IFrameSplitOperator.IsNumber(textHeight)) textHeight=fontInfo.width+2*GetDevicePixelRatio();
return textHeight;
}
function IsPhoneWeb()
{
var userAgentInfo=navigator.userAgent;
const Agents =new Array("Android","iPhone","SymbianOS","Windows Phone","iPad","iPod");
for(var v=0;v<Agents.length;v++)
{
if(userAgentInfo.indexOf(Agents[v])>0) return true;
}
return false;
}
function OnKeyDown(e) //键盘事件
{
if(this.JSChartContainer && this.JSChartContainer.OnKeyDown)
this.JSChartContainer.OnKeyDown(e);
}
function OnWheel(e) //上下滚动事件
{
if(this.JSChartContainer && this.JSChartContainer.OnWheel)
this.JSChartContainer.OnWheel(e);
}
function ToFixed(number, precision)
{
var b = 1;
if (isNaN(number)) return number;
if (number < 0) b = -1;
var multiplier = Math.pow(10, precision);
var value=Math.round(Math.abs(number) * multiplier) / multiplier * b;
if (/^(\d+(?:\.\d+)?)(e)([\-]?\d+)$/.test(value))
var s=value.toFixed2(precision);
else
var s = value.toString();
var rs = s.indexOf('.');
if (rs < 0 && precision>0)
{
rs = s.length;
s += '.';
}
while (s.length <= rs + precision)
{
s += '0';
}
return s;
}
Number.prototype.toFixed2=Number.prototype.toFixed; //备份下老的
Number.prototype.toFixed = function( precision )
{
return ToFixed(this,precision);
}
function Guid()
{
function S4()
{
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
return "guid" + (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
function GetScrollPosition()
{
var scrollPos={};
var scrollTop=0;
var scrollLeft=0;
if (document.documentElement && (document.documentElement.scrollTop || document.documentElement.scrollLeft))
{
scrollTop=document.documentElement.scrollTop;
scrollLeft=document.documentElement.scrollLeft;
}
else if(document.body)
{
scrollTop=document.body.scrollTop;
scrollLeft=document.body.scrollLeft;
}
scrollPos.Top=scrollTop;
scrollPos.Left=scrollLeft;
return scrollPos;
}
//修正线段有毛刺
function ToFixedPoint(value)
{
return parseInt(value)+0.5;
}
//修正粗线段毛刺
function ToFixedPoint2(width, value)
{
var fixValue=(width % 2)===0 ? Math.floor(value):Math.floor(value) + 0.5; //毛边修正
return fixValue;
}
function ToFixedRect(value)
{
// With a bitwise or.
//rounded = (0.5 + somenum) | 0;
// A double bitwise not.
//rounded = ~~ (0.5 + somenum);
// Finally, a left bitwise shift.
//value*=GetDevicePixelRatio();
var rounded;
return rounded = (0.5 + value) << 0;
}
function PtInRect(x,y, rect)
{
if (x>=rect.Left && x<=rect.Right && y>=rect.Top && y<=rect.Bottom) return true;
return false;
}
//深拷贝
function CloneData(data)
{
if (!data) return null;
var strData=JSON.stringify(data);
var item= JSON.parse(strData);
return item;
}
function IsRecvOverlap(rect1, rect2)
{
return Math.max(rect1.Left,rect2.Left) < Math.min(rect1.Right,rect2.Right) && Math.max(rect1.Top,rect2.Top) < Math.min(rect1.Bottom,rect2.Bottom);
}
function CopyMarginConfig(dest,src)
{
if (!src || !dest) return;
if (IFrameSplitOperator.IsNumber(src.Left)) dest.Left=src.Left;
if (IFrameSplitOperator.IsNumber(src.Top)) dest.Top=src.Top;
if (IFrameSplitOperator.IsNumber(src.Right)) dest.Right=src.Right;
if (IFrameSplitOperator.IsNumber(src.Bottom)) dest.Bottom=src.Bottom;
}
//兼容老版本
function CopyMerginConfig(dest,src) { CopyMarginConfig(dest,src); }
//数值比较
function NumberCompare() { }
//<
NumberCompare.LT=function(left, right)
{
if (IFrameSplitOperator.IsNumberV2(left, right))
{
//==
if (Math.abs(left - right)< 0.0000001) return false;
}
return left<right;
}
//>
NumberCompare.GT=function(left, right)
{
if (IFrameSplitOperator.IsNumberV2(left, right))
{
//==
if (Math.abs(left - right)< 0.0000001) return false;
}
return left>right;
}
function Point()
{
this.X;
this.Y;
}
function SelectRectData()
{
this.Data; //主数据
this.JSChartContainer; //行情控件
this.Start; //数据起始位子
this.End; //数据结束位置
this.XStart;//X坐标起始位置
this.YStart;
this.XEnd; //X位置结束为止
this.YEnd;
}
//坐标信息
function CoordinateInfo()
{
this.Value; //坐标数据
this.Message=[]; //坐标输出文字信息 0=左 1=右 2=内左 3=内右
this.TextColor=g_JSChartResource.FrameSplitTextColor //文字颜色
this.TextBGColor; //文字背景色
this.TextColor2; //右侧文字颜色,空使用TextColor
this.Font=g_JSChartResource.FrameSplitTextFont; //字体
this.LineColor=g_JSChartResource.FrameSplitPen; //线段颜色
this.LineDash=null; //当线段类型==2时 可以设置虚线样式
this.LineType=1; //线段类型 -1=不画线段 0=虚线 1,2=虚线, 3=短线 8,9=集合竞价坐标
this.LineWidth; //线段宽度
this.ExtendLine; //延长线长度[ ] { Width:长度 } [0]=左 [1]=右 实例: [null, { Width: 50}];
this.ExtendData; //扩展属性
//百分比 { PriceColor:, PercentageColor:, SplitColor:, Font: }
//自定义刻度 { Custom:{ Position: 1=强制内部 }}
//输出位置的Y轴偏移
//this.YOffset;
this.AreaData; //区域: { Start:, End:, BGColor:, Position:[0=左, 1=右] }
//不在当前屏范围 (可定义刻度使用)
//this.OutRange={ BGColor:"", TextColor:, BorderColor: TopYOffset:, BottomYOffset: }
//Y轴文字偏移
//this.YOffset=[{ Offset:5}, { Offset:10}] //目前只对框子外的刻度文字生效
}
//边框信息
function ChartBorder()
{
this.UIElement;
//四周间距
this.Left=50;
this.Right=80;
this.Top=50;
this.Bottom=50;
this.TitleHeight=24; //标题高度
this.TopSpace=0;
this.BottomSpace=0;
this.LeftExtendWidth=0; //左边扩展图形宽度
this.RightExtendWidth=0;
this.MultiDayMinute={ Count:1, Left:0, Right:0 } // { Count:天数, Left:, Right: }
this.IsShowTitleOnly=false; // 是否只显示标题
this.GetBorder=function()
{
var data=
{
Left:this.Left,
LeftEx:this.Left+this.LeftExtendWidth,
Right:this.UIElement.width-this.Right,
RightEx:this.UIElement.width-this.Right-this.RightExtendWidth,
Top:this.Top,
TopEx:this.Top+this.TitleHeight+this.TopSpace,
TopTitle:this.Top+this.TitleHeight,
Bottom:this.UIElement.height-this.Bottom,
BottomEx:this.UIElement.height-this.Bottom-this.BottomSpace,
ChartWidth:this.UIElement.width,
ChartHeight:this.UIElement.height
};
if (this.MultiDayMinute && this.MultiDayMinute.Count>1 && ( this.MultiDayMinute.Left>0 || this.MultiDayMinute.Right>0 ))
{
var frameWidth=this.UIElement.width-this.Left-this.Right; //坐标框子宽度
var dayWidth=frameWidth/this.MultiDayMinute.Count; // 每天的框子的宽度
var dayBorder=[];
for(var i=0;i<this.MultiDayMinute.Count;++i)
{
var item={ Left:this.Left+dayWidth*i, Right:this.Left+dayWidth*(i+1) };
item.LeftEx=item.Left+this.MultiDayMinute.Left;
item.RightEx=item.Right-this.MultiDayMinute.Right;
if (i>0) item.Left+=1; //第2天的盘前 移到一个像素,跟上一天分开
dayBorder.push(item);
}
data.DayBorder=dayBorder;
}
return data;
}
this.GetHScreenBorder=function()
{
var data=
{
Left:this.Left,
LeftEx:this.Left+this.BottomSpace,
Right:this.UIElement.width-this.Right,
RightEx:this.UIElement.width-this.Right-this.TitleHeight- this.TopSpace,
RightTitle:this.UIElement.width-this.Right-this.TitleHeight,
Top:this.Top,
TopEx:this.Top+this.LeftExtendWidth,
Bottom:this.UIElement.height-this.Bottom,
BottomEx:this.UIElement.height-this.Bottom-this.RightExtendWidth,
ChartWidth:this.UIElement.width,
ChartHeight:this.UIElement.height
};
if (this.MultiDayMinute && this.MultiDayMinute.Count>1 && ( this.MultiDayMinute.Left>0 || this.MultiDayMinute.Right>0 ))
{
var frameWidth=this.UIElement.height-this.Top-this.Bottom; //坐标框子宽度
var dayWidth=frameWidth/this.MultiDayMinute.Count; //每天的框子的宽度
var dayBorder=[];
for(var i=0;i<this.MultiDayMinute.Count;++i)
{
var item={ Top:this.Top+dayWidth*i, Bottom:this.Top+dayWidth*(i+1) };
item.TopEx=item.Top+this.MultiDayMinute.Left;
item.BottomEx=item.Bottom-this.MultiDayMinute.Right;
dayBorder.push(item);
}
data.DayBorder=dayBorder;
}
return data;
}
//1=在K线上 -1不在图上 [200-299]=集合竞价 [300-399]=集合竞价 2=左边集合竞价 3=右边集合竞价
this.PtInClient=function(x, y, canvas, isHScreen)
{
if (isHScreen)
{
var border=this.GetHScreenBorder();
canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
}
else
{
var border=this.GetBorder();
if (border.DayBorder) //多日分时+多日集合竞价
{
for(var i=0;i<border.DayBorder.length;++i)
{
var client=border.DayBorder[i];
canvas.beginPath();
canvas.rect(client.LeftEx,border.TopEx,client.RightEx-client.LeftEx,border.BottomEx-border.TopEx);
if (canvas.isPointInPath(x,y)) return 1;
//盘前
canvas.beginPath();
canvas.rect(client.Left,border.TopEx,client.LeftEx-client.Left,border.BottomEx-border.TopEx);
if (canvas.isPointInPath(x,y))
return 200+parseInt(i);
//盘后
canvas.beginPath();
canvas.rect(client.RightEx,border.TopEx,client.Right-client.RightEx,border.BottomEx-border.TopEx);
if (canvas.isPointInPath(x,y))
return 300+parseInt(i);
}
return -1;
}
canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
}
if (canvas.isPointInPath(x,y)) return 1;
if (this.LeftExtendWidth>10)
{
canvas.beginPath();
if (isHScreen===true)
{
canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
}
else
{
canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
}
if (canvas.isPointInPath(x,y)) return 2;
}
if (this.RightExtendWidth>10)
{
canvas.beginPath();
if (isHScreen===true)
{
canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
}
else
{
canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
}
if (canvas.isPointInPath(x,y)) return 3;
}
return -1;
}
this.GetChartWidth=function()
{
return this.UIElement.width;
}
this.GetChartHeight=function()
{
return this.UIElement.height;
}
this.GetLeft=function()
{
return this.Left+this.LeftExtendWidth;
}
this.GetRight=function()
{
return this.UIElement.width-this.Right-this.RightExtendWidth;
}
this.GetTop=function()
{
return this.Top;
}
this.GetTopEx=function() //去掉标题,上面间距
{
return this.Top+this.TitleHeight+this.TopSpace;
}
this.GetTopTitle=function() //去掉标题
{
return this.Top+this.TitleHeight;
}
this.GetBottom=function()
{
return this.UIElement.height-this.Bottom;
}
this.GetBottomEx=function()
{
return this.UIElement.height-this.Bottom-this.BottomSpace;
}
this.GetWidth=function()
{
return this.UIElement.width-this.Left-this.Right-this.LeftExtendWidth-this.RightExtendWidth;
}
this.GetHeight=function()
{
return this.UIElement.height-this.Top-this.Bottom;
}
this.GetHeightEx=function() //去掉标题的高度, 上下间距
{
return this.UIElement.height-this.Top-this.Bottom-this.TitleHeight-this.TopSpace-this.BottomSpace;
}
this.GetRightEx=function() //横屏去掉标题高度的 上面间距
{
return this.UIElement.width-this.Right-this.TitleHeight- this.TopSpace;
}
this.GetWidthEx=function() //横屏去掉标题宽度 上下间距
{
return this.UIElement.width-this.Left-this.Right-this.TitleHeight- this.TopSpace - this.BottomSpace;
}
this.GetLeftEx = function () //横屏
{
return this.Left+this.BottomSpace;
}
this.GetRightTitle = function ()//横屏
{
return this.UIElement.width - this.Right - this.TitleHeight;
}
this.GetTitleHeight=function()
{
return this.TitleHeight;
}
}
//框架外部挂接
function ChartFrameFactory()
{
//[key:name, { Create:function(option) { return new class(); }} ]
this.DataMap=new Map(
[
["KLineFrame", { Create:function(option) { return new KLineFrame(); } }], //K线图
["KLineHScreenFrame", { Create:function(option) { return new KLineHScreenFrame(); } }],
]);
this.Create=function(name, option)
{
if (!this.DataMap.has(name))
{
JSConsole.Warn(`[ChartFrameFactory::Create] can't find class=${name}.`);
return null;
}
var item=this.DataMap.get(name);
return item.Create(option);
}
this.Add=function(name, option)
{
var oldData=null;
if (this.DataMap.has(name)) oldData=this.DataMap.get(name);
this.DataMap.set(name, { Create:option.Create } );
return oldData;
}
}
var g_ChartFrameFactory=new ChartFrameFactory();
function IChartFramePainting()
{
this.HorizontalInfo=new Array(); //Y轴
this.VerticalInfo=new Array(); //X轴
this.ClassName='IChartFramePainting';
this.Canvas; //画布
this.Identify; //窗口标识
this.Guid=Guid(); //内部窗口唯一标识
this.ChartBorder;
this.PenBorder=g_JSChartResource.FrameBorderPen; //边框颜色
this.TitleBGColor=g_JSChartResource.FrameTitleBGColor; //标题背景色
this.IsShow=true; //是否显示
this.SizeChange=true; //大小是否改变
this.XYSplit=true; //XY轴坐标信息改变
this.XSplit=true; //X轴变化
this.YCustomSplit=true; //自定义Y轴分割线
this.HorizontalMax; //Y轴最大值
this.HorizontalMin; //Y轴最小值
this.HorizontalReserved=null; //Y轴预留高度 { Top:上, Bottom:下 }
this.XPointCount=10; //X轴数据个数
this.ClientBGColor; //客户区背景色
//Y轴原始的最大值 最小值
this.YMaxMin={ Max:null, Min:null };
this.YSplitOperator; //Y轴分割
this.XSplitOperator; //X轴分割
this.Data; //主数据
this.IsLocked=false; //是否上锁
this.LockPaint = null;
this.YSpecificMaxMin=null; //指定Y轴最大最小值
this.IsShowBorder = true; //是否显示边框
this.IsShowTitleArrow=g_JSChartResource.IndexTitle.EnableIndexArrow; //是否显示指标信息上涨下跌箭头
this.TitleArrowType=g_JSChartResource.IndexTitle.ArrowType; //指标信息上涨下跌箭头类型 0=独立颜色 1=跟指标名字颜色一致
this.IsShowIndexName=true; //是否显示指标名字
this.IsShowOverlayIndexName=true; //是否显示叠加指标名字
//this.OverlayIndexType= { Position:0, LineSpace:5 };
this.OverlayIndexType= { Position:1, LineSpace:3 };
this.IndexParamSpace=2; //指标参数数值显示间距
this.IndexTitleSpace=0; //指标标题和参数值之间的间距
this.IsShowIndexTitle=true; //显示整个指标标题信息
this.IsDrawTitleBottomLine=false;
this.BorderLine=null; //1=上 2=下 4=左 8=右
this.Buttons=[]; //按钮事件
this.LeftButtonWidth=0; //左侧按钮的宽度
this.IsMinSize=false; //窗口是否最小化
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
this.LogoBGColor=g_JSChartResource.FrameLogo.BGColor;
this.GlobalOption;
//this.IsDrawLeftBorder;
this.IsDrawRightBorder=false; //是否绘制右侧刻度空白的边框
this.IsDrawLeftBorder=false; //是否绘制右侧刻度空白的边框
this.HorizontalLabel; //Y轴刻度标签页 (支持点击的才会有)[ { ID:, Args:[], }]
this.PtInButtons=function(x,y) //坐标是否在按钮上
{
for(var i=0;i<this.Buttons.length;++i)
{
var item=this.Buttons[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { ID:item.ID, Rect:rect };
}
}
return null;
}
//Y轴标签文字
this.PtInHorizontalLabel=function(x,y)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.HorizontalLabel)) return null;
for(var i=0;i<this.HorizontalLabel.length;++i)
{
var item=this.HorizontalLabel[i];
var rect=item.Rect;
if (PtInRect(x,y, rect))
{
return { ID:item.ID, Rect:rect, Item:item.Item, LineID:item.LineID };
}
}
return;
}
this.GetBorder=function()
{
if (this.IsHScreen) return this.ChartBorder.GetHScreenBorder();
else return this.ChartBorder.GetBorder();
}
this.Draw=function()
{
this.Buttons=[];
this.HorizontalLabel=[];
this.DrawClientBG();
this.DrawFrame();
this.DrawBorder();
this.SizeChange=false;
this.XYSplit=false;
this.XSplit=false;
this.YCustomSplit=false; //自定义Y轴分割线
}
this.DrawFrame=function() { }
this.DrawClientBG=function()
{
if (!this.ClientBGColor) return;
var border=this.IsHScreen==true?this.ChartBorder.GetHScreenBorder():this.ChartBorder.GetBorder();
var left=ToFixedPoint(border.Left);
var top=ToFixedPoint(border.Top);
//var top=ToFixedPoint(border.TopEx);
var right=ToFixedPoint(border.Right);
var bottom=ToFixedPoint(border.Bottom);
var width=right-left;
var height=bottom-top;
this.Canvas.fillStyle=this.ClientBGColor;
this.Canvas.fillRect(left,top,width,height);
}
this.ClearCoordinateText=function(option)
{
if (IFrameSplitOperator.IsNonEmptyArray(this.HorizontalInfo))
{
for(var i=0;i<this.HorizontalInfo.length;++i)
{
var item=this.HorizontalInfo[i];
if (item && item.Message && Array.isArray(item.Message)) item.Message[0]=item.Message[1]=null;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(this.VerticalInfo))
{
for(var i=0;i<this.VerticalInfo.length;++i)
{
var item=this.VerticalInfo[i];
if (item && item.Message && Array.isArray(item.Message)) item.Message[0]=item.Message[1]=null;
}
}
}
//画边框
this.DrawBorder=function()
{
if (!this.IsShowBorder) return;
if (this.IsMinSize) return;
var border=this.IsHScreen==true?this.ChartBorder.GetHScreenBorder():this.ChartBorder.GetBorder();
var left=ToFixedPoint(border.Left);
var top=ToFixedPoint(border.Top);
//var top=ToFixedPoint(border.TopEx);
var right=ToFixedPoint(border.Right);
var bottom=ToFixedPoint(border.Bottom);
var width=right-left;
var height=bottom-top;
//JSConsole.Chart.Log(`[IChartFramePainting.DrawBorder] left=${left} `);
if (this.BorderLine==null)
{
if (this.IsDrawRightBorder || this.IsDrawLeftBorder)
{
this.Canvas.strokeStyle=this.PenBorder;
if (this.IsDrawRightBorder && this.IsDrawLeftBorder)
{
var xRight=ToFixedPoint(border.ChartWidth);
var xLeft=ToFixedPoint(0);
this.Canvas.strokeRect(xLeft,top,xRight-xLeft-1,height); //少一个像素让边框显示出来
}
else if (this.IsDrawRightBorder)
{
var xRight=ToFixedPoint(border.ChartWidth);
this.Canvas.strokeRect(left,top,xRight-left-1,height); //少一个像素让边框显示出来
}
else if (this.IsDrawLeftBorder)
{
var xLeft=ToFixedPoint(0);
this.Canvas.strokeRect(xLeft,top,right-xLeft,height); //少一个像素让边框显示出来
}
if (this.IsDrawRightBorder)
{
this.Canvas.beginPath();
this.Canvas.moveTo(right,top);
this.Canvas.lineTo(right,bottom);
this.Canvas.stroke();
}
if (this.IsDrawLeftBorder)
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,top);
this.Canvas.lineTo(left,bottom);
this.Canvas.stroke();
}
}
else
{
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.strokeRect(left,top,width,height);
}
}
else if (IFrameSplitOperator.IsPlusNumber(this.BorderLine)) //单独绘制每个边框
{
this.Canvas.strokeStyle=this.PenBorder;
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();
}
/*
if (this.IsDrawRightBorder)
{
var xRight=ToFixedPoint(border.ChartWidth);
var xLeft=right;
this.Canvas.beginPath();
this.Canvas.moveTo(xLeft,top);
this.Canvas.lineTo(xRight,top);
this.Canvas.lineTo(xRight,bottom);
this.Canvas.lineTo(xLeft,bottom);
this.Canvas.stroke();
}
*/
}
//画标题背景色
this.DrawTitleBG=function()
{
if (this.ChartBorder.TitleHeight<=0) return;
var border=this.GetBorder();
var left=ToFixedPoint(border.Left);
var top=ToFixedPoint(border.Top);
var right=ToFixedPoint(border.Right);
var bottom=ToFixedPoint(this.ChartBorder.GetTopTitle());
var width=right-left;
var height=bottom-top;
this.Canvas.fillStyle=this.TitleBGColor;
this.Canvas.fillRect(left,top,width,height);
if (this.IsDrawTitleBottomLine)
{
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(border.TopTitle));
this.Canvas.lineTo(right,ToFixedPoint(border.TopTitle));
this.Canvas.stroke();
}
}
this.DrawLock=function()
{
if (this.IsLocked)
{
if (this.LockPaint == null)
this.LockPaint = new ChartLock();
this.LockPaint.Canvas=this.Canvas;
this.LockPaint.ChartBorder=this.ChartBorder;
this.LockPaint.ChartFrame=this;
this.LockPaint.Draw(true);
}
}
this.DrawLogo=function()
{
var border=this.GetBorder();
var text=g_JSChartResource.FrameLogo.Text;
if (!IFrameSplitOperator.IsString(text)) return;
this.Canvas.font=this.LogoTextFont;
this.Canvas.textAlign = 'left';
this.Canvas.textBaseline = 'bottom';
var height=this.Canvas.measureText("擎").width;
var width=this.Canvas.measureText(text).width;
if (this.IsHScreen)
{
var x=border.Left+5;
var y=border.Top+5;
this.Canvas.save();
this.Canvas.translate(x,y);
this.Canvas.rotate(90 * Math.PI / 180);
var rtBG={ Left:0, Bottom:0, Width:width+4, Height:height+4 };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
if (this.LogoBGColor)
{
this.Canvas.fillStyle=this.LogoBGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
this.Canvas.fillStyle=this.LogoTextColor;
this.Canvas.fillText(text,1,0);
this.Canvas.restore();
}
else
{
var rtBG={ Left:border.Left+5, Bottom:border.Bottom-5, Width:width+4, Height:height+4 };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
if (this.LogoBGColor)
{
this.Canvas.fillStyle=this.LogoBGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
var x=rtBG.Left+1;
var y=rtBG.Bottom-1;
this.Canvas.fillStyle=this.LogoTextColor;
this.Canvas.fillText(text,x,y);
}
}
this.CalculateLock=function()
{
if (this.IsLocked)
{
if (this.LockPaint == null)
this.LockPaint = new ChartLock();
this.LockPaint.Canvas=this.Canvas;
this.LockPaint.ChartBorder=this.ChartBorder;
this.LockPaint.ChartFrame=this;
this.LockPaint.Draw(false);
}
}
//设施上锁
this.SetLock=function(lockData)
{
if (!lockData) //空数据不上锁
{
this.IsLocked=false;
return;
}
this.IsLocked=true;
if (!this.LockPaint) this.LockPaint=new ChartLock(); //创建锁
if (lockData.Callback) this.LockPaint.Callback=lockData.Callback; //回调
if (lockData.IndexName) this.LockPaint.IndexName=lockData.IndexName; //指标名字
if (lockData.ID) this.LockPaint.LockID=lockData.ID; //锁ID
if (lockData.BG) this.LockPaint.BGColor=lockData.BG; //背景色
if (lockData.Text) this.LockPaint.Title= lockData.Text;
if (lockData.TextColor) this.LockPaint.TextColor=lockData.TextColor;
if (lockData.Font) this.LockPaint.Font=lockData.Font;
if (lockData.Count) this.LockPaint.LockCount=lockData.Count;
if (lockData.MinWidth>0) this.LockPaint.MinWidth=lockData.MinWidth;
}
this.GetLockRect=function()
{
if (!this.IsLocked) return null;
if (!this.LockPaint) return null;
return this.LockPaint.LockRect;
}
this.ReloadResource=function(resource)
{
if (!resource)
{
this.PenBorder=g_JSChartResource.FrameBorderPen; //边框颜色
this.TitleBGColor=g_JSChartResource.FrameTitleBGColor; //标题背景色
}
for(var i in this.HorizontalInfo)
{
var item=this.HorizontalInfo[i];
if (item.Font) item.Font=g_JSChartResource.FrameSplitTextFont; //字体
if (item.TextColor) item.TextColor=g_JSChartResource.FrameSplitTextColor //文字颜色
if (item.LineColor) item.LineColor=g_JSChartResource.FrameSplitPen; //线段颜色
}
for(var i in this.VerticalInfo)
{
var item=this.VerticalInfo[i];
if (item.Font) item.Font=g_JSChartResource.FrameSplitTextFont; //字体
if (item.TextColor) item.TextColor=g_JSChartResource.FrameSplitTextColor //文字颜色
if (item.LineColor) item.LineColor=g_JSChartResource.FrameSplitPen; //线段颜色
}
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
//左右刻度文字宽度
this.GetScaleTextWidth=function()
{
}
//bIncludeOverlay =false不包含叠加框架 true=主框架+叠加框架 默认true
this.IsMinuteFrame=function(bIncludeOverlay)
{
var aryName=["MinuteFrame", "MinuteHScreenFrame", "OverlayMinuteFrame", "OverlayMinuteHScreenFrame"];
if (bIncludeOverlay===false) aryName=["MinuteFrame", "MinuteHScreenFrame"];
var isMinute=aryName.includes(this.ClassName);
return isMinute;
}
//bIncludeOverlay =false不包含叠加框架 true=主框架+叠加框架 默认true
this.IsKLineFrame=function(bIncludeOverlay)
{
var aryName=["KLineFrame", "KLineHScreenFrame", "KLineHScreenFrame", "OverlayKLineHScreenFrame"];
if (bIncludeOverlay===false) aryName=["KLineFrame", "KLineHScreenFrame"];
var isKline=aryName.includes(this.ClassName);
return isKline;
}
}
//空框架只画边框
function NoneFrame()
{
this.newMethod=IChartFramePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="NoneFrame";
this.Snapshot=function()
{
}
this.SetSizeChage=function(sizeChange)
{
this.SizeChange=sizeChange;
//画布的位置
this.Position={
X:this.ChartBorder.UIElement.offsetLeft,
Y:this.ChartBorder.UIElement.offsetTop,
W:this.ChartBorder.UIElement.clientWidth,
H:this.ChartBorder.UIElement.clientHeight
};
}
}
function AverageWidthFrame()
{
this.newMethod=IChartFramePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="AverageWidthFrame";
this.DataWidth=50*GetDevicePixelRatio();
this.DistanceWidth=10*GetDevicePixelRatio();
this.MinXDistance = 30*GetDevicePixelRatio(); //X轴刻度最小间距
this.MinYDistance=12*GetDevicePixelRatio(); //Y轴刻度最小间距
this.CoordinateType=0; //坐标类型 0=普通坐标 1=反转坐标
this.IsShowYText=[true,true]; //是否显示Y轴坐标坐标 [0=左侧] [1=右侧]
this.XBottomOffset=g_JSChartResource.Frame.XBottomOffset; //X轴文字显示向下偏移
this.YTextTopOffset=g_JSChartResource.Frame.YTopOffset; //Y轴顶部文字向下偏移
this.YTextPosition=[0,0], //是坐标否强制画在内部 [0=左侧] [1=右侧] 1=OUT" , 2=INSIDE
this.YTextPadding=[g_JSChartResource.Frame.YTextPadding[0], g_JSChartResource.Frame.YTextPadding[1]], //Y轴文字和边框间距 [0=左侧] [1=右侧]
this.IsShowXLine=true; //是否显示X轴刻度线
this.IsShowYLine=true;
this.YInsideOffset=0;
this.YTextBaseline=0; //0=居中 1=上部 (目前就支持内部刻度)
this.MultiTextFormat=0; //多行刻度信息显示模式 0=显示第1行 1=价格/百分比 2=显示2行
this.RightTextMaxWidth=0;
this.ShortYLineLength=5;
this.ShortXLineLength=5;
this.BeforeDrawXYCallback; //坐标绘制前回调,绘制深度图
this.GetEventCallback; //事件回调
//工具栏的按钮样式
this.ToolbarButtonStyle=g_JSChartResource.ToolbarButtonStyle;
this.CloseWindowButton=CloneData(g_JSChartResource.Buttons.CloseWindow);
this.OverlayIndexButton=CloneData(g_JSChartResource.Buttons.OverlayIndex);
this.ChangeIndexButton=CloneData(g_JSChartResource.Buttons.ChangeIndex);
this.ModifyIndexParamButton=CloneData(g_JSChartResource.Buttons.ModifyIndexParam);
this.MaxMinWindowButton=CloneData(g_JSChartResource.Buttons.MaxMinWindow);
this.TitleWindowButton=CloneData(g_JSChartResource.Buttons.TitleWindow);
this.ExportDataButton=CloneData(g_JSChartResource.Buttons.ExportData);
this.ButtonTooltip=CloneData(g_JSChartResource.Buttons.Tooltip);
//Y轴刻度长线
this.YLineExtend; //[0]=左 [1]=右 { Width:5, Color:颜色, }
this.YTextExtend; //[0]=左 [1]=右 { Align:0=默认 1=左对齐 2=右对齐 }
this.YRightTextInfo;
//X轴延长线
this.XTextExtend; //[0]=底部 { Align:0=默认(居中), 1=左对齐 }
this.XLineExtend; //[0]=底部 { Mode:1, Color: } Mode=1 分割线 Mode=2短线
this.FrameData={ SubFrameItem:null }; //窗口框架信息
//画图工具刻度
this.DrawPicture={
BGColor:g_JSChartResource.DrawPicture.XYCoordinate.BGColor,
TextBGColor:g_JSChartResource.DrawPicture.XYCoordinate.TextBGColor,
TextColor:g_JSChartResource.DrawPicture.XYCoordinate.TextColor, Font:g_JSChartResource.DrawPicture.XYCoordinate.Font };
this.IChartFramePainting_ReloadResource=this.ReloadResource;
this.ReloadResource=function(resource)
{
this.IChartFramePainting_ReloadResource(resource);
if (!resource)
{
this.ToolbarButtonStyle=g_JSChartResource.ToolbarButtonStyle;
this.CloseWindowButton=CloneData(g_JSChartResource.Buttons.CloseWindow);
this.OverlayIndexButton=CloneData(g_JSChartResource.Buttons.OverlayIndex);
this.ChangeIndexButton=CloneData(g_JSChartResource.Buttons.ChangeIndex);
this.ModifyIndexParamButton=CloneData(g_JSChartResource.Buttons.ModifyIndexParam);
this.MaxMinWindowButton=CloneData(g_JSChartResource.Buttons.MaxMinWindow);
this.TitleWindowButton=CloneData(g_JSChartResource.Buttons.TitleWindow);
this.ButtonTooltip=CloneData(g_JSChartResource.Buttons.Tooltip);
}
}
this.DrawFrame=function()
{
if (this.XPointCount>0)
{
let dInterval=this.ChartBorder.GetWidth()/(6*this.XPointCount); //分6份, 数据4 间距2
this.DistanceWidth=2*dInterval;
this.DataWidth=4*dInterval;
}
this.DrawHorizontal();
this.DrawVertical();
}
this.DrawTitleButton=function(aryButton, moveonPoint, mouseStatus)
{
var border=this.GetBorder();
if (this.IsHScreen)
{
var y=border.Bottom-3;
var x=border.RightTitle+this.ChartBorder.TitleHeight/2;
this.Canvas.save();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
//底部开始画
var yButton=0, xButton=0, bottom=0;
for(var i=0;i<aryButton.length;++i)
{
var item=aryButton[i];
var size=item.Style.Size;
var xButton=bottom-size-item.Style.MerginLeft;
var font=`${size}px ${item.Style.Family}`;
var color=item.Style.Color;
this.Canvas.fillStyle=color;
this.Canvas.font=font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Style.Text, xButton, 0);
var rtButton={ Left:x-size/2, Right:x+size/2, Bottom:y, Width:size, Height:size+item.Style.MerginLeft };
rtButton.Top=rtButton.Bottom-size-item.Style.MerginLeft;
this.Buttons.push({ ID:item.ID, Rect:rtButton });
bottom=xButton;
y=rtButton.Top;
}
this.Canvas.restore();
}
else
{
var right=border.Right-3;
var left=border.Left;
var yButton=border.Top+this.ChartBorder.TitleHeight/2;
//右往左绘制
for(var i=0;i<aryButton.length;++i)
{
var item=aryButton[i];
var size=item.Style.Size;
var xBotton=right-size-item.Style.MerginLeft;
var font=`${size}px ${item.Style.Family}`;
var rtButton={ Left:xBotton, Top:yButton-size/2, Right:xBotton+size+item.Style.MerginLeft, Bottom:yButton+size/2, Width:size+item.Style.MerginLeft, Height:size };
var color=item.Style.Color;
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
color=item.Style.MoveOnColor;
if (mouseStatus)
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:item, Frame:this, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
this.Canvas.fillStyle=color;
this.Canvas.font=font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Style.Text, xBotton, yButton);
this.Buttons.push({ ID:item.ID, Rect:rtButton });
right=xBotton;
}
}
}
this.DrawToolbarTooltip=function(mouseOnToolbar)
{
if (!mouseOnToolbar) return;
var border=this.GetBorder();
var text=null;
if (mouseOnToolbar.Item.TooltipText)
{
text=mouseOnToolbar.Item.TooltipText;
}
else
{
var key='Toolbar-'+mouseOnToolbar.Item.ID;
text=g_JSChartLocalization.GetText(key,0);
}
if (!text) return;
var pixelRatio=GetDevicePixelRatio();
var canvas=this.Canvas;
if (this.GetExtraCanvas)
{
var finder=this.GetExtraCanvas(JSChart.TooltipCursorCanvasKey);
if (finder) canvas=finder.Canvas;
}
var xCenter=mouseOnToolbar.Rect.Left+mouseOnToolbar.Rect.Width/2;
canvas.font=this.ButtonTooltip.Font;
canvas.textAlign="left";
canvas.textBaseline="bottom";
var mergin= this.ButtonTooltip.Mergin;
var textWidth=canvas.measureText(text).width+mergin.Left+mergin.Right;
var textHeight=this.GetFontHeight();
var bgHeight=textHeight+mergin.Top+mergin.Bottom;
if (mouseOnToolbar.ID=="TitleButton")
{
var x=mouseOnToolbar.Point.X;
var y=mouseOnToolbar.Point.Y+20;
}
else if (JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID==mouseOnToolbar.Item.ID)
{
var x=mouseOnToolbar.Rect.Right+5;
var y=mouseOnToolbar.Rect.Top;
}
else if (JSCHART_BUTTON_ID.DRAW_PICTURE_DELETE==mouseOnToolbar.Item.ID || JSCHART_BUTTON_ID.DRAW_PICTURE_SETTING==mouseOnToolbar.Item.ID ||
(mouseOnToolbar.Item.ID>=JSCHART_BUTTON_ID.DRAW_PICTURE_BUTTON_1 && mouseOnToolbar.Item.ID<=JSCHART_BUTTON_ID.DRAW_PICTURE_BUTTON_18 ))
{
var x=mouseOnToolbar.Point.X;
var y=mouseOnToolbar.Point.Y+20;
if ((x+textWidth)>=border.ChartWidth) x=border.ChartWidth-textWidth-2;
}
else
{
var x=xCenter-textWidth/2;
var y=border.Top-bgHeight;
if (y<0) y=border.TopEx+1;
if (x+textWidth>border.ChartWidth) x=border.ChartWidth-textWidth-2;
}
if (IFrameSplitOperator.IsNumber(this.ButtonTooltip.BorderRadius)) //圆角
{
var roundRadius=this.ButtonTooltip.BorderRadius;
canvas.beginPath();
canvas.roundRect(ToFixedPoint(x), ToFixedPoint(y), ToFixedRect(textWidth), ToFixedRect(bgHeight), [roundRadius]);
canvas.closePath();
canvas.fillStyle=this.ButtonTooltip.ColorBG;
canvas.fill();
canvas.strokeStyle=this.ButtonTooltip.ColorBorder;
canvas.stroke();
canvas.fillStyle=this.ButtonTooltip.Color;
canvas.fillText(text, x+mergin.Left, y+bgHeight-mergin.Bottom);
}
else
{
canvas.fillStyle=this.ButtonTooltip.ColorBG;
canvas.fillRect(x,y,textWidth,bgHeight); //画一个背景色, 不然是一个黑的背景
canvas.fillStyle=this.ButtonTooltip.Color;
canvas.fillText(text, x+mergin.Left,y+bgHeight-mergin.Bottom);
}
}
//isLimit 是否限制在当前坐标下
this.GetYFromData=function(value, isLimit)
{
if (this.Logarithmic && this.GetYLogarithmicFromData)
{
return this.GetYLogarithmicFromData(value, isLimit);
}
if (isLimit===false)
{
if (this.CoordinateType==1)
{
var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return this.ChartBorder.GetTopEx()+height;
}
else
{
var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return this.ChartBorder.GetBottomEx()-height;
}
}
else
{
if (this.CoordinateType==1)
{
if(value<=this.HorizontalMin) return this.ChartBorder.GetTopEx();
if(value>=this.HorizontalMax) return this.ChartBorder.GetBottomEx();
var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return this.ChartBorder.GetTopEx()+height;
}
else
{
if(value<=this.HorizontalMin) return this.ChartBorder.GetBottomEx();
if(value>=this.HorizontalMax) return this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return this.ChartBorder.GetBottomEx()-height;
}
}
}
//画Y轴
this.DrawHorizontal=function()
{
this.RightTextMaxWidth=0;
if (!IFrameSplitOperator.IsNonEmptyArray(this.HorizontalInfo)) return;
if (this.ChartBorder.IsShowTitleOnly) return;
var border=this.ChartBorder.GetBorder();
var left=border.Left;
var right=border.Right
var bottom = border.Bottom
var top = this.ChartBorder.GetTop();
var borderRight=this.ChartBorder.Right;
var borderLeft=this.ChartBorder.Left;
var isDrawLeft=borderLeft>10 && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
var rightExtendLine=null; //右侧延长线
var leftExtendLine=null; //左侧延长线
if (IFrameSplitOperator.IsNonEmptyArray(this.YLineExtend))
{
rightExtendLine=this.YLineExtend[1];
leftExtendLine=this.YLineExtend[0];
}
var rightExtendText=null; //右侧文字设置
var leftExtendText=null; //左侧文字设置
if (IFrameSplitOperator.IsNonEmptyArray(this.YTextExtend))
{
leftExtendText=this.YTextExtend[0];
rightExtendText=this.YTextExtend[1];
}
var yPrev=null; //上一个坐标y的值
var pixelRatio=GetDevicePixelRatio();
var itemHeight=(border.BottomEx-border.TopEx)/this.HorizontalInfo.length;
var aryMultiText=[];
var rtPreRight, rtRight, rtLeft, rtPreLeft;
var textBaseline=0; //0=上 1=中 2=下
for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从上往下画分割线
{
var item=this.HorizontalInfo[i];
if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
if (NumberCompare.GT(item.Value,this.HorizontalMax) || NumberCompare.LT(item.Value,this.HorizontalMin))
continue;
var y=this.GetYFromData(item.Value);
if (y!=null && yPrev!=null && Math.abs(y-yPrev)<this.MinYDistance) continue; //两个坐标在近了 就不画了
var yFixed=ToFixedPoint(y);
//绘制刻度线
if (y!=bottom && this.IsShowYLine)
{
var bChangeLineWidth=false;
if (IFrameSplitOperator.IsPlusNumber(item.LineWidth)) //刻度线宽度
{
this.Canvas.lineWidth=item.LineWidth*pixelRatio;
bChangeLineWidth=true;
}
this.Canvas.strokeStyle=item.LineColor;
if (item.LineType==2)
{
this.Canvas.save();
if (item.LineDash) this.Canvas.setLineDash(item.LineDash);
else this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,yFixed);
this.Canvas.lineTo(right,yFixed);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
this.Canvas.restore();
}
else if (item.LineType==3) //只在刻度边上画一个短横线
{
}
else if (item.LineType==8 || item.LineType==9) //集合竞价不画线
{
}
else if (item.LineType>0)
{
if (g_JSChartResource.FrameYLineDash)
{
this.Canvas.save();
this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,yFixed);
this.Canvas.lineTo(right,yFixed);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
this.Canvas.restore();
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,yFixed);
this.Canvas.lineTo(right,yFixed);
this.Canvas.stroke();
}
}
if (bChangeLineWidth)
{
this.Canvas.lineWidth=pixelRatio;
}
}
var yText=y;
if (y >= bottom - 2)
{
this.Canvas.textBaseline = 'bottom';
textBaseline=2;
}
else if (y <= top + 2)
{
this.Canvas.textBaseline = 'top';
yText+=this.YTextTopOffset;
textBaseline=0;
}
else
{
this.Canvas.textBaseline = "middle";
textBaseline=1;
}
//左边 坐标信息 间距小于10 不画坐标
this.Canvas.strokeStyle=item.TextColor;
this.Canvas.fillStyle=item.TextColor;
if (item.Message[0]!=null && isDrawLeft)
{
var yOffset=0;
if (IFrameSplitOperator.IsNonEmptyArray(item.YOffset)) //文字Y轴偏移
{
var offsetItem=item.YOffset[0];
if (offsetItem && IFrameSplitOperator.IsNumber(offsetItem.Offset))
yOffset=offsetItem.Offset;
}
if (Array.isArray(item.Message[0]))
{
if (this.MultiTextFormat==3)
{
var obj={ Data:item.Message[0], X:left, Y:yText, TextBaseLine:textBaseline, IsLeft:true, Item:item, TextPadding:this.YTextPadding[0] };
this.DrawMultiLineText(obj);
}
}
else
{
if (item.Font!=null) this.Canvas.font=item.Font;
var xText=left;
if (leftExtendLine && leftExtendLine.Width>1)
{
var lineLength=leftExtendLine.Width;
if (leftExtendLine.Color) this.Canvas.strokeStyle=leftExtendLine.Color;
else this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(xText,yFixed);
this.Canvas.lineTo(xText-lineLength,yFixed);
this.Canvas.stroke();
xText-=lineLength;
}
rtLeft=this.GetTextTopBottom(textBaseline,yText);
if (!rtPreLeft || (rtLeft && !this.IsTextTopBottomOverlap(rtLeft, rtPreLeft)))
{
if (leftExtendText && leftExtendText.Align===1)
{
this.Canvas.textAlign="left";
this.Canvas.fillText(item.Message[0],this.YTextPadding[0],yText+yOffset);
}
else
{
this.Canvas.textAlign="right";
this.Canvas.fillText(item.Message[0],xText-this.YTextPadding[0],yText+yOffset);
rtPreLeft=rtLeft;
}
}
}
}
//右边 坐标信息 间距小于10 不画坐标
if (item.Message[1]!=null && isDrawRight)
{
var yOffset=0;
if (IFrameSplitOperator.IsNonEmptyArray(item.YOffset)) //文字Y轴偏移
{
var offsetItem=item.YOffset[1];
if (offsetItem && IFrameSplitOperator.IsNumber(offsetItem.Offset))
yOffset=offsetItem.Offset;
}
if (item.Font!=null) this.Canvas.font=item.Font;
var xText=right;
if (item.LineType==3)
{
var lineLength=this.ShortYLineLength*GetDevicePixelRatio();
this.Canvas.beginPath();
this.Canvas.moveTo(xText,yFixed);
this.Canvas.lineTo(xText+lineLength,yFixed);
this.Canvas.stroke();
xText+=lineLength;
}
//右侧延长线
if (rightExtendLine && rightExtendLine.Width>1)
{
var lineLength=rightExtendLine.Width;
if (rightExtendLine.Color) this.Canvas.strokeStyle=rightExtendLine.Color;
else this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(xText,yFixed);
this.Canvas.lineTo(xText+lineLength,yFixed);
this.Canvas.stroke();
xText+=lineLength+2;
}
this.Canvas.textAlign="left";
if (Array.isArray(item.Message[1]))
{
if (this.MultiTextFormat==1) //显示1行 格式:价格/百分比
{
if (item.ExtendData)
{
if (item.ExtendData.Font) this.Canvas.font=item.ExtendData.Font;
}
var textData=
{
Text:
[
{Text:item.Message[1][0], Width:this.Canvas.measureText(item.Message[1][0]).width },
{Text:item.Message[1][1], Width:this.Canvas.measureText(item.Message[1][1]).width }
],
X:xText+2,
Y:yText,
TextBaseline:this.Canvas.textBaseline,
Item:item
}
aryMultiText.push(textData);
}
else if (this.MultiTextFormat==2) //显示2行
{
this.Canvas.fillText(item.Message[1][0],xText+this.YTextPadding[1],yText);
var lineHeight=this.Canvas.measureText('M').width;
if (itemHeight>lineHeight*2) this.Canvas.fillText(item.Message[1][1],xText+this.YTextPadding[1],yText+lineHeight);
}
else if (this.MultiTextFormat==3)
{
var obj={ Data:item.Message[1], X:xText, Y:yText, TextBaseLine:textBaseline, IsLeft:false, Item:item, TextPadding:this.YTextPadding[1] };
this.DrawMultiLineText(obj);
}
else //显示第1行
{
var text=item.Message[1][0];
if (item.TextColor2) this.Canvas.fillStyle=item.TextColor2;
if (rightExtendText && rightExtendText.Align===2 && this.YRightTextInfo) //右对齐
{
this.Canvas.textAlign="right";
var xRight=this.YRightTextInfo.MainTextWidth+right-this.YTextPadding[1];
this.Canvas.fillText(text,xRight,yText);
}
else
{
this.Canvas.fillText(text,xText+this.YTextPadding[1],yText);
}
}
}
else
{
//计算显示的区域
rtRight=this.GetTextTopBottom(textBaseline,yText);
if (!rtPreRight || (rtRight && !this.IsTextTopBottomOverlap(rtRight,rtPreRight)))
{
if (item.TextColor2) this.Canvas.fillStyle=item.TextColor2;
if (rightExtendText && rightExtendText.Align===2 && this.YRightTextInfo) //右对齐
{
this.Canvas.textAlign="right";
var xRight=this.YRightTextInfo.MainTextWidth+right-this.YTextPadding[1];
this.Canvas.fillText(item.Message[1],xRight,yText+yOffset);
}
else
{
this.Canvas.fillText(item.Message[1],xText+this.YTextPadding[1],yText+yOffset);
}
rtPreRight=rtRight;
}
}
}
yPrev=y;
}
if (IFrameSplitOperator.IsNonEmptyArray(aryMultiText) && this.MultiTextFormat==1) this.DrawHorizontalMuText(aryMultiText);
if (isDrawRight && this.IsDrawRightBorder && this.YRightTextInfo)
{
var xRight=this.YRightTextInfo.MainTextWidth+right;
xLine=ToFixedPoint(xRight);
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(xLine,top);
this.Canvas.lineTo(xLine,bottom);
this.Canvas.stroke();
if (IFrameSplitOperator.IsNonEmptyArray(this.YRightTextInfo.AryOverlayWidth))
{
this.Canvas.beginPath();
for(var i=0;i<this.YRightTextInfo.AryOverlayWidth.length;++i)
{
var width=this.YRightTextInfo.AryOverlayWidth[i];
xRight+=width;
xLine=ToFixedPoint(xRight);
this.Canvas.moveTo(xLine,top);
this.Canvas.lineTo(xLine,bottom);
}
this.Canvas.stroke();
}
}
}
//多行文字刻度输出 obj={ Data:, X:, Y:, TextBaseLine:, IsLeft:, Item:刻度数据 }
this.DrawMultiLineText=function(obj)
{
var lineSpacing=2;
var lineHeight=this.Canvas.measureText('擎').width;
var lineCount=obj.Data.length;
var textHeight=lineHeight*lineCount+(lineSpacing*(lineCount-1));
var yText=obj.Y;
if (obj.Item.Font!=null) this.Canvas.font=obj.Item.Font;
if (obj.IsLeft)
{
this.Canvas.textAlign="right";
var xText=obj.X-obj.TextPadding;
}
else
{
this.Canvas.textAlign="left";
var xText=obj.X+obj.TextPadding;
}
var textBaseline=this.Canvas.textBaseline; //备份下原来的对齐方式
this.Canvas.textBaseline='top';
if (obj.TextBaseLine==1) //middle
{
yText-=textHeight/2;
}
else if (obj.TextBaseLine==0) //top
{
}
else if (obj.TextBaseLine==2) //bottom
{
yText-=textHeight;
}
for(var i=0;i<obj.Data.length;++i)
{
var item=obj.Data[i];
var text=item.Text;
var backupTextColor=null;
if (item.Color)
{
backupTextColor=this.Canvas.fillStyle;
this.Canvas.fillStyle=item.Color;
}
this.Canvas.fillText(text,xText,yText);
yText+=lineHeight+lineSpacing;
if (backupTextColor) this.Canvas.fillStyle=backupTextColor;
}
this.Canvas.textBaseline=textBaseline; //还原对齐方式
}
//上下区域是否重叠
this.IsTextTopBottomOverlap=function(rt, rt2)
{
if (rt2.Top>=rt.Top && rt2.Top<=rt.Bottom) return true;
if (rt2.Bottom>=rt.Top && rt2.Bottom<=rt.Bottom) return true;
return false;
}
this.GetTextTopBottom=function(textBaseline, yText)
{
var rtRight=null;
var textHeight=this.Canvas.measureText('擎').width;
if (textBaseline==0)
{
rtRight={ Top: yText, Bottom:yText+textHeight }
}
else if (textBaseline==1)
{
rtRight={ Top: yText-textHeight/2 };
rtRight.Bottom=rtRight.Top+textHeight;
}
else if (textBaseline==2)
{
rtRight={ Bottom:yText };
rtRight.Top=rtRight.Bottom-textHeight;
}
return rtRight;
}
this.DrawHorizontalMuText=function(aryText)
{
var maxWidth=[null,null];
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
var width=item.Text[0].Width;
if (!IFrameSplitOperator.IsNumber(maxWidth[0])) maxWidth[0]=width;
else if (maxWidth[0]<width) maxWidth[0]=width;
width=item.Text[1].Width;
if (!IFrameSplitOperator.IsNumber(maxWidth[1])) maxWidth[1]=width;
else if (maxWidth[1]<width) maxWidth[1]=width;
}
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
var message=item.Item;
this.Canvas.textBaseline=message.TextBaseline;
if (message.ExtendData && message.ExtendData.Font) this.Canvas.font=message.ExtendData.Font;
else if (message.Font) this.Canvas.font=message.Font;
if (message.ExtendData && message.ExtendData.PriceColor) this.Canvas.fillStyle=message.ExtendData.PriceColor;
else this.Canvas.fillStyle=message.TextColor;
this.Canvas.textAlign="right";
var x=item.X+maxWidth[1];
this.Canvas.fillText(item.Text[1].Text,x,item.Y);
if (message.ExtendData && message.ExtendData.SplitColor) this.Canvas.fillStyle=message.ExtendData.SplitColor;
else this.Canvas.fillStyle=message.TextColor;
this.Canvas.textAlign="left";
var splitWidth=this.Canvas.measureText('/').width;
this.Canvas.fillText('/',x,item.Y);
if (message.ExtendData && message.ExtendData.PercentageColor) this.Canvas.fillStyle=message.ExtendData.PercentageColor;
else this.Canvas.fillStyle=message.TextColor;
this.Canvas.textAlign="right";
var x=item.X+maxWidth[1]+maxWidth[0]+splitWidth;
this.Canvas.fillText(item.Text[0].Text,x,item.Y);
var textWidth=maxWidth[1]+maxWidth[0]+splitWidth*4;
if (this.RightTextMaxWidth<textWidth) this.RightTextMaxWidth=textWidth;
}
}
//画Y轴Message[2,3]两个内部刻度
this.DrawInsideClientHorizontal=function()
{
var border=this.GetBorder();
if (border.DayBorder && IFrameSplitOperator.IsNonEmptyArray(border.DayBorder))
{
var item=border.DayBorder[0];
var left=item.LeftEx;
var item=border.DayBorder[border.DayBorder.length-1];
var right=item.RightEx;
var bottom=border.Bottom;
var top=border.TopTitle;
}
else
{
var left=border.LeftEx;
var right=border.RightEx;
var bottom=border.Bottom;
var top=border.TopTitle;
}
var pixelTatio = GetDevicePixelRatio();
var yPrev = null; //上一个坐标y的值
var yInsideText=null;
for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线
{
var item = this.HorizontalInfo[i];
var y = this.GetYFromData(item.Value);
if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了
if (item.Message[2])
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
var yText=y;
if (y >= bottom - 2)
{
this.Canvas.textBaseline = 'bottom';
}
else if (y <= top + 2)
{
this.Canvas.textBaseline = 'top';
yText+=this.YTextTopOffset;
}
else
{
this.Canvas.textBaseline = "middle";
}
var textObj={ X:left, Y:yText, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[0]}} ;
if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj))
{
this.Canvas.fillText(item.Message[2], left + 1*pixelTatio, yText);
if (yInsideText==null || yInsideText>yText)
{
this.YInsideOffset=this.Canvas.measureText(item.Message[2]).width+4*GetDevicePixelRatio();
yInsideText=yText;
}
}
}
if (item.Message[3])
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
var yText=y;
if (y >= bottom - 2)
{
this.Canvas.textBaseline = 'bottom';
}
else if (y <= top + 2)
{
this.Canvas.textBaseline = 'top';
yText+=this.YTextTopOffset;
}
else
{
this.Canvas.textBaseline = "middle";
}
var textWidth = this.Canvas.measureText(item.Message[3]).width;
var textObj={ X:right-textWidth, Y:yText, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[1]}} ;
if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj))
this.Canvas.fillText(item.Message[3], right - 1*pixelTatio, yText);
}
yPrev = y;
}
}
//Y刻度画在左边内部
this.DrawInsideHorizontal = function ()
{
if (this.IsHScreen===true) return; //横屏不画
if (this.IsMinSize) return;
if (this.ChartBorder.IsShowTitleOnly) return;
if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;
this.DrawInsideClientHorizontal();
var border=this.ChartBorder.GetBorder();
var left = border.Left
var right = border.Right;
var bottom = border.Bottom;
var top = border.TopTitle;
var borderRight = this.ChartBorder.Right;
var borderLeft = this.ChartBorder.Left;
var titleHeight = this.ChartBorder.TitleHeight;
var isDrawLeft= (borderLeft<10 || this.YTextPosition[0]==2) && this.IsShowYText[0]===true;
var isDrawRight= (borderRight<10 || this.YTextPosition[1]==2) && this.IsShowYText[1]===true;
if ( isDrawLeft || isDrawRight )
{
var pixelTatio = GetDevicePixelRatio();
var yPrev = null; //上一个坐标y的值
var yInsideText=null;
for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线
{
var item = this.HorizontalInfo[i];
var y = this.GetYFromData(item.Value);
if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了
//坐标信息 左边 间距小于10 画在内部
if (item.Message[0] != null && isDrawLeft)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
var textHeight=this.Canvas.measureText("擎").width;
var yText=y;
if (y >= bottom - 2)
{
this.Canvas.textBaseline = 'bottom';
}
else if ((y-textHeight/2)<=top)
{
this.Canvas.textBaseline = 'top';
yText+=this.YTextTopOffset;
}
else
{
if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom";
else this.Canvas.textBaseline = "middle";
}
var textObj={ X:left, Y:yText, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[0]}} ;
if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj))
{
this.Canvas.fillText(item.Message[0], left + 1*pixelTatio, yText);
if (yInsideText==null || yInsideText>yText)
{
this.YInsideOffset=this.Canvas.measureText(item.Message[0]).width+4*GetDevicePixelRatio();
yInsideText=yText;
}
}
}
if (item.Message[1] != null && isDrawRight)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
var textHeight=this.Canvas.measureText("擎").width;
var yText=y;
if (y >= bottom - 2)
{
this.Canvas.textBaseline = 'bottom';
}
else if (y-textHeight/2 <= top)
{
this.Canvas.textBaseline = 'top';
yText+=this.YTextTopOffset;
}
else
{
if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom";
else this.Canvas.textBaseline = "middle";
}
if (Array.isArray(item.Message[1])) var text=item.Message[1][0];
else var text=item.Message[1];
var textWidth = this.Canvas.measureText(text).width;
var textObj={ X:right-textWidth, Y:yText, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[1]}} ;
if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj))
this.Canvas.fillText(text, right - 1*pixelTatio, yText);
}
yPrev = y;
}
}
}
this.GetXFromIndex=function(index)
{
var count=this.XPointCount;
if (count==1)
{
if (index==0) return this.ChartBorder.GetLeft();
else return this.ChartBorder.GetRight();
}
else if (count<=0)
{
return this.ChartBorder.GetLeft();
}
else if (index>=count)
{
return this.ChartBorder.GetRight();
}
else
{
var offset=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*index/count;
return offset;
}
}
//画X轴
this.DrawVertical=function()
{
var border=this.GetBorder();
var top=border.TopTitle;
var bottom=border.Bottom;
var right=border.RightEx;
var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率
//JSConsole.Chart.Log('[AverageWidthFrame.DrawVertical] bottom',bottom);
//if (this.ChartBorder.Bottom<=5*GetDevicePixelRatio()) return; //高度不够 不显示
var mapX=null;
if (this.GetVerticalXCache) mapX=this.GetVerticalXCache();
var bottomTextExtend=null;
if (this.XTextExtend)
{
bottomTextExtend=this.XTextExtend[0];
}
var bottomLineExtend=null;
if (this.XLineExtend)
{
bottomLineExtend=this.XLineExtend[0];
}
var xPrev=null; //上一个坐标x的值
var textRightPrev=null; //上一次刻度输出右边x坐标
for(var i=0; i<this.VerticalInfo.length; ++i)
{
var item=this.VerticalInfo[i];
var x=null;
if (mapX && mapX.has(item.Value)) x=mapX.get(item.Value);
else x=this.GetXFromIndex(item.Value);
if (x>right) break;
if (xPrev!=null && Math.abs(x-xPrev)<this.MinXDistance) continue;
var item=this.VerticalInfo[i];
var xFixed=ToFixedPoint(x);
if (this.IsShowXLine)
{
if (item.LineType==2) //虚线
{
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
if (item.LineDash) this.Canvas.setLineDash(item.LineDash);
else this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else if (item.LineType==3)
{
}
else if (item.LineType>0) //实线
{
if (g_JSChartResource.FrameXLineDash)
{
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else
{
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
}
}
}
if (item.BG && this.DrawDayVertical)
{
this.DrawDayVertical(item, x, border);
}
if (this.VerticalInfo[i].Message[0]!=null && this.ChartBorder.Bottom>5*pixelRatio)
{
if (this.VerticalInfo[i].Font) this.Canvas.font=this.VerticalInfo[i].Font;
var textLeft=0;
this.Canvas.strokeStyle=item.TextColor;
var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width;
var textHeight=this.Canvas.measureText("擎").width;
if (bottomTextExtend && bottomTextExtend.Align==1)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
textLeft=x;
}
else
{
if (x<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
textLeft=x;
}
else if ((x + testWidth / 2) >= this.ChartBorder.GetChartWidth())
{
this.Canvas.textAlign = "right";
this.Canvas.textBaseline="top";
textLeft=x-testWidth;
}
else
{
this.Canvas.textAlign="center";
this.Canvas.textBaseline="top";
textLeft=x-(testWidth/2);
}
}
if (textRightPrev==null || textLeft>textRightPrev)
{
var yText=bottom;
if (item.LineType==3)
{
var lineLength=this.ShortXLineLength*pixelRatio;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,yText);
this.Canvas.lineTo(xFixed,yText+lineLength);
this.Canvas.stroke();
yText+=lineLength+2*pixelRatio;
}
if (bottomLineExtend)
{
if (bottomLineExtend.Mode===1)
{
if (item.Value>1)
{
if (bottomLineExtend.Color) this.Canvas.strokeStyle=bottomLineExtend.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,bottom);
this.Canvas.lineTo(xFixed,border.ChartHeight);
this.Canvas.stroke();
x+=1;
}
}
else if (bottomLineExtend.Mode===2)
{
if (bottomLineExtend.Width>=1)
{
var lineLength=bottomLineExtend.Width;
if (bottomLineExtend.Color) this.Canvas.strokeStyle=bottomLineExtend.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,yText);
this.Canvas.lineTo(xFixed,yText+lineLength);
this.Canvas.stroke();
yText+=lineLength+2;
}
}
}
//item.TextBGColor="rgb(0,255,0)";
if (item.TextBGColor) //文字背景色
{
var rtText={ Left:textLeft, Top:yText+this.XBottomOffset, Width:testWidth, Height:textHeight };
this.Canvas.fillStyle=item.TextBGColor;
this.Canvas.fillRect(rtText.Left-1, rtText.Top, rtText.Width+2, rtText.Height);
}
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(this.VerticalInfo[i].Message[0],x,yText+this.XBottomOffset);
textRightPrev=textLeft+testWidth;
}
}
xPrev=x;
}
}
//Y坐标转y轴数值
this.GetYData=function(y,isLimit)
{
if (this.Logarithmic && this.GetYLogarithmicFromData)
{
return this.GetYLogarithmicData(y);
}
if (this.CoordinateType==1) //反转坐标
{
if (isLimit==false)
{
return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
else
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMin;
if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMax;
return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
}
else
{
if (isLimit==false)
{
return (this.ChartBorder.GetBottomEx()-y)/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
else
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMax;
if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMin;
return (this.ChartBorder.GetBottomEx()-y)/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
}
}
//X坐标转x轴数值
this.GetXData=function(x)
{
if (x<=this.ChartBorder.GetLeft()) return 0;
if (x>=this.ChartBorder.GetRight()) return this.XPointCount;
return (x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth());
}
//选中的画图工具X,Y轴坐标信息
this.DrawPictureXCoordinate=function(drawPicture, range, option)
{
if (this.IsHScreen) return;
if (!range) return;
if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
this.Canvas.font=this.DrawPicture.Font;
var fontHeight=this.GetFontHeight();
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "bottom";
if (range.X)
{
var xRange=range.X;
var xLeft=xRange.Min.X;
var xRight=xRange.Max.X;
if (xLeft<left) xLeft=left;
if (xRight>right) xRight=right;
this.Canvas.fillStyle=this.DrawPicture.BGColor;
this.Canvas.fillRect(xLeft, border.Bottom, xRight-xLeft, fontHeight);
}
for(var i=0;i<range.Points.length;++i)
{
var item=range.Points[i];
if (item.X<left || item.X>right) continue;
var index=this.GetXData(item.X, false);
var index=Math.round(index);
var kItem=this.GetKItem(index);
if (kItem)
{
var text=IFrameSplitOperator.FormatDateString(kItem.Date,null);
if (ChartData.IsMinutePeriod(option.Period)) text+=" " + IFrameSplitOperator.FormatTimeString(kItem.Time, "HH:MM");
else if (ChartData.IsMilliSecondPeriod(option.Period)) text+=" " + IFrameSplitOperator.FormatTimeString(kItem.Time, "HH:MM:SS.fff");
var textWidth=this.Canvas.measureText(text).width+2;
var textLeft=item.X-textWidth/2;
if (textLeft<left) textLeft=left;
this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
this.Canvas.fillRect(textLeft, border.Bottom, textWidth, fontHeight);
this.Canvas.fillStyle=this.DrawPicture.TextColor;
var yCenter=border.Bottom+fontHeight;
this.Canvas.fillText(text,textLeft+1,yCenter);
}
}
}
this.GetKItem=function(currentIndex)
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var index=this.Data.DataOffset+currentIndex;
return this.Data.Data[index];
}
this.DrawPictureYCoordinate=function(drawPicture, range, option)
{
if (this.IsHScreen) return;
if (!range) return;
if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;
var border=this.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
var right=border.Right;
this.Canvas.font=this.DrawPicture.Font;
var fontHeight=this.GetFontHeight();
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "bottom";
var defaultfloatPrecision=2;
if (option && option.Symbol) defaultfloatPrecision=GetfloatPrecision(option.Symbol);
var textWidth=0;
for(var i=0;i<range.Points.length; ++i)
{
var item=range.Points[i];
var Value=this.GetYData(item.Y);
var text=Value.toFixed(defaultfloatPrecision);
var value=this.Canvas.measureText(text).width;
if (textWidth<value) textWidth=value;
range.Points[i].Text=text;
}
textWidth+=this.YTextPadding[1]+2;
if (range.Y)
{
var yRange=range.Y;
var yTop=yRange.Min.Y;
var yBottom=yRange.Max.Y;
if (yRange.Min.Y<top) yTop=top;
if (yRange.Max.Y>bottom) yBottom=bottom;
this.Canvas.fillStyle=this.DrawPicture.BGColor;
this.Canvas.fillRect(right, yTop, textWidth+5, yBottom-yTop);
}
for(var i=0;i<range.Points.length; ++i)
{
var item=range.Points[i];
if (item.Y<top || item.Y>bottom) continue;
this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
this.Canvas.fillRect(right, item.Y-fontHeight/2, textWidth, fontHeight);
this.Canvas.fillStyle=this.DrawPicture.TextColor;
var yText=item.Y+fontHeight/2;
this.Canvas.fillText(item.Text,right+this.YTextPadding[1],yText);
}
}
this.DrawPicturePointYCoordinate=function(drawPicture, option)
{
if (this.IsHScreen) return;
if (!drawPicture.GetYCoordinatePoint) return;
var aryPoint=drawPicture.GetYCoordinatePoint();
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return;
var border=this.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
var right=border.Right;
this.Canvas.font=this.DrawPicture.Font;
var fontHeight=this.GetFontHeight();
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "bottom";
var defaultfloatPrecision=2;
if (option && option.Symbol) defaultfloatPrecision=GetfloatPrecision(option.Symbol);
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
if (!item) continue;
if (item.Y<top || item.Y>bottom) continue;
var text=item.YValue.toFixed(defaultfloatPrecision);
var textWidth=this.Canvas.measureText(text).width+2;
textWidth+=this.YTextPadding[1];
this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
this.Canvas.fillRect(right, item.Y-fontHeight/2, textWidth, fontHeight);
this.Canvas.fillStyle=this.DrawPicture.TextColor;
var yText=item.Y+fontHeight/2;
this.Canvas.fillText(text,right+this.YTextPadding[1],yText);
}
}
//字体外部设置好
this.GetCustomItemTextInfo=function(item, bLeft,pixelTatio)
{
var text=bLeft?item.Message[0]:item.Message[1];
var aryText=[];
var width=0;
if (Array.isArray(text))
{
for(var i=0;i<text.length;++i)
{
var item=text[i];
if (item.Type===1)
{
aryText.push({ Type: item.Type });
}
else
{
var value=this.Canvas.measureText(text[i].Text).width;
if (value>width) width=value;
var outItem={ Text:text[i].Text, Width:value+2*pixelTatio };
if (item.TextColor) outItem.TextColor=item.TextColor;
if (item.BGColor) outItem.BGColor=item.BGColor;
if (IFrameSplitOperator.IsBool(item.EnableBGColor)) outItem.EnableBGColor=item.EnableBGColor; //是否启用背景色
aryText.push(outItem);
}
}
if (width>0) width+=2*pixelTatio;
}
else
{
width=this.Canvas.measureText(text).width+2*pixelTatio;
aryText.push( {Text:text, Width:width} );
}
return { MaxWidth:width, Text:aryText };
}
this.DrawOutRangeCustomItem=function(item, mapTextRect)
{
if (this.IsHScreen===true) return;
if (!this.IsShow && !this.IsYDrawMainFrame) return;
if (!item.Message[1] && !item.Message[0]) return;
if (!item.OutRange) return;
var position=0; //1=top 2=bottom
if (item.Value>this.HorizontalMax) position=1;
else if (item.Value<this.HorizontalMin) position=2;
else return;
this.Canvas.save();
var outRange=item.OutRange;
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
var bottom=border.Bottom;
var top=border.Top;
var borderRight = this.ChartBorder.Right;
var borderLeft = this.ChartBorder.Left;
var titleHeight = this.ChartBorder.TitleHeight;
if (this.IsHScreen)
{
borderLeft=this.ChartBorder.Top;
borderRight=this.ChartBorder.Bottom;
top=border.Top;
bottom=border.Bottom;
}
var pixelTatio = GetDevicePixelRatio();
var defaultTextHeight=18*pixelTatio;
var textHeight=defaultTextHeight;
if (item.Message[0] && borderLeft>=10)
{
if (item.Font != null) this.Canvas.font = item.Font;
var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
var textWidth=textInfo.MaxWidth;
var itemLeft=left-textWidth;
var fontHeight=this.GetFontHeight();
var textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
this.Canvas.textAlign = "right";
this.Canvas.textBaseline = "middle";
var yText=null;
if (position==1)
{
yText=border.TopEx;
if (IFrameSplitOperator.IsNumber(outRange.TopYOffset)) yText+=outRange.TopYOffset;
}
else if (position==2)
{
yText=border.BottomEx+textHeight;
if (IFrameSplitOperator.IsNumber(outRange.BottomYOffset)) yText+=outRange.BottomYOffset;
}
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
var rtBG={ Left:itemLeft, Width:itemText.Width, Bottom:yText, Height:textHeight };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
if (item.ExtendLine && item.ExtendLine[0]) //右侧延长线
{
var exLine=item.ExtendLine[0];
if (IFrameSplitOperator.IsNumber(exLine.Width))
{
var yLine=rtBG.Bottom;
if (position==2) yLine=rtBG.Top;
var lineType=item.LineType;
if (IFrameSplitOperator.IsNumber(outRange.ExtendLine.Type)) lineType=outRange.ExtendLine.Type;
if (i==0) this.DrawLine(left,left-exLine.Width,yLine,item.LineColor,lineType,item);
rtBG.Left-=exLine.Width;
rtBG.Right-=exLine.Width;
}
}
this.Canvas.fillStyle=outRange.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
if (outRange.Border && outRange.Border.Color)
{
if (IFrameSplitOperator.IsNonEmptyArray(outRange.Border.LineDash))
this.Canvas.setLineDash(outRange.Border.LineDash); //虚线
this.Canvas.strokeStyle = outRange.Border.Color;
this.Canvas.strokeRect(ToFixedPoint(rtBG.Left), ToFixedPoint(rtBG.Top), ToFixedRect(rtBG.Width), ToFixedRect(rtBG.Height));
}
this.Canvas.fillStyle = outRange.TextColor;
this.Canvas.fillText(itemText.Text, rtBG.Right - 1*pixelTatio, rtBG.Top+rtBG.Height/2+1*pixelTatio);
yText+=textHeight+1;
}
}
else if (item.Message[1] && borderRight>=10)
{
if (item.Font != null) this.Canvas.font = item.Font;
var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
var textWidth=textInfo.MaxWidth;
var itemRight=right+textWidth;
var fontHeight=this.GetFontHeight();
var textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var yText=null;
if (position==1)
{
yText=border.TopEx;
if (IFrameSplitOperator.IsNumber(outRange.TopYOffset)) yText+=outRange.TopYOffset;
}
else if (position==2)
{
yText=border.BottomEx+textHeight;
if (IFrameSplitOperator.IsNumber(outRange.BottomYOffset)) yText+=outRange.BottomYOffset;
}
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
var rtBG={ Right:itemRight, Width:itemText.Width, Bottom:yText, Height:textHeight };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Left=rtBG.Right-rtBG.Width;
if (item.ExtendLine && item.ExtendLine[1]) //右侧延长线
{
var exLine=item.ExtendLine[1];
if (IFrameSplitOperator.IsNumber(exLine.Width))
{
var yLine=rtBG.Bottom;
if (position==2) yLine=rtBG.Top;
var lineType=item.LineType;
if (IFrameSplitOperator.IsNumber(outRange.ExtendLine.Type)) lineType=outRange.ExtendLine.Type;
if (i==0) this.DrawLine(right,right+exLine.Width,yLine,item.LineColor,lineType,item);
rtBG.Left+=exLine.Width;
rtBG.Right+=exLine.Width;
}
}
this.Canvas.fillStyle=outRange.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
if (outRange.Border && outRange.Border.Color)
{
if (IFrameSplitOperator.IsNonEmptyArray(outRange.Border.LineDash))
this.Canvas.setLineDash(outRange.Border.LineDash); //虚线
this.Canvas.strokeStyle = outRange.Border.Color;
this.Canvas.strokeRect(ToFixedPoint(rtBG.Left), ToFixedPoint(rtBG.Top), ToFixedRect(rtBG.Width), ToFixedRect(rtBG.Height));
}
this.Canvas.fillStyle = outRange.TextColor;
this.Canvas.fillText(itemText.Text, rtBG.Left + 1*pixelTatio, rtBG.Top+rtBG.Height/2+1*pixelTatio);
yText+=textHeight+1;
}
}
this.Canvas.restore();
}
this.DrawCustomItem=function(item, mapTextRect) //显示自定义Y刻度
{
if (!item.Message[1] && !item.Message[0]) return;
if (item.Value>this.HorizontalMax || item.Value<this.HorizontalMin)
{
this.DrawOutRangeCustomItem(item, mapTextRect);
this.SendDrawCountDownEvent( { IsShow:false } );
return;
}
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
var bottom=border.Bottom;
var top=border.Top;
var borderRight = this.ChartBorder.Right;
var borderLeft = this.ChartBorder.Left;
var titleHeight = this.ChartBorder.TitleHeight;
if (this.IsHScreen)
{
borderLeft=this.ChartBorder.Top;
borderRight=this.ChartBorder.Bottom;
top=border.Top;
bottom=border.Bottom;
}
var pixelTatio = GetDevicePixelRatio();
var defaultTextHeight=5*pixelTatio;
var textHeight=defaultTextHeight;
var y;
if (item.Value=="TopEx") y=border.TopEx;
else if (item.Value=="TopTitle") y=border.TopTitle;
else if (item.Value=="Top") y=border.Top;
else if (item.Value=="BottomEx") y=border.BottomEx;
else if (item.Value=="Bottom") y=border.Bottom;
else y = this.GetYFromData(item.Value);
if (IFrameSplitOperator.IsNumber(item.YOffset)) y+=item.YOffset;
var position=0;
var emptyBGColor;
if (item.ExtendData && item.ExtendData.Custom)
{
var customItem=item.ExtendData.Custom;
if (IFrameSplitOperator.IsNumber(customItem.Position)) position=customItem.Position;
if (customItem.EmptyBGColor) emptyBGColor=customItem.EmptyBGColor;
}
if (item.Message[0]) // 左 position=2 集合竞价右侧
{
if (borderLeft<10 || position==1 || position==2)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
if (item.BGColor) bgColor=item.BGColor;
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=top;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
}
else
{
if (position==2) left=border.LeftEx-textInfo.MaxWidth;
var bgTop=yText-textHeight/2-1*pixelTatio;
var textLeft=left + 1*pixelTatio;
if (item.ExtendLine && item.ExtendLine[0] && position==2) //左侧延长线
{
var exLine=item.ExtendLine[0];
if (IFrameSplitOperator.IsNumber(exLine.Width))
{
var lineType=item.LineType;
if (IFrameSplitOperator.IsNumber(exLine.Type)) lineType=exLine.Type; //外部设置延长线样式
if (i==0)
{
var yLine=border.LeftEx-exLine.Width;
this.DrawLine(yLine,yLine+exLine.Width,y,item.LineColor,lineType,item);
}
textLeft-=exLine.Width;
//rectLeft-=exLine.Width
}
}
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
if (i==0)
{
if (position==2) this.DrawLine(border.LeftEx,right,yText,item.LineColor,item.LineType,item);
else this.DrawLine(textLeft+itemText.Width,right,yText,item.LineColor,item.LineType,item);
}
if (item.ClickData)
this.AddHorizontalLabel(textLeft, bgTop, itemText.Width,textHeight, item, i);
yText+=textHeight+1*pixelTatio;
}
}
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "right";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
if (i==0) var bgTop=top-itemText.Width;
else var bgTop=top-textWidth;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
if (i==0)
{
var rectLeft=left-itemText.Width;
var textLeft=left;
}
else
{
var rectLeft=left-textWidth;
var textLeft=left-(textWidth-itemText.Width);
}
if (item.ExtendLine && item.ExtendLine[0]) //右侧延长线
{
var exLine=item.ExtendLine[0];
if (IFrameSplitOperator.IsNumber(exLine.Width))
{
var lineType=item.LineType;
if (IFrameSplitOperator.IsNumber(exLine.Type)) lineType=exLine.Type; //外部设置延长线样式
var exLineColor=item.LineColor;
if (exLine.LineColor) exLineColor=exLine.LineColor; //设置线段颜色
if (i==0) this.DrawLine(left,left-exLine.Width,y,exLineColor,lineType,item);
textLeft-=exLine.Width;
rectLeft-=exLine.Width;
}
}
if (emptyBGColor)
{
this.Canvas.fillStyle=emptyBGColor;
this.Canvas.fillRect(rectLeft-1,bgTop,itemText.Width+1,textHeight);
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.strokeRect(ToFixedPoint(rectLeft-1),ToFixedPoint(bgTop),ToFixedPoint(itemText.Width+1),ToFixedPoint(textHeight));
this.Canvas.fillStyle = item.LineColor;
this.Canvas.fillText(itemText.Text, textLeft - 1*pixelTatio, yText);
}
else
{
if (!(itemText.EnableBGColor===false))
{
var textBGColor=item.LineColor;
if (itemText.BGColor) textBGColor=itemText.BGColor;
this.Canvas.fillStyle=textBGColor;
this.Canvas.fillRect(rectLeft,bgTop,itemText.Width,textHeight);
}
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft - 1*pixelTatio, yText);
}
if (i==0) this.DrawLine(left,right,yText,item.LineColor,item.LineType,item);
if (item.ClickData) //点击事件
this.AddHorizontalLabel(textLeft, bgTop, itemText.Width,textHeight, item, i);
yText+=textHeight+1*pixelTatio;
}
}
}
}
else if (item.Message[1]) //右
{
if (borderRight<10 || position==1)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=bottom-itemText.Width;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
if (this.GetEventCallback)
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var sendData=
{
Top:bgTop, Right:right, Height:null,
IsShow:true, BGColor:item.LineColor, TextColor:item.TextColor, PixelTatio:pixelTatio, Position:"Right", IsInside:true
};
if (this.SendDrawCountDownEvent(sendData))
{
if (IFrameSplitOperator.IsPlusNumber(sendData.Height))
yText+=textHeight+1*pixelTatio;
}
}
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var textLeft=right-itemText.Width;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight); //文本背景区域
if (itemText.TextColor) this.Canvas.fillStyle=itemText.TextColor;
else this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
if (i==0) this.DrawLine(left,textLeft,yText,item.LineColor,item.LineType,item);
yText+=textHeight+1*pixelTatio;
}
}
}
if (item.Type==3 || item.Type==4)
{
if (item.Title)
{
var width=this.Canvas.measureText(item.Title).width+2*pixelTatio;
if (this.IsHScreen)
{
var bgTop=bottom-itemText.Width-width;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,width);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Title, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=right-textWidth-width-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Title, textLeft + 1*pixelTatio, y);
}
}
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var preTextRect=null;
if (mapTextRect && mapTextRect.has(3)) preTextRect=mapTextRect.get(3);
var yText=y;
var rtText={ };
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=bottom;
//bgTop+=(textWidth-itemText.Width);
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
if (this.GetEventCallback)
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var sendData=
{
Top:bgTop, Left:right, Right:this.ChartBorder.GetChartWidth(), Height:null,
IsShow:true, BGColor:item.LineColor, TextColor:item.TextColor, PixelTatio:pixelTatio, Position:"Right", IsInside:false
};
if (this.SendDrawCountDownEvent(sendData))
{
if (IFrameSplitOperator.IsPlusNumber(sendData.Height))
yText+=textHeight+1*pixelTatio;
}
}
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
if (i==0 && textInfo.Text.length==0)
{
var textLeft=right;
rtText.Left=textLeft;
if (preTextRect && bgTop<preTextRect.Rect.Bottom)
{
yText=preTextRect.Rect.Bottom;
bgTop=yText-textHeight/2-1*pixelTatio;
}
}
else
{
var textLeft=right+textWidth-itemText.Width;
}
if (item.ExtendLine && item.ExtendLine[1]) //右侧延长线
{
var exLine=item.ExtendLine[1];
if (IFrameSplitOperator.IsNumber(exLine.Width))
{
var lineType=item.LineType;
if (IFrameSplitOperator.IsNumber(exLine.Type)) lineType=exLine.Type; //外部设置延长线样式
if (i==0) this.DrawLine(right,textLeft+exLine.Width,y,item.LineColor,lineType,item);
textLeft+=exLine.Width;
}
}
if (emptyBGColor)
{
this.Canvas.fillStyle=emptyBGColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width+1,textHeight);
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.strokeRect(ToFixedPoint(textLeft),ToFixedPoint(bgTop),ToFixedRect(itemText.Width+1),ToFixedRect(textHeight));
this.Canvas.fillStyle = item.LineColor;
this.Canvas.fillText(itemText.Text, textLeft + 2*pixelTatio, yText);
}
else
{
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
if (itemText.TextColor) this.Canvas.fillStyle=itemText.TextColor;
else this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
}
if (i==0) this.DrawLine(left,right,y,item.LineColor,item.LineType,item);
if (item.ClickData) //点击事件
this.AddHorizontalLabel(textLeft, bgTop, itemText.Width,textHeight, item, i);
yText+=textHeight+1*pixelTatio;
rtText.Bottom=yText;
}
}
}
if (mapTextRect && IFrameSplitOperator.IsNumber(rtText.Left) && IFrameSplitOperator.IsNumber(rtText.Bottom))
{
mapTextRect.set(3, { Rect:rtText, Item:item });
}
if (item.Type==3 || item.Type==4)
{
if (item.Title)
{
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
var width=this.Canvas.measureText(item.Title).width+2*pixelTatio;
if (this.IsHScreen)
{
var bgTop=bottom-width;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,width);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Title, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=right-width-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Title, textLeft + 1*pixelTatio, y);
}
}
}
}
}
}
this.AddHorizontalLabel=function(left, top, width, height, item, lineID)
{
var rtLabel={ Left:left, Top:top, Width:width, Height:height };
rtLabel.Right=rtLabel.Left+rtLabel.Width;
rtLabel.Bottom=rtLabel.Top+rtLabel.Height;
var lableItem={ Rect:rtLabel, Item:item, ID:item.ClickData.ID, Args:item.ClickData.Args, LineID:lineID };
this.HorizontalLabel.push(lableItem);
}
this.DrawCustomAreaItem=function(item) //自定义Y轴区域
{
if (!item.AreaData) return;
if (this.IsHScreen) return; //暂时不支持横屏
//item.AreaData; //区域: { Value[], BGColor:, Position:[0=左, 1=右], Width:[左, 右] }
if (!IFrameSplitOperator.IsNonEmptyArray(item.AreaData.Value) || item.AreaData.Value.length!=2) return;
var max=Math.max(item.AreaData.Value[0],item.AreaData.Value[1]);
var min=Math.min(item.AreaData.Value[0],item.AreaData.Value[1]);
if (min>=this.HorizontalMax) return;
if (max<=this.HorizontalMin) return;
if (max>this.HorizontalMax) max=this.HorizontalMax;
if (min<this.HorizontalMin) min=this.HorizontalMin;
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
var borderRight = this.ChartBorder.Right;
var borderLeft = this.ChartBorder.Left;
var yTop=this.GetYFromData(max);
var yBottom=this.GetYFromData(min);
if (item.AreaData.Position.includes(0) && borderLeft>10) //左
{
var rtBG={ Left:0, Right:left-1, Top:yTop, Bottom:yBottom };
rtBG.Height=rtBG.Bottom-rtBG.Top;
rtBG.Width=rtBG.Right-rtBG.Left;
if (IFrameSplitOperator.IsNonEmptyArray(item.AreaData.Width)) //指定宽度
{
var bgWidth=item.AreaData.Width[0];
if (IFrameSplitOperator.IsNumber(bgWidth))
{
if (rtBG.Width>bgWidth)
{
rtBG.Width=bgWidth;
rtBG.Left=rtBG.Right-rtBG.Width;
}
}
}
this.Canvas.fillStyle=item.AreaData.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
this.DrawCustomAreaText(rtBG, item, 0);
}
if (item.AreaData.Position.includes(1) && borderRight>10) //右
{
var rtBG={ Left:right+1, Top:yTop, Bottom:yBottom };
rtBG.Height=rtBG.Bottom-rtBG.Top;
if (this.YRightTextInfo && IFrameSplitOperator.IsNumber(this.YRightTextInfo.MainTextWidth)) //右侧自动调整 可以获取宽度
{
rtBG.Width=this.YRightTextInfo.MainTextWidth-1;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else
{
rtBG.Right=border.ChartWidth;
rtBG.Width=rtBG.Right-rtBG.Left;
}
if (IFrameSplitOperator.IsNonEmptyArray(item.AreaData.Width)) //指定宽度
{
var bgWidth=item.AreaData.Width[1];
if (IFrameSplitOperator.IsNumber(bgWidth))
{
if (rtBG.Width>bgWidth)
{
rtBG.Width=bgWidth;
rtBG.Right=rtBG.Left+rtBG.Width;
}
}
}
this.Canvas.fillStyle=item.AreaData.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
this.DrawCustomAreaText(rtBG, item, 1);
}
}
this.DrawCustomAreaText=function(rtBG, item, position) //position 0=左 1=右
{
if (item.Font != null) this.Canvas.font = item.Font;
var fontHeight=this.GetFontHeight();
if (rtBG.Height<fontHeight) return;
var pixelTatio = GetDevicePixelRatio();
var text, xText;
if (position==0)
{
if (!item.Message[0]) return;
this.Canvas.textAlign = "right";
text=item.Message[0];
xText=rtBG.Right-2*pixelTatio;
}
else if (position==1)
{
if (!item.Message[1]) return;
this.Canvas.textAlign = "left";
text=item.Message[1];
xText=rtBG.Left+2*pixelTatio
}
var yText=rtBG.Top+rtBG.Height/2;
this.Canvas.textBaseline = "middle";
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(text, xText, yText);
}
this.SendDrawCountDownEvent=function(sendData)
{
if (!this.GetEventCallback) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_COUNTDOWN);
if (!event || !event.Callback) return false;
event.Callback(event,sendData,this);
return true;
}
this.DrawDotLine=function(left,right,y, color, option)
{
var pixelTatio = GetDevicePixelRatio();
this.Canvas.save();
this.Canvas.strokeStyle=color;
if (option && IFrameSplitOperator.IsPlusNumber(option.LineWidth)) this.Canvas.lineWidth=option.LineWidth*pixelTatio;
if (option.LineDash) this.Canvas.setLineDash(option.LineDash);
else this.Canvas.setLineDash([5*pixelTatio,5*pixelTatio]); //虚线
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),left);
this.Canvas.lineTo(ToFixedPoint(y),right);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawLine=function(left,right,y, color,lineType, option)
{
if (lineType==-1) return;
if (lineType==0) //直线
{
var pixelRatio=GetDevicePixelRatio();
this.Canvas.strokeStyle=color;
var bChangeLineWidth=false;
if (option && IFrameSplitOperator.IsPlusNumber(option.LineWidth))
{
this.Canvas.lineWidth=option.LineWidth*pixelRatio;
bChangeLineWidth=true;
}
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),left);
this.Canvas.lineTo(ToFixedPoint(y),right);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
this.Canvas.stroke();
if (bChangeLineWidth)
{
this.Canvas.lineWidth=pixelRatio;
}
}
else if (lineType==3) //绘制短线
{
var lineWidth=10*GetDevicePixelRatio();
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),left);
this.Canvas.lineTo(ToFixedPoint(y),left+lineWidth);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(left+lineWidth,ToFixedPoint(y));
}
this.Canvas.stroke();
}
else if (lineType==1 || lineType==2) //虚线
{
this.DrawDotLine(left,right,y, color, option);
}
}
this.DrawHScreenText=function(center,data)
{
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
this.Canvas.fillStyle = data.Color;
this.Canvas.save();
this.Canvas.translate(center.X, center.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(data.Text, data.XOffset, data.YOffset);
this.Canvas.restore();
}
this.RGBToStruct=function(rgb)
{
if(/^(rgb|RGB)/.test(rgb))
{
var aColor = rgb.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
var result={};
if (aColor.length!=3) return null;
result.R = Number(aColor[0]);
result.G = Number(aColor[1]);
result.B = Number(aColor[2]);
return result;
}
return null;
}
this.GetMulitTextMaxWidth=function(aryData)
{
var width=null;
for(var i=0;i<aryData.length;++i)
{
var item=aryData[i];
var text=item.Text;
if (!text) continue;
var value=this.Canvas.measureText(text).width;
if (width==null) width=value;
else if(width<value) width=value;
}
return width;
}
this.GetScaleTextWidth=function()
{
var border=this.ChartBorder.GetBorder();
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
if (this.IsHScreen)
{
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var isDrawLeft=borderTop>10*pixelTatio && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
}
else
{
var borderRight=this.ChartBorder.Right;
var borderLeft=this.ChartBorder.Left;
var isDrawLeft=borderLeft>10 && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
}
if (!isDrawRight && !isDrawLeft) return null;
var width={ Left:null, Right:null };
var rightExtendWidth=0;
var isYPercentage=false; //是否是百分比坐标
if (this.YSplitOperator && this.YSplitOperator.CoordinateType==1) isYPercentage=true;
var leftExtendLineWidth=0;
var rightExtendLineWidth=0;
if (IFrameSplitOperator.IsNonEmptyArray(this.YLineExtend))
{
if (this.YLineExtend[0] && this.YLineExtend[0].Width>1)
leftExtendLineWidth=this.YLineExtend[0].Width;
if (this.YLineExtend[1] && this.YLineExtend[1].Width>1)
rightExtendLineWidth=this.YLineExtend[1].Width;
}
for(var i=0;i<this.HorizontalInfo.length;++i)
{
var textWidth=null;
var item=this.HorizontalInfo[i];
if (!item) continue;
if (item.Font!=null) this.Canvas.font=item.Font;
if (item.Message[0]!=null && isDrawLeft)
{
if (Array.isArray(item.Message[0]))
{
textWidth=this.GetMulitTextMaxWidth(item.Message[0]);
}
else
{
textWidth=this.Canvas.measureText(item.Message[0]).width;
}
if (width.Left==null || width.Left<textWidth)
width.Left=textWidth;
//JSConsole.Chart.Log(`[ChartData::GetScaleTextWidth] ${item.Message[0]} ${textWidth}`);
}
if (item.Message[1]!=null && isDrawRight)
{
if (item.Font!=null) this.Canvas.font=item.Font;
if (Array.isArray(item.Message[1]))
{
if (this.MultiTextFormat==1) //显示1行 格式:价格/百分比
{
if (item.ExtendData)
{
if (item.ExtendData.Font) this.Canvas.font=item.ExtendData.Font;
var width1=this.Canvas.measureText(item.Message[1][0]).width;
var width2=this.Canvas.measureText(item.Message[1][1]).width;
var width3=this.Canvas.measureText('/').width;
textWidth=width1+width3;
if (rightExtendWidth<width2) rightExtendWidth=width2;
//JSConsole.Chart.Log(`[ChartData::GetScaleTextWidth] ${item.Message[1][1]}/${item.Message[1][0]} ${textWidth}, ${rightExtendWidth}`);
}
}
else if (this.MultiTextFormat==2) //显示2行
{
textWidth=this.Canvas.measureText(item.Message[1][0]).width;
var textWidth2=this.Canvas.measureText(item.Message[1][1]).width;
if (textWidth<textWidth2) textWidth=textWidth2;
}
else if (this.MultiTextFormat==3)
{
textWidth=this.GetMulitTextMaxWidth(item.Message[1]);
}
else //显示第1行
{
textWidth=this.Canvas.measureText(item.Message[1][0]).width;
if (isYPercentage)
{
var perTextWidth=this.Canvas.measureText("-00.00%").width;
if (perTextWidth>textWidth) textWidth=perTextWidth;
}
}
}
else
{
textWidth=this.Canvas.measureText(item.Message[1]).width;
}
if (width.Right==null || width.Right<textWidth)
width.Right=textWidth;
}
}
if (IFrameSplitOperator.IsNumber(width.Right)) width.Right+=rightExtendWidth;
if (IFrameSplitOperator.IsNumber(width.Left)) width.Left+=this.YTextPadding[0]+leftExtendLineWidth;
if (IFrameSplitOperator.IsNumber(width.Right)) width.Right+=this.YTextPadding[1]+rightExtendLineWidth;
return { TextWidth:width };
}
this.ClearToolbar=function()
{
if (!this.ToolbarID) return;
var divToolbar=document.getElementById(this.ToolbarID);
if (!divToolbar) return;
this.ChartBorder.UIElement.parentNode.removeChild(divToolbar);
this.ToolbarRect=null;
}
this.HideToolbar=function()
{
if (!this.ToolbarID) return;
this.ToolbarRect=null;
var divToolbar=document.getElementById(this.ToolbarID);
if (!divToolbar) return;
if (divToolbar.style.display!='none') divToolbar.style.display='none';
}
this.GetMainOverlayFrame=function()
{
if (!this.FrameData || !this.FrameData.SubFrameItem) return null;
var subFrame=this.FrameData.SubFrameItem;
var leftFrame=null, rightFrame=null;
for(var i=0;i<subFrame.OverlayIndex.length;++i)
{
var item=subFrame.OverlayIndex[i];
var overlayFrame=item.Frame;
if (overlayFrame.IsShowMainFrame==2) rightFrame=overlayFrame;
else if (overlayFrame.IsShowMainFrame==1) leftFrame=overlayFrame;
}
if (!leftFrame && !rightFrame) return null;
return [leftFrame, rightFrame];
}
}
function MinuteFrame()
{
this.newMethod=AverageWidthFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="MinuteFrame";
this.DataWidth=1*GetDevicePixelRatio();
this.DistanceWidth=1*GetDevicePixelRatio();
this.MinuteCount=243; //每天的分钟个数
this.BeforeBGColor=g_JSChartResource.Minute.Before.BGColor; //集合竞价背景
this.AfterBGColor=g_JSChartResource.Minute.After.BGColor;
this.MultiDayBorderPen=g_JSChartResource.MultiDayBorderPen;
this.CustomHorizontalInfo=[];
this.RightFrame=null; //右侧多重坐标
this.ToolbarID=Guid(); //工具条Div id
this.ReDrawToolbar=false;
this.DayCount=1; //显示天数
this.ModifyIndex=g_JSChartResource.MinuteToolbar.ModifyIndex; //是否显示'改参数'菜单
this.ChangeIndex=g_JSChartResource.MinuteToolbar.ChangeIndex; //是否显示'换指标'菜单
this.CloseIndex=g_JSChartResource.MinuteToolbar.CloseIndex; //是否显示'关闭指标窗口'菜单
this.MaxMinWindow=g_JSChartResource.MinuteToolbar.MaxMinWindow;
this.TitleWindow=g_JSChartResource.MinuteToolbar.TitleWindow;
this.ExportData=g_JSChartResource.MinuteToolbar.ExportData; //是否显示'导出数据'菜单
this.OverlayIndex=g_JSChartResource.MinuteToolbar.OverlayIndex; //是否显示叠加指标
this.ModifyIndexEvent; //改参数 点击事件
this.ToolbarRect=null; //保存工具条的位置
this.IsShowPositionTitle=false; //是否显示持仓标题
this.LastCalculateStatus={ Width:0, XPointCount:0 }; //最后一次计算宽度的状态
this.BeforeCloseIcon=CloneData(g_JSChartResource.Minute.Before.CloseIcon);
this.IsShowCloseButton=true, //是否关闭集合竞价按钮
this.BeforeOpenVerticalInfo=[]; //盘前集合竞价X轴
this.AfterCloseVerticalInfo=[]; //收盘集合竞价X轴
this.NightDayConfig=CloneData(g_JSChartResource.Minute.NightDay);
this.MinuteFrame_ReloadResource=this.ReloadResource;
this.ReloadResource=function(resource)
{
this.MinuteFrame_ReloadResource(resource);
//集合竞价配色修改
this.BeforeBGColor=g_JSChartResource.Minute.Before.BGColor;
this.AfterBGColor=g_JSChartResource.Minute.After.BGColor;
this.MultiDayBorderPen=g_JSChartResource.MultiDayBorderPen;
}
this.DrawFrame=function()
{
if (!this.IsMinSize)
{
this.SplitXYCoordinate();
this.DrawBeforeDataBG();
this.YInsideOffset=0;
if (this.BeforeDrawXYCallback) this.BeforeDrawXYCallback(this);
this.DrawNightDayBG(); //绘制夜盘 日盘背景
this.DrawCustomBG(); //绘制自定义背景色
this.DrawTitleBG();
this.DrawCustomHorizontalArea(); //Y轴背景区域 在刻度前面绘制
this.DrawHorizontal();
this.DrawVertical();
}
if (this.SizeChange==true || this.ReDrawToolbar==true)
{
this.DrawToolbar(); //大小变动才画工具条
this.ReDrawToolbar=false;
}
}
//Y轴面积背景
this.DrawCustomHorizontalArea=function()
{
if (this.IsMinSize) return;
if (this.ChartBorder.IsShowTitleOnly) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.CustomHorizontalInfo)) return;
for(var i=0;i<this.CustomHorizontalInfo.length;++i)
{
var item=this.CustomHorizontalInfo[i];
if (item.Type==5) this.DrawCustomAreaItem(item);
}
}
//画边框
this.SuperDrawBorder=this.DrawBorder;
this.DrawBorder=function()
{
if (!this.IsShowBorder) return;
if (this.IsMinSize) return;
this.SuperDrawBorder();
if (this.Identify==1) //走势图和成交量中间用粗线分割开
{
var border=this.ChartBorder.GetBorder();
var left=ToFixedPoint(border.Left);
var top=ToFixedPoint(border.Top);
var right=ToFixedPoint(border.Right);
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(left,top);
this.Canvas.lineTo(right,top);
this.Canvas.save();
this.Canvas.lineWidth=2 * GetDevicePixelRatio();
this.Canvas.stroke();
this.Canvas.restore();
}
}
this.DrawVolTitle=function(symbol)
{
if (!MARKET_SUFFIX_NAME.IsShowMinuteVolTitle(symbol)) return;
if (this.Identify==1) //显示"成交量"
{
var pixelRatio=GetDevicePixelRatio();
var left=this.ChartBorder.GetLeft()+2*pixelRatio+this.YInsideOffset;
var top=this.ChartBorder.GetTopEx()+2*pixelRatio;
this.Canvas.textAlign='left';
this.Canvas.textBaseline='top';
if (g_JSChartResource.Minute.VolBarColor || g_JSChartResource.Minute.VolTitleColor)
{
if (g_JSChartResource.Minute.VolBarColor) this.Canvas.fillStyle=g_JSChartResource.Minute.VolBarColor
else this.Canvas.fillStyle=g_JSChartResource.Minute.VolTitleColor;
var languageID=this.YSplitOperator.LanguageID;
var text=g_JSChartLocalization.GetText('MVol-Vol',languageID);
this.Canvas.fillText(text,left,top);
left+=this.Canvas.measureText(text).width;
left+=6*GetDevicePixelRatio();
}
if (this.IsShowPositionTitle)
{
text=g_JSChartLocalization.GetText('MVol-Position',languageID);
this.Canvas.fillStyle=g_JSChartResource.Minute.PositionColor;
this.Canvas.fillText(text,left,top);
}
}
}
this.DrawToolbar=function()
{
if (this.ToolbarButtonStyle==1) return;
if (g_JSChartResource.IsDOMFrameToolbar===true) return;
if (typeof($)=="undefined") return;
if (this.Identify<2) return;
if (!this.ChartBorder.UIElement) return;
var divToolbar=document.getElementById(this.ToolbarID);
if (divToolbar && this.SizeChange==false && this.ReDrawToolbar==false) return;
if (!divToolbar)
{
divToolbar=document.createElement("div");
divToolbar.className='klineframe-toolbar';
divToolbar.id=this.ToolbarID;
divToolbar.oncontextmenu = function() { return false;}; //屏蔽右键系统菜单
//为divToolbar添加属性identify
divToolbar.setAttribute("identify",this.Identify.toString());
this.ChartBorder.UIElement.parentNode.appendChild(divToolbar);
}
if (!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex && !this.CloseIndex)
{
if (divToolbar.style.display!='none')
divToolbar.style.display='none';
return;
}
//使用外城div尺寸 画图尺寸是被放大的
var pixelTatio = GetDevicePixelRatio();
var chartWidth=parseInt(this.ChartBorder.UIElement.parentElement.style.width.replace("px",""));
var chartHeight=parseInt(this.ChartBorder.UIElement.parentElement.style.height.replace("px",""));
//JSConsole.Chart.Log('[KLineFrame::DrawToolbar] ',chartWidth,chartHeight,pixelTatio);
var toolbarWidth=100;
var toolbarHeight=this.ChartBorder.GetTitleHeight();
var left=chartWidth-(this.ChartBorder.Right/pixelTatio)-toolbarWidth;
var top=this.ChartBorder.GetTop()/pixelTatio;
if (this.ToolbarRect)
{
//尺寸变动移动才重新设置DOM
if (this.ToolbarRect.Left==left && this.ToolbarRect.Top==top &&
this.ToolbarRect.Width==toolbarWidth && this.ToolbarRect.Height==toolbarHeight/pixelTatio)
{
return;
}
}
this.ToolbarRect={ Left:left, Top:top, Width:toolbarWidth, Height:toolbarHeight/pixelTatio };
const modifyButton=`<span class='index_param icon iconfont icon-index_param' id='modifyindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='调整指标参数'></span>`;
const changeButton=`<span class='index_change icon iconfont icon-change_index' id='changeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='切换指标'></span>`;
const closeButton=`<span class='index_close icon iconfont icon-close' id='closeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='关闭指标窗口'></span>`;
var spanIcon=modifyButton+changeButton;
if (this.CloseIndex)
{
spanIcon+=closeButton;
}
//var scrollPos=GetScrollPosition();
//left = left+scrollPos.Left;
//top = top+scrollPos.Top;
divToolbar.style.left = left + "px";
divToolbar.style.top = top + "px";
divToolbar.style.width=toolbarWidth+"px"; //宽度先不调整吧
divToolbar.style.height=(toolbarHeight/pixelTatio)+'px'; //只调整高度
divToolbar.innerHTML=spanIcon;
var chart=this.ChartBorder.UIElement.JSChartContainer;
var identify=this.Identify;
if (!this.ModifyIndex) //隐藏'改参数'
$("#"+divToolbar.id+" .index_param").hide();
else if (typeof(this.ModifyIndexEvent)=='function') //绑定点击事件
$("#"+divToolbar.id+" .index_param").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify
},this.ModifyIndexEvent);
if (!this.ChangeIndex) //隐藏'换指标'
{
$("#"+divToolbar.id+" .index_change").hide();
}
else if (typeof(this.ChangeIndexEvent)=='function')
{
$("#"+divToolbar.id+" .index_change").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify,
IsOverlay:false
},this.ChangeIndexEvent);
}
$("#"+divToolbar.id+" .index_close").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify
},
function(event)
{
var hqChart=event.data.Chart;
var id=event.data.Identify;
hqChart.RemoveIndexWindow(id);
});
divToolbar.style.display = "block";
}
//手绘,不用DOM,使用DOM太麻烦了
this.DrawToolbarV2=function(moveonPoint, mouseStatus)
{
if (g_JSChartResource.IsDOMFrameToolbar===true) return;
if (this.Identify==0 && this.IsShowCloseButton) this.DrawCloseBeforeButton(moveonPoint, mouseStatus); //盘前集合竞价关闭按钮
if (this.ChartBorder.TitleHeight<5) return;
var aryButton=[];
if (this.Identify!=0 && this.Identify!=1) //价格图和成交量图只有自定义按钮
{
if (this.CloseIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.CLOSE_INDEX_WINDOW, Style:this.CloseWindowButton });
if (this.MaxMinWindow) aryButton.push({ ID:JSCHART_BUTTON_ID.MAX_MIN_WINDOW, Style:this.MaxMinWindowButton })
if (this.TitleWindow) aryButton.push({ ID:JSCHART_BUTTON_ID.TITLE_WINDOW, Style:this.TitleWindowButton });
if (this.ExportData) aryButton.push( {ID:JSCHART_BUTTON_ID.EXPORT_DATA, Style:this.ExportDataButton});
if (this.OverlayIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.OVERLAY_INDEX, Style:this.OverlayIndexButton });
if (this.ChangeIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.CHANGE_INDEX, Style:this.ChangeIndexButton });
if (this.ModifyIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.MODIFY_INDEX_PARAM, Style:this.ModifyIndexParamButton });
}
if (IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar))
{
for(var i=0;i<this.CustomToolbar.length;++i)
{
var item=this.CustomToolbar[i];
if (item.ID && item.Style) aryButton.push({ ID:item.ID, Style:item.Style, TooltipText:item.TooltipText, Data:item.Data });
}
}
this.DrawTitleButton(aryButton, moveonPoint, mouseStatus);
}
this.DrawCloseBeforeButton=function(moveonPoint, mouseStatus)
{
if (this.Identify!=0) return;
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return;
if (this.ChartBorder.LeftExtendWidth<10) return;
var rtButton={ Left:border.Left, Top:border.TopEx, Width:this.BeforeCloseIcon.Size, Height:this.BeforeCloseIcon.Size };
rtButton.Right=rtButton.Left+this.BeforeCloseIcon.Size;
rtButton.Bottom=rtButton.Top+this.BeforeCloseIcon.Size;
var item={ Rect:rtButton, Name:"集合竞价关闭按钮" , ID:JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID };
var color=this.BeforeCloseIcon.Color;
if (moveonPoint &&
(moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
color=this.BeforeCloseIcon.MoveOnColor;
if (mouseStatus)
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:item, Frame:this, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
var font=`${this.BeforeCloseIcon.Size}px ${this.BeforeCloseIcon.Family}`;
this.Canvas.font=font;
this.Canvas.fillStyle=color;
this.Canvas.textAlign = 'left';
this.Canvas.textBaseline='top';
this.Canvas.fillText(this.BeforeCloseIcon.Text,border.Left,border.TopEx);
this.Buttons.push(item);
}
this.DrawMultiDayBeforeDataBG=function(border)
{
var dayBorder=border.DayBorder;
var top=ToFixedPoint(border.Top);
var bottom=ToFixedPoint(border.Bottom);
var height=bottom-top;
this.Canvas.strokeStyle=this.MultiDayBorderPen;
for(var i=0; i<dayBorder.length; ++i)
{
var drawCount=0;
var item=dayBorder[i];
var left=ToFixedPoint(item.Left);
var right=ToFixedPoint(item.LeftEx);
var width=right-left;
if (width>3) //盘前
{
this.Canvas.fillStyle=this.BeforeBGColor;
this.Canvas.fillRect(left,top,width,height);
++drawCount;
}
var left=ToFixedPoint(item.RightEx);
var right=ToFixedPoint(item.Right);
var width=right-left;
if (width>3) //盘后
{
this.Canvas.fillStyle=this.AfterBGColor;
this.Canvas.fillRect(left,top,width,height);
++drawCount;
}
if (drawCount==2 && i!=dayBorder.length-1)
{
this.Canvas.beginPath();
this.Canvas.moveTo(right,top);
this.Canvas.lineTo(right,bottom);
this.Canvas.stroke();
}
}
}
this.DrawCallAuctionVertical=function(verticalInfo, callAuctionData, border, isBeforeClose)
{
if (!callAuctionData) return;
var top=border.TopTitle;
var bottom=border.Bottom;
var left=border.Left;
var right=border.LeftEx;
var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率
var xPrev=null; //上一个坐标x的值
var textRightPrev=null; //上一次刻度输出右边x坐标
for(var i in verticalInfo)
{
var item=verticalInfo[i];
var x=this.GetLeftExtendXFromIndex(item.Value,callAuctionData);
if (x>right) break;
if (xPrev!=null && Math.abs(x-xPrev)<this.MinXDistance) continue;
var xFixed=ToFixedPoint(x);
if (this.IsShowXLine)
{
if (item.LineType==2) //虚线
{
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else if (item.LineType==3)
{
}
else if (item.LineType>0) //实线
{
if (g_JSChartResource.FrameXLineDash)
{
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else
{
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,top);
this.Canvas.lineTo(xFixed,bottom);
this.Canvas.stroke();
}
}
}
if (item.Message[0]!=null && this.ChartBorder.Bottom>5*pixelRatio)
{
if (item.Font!=null) this.Canvas.font=item.Font;
var textLeft=0;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.strokeStyle=item.TextColor;
var testWidth=this.Canvas.measureText(item.Message[0]).width;
if (x<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
textLeft=x;
}
else if ((x + testWidth / 2) >= border.ChartWidth)
{
this.Canvas.textAlign = "right";
this.Canvas.textBaseline="top";
textLeft=x-testWidth;
}
else
{
this.Canvas.textAlign="center";
this.Canvas.textBaseline="top";
textLeft=x-(testWidth/2);
}
if (textRightPrev==null || textLeft>textRightPrev)
{
var yText=bottom;
if (item.LineType==3)
{
var lineLength=this.ShortXLineLength*pixelRatio;
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed,yText);
this.Canvas.lineTo(xFixed,yText+lineLength);
this.Canvas.stroke();
yText+=lineLength+2*pixelRatio;
}
this.Canvas.fillText(item.Message[0],x,yText+this.XBottomOffset);
textRightPrev=textLeft+testWidth;
}
}
xPrev=x;
}
}
//画集合竞价背景
this.DrawBeforeDataBG=function()
{
var border=this.ChartBorder.GetBorder();
if (border.DayBorder)
{
this.DrawMultiDayBeforeDataBG(border);
return;
}
if (this.ChartBorder.LeftExtendWidth<10 && this.ChartBorder.RightExtendWidth<10) return;
//if (this.Identify>=2) return;
var top=ToFixedPoint(border.Top);
var bottom=ToFixedPoint(border.Bottom);
this.Canvas.fillStyle=this.BeforeBGColor;
if (this.ChartBorder.LeftExtendWidth>10) //盘前
{
var left=ToFixedPoint(border.Left);
var right=ToFixedPoint(this.ChartBorder.GetLeft());
var width=right-left;
var height=bottom-top;
this.Canvas.fillRect(left,top,width,height);
this.DrawCallAuctionVertical(this.BeforeOpenVerticalInfo, this.YSplitOperator.BeforeOpenData, border, true);
}
if (this.ChartBorder.RightExtendWidth>10) //盘后
{
this.Canvas.fillStyle=this.AfterBGColor;
var left=ToFixedPoint(this.ChartBorder.GetRight());
var right=ToFixedPoint(border.Right);
var width=right-left;
var height=bottom-top;
this.Canvas.fillRect(left,top,width,height);
}
}
this.DrawCustomBG=function()
{
if (!this.HQChart) return;
if (this.IsHScreen) return;
var symbol=this.HQChart.Symbol;
if (!symbol) return;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_MINUTE_BG)
if (!event || !event.Callback) return;
var aryDay=null;
if (this.DayCount>1)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.HQChart.DayData)) return;
aryDay=[];
for(var i=this.HQChart.DayData.length-1;i>=0;--i)
{
aryDay.push({ Date:this.HQChart.DayData[i].Date, BGColor:null } );
}
}
else if (this.DayCount==1)
{
if (!IFrameSplitOperator.IsPlusNumber(this.HQChart.DataStatus.LatestDate)) return;
aryDay=[{ Date:this.HQChart.DataStatus.LatestDate, BGColor:null }];
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryDay)) return;
var sendData={ XPointCount:this.XPointCount, DayCount:this.DayCount, MinuteCount:this.MinuteCount , AryDay:aryDay, PreventDefault:false };
event.Callback(event, sendData, this);
if (sendData.PreventDefault) return;
var border=this.ChartBorder.GetBorder();
for(var i=0;i<aryDay.length;++i)
{
var item=aryDay[i];
if (!item.BGColor) continue;
var start=i*this.MinuteCount;
var end=start+this.MinuteCount-1;
var xStart=this.GetXFromIndex(start);
var xEnd=this.GetXFromIndex(end);
var rtDay={Left:xStart, Top:border.Top, Right:xEnd, Bottom:border.Bottom };
rtDay.Width=rtDay.Right-rtDay.Left;
rtDay.Height=rtDay.Bottom-rtDay.Top;
this.Canvas.fillStyle =item.BGColor;
this.Canvas.fillRect(rtDay.Left, rtDay.Top, rtDay.Width, rtDay.Height);
}
}
this.DrawNightDayBG=function()
{
if (this.DayCount!=1) return;
if (!this.HQChart) return;
if (!this.HQChart.EnableNightDayBG) return;
var symbol=this.HQChart.Symbol;
if (!symbol) return;
var xIndex=-1;
//获取夜盘和日期的分界线X索引位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_MINUTE_NIGHT_DAY_X_INDEX)
if (!event || !event.Callback) return;
var sendData={ Symbol:symbol, XIndex:xIndex, MinuteTimeStringData:g_MinuteTimeStringData };
event.Callback(event,sendData,this);
xIndex=sendData.XIndex;
if (xIndex<0) return;
var border=this.ChartBorder.GetBorder();
var x=this.GetXFromIndex(xIndex);
var rtNight={ Left: border.Left, Top:border.TopEx, Right:x, Bottom:border.Bottom };
rtNight.Width=rtNight.Right-rtNight.Left;
rtNight.Height=rtNight.Bottom-rtNight.Top;
this.Canvas.fillStyle = this.NightDayConfig.NightBGColor;
this.Canvas.fillRect(rtNight.Left, rtNight.Top, rtNight.Width, rtNight.Height);
if (this.Identify!=0) return;
//显示 日盘夜盘文字
this.Canvas.font=this.NightDayConfig.Font;
this.Canvas.textBaseline = "bottom";
this.Canvas.textAlign = 'left';
var aryTitle=[{ Title:"夜盘", Position:1, Config:this.NightDayConfig.Night }, { Title:"日盘", Position:0,Config:this.NightDayConfig.Day }];
var textHeight= this.Canvas.measureText("擎").width;
for(var i=0;i<aryTitle.length;++i)
{
var item=aryTitle[i];
var text=g_JSChartLocalization.GetText(item.Title,this.HQChart.LanguageID);
var testWidth = this.Canvas.measureText(text).width;
var rtItem=
{
Width:testWidth+item.Config.Margin.Left+item.Config.Margin.Right,
Height:textHeight+item.Config.Margin.Top+item.Config.Margin.Bottom,
Bottom:border.Bottom
};
rtItem.Top=rtItem.Bottom-rtItem.Height;
if (item.Position===1)
{
rtItem.Right=x-1;
rtItem.Left=rtItem.Right-rtItem.Width;
}
else
{
rtItem.Left=x+1;
rtItem.Right=rtItem.Left+rtItem.Width;
}
if (item.Config.BGColor)
{
this.Canvas.fillStyle = item.Config.BGColor;
this.Canvas.fillRect(rtItem.Left, rtItem.Top, rtItem.Width, rtItem.Height);
}
if (item.Config.BorderColor)
{
this.Canvas.strokeStyle = item.Config.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtItem.Left), ToFixedPoint(rtItem.Top), ToFixedRect(rtItem.Width), ToFixedRect(rtItem.Height));
}
this.Canvas.fillStyle = item.Config.Color;
this.Canvas.fillText(text, rtItem.Left+item.Config.Margin.Left, rtItem.Bottom-item.Config.Margin.Bottom );
}
}
//选中的画图工具X轴坐标信息
this.DrawPictureXCoordinate=function(drawPicture, range, option)
{
if (this.IsHScreen) return;
if (!range) return;
if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
this.Canvas.font=this.DrawPicture.Font;
var fontHeight=this.GetFontHeight();
if (range.X)
{
var xRange=range.X;
var xLeft=xRange.Min.X;
var xRight=xRange.Max.X;
if (xLeft<left) xLeft=left;
if (xRight>right) xRight=right;
this.Canvas.fillStyle=this.DrawPicture.BGColor;
this.Canvas.fillRect(xLeft, border.Bottom, xRight-xLeft, fontHeight);
}
for(var i=0;i<range.Points.length;++i)
{
var item=range.Points[i];
if (item.X<left || item.X>right) continue;
var index=parseInt(this.GetXData(item.X));
var kItem=this.GetKItem(index,option);
if (kItem)
{
//var text=IFrameSplitOperator.FormatDateString(kItem.Date,null);
var text=IFrameSplitOperator.FormatTimeString(kItem.Time, "HH:MM");
var textWidth=this.Canvas.measureText(text).width+2;
var textLeft=item.X-textWidth/2;
if (textLeft<left) textLeft=left;
this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
this.Canvas.fillRect(textLeft, border.Bottom, textWidth, fontHeight);
this.Canvas.fillStyle=this.DrawPicture.TextColor;
var yCenter=border.Bottom+fontHeight;
this.Canvas.fillText(text,textLeft+1,yCenter);
}
}
}
this.GetKItem=function(currentIndex,option)
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
if (currentIndex<this.Data.Data.length)
{
return this.Data.Data[currentIndex];
}
else
{
var kItem=this.Data.Data[this.Data.Data.length-1];
var xDatetime=g_MinuteTimeStringData.GetTimeData(option.Symbol);
var index=currentIndex%xDatetime.length;
var timeItem=xDatetime[index];
return { Date:kItem.Date, Time:timeItem };
}
}
this.DrawDayVertical=function(dayItem, x, border)
{
if (!dayItem.BG) return;
var bgItem=dayItem.BG;
var xStart=this.GetXFromIndex(bgItem.Index.Start);
var xEnd=this.GetXFromIndex(bgItem.Index.End);
var maxWidth=xEnd-xStart;
var bgHeight=this.ChartBorder.Bottom;
if (IFrameSplitOperator.IsNumber(bgItem.Height)) bgHeight=bgItem.Height;
if (bgItem.Color)
{
this.Canvas.fillStyle=bgItem.Color;
var rtBG={Left:xStart, Width:maxWidth, Top:border.Bottom, Height: bgHeight };
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
if (IFrameSplitOperator.IsNonEmptyArray(dayItem.AryText)) //[ [{Text:, Color:},], []]
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
var yText=border.Bottom+2;
var lineHeight=this.Canvas.measureText("擎").width+2;
for(var i=0,j=0;i<dayItem.AryText.length;++i)
{
var aryText=dayItem.AryText[i];
var itemWidth=0;
var aryOut=[];
for(j=0;j<aryText.length;++j)
{
var item=aryText[j];
var textWidth=this.Canvas.measureText(item.Text).width;
if (itemWidth+textWidth>maxWidth) break;
var newItem={ Text:item.Text, Width:textWidth, Color:item.Color, Space:item.Space };
itemWidth+=textWidth;
item.Width=textWidth;
if (item.Space>=1) itemWidth+=item.Space;
aryOut.push(newItem);
}
var xText=xStart+(maxWidth-itemWidth)/2;
for(var j=0;j<aryOut.length;++j)
{
var item=aryOut[j];
if (!IFrameSplitOperator.IsNumber(item.Width)) break;
if (item.Color) this.Canvas.fillStyle=item.Color;
else if (dayItem.TextColor) this.Canvas.fillStyle=dayItem.TextColor;
this.Canvas.fillText(item.Text,xText,yText);
xText+=item.Width;
if (item.Space>=1) xText+=item.Space;
}
yText+=lineHeight;
}
}
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false)
{
//计算自定义刻度
if (this.YCustomSplit)
{
if (this.YSplitOperator && this.YSplitOperator.CustomCoordinate)
this.YSplitOperator.CustomCoordinate();
}
return;
}
if (this.XSplitOperator!=null) this.XSplitOperator.Operator();
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
}
this.GetMultiDayXFromIndex=function(index, border)
{
var dayBorder=border.DayBorder;
var minuteIndex=index%this.MinuteCount;
var dayIndex=parseInt(index/this.MinuteCount);
if (dayIndex>=dayBorder.length) dayIndex=dayBorder.length-1;
var client=dayBorder[dayIndex];
var count=this.MinuteCount-1;
if (minuteIndex>=count)
{
return client.RightEx;
}
else
{
var width=(client.RightEx-client.LeftEx);
var offset=client.LeftEx+width*minuteIndex/count;
return offset;
}
}
this.GetXFromIndex=function(index)
{
var count=this.XPointCount-1;
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetMultiDayXFromIndex(index, border);
if (count==1)
{
if (index==0) return border.LeftEx;
else return border.RightEx;
}
else if (count<=0)
{
return border.LeftEx;
}
else if (index>=count)
{
return border.RightEx;
}
else
{
var width=(border.RightEx-border.LeftEx);
var offset=border.LeftEx+width*index/count;
return offset;
}
}
this.GetMultiDayXData=function(x,border)
{
var dayBorder=border.DayBorder;
for(var i=0;i<dayBorder.length;++i)
{
var client=dayBorder[i];
if (x>=client.Left && x<=client.Right)
{
var count=this.MinuteCount-1;
var dayMinuteCount=this.MinuteCount*i;
if (x<=client.LeftEx) return 0+dayMinuteCount;
if (x>=client.RightEx) return count+dayMinuteCount;
var width=client.RightEx-client.LeftEx;
return (x-client.LeftEx)*(count*1.0/width)+dayMinuteCount;
}
}
}
//X坐标转x轴数值
this.GetXData=function(x)
{
var count=this.XPointCount-1;
if (count<0) count=0;
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetMultiDayXData(x, border);
if (x<=border.LeftEx) return 0;
if (x>=border.RightEx) return count;
var width=border.RightEx-border.LeftEx;
return (x-border.LeftEx)*(count*1.0/width);
}
this.DrawCustomHorizontal=function() //Y轴刻度定制显示
{
if (this.IsMinSize) return;
for(var i in this.CustomHorizontalInfo)
{
var item=this.CustomHorizontalInfo[i];
switch(item.Type)
{
case 0:
case 1:
case 10://自定义的
this.DrawCustomItem(item); //自定义刻度
break;
}
}
}
this.GetLeftExtendXFromIndex=function(index, obj)
{
var count=obj.TotalCount-1;
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetLeftExtendMultiDayXFromIndex(index, obj, border);
var left=border.Left;
var width=this.ChartBorder.LeftExtendWidth;
var offset=left+width*index/count;
return offset;
}
this.GetLeftExtendMultiDayXFromIndex=function(index, obj, border)
{
var dayBorder=border.DayBorder;
var client=dayBorder[obj.Index];
var count=obj.TotalCount-1;
var left=client.Left;
var right=client.LeftEx;
var width=right-left;
var offset=left+width*index/count;
return offset;
}
this.GetLeftExtendMultiDayXData=function(x, obj, border)
{
var dayBorder=border.DayBorder;
for(var i=0; i<dayBorder.length; ++i)
{
var client=dayBorder[i];
if (x>=client.Left && x<=client.LeftEx)
{
if (!obj[i]) return null;
var count=obj[i].TotalCount-1;
var left=client.Left;
var right=client.LeftEx;
var width=right-left;
var index=(x-left)*(count*1.0/width);
return { DayIndex:parseInt(i), DataIndex:index };
}
}
}
this.GetLeftExtendXData=function(x, obj)
{
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetLeftExtendMultiDayXData(x, obj, border);
var count=obj.TotalCount-1;
if (count<0) count=0;
var left=border.Left;
var right=border.LeftEx;
if (x<=left) return 0;
if (x>=right) return count;
var width=right-left;
return (x-left)*(count*1.0/width);
}
this.MoveXIndexLeft=function(step, obj)
{
JSConsole.Chart.Log("[MinuteFrame::MoveXIndexLeft] obj ", obj);
if (obj.DataType==2) //多日数据
{
var dayIndex=obj.IndexData.DayIndex;
var dataIndex=obj.IndexData.DataIndex-step;
var itemIndex=-1;
if (obj.IndexData.Type==20) itemIndex=0;
else if (obj.IndexData.Type==10) itemIndex=1;
else if (obj.IndexData.Type==30) itemIndex=2;
else return false;
for(var i=dayIndex, j=itemIndex; i>=0; --i)
{
var dayItem=obj.Data[i];
for(; j>=0; --j)
{
var dataItem=dayItem[j];
if (!dataItem.DayItem || !dataItem.DayItem.Data) continue;
if (dataIndex==null) dataIndex=dataItem.DayItem.Data.length-1;
for(; dataIndex>=0;--dataIndex)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (dataItem.Type==10)
{
var cursorIndex=this.MinuteCount*i+dataIndex;
obj.Point.X=this.GetXFromIndex(cursorIndex);
obj.Point.Y=this.GetYFromData(item.Close);
obj.IndexData.CursorIndex=cursorIndex;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==20)
{
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetLeftExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetLeftExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==30)
{
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetRightExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetRightExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
}
dataIndex=null;
}
j=2;
}
return false;
}
else if (obj.DataType==1) //单日
{
var dayIndex=obj.IndexData.DayIndex;
var dataIndex=obj.IndexData.DataIndex-step;
var itemIndex=-1;
if (obj.IndexData.Type==2) itemIndex=0;
else if (obj.IndexData.Type==1) itemIndex=1;
else if (obj.IndexData.Type==3) itemIndex=2;
else return false;
for(var i=itemIndex; i>=0; --i)
{
var dataItem=obj.Data[i];
if (!dataItem || !dataItem.DayItem || !dataItem.DayItem.Data) continue;
if (dataIndex==null) dataIndex=dataItem.DayItem.Data.length-1;
for(; dataIndex>=0;--dataIndex)
{
if (dataItem.Type==1)
{
var offset=dataItem.DayItem.DataOffset;
var item=dataItem.DayItem.Data[dataIndex+offset];
if (!item) continue;
var cursorIndex=dataIndex;
obj.Point.X=this.GetXFromIndex(cursorIndex);
obj.Point.Y=this.GetYFromData(item.Close);
obj.IndexData.CursorIndex=cursorIndex;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==2)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetLeftExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetLeftExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==3)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetRightExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetRightExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
}
dataIndex=null;
}
}
}
this.MoveXIndexRight=function(step, obj)
{
JSConsole.Chart.Log("[MinuteFrame::MoveXIndexRight] obj ", obj);
if (obj.DataType==2) //多日数据
{
var dayIndex=obj.IndexData.DayIndex;
var dataIndex=obj.IndexData.DataIndex+step;
var itemIndex=-1;
if (obj.IndexData.Type==20) itemIndex=0;
else if (obj.IndexData.Type==10) itemIndex=1;
else if (obj.IndexData.Type==30) itemIndex=2;
else return false;
for(var i=dayIndex, j=itemIndex; i<obj.Data.length; ++i)
{
var dayItem=obj.Data[i];
for(; j<3; ++j)
{
var dataItem=dayItem[j];
if (!dataItem.DayItem || !dataItem.DayItem.Data) continue;
if (dataIndex==null) dataIndex=0;
for(; dataIndex<dataItem.DayItem.Data.length;++dataIndex)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (dataItem.Type==10)
{
var cursorIndex=this.MinuteCount*i+dataIndex;
obj.Point.X=this.GetXFromIndex(cursorIndex);
obj.Point.Y=this.GetYFromData(item.Close);
obj.IndexData.CursorIndex=cursorIndex;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==20)
{
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetLeftExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetLeftExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==30)
{
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetRightExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetRightExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
}
dataIndex=null;
}
j=0;
}
return false;
}
else if (obj.DataType==1) //单日
{
var dayIndex=obj.IndexData.DayIndex;
var dataIndex=obj.IndexData.DataIndex+step;
var itemIndex=-1;
if (obj.IndexData.Type==2) itemIndex=0;
else if (obj.IndexData.Type==1) itemIndex=1;
else if (obj.IndexData.Type==3) itemIndex=2;
else return false;
for(var i=itemIndex; i<obj.Data.length; ++i)
{
var dataItem=obj.Data[i];
if (!dataItem.DayItem || !dataItem.DayItem.Data) continue;
if (dataIndex==null) dataIndex=0;
for(; dataIndex<dataItem.DayItem.Data.length;++dataIndex)
{
if (dataItem.Type==1)
{
if (dataIndex>=this.XPointCount) break;
var offset=dataItem.DayItem.DataOffset;
var item=dataItem.DayItem.Data[dataIndex+offset];
if (!item) continue;
var cursorIndex=dataIndex;
obj.Point.X=this.GetXFromIndex(cursorIndex);
obj.Point.Y=this.GetYFromData(item.Close);
obj.IndexData.CursorIndex=cursorIndex;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==2)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetLeftExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetLeftExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
else if (dataItem.Type==3)
{
var item=dataItem.DayItem.Data[dataIndex];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
obj.Point.X=this.GetRightExtendXFromIndex(dataIndex,dataItem.DayItem);
obj.Point.Y=this.GetRightExtendYFromData(item.Price);
obj.IndexData.CursorIndex=-1;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=dataIndex;
obj.IndexData.Type=dataItem.Type;
return true;
}
}
dataIndex=null;
}
}
}
//获取有效数据
this.GetLeftExtendXValidData=function(x, obj)
{
var border=this.ChartBorder.GetBorder();
if (border.DayBorder)
{
var indexData=this.GetLeftExtendXData(x, obj.Data);
if (!indexData) return false;
var index=parseInt(indexData.DataIndex.toFixed(0));
var dayData=obj.Data[indexData.DayIndex];
if (index>=0 && index<dayData.Data.length)
{
var item=dayData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
obj.IndexData.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=dayData.Data.length) index=dayData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=dayData.Data[i];
if (item && IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0) return false;
obj.IndexData.DataIndex=findIndex;
obj.IndexData.Point.X=this.GetLeftExtendXFromIndex(findIndex, dayData); //调整X轴坐标
JSConsole.Chart.Log(`[MinuteFrame::GetLeftExtendXValidData] DayIndex:${obj.IndexData.DayIndex}, Type:${obj.IndexData.Type}, x:${x}=>${obj.IndexData.Point.X}, index:${index}=>${findIndex}`);
return true;
}
else
{
var index=this.GetLeftExtendXData(x, obj.Data);
index=parseInt(index.toFixed(0));
if (index>=0 && index<obj.Data.Data.length)
{
var item=obj.Data.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
obj.IndexData.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=obj.Data.Data.length) index=obj.Data.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=obj.Data.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0)
{
for(var i=index+1; i<obj.Data.Data.length;++i)
{
var item=obj.Data.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
}
if (findIndex<0) return false;
obj.IndexData.DataIndex=findIndex;
obj.IndexData.Point.X=this.GetLeftExtendXFromIndex(findIndex, obj.Data); //调整X轴坐标
JSConsole.Chart.Log(`[MinuteFrame::GetLeftExtendXValidData] DayIndex:${obj.IndexData.DayIndex}, Type:${obj.IndexData.Type}, x:${x}=>${obj.IndexData.Point.X}, index:${index}=>${findIndex}`);
return true;
}
}
this.GetRightExtendXValidData=function(x, obj)
{
var border=this.ChartBorder.GetBorder();
if (border.DayBorder)
{
var indexData=this.GetRightExtendXData(x, obj.Data);
if (!indexData) return false;
var index=parseInt(indexData.DataIndex.toFixed(0));
var dayData=obj.Data[indexData.DayIndex];
if (index>=0 && index<dayData.Data.length)
{
var item=dayData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
obj.IndexData.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=dayData.Data.length) index=dayData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=dayData.Data[i];
if (item && IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0) return false;
obj.IndexData.DataIndex=findIndex;
obj.IndexData.Point.X=this.GetRightExtendXFromIndex(findIndex, dayData); //调整X轴坐标
JSConsole.Chart.Log(`[MinuteFrame::GetRightExtendXValidData] DayIndex:${obj.IndexData.DayIndex}, Type:${obj.IndexData.Type}, x:${x}=>${obj.IndexData.Point.X}, index:${index}=>${findIndex}`);
return true;
}
else
{
if (!obj || !obj.Data) return false;
var index=this.GetRightExtendXData(x, obj.Data);
index=parseInt(index.toFixed(0));
if (index>=0 && index<obj.Data.Data.length)
{
var item=obj.Data.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
obj.IndexData.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=obj.Data.Data.length) index=obj.Data.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=obj.Data.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0)
{
for(var i=index+1; i<obj.Data.Data.length;++i)
{
var item=obj.Data.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
}
if (findIndex<0) return false;
obj.IndexData.DataIndex=findIndex;
obj.IndexData.Point.X=this.GetRightExtendXFromIndex(findIndex, obj.Data); //调整X轴坐标
JSConsole.Chart.Log(`[MinuteFrame::GetRightExtendXValidData] DayIndex:${obj.IndexData.DayIndex}, Type:${obj.IndexData.Type}, x:${x}=>${obj.IndexData.Point.X}, index:${index}=>${findIndex}`);
return true;
}
}
this.GetLeftExtendYFromData=function(value,isLimit,obj)
{
if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);
var range=obj.Range;
var border=this.ChartBorder.GetBorder();
var height=border.BottomEx-border.TopEx;
var offset=height*(value-range.Min)/(range.Max-range.Min);
return border.BottomEx-offset;
}
this.GetLeftExtendYData=function(y, isLimit, obj)
{
if (!obj || !obj.Range) return this.GetYData(y,isLimit);
var range=obj.Range;
var border=this.ChartBorder.GetBorder();
var height=border.BottomEx-border.TopEx;
return (border.BottomEx-y)/height*(range.Max-range.Min)+range.Min;
}
this.GetRightExtendMultiDayXFromIndex=function(index, obj, border)
{
var dayBorder=border.DayBorder;
var client=dayBorder[obj.Index];
var count=obj.TotalCount-1;
var left=client.RightEx;
var right=client.Right;
var width=right-left;
var offset=left+width*index/count;
return offset;
}
this.GetRightExtendXFromIndex=function(index, obj)
{
var count=obj.TotalCount-1;
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetRightExtendMultiDayXFromIndex(index, obj, border);
var left=border.RightEx;
var width=this.ChartBorder.RightExtendWidth;
var offset=left+width*index/count;
return offset;
}
this.GetRightExtendYFromData=function(value,isLimit,obj)
{
return this.GetLeftExtendYFromData(value,isLimit,obj)
}
this.GetRightExtendYData=function(y, isLimit, obj)
{
if (!obj || !obj.Range) return this.GetYData(y,isLimit);
return this.GetLeftExtendYData(y, isLimit, obj);
}
this.GetRightExtendMultiDayXData=function(x, obj, border)
{
var dayBorder=border.DayBorder;
for(var i=0; i<dayBorder.length; ++i)
{
var client=dayBorder[i];
if (x>=client.RightEx && x<=client.Right)
{
if (!obj[i]) return null;
var count=obj[i].TotalCount-1;
var left=client.RightEx;
var right=client.Right;
var width=right-left;
var index=(x-left)*(count*1.0/width);
return { DayIndex:parseInt(i), DataIndex:index };
}
}
return null;
}
this.GetRightExtendXData=function(x, obj)
{
var border=this.ChartBorder.GetBorder();
if (border.DayBorder) return this.GetRightExtendMultiDayXData(x, obj, border);
var count=obj.TotalCount-1;
if (count<0) count=0;
var left=border.RightEx;
var right=border.Right;
if (x<=left) return 0;
if (x>=right) return count;
var width=right-left;
return (x-left)*(count*1.0/width);
}
}
//走势图 横屏框架
function MinuteHScreenFrame()
{
this.newMethod=MinuteFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="MinuteHScreenFrame";
this.IsHScreen=true; //是否是横屏
//画标题背景色
this.DrawTitleBG=function()
{
if (this.ChartBorder.TitleHeight<=0) return;
var border=this.ChartBorder.GetHScreenBorder();
var left=ToFixedPoint(border.RightEx);
var top=ToFixedPoint(border.Top);
var bottom=ToFixedPoint(border.Bottom);
var width=this.ChartBorder.TitleHeight;
var height=bottom-top;
this.Canvas.fillStyle=this.TitleBGColor;
this.Canvas.fillRect(left,top,width,height);
}
this.DrawToolbar=function()
{
return;
}
//画集合竞价背景
this.DrawBeforeDataBG=function()
{
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder)
{
this.DrawMultiDayBeforeDataBG(border);
return;
}
if (this.ChartBorder.LeftExtendWidth<10 && this.ChartBorder.RightExtendWidth<10) return;
var left=ToFixedPoint(border.Left);
var right=ToFixedPoint(border.Right);
this.Canvas.fillStyle=this.BeforeBGColor;
if (this.ChartBorder.LeftExtendWidth>10)
{
var top=ToFixedPoint(border.Top);
var bottom=ToFixedPoint(border.TopEx);
var width=right-left;
var height=bottom-top;
this.Canvas.fillRect(left,top,width,height);
}
if (this.ChartBorder.RightExtendWidth>10)
{
var top=border.BottomEx;
var bottom=border.Bottom;
var width=right-left;
var height=bottom-top;
this.Canvas.fillRect(left,top,width,height);
}
}
this.DrawMultiDayBeforeDataBG=function(border)
{
var dayBorder=border.DayBorder;
var left=ToFixedPoint(border.Left);
var right=ToFixedPoint(border.Right);
var width=right-left;
this.Canvas.strokeStyle=this.MultiDayBorderPen;
for(var i=0; i<dayBorder.length; ++i)
{
var drawCount=0;
var item=dayBorder[i];
var top=ToFixedPoint(item.Top);
var bottom=ToFixedPoint(item.TopEx);
var height=bottom-top;
if (height>3) //盘前
{
this.Canvas.fillStyle=this.BeforeBGColor;
this.Canvas.fillRect(left,top,width,height);
++drawCount;
}
var top=ToFixedPoint(item.BottomEx);
var bottom=ToFixedPoint(item.Bottom);
var height=bottom-top;
if (height>3) //盘后
{
this.Canvas.fillStyle=this.AfterBGColor;
this.Canvas.fillRect(left,top,width,height);
++drawCount;
}
if (drawCount==2 && i!=dayBorder.length-1)
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,bottom);
this.Canvas.lineTo(right,bottom);
this.Canvas.stroke();
}
}
}
//Y坐标转y轴数值
this.GetYData=function(x)
{
var border=this.ChartBorder.GetHScreenBorder();
if (x<border.LeftEx) return this.HorizontalMin;
if (x>border.RightEx) return this.HorizontalMax;
var width=border.RightEx-border.LeftEx;
return (x-border.LeftEx)/width*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
this.GetMultiDayXData=function(y,border)
{
var dayBorder=border.DayBorder;
for(var i=0;i<dayBorder.length;++i)
{
var client=dayBorder[i];
if (y>=client.Top && y<=client.Bottom)
{
var count=this.MinuteCount-1;
var dayMinuteCount=this.MinuteCount*i;
if (y<=client.TopEx) return 0+dayMinuteCount;
if (y>=client.BottomEx) return count+dayMinuteCount;
var width=client.BottomEx-client.TopEx;
return (y-client.TopEx)*(count*1.0/width)+dayMinuteCount;
}
}
}
//X坐标转x轴数值
this.GetXData=function(y)
{
var count=this.XPointCount-1;
if (count<0) count=0;
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetMultiDayXData(y, border);
if (y<=border.TopEx) return 0;
if (y>=border.BottomEx) return count;
var height=(border.BottomEx-border.TopEx);
return (y-border.TopEx)*(count*1.0/height);
}
this.GetMultiDayXFromIndex=function(index, border)
{
var dayBorder=border.DayBorder;
var minuteIndex=index%this.MinuteCount;
var dayIndex=parseInt(index/this.MinuteCount);
if (dayIndex>=dayBorder.length) dayIndex=dayBorder.length-1;
var client=dayBorder[dayIndex];
var count=this.MinuteCount-1;
if (minuteIndex>=count)
{
return client.BottomEx;
}
else
{
var width=(client.BottomEx-client.TopEx);
var offset=client.TopEx+width*minuteIndex/count;
return offset;
}
}
this.GetXFromIndex=function(index)
{
var count=this.XPointCount-1;
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetMultiDayXFromIndex(index, border);
if (count==1)
{
if (index==0) return border.TopEx;
else return border.BottomEx;
}
else if (count<=0)
{
return border.TopEx;
}
else if (index>=count)
{
return border.BottomEx;
}
else
{
var height=border.BottomEx-border.TopEx;
var offset=border.TopEx+height*index/count;
return offset;
}
}
this.GetYFromData=function(value)
{
var border=this.ChartBorder.GetHScreenBorder();
if(value<=this.HorizontalMin) return border.LeftEx;
if(value>=this.HorizontalMax) return border.RightEx;
var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return border.LeftEx+width;
}
this.DrawVolTitle=function(symbol)
{
if (!MARKET_SUFFIX_NAME.IsShowMinuteVolTitle(symbol)) return;
if (this.Identify==1) //显示"成交量"
{
var pixelRatio=GetDevicePixelRatio();
var left=this.ChartBorder.GetRight()-2*pixelRatio;
var top=this.ChartBorder.GetTopEx()+2*pixelRatio;
var xText=left,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
var x=this.YInsideOffset,y=0;
this.Canvas.textAlign='left';
this.Canvas.textBaseline='top';
if (g_JSChartResource.Minute.VolBarColor || g_JSChartResource.Minute.VolTitleColor)
{
if (g_JSChartResource.Minute.VolBarColor) this.Canvas.fillStyle=g_JSChartResource.Minute.VolBarColor
else this.Canvas.fillStyle=g_JSChartResource.Minute.VolTitleColor;
var languageID=this.YSplitOperator.LanguageID;
var text=g_JSChartLocalization.GetText('MVol-Vol',languageID);
this.Canvas.fillText(text,x,y);
x+=this.Canvas.measureText(text).width;
x+=6*GetDevicePixelRatio();
}
if (this.IsShowPositionTitle)
{
text=g_JSChartLocalization.GetText('MVol-Position',languageID);
this.Canvas.fillStyle=g_JSChartResource.Minute.PositionColor;
this.Canvas.fillText(text,x,y);
}
this.Canvas.restore();
}
}
//画Y轴
this.DrawHorizontal=function()
{
var border=this.ChartBorder.GetHScreenBorder();
var top=border.Top;
var bottom=border.Bottom;
var left=border.Left;
var right=border.Right;
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var yPrev=null; //上一个坐标y的值
for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从左往右画分割线
{
var item=this.HorizontalInfo[i];
var y=this.GetYFromData(item.Value);
if (y!=null && Math.abs(y-yPrev)<this.MinYDistance) continue; //两个坐标在近了 就不画了
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(y),top);
this.Canvas.lineTo(ToFixedPoint(y),bottom);
this.Canvas.stroke();
if (y >= right - 2)
{
this.Canvas.textBaseline = 'top';
y = right;
}
else if (y <= left + 2)
{
this.Canvas.textBaseline = 'bottom';
y=left;
if (y != null && Math.abs(y - yPrev) < 2*this.MinYDistance) continue; //两个坐标在近了 就不画了
}
else
{
this.Canvas.textBaseline = "middle";
}
//坐标信息 左边 间距小于10 不画坐标
if (item.Message[0]!=null && borderTop>10)
{
if (item.Font!=null) this.Canvas.font=item.Font;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="right";
var xText=y,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[0], -2, 0);
this.Canvas.restore();
}
//坐标信息 右边 间距小于10 不画坐标
if (item.Message[1]!=null && borderBottom>10)
{
if (item.Font!=null) this.Canvas.font=item.Font;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="left";
var xText=y,yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[1], 2, 0);
this.Canvas.restore();
}
yPrev=y;
}
}
this.DrawInsideClientHorizontal=function()
{
var border=this.GetBorder();
var left=border.Left;
var right=border.Right;
var bottom=border.BottomEx;
var top=border.TopEx;
var pixelTatio = GetDevicePixelRatio();
var yPrev = null; //上一个坐标y的值
var yInsideText=null;
for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线
{
var item = this.HorizontalInfo[i];
if (!item || !item.Message[2] || !item.Message[3]) continue;
var y = this.GetYFromData(item.Value);
if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y >= right - 2)
{
this.Canvas.textBaseline = 'top';
y = right;
}
else if (y <= left + 2)
{
this.Canvas.textBaseline = 'bottom';
y=left;
if (y != null && Math.abs(y - yPrev) < 2*this.MinYDistance) continue; //两个坐标在近了 就不画了
}
else
{
this.Canvas.textBaseline = "middle";
}
if (item.Message[2])
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
var xText=y,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[2], 2, 0);
this.Canvas.restore();
}
if (item.Message[3])
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
var xText=y,yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[3], -2, 0);
this.Canvas.restore();
}
yPrev = y;
}
}
//画X轴
this.DrawVertical=function()
{
var border=this.ChartBorder.GetHScreenBorder();
var left=border.Left;
var right=border.Right;
var bottom=border.Bottom;
var xPrev=null; //上一个坐标x的值
for(var i in this.VerticalInfo)
{
var x=this.GetXFromIndex(this.VerticalInfo[i].Value);
if (x>bottom) break;
if (xPrev!=null && Math.abs(x-xPrev)<this.MinXDistance) continue;
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(x));
this.Canvas.lineTo(right,ToFixedPoint(x));
this.Canvas.stroke();
if (this.VerticalInfo[i].Message[0]!=null)
{
if (this.VerticalInfo[i].Font!=null)
this.Canvas.font=this.VerticalInfo[i].Font;
this.Canvas.fillStyle=this.VerticalInfo[i].TextColor;
var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width;
if (x<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
}
else if ((x + testWidth / 2) >= this.ChartBorder.GetChartHeight())
{
this.Canvas.textAlign = "right";
this.Canvas.textBaseline = "top";
}
else
{
this.Canvas.textAlign="center";
this.Canvas.textBaseline="top";
}
var xText=left,yText=x;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.VerticalInfo[i].Message[0], 0, 0);
this.Canvas.restore();
}
xPrev=x;
}
}
//Y刻度画在左边内部
this.DrawInsideHorizontal = function ()
{
if (this.IsMinSize) return;
if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;
this.DrawInsideClientHorizontal();
var border=this.ChartBorder.GetHScreenBorder();
var left = border.Left;
var right = border.RightEx;
var top=border.Top;
var bottom=border.Bottom;
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var titleHeight = this.ChartBorder.TitleHeight;
var pixelTatio = GetDevicePixelRatio();
if ( (borderTop<10*pixelTatio && this.IsShowYText[0]===true) || (borderBottom<10*pixelTatio && this.IsShowYText[1]===true) )
{
var pixelTatio = GetDevicePixelRatio();
var yPrev = null; //上一个坐标y的值
var yInsideText=null;
for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线
{
var item = this.HorizontalInfo[i];
var y = this.GetYFromData(item.Value);
if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了
//坐标信息 左边 间距小于10 画在内部
if (item.Message[0] != null && borderTop < 10*pixelTatio && this.IsShowYText[0]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
else this.Canvas.textBaseline = "middle";
var textObj={ X:left, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[0]}} ;
var xText=y,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[0], 2*pixelTatio, 0);
this.Canvas.restore();
if (yInsideText==null || yInsideText<xText)
{
this.YInsideOffset=this.Canvas.measureText(item.Message[0]).width+4*GetDevicePixelRatio();
yInsideText=xText;
}
}
if (item.Message[1] != null && borderBottom < 10*pixelTatio && this.IsShowYText[1]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
else this.Canvas.textBaseline = "middle";
var textWidth = this.Canvas.measureText(item.Message[1]).width;
var textObj={ X:right-textWidth, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[1]}} ;
var xText=y,yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[1], -2*pixelTatio, 0);
this.Canvas.restore();
}
yPrev = y;
}
}
}
this.GetLeftExtendXFromIndex=function(index, obj)
{
var count=obj.TotalCount-1;
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetLeftExtendMultiDayXFromIndex(index, obj, border);
var left=border.Top;
var width=this.ChartBorder.LeftExtendWidth;
var offset=left+width*index/count;
return offset;
}
this.GetLeftExtendMultiDayXFromIndex=function(index, obj, border)
{
var dayBorder=border.DayBorder;
var client=dayBorder[obj.Index];
var count=obj.TotalCount-1;
var left=client.Top;
var right=client.TopEx;
var width=right-left;
var offset=left+width*index/count;
return offset;
}
this.GetLeftExtendMultiDayXData=function(y, obj, border)
{
var dayBorder=border.DayBorder;
for(var i=0; i<dayBorder.length; ++i)
{
var client=dayBorder[i];
if (y>=client.Top && y<=client.TopEx)
{
if (!obj[i]) return null;
var count=obj[i].TotalCount-1;
var left=client.Top;
var right=client.TopEx;
var width=right-left;
var index=(y-left)*(count*1.0/width);
return { DayIndex:parseInt(i), DataIndex:index };
}
}
return null;
}
this.GetLeftExtendXData=function(y, obj)
{
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetLeftExtendMultiDayXData(y, obj, border);
var count=obj.TotalCount-1;
if (count<0) count=0;
var left=border.Top;
var right=border.TopEx;
if (y<=left) return 0;
if (y>=right) return count;
var width=right-left;
return (y-left)*(count*1.0/width);
}
this.GetLeftExtendYFromData=function(value,isLimit,obj)
{
if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);
var range=obj.Range;
var border=this.ChartBorder.GetHScreenBorder();
var width=border.RightEx-border.LeftEx;
var offset=width*(value-range.Min)/(range.Max-range.Min);
return border.LeftEx+offset;
}
this.GetLeftExtendYData=function(x, isLimit, obj)
{
if (!obj || !obj.Range) return this.GetYData(y,isLimit);
var range=obj.Range;
var border=this.ChartBorder.GetHScreenBorder();
var width=border.RightEx-border.LeftEx;
return (x-border.LeftEx)/width*(range.Max-range.Min)+range.Min;
}
this.GetRightExtendMultiDayXFromIndex=function(index, obj, border)
{
var dayBorder=border.DayBorder;
var client=dayBorder[obj.Index];
var count=obj.TotalCount-1;
var left=client.BottomEx;
var right=client.Bottom;
var width=right-left;
var offset=left+width*index/count;
return offset;
}
this.GetRightExtendXFromIndex=function(index, obj)
{
var count=obj.TotalCount-1;
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetRightExtendMultiDayXFromIndex(index, obj, border);
var left=border.BottomEx;
var width=this.ChartBorder.RightExtendWidth;
var offset=left+width*index/count;
return offset;
}
this.GetRightExtendMultiDayXData=function(y, obj, border)
{
var dayBorder=border.DayBorder;
for(var i=0; i<dayBorder.length; ++i)
{
var client=dayBorder[i];
if (y>=client.BottomEx && y<=client.Bottom)
{
if (!obj[i]) return null;
var count=obj[i].TotalCount-1;
var left=client.BottomEx;
var right=client.Bottom;
var width=right-left;
var index=(y-left)*(count*1.0/width);
return { DayIndex:parseInt(i), DataIndex:index };
}
}
return null;
}
this.GetRightExtendXData=function(y, obj)
{
var border=this.ChartBorder.GetHScreenBorder();
if (border.DayBorder) return this.GetRightExtendMultiDayXData(y, obj, border);
var count=obj.TotalCount-1;
if (count<0) count=0;
var left=border.BottomEx;
var right=border.Bottom;
if (y<=left) return 0;
if (y>=right) return count;
var width=right-left;
return (y-left)*(count*1.0/width);
}
this.GetRightExtendYFromData=function(value,isLimit,obj)
{
if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);
return this.GetLeftExtendYFromData(value,isLimit,obj);
}
this.DrawNightDayBG=function()
{
if (this.DayCount!=1) return;
if (!this.HQChart) return;
if (!this.HQChart.EnableNightDayBG) return;
var symbol=this.HQChart.Symbol;
if (!symbol) return;
var xIndex=-1;
//获取夜盘和日期的分界线X索引位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_MINUTE_NIGHT_DAY_X_INDEX)
if (!event || !event.Callback) return;
var sendData={ Symbol:symbol, XIndex:xIndex, MinuteTimeStringData:g_MinuteTimeStringData };
event.Callback(event,sendData,this);
xIndex=sendData.XIndex;
if (xIndex<0) return;
var border=this.ChartBorder.GetHScreenBorder();
var y=this.GetXFromIndex(xIndex);
var rtNight={ Left: border.Left, Top:border.Top, Right:border.RightEx, Bottom:y };
rtNight.Width=rtNight.Right-rtNight.Left;
rtNight.Height=rtNight.Bottom-rtNight.Top;
this.Canvas.fillStyle = this.NightDayConfig.NightBGColor;
this.Canvas.fillRect(rtNight.Left, rtNight.Top, rtNight.Width, rtNight.Height);
if (this.Identify!=0) return;
//显示 日盘夜盘文字
this.Canvas.font=this.NightDayConfig.Font;
this.Canvas.textBaseline = "bottom";
this.Canvas.textAlign = 'left';
var aryTitle=[{ Title:"夜盘", Position:1, Config:this.NightDayConfig.Night }, { Title:"日盘", Position:0,Config:this.NightDayConfig.Day }];
var textHeight= this.Canvas.measureText("擎").width;
for(var i=0;i<aryTitle.length;++i)
{
var item=aryTitle[i];
var text=g_JSChartLocalization.GetText(item.Title,this.HQChart.LanguageID);
var testWidth = this.Canvas.measureText(text).width;
var rtItem=
{
Height:testWidth+item.Config.Margin.Left+item.Config.Margin.Right,
Width:textHeight+item.Config.Margin.Top+item.Config.Margin.Bottom,
Left:border.Left
};
rtItem.Right=rtItem.Left+rtItem.Width;
if (item.Position===1)
{
rtItem.Bottom=y-1;
rtItem.Top=rtItem.Bottom-rtItem.Height;
}
else
{
rtItem.Top=y+1;
rtItem.Bottom=rtItem.Top+rtItem.Height;
}
if (item.Config.BGColor)
{
this.Canvas.fillStyle = item.Config.BGColor;
this.Canvas.fillRect(rtItem.Left, rtItem.Top, rtItem.Width, rtItem.Height);
}
if (item.Config.BorderColor)
{
this.Canvas.strokeStyle = item.Config.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtItem.Left), ToFixedPoint(rtItem.Top), ToFixedRect(rtItem.Width), ToFixedRect(rtItem.Height));
}
this.Canvas.fillStyle = item.Config.Color;
var xText=rtItem.Left;
var yText=rtItem.Top;
this.Canvas.save();
this.Canvas.translate(xText,yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text, item.Config.Margin.Left, -item.Config.Margin.Bottom);
this.Canvas.restore();
}
}
}
function OverlayMinuteFrame()
{
this.newMethod=MinuteFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="OverlayMinuteFrame";
this.IsShow=true; //坐标是否显示
this.IsShareY=false; //使用和主框架公用Y轴
this.IsCalculateYMaxMin=true; //是否计算Y最大最小值
this.IsShowMainFrame=0; //是否显示在主框架坐标上 1=左边 2=右边
this.Draw=function()
{
this.SplitXYCoordinate();
if (this.IsShow)
{
}
this.SizeChange=false;
this.XYSplit=false;
this.XSplit=false;
this.YCustomSplit=false; //自定义Y轴分割线
}
this.DrawToolbar=function()
{
return;
}
this.GetScaleTextWidth=function()
{
return { TextWidth:0 };
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false) return;
if (this.IsShareY) //和主图指标共享Y轴坐标
{
this.HorizontalMax=this.MainFrame.HorizontalMax;
this.HorizontalMin=this.MainFrame.HorizontalMin;
this.HorizontalInfo=[];
for(var i=0; i<this.MainFrame.HorizontalInfo.length; ++i)
{
var item=this.MainFrame.HorizontalInfo[i];
this.HorizontalInfo.push(item);
}
}
else //独立Y轴坐标
{
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
}
// if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
}
}
function OverlayMinuteHScreenFrame()
{
this.newMethod=MinuteHScreenFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="OverlayMinuteHScreenFrame";
this.IsShow=true; //坐标是否显示
this.Draw=function()
{
this.SplitXYCoordinate();
if (this.IsShow)
{
}
this.SizeChange=false;
this.XYSplit=false;
this.XSplit=false;
this.YCustomSplit=false; //自定义Y轴分割线
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false) return;
if (this.IsShareY) //和主图指标共享Y轴坐标
{
this.HorizontalMax=this.MainFrame.HorizontalMax;
this.HorizontalMin=this.MainFrame.HorizontalMin;
this.HorizontalInfo=[];
for(var i in this.MainFrame.HorizontalInfo)
{
var item=this.MainFrame.HorizontalInfo[i];
this.HorizontalInfo.push(item);
}
}
else //独立Y轴坐标
{
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
}
// if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
}
}
//K线框架
function KLineFrame()
{
this.newMethod=AverageWidthFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='KLineFrame';
this.ToolbarID=Guid(); //工具条Div id
this.ModifyIndex=g_JSChartResource.KLineToolbar.ModifyIndex; //是否显示'改参数'菜单
this.ChangeIndex=g_JSChartResource.KLineToolbar.ChangeIndex; //是否显示'换指标'菜单
this.CloseIndex=g_JSChartResource.KLineToolbar.CloseIndex; //是否显示'关闭指标窗口'菜单
this.OverlayIndex=g_JSChartResource.KLineToolbar.OverlayIndex; //是否显示叠加指标
this.MaxMinWindow=g_JSChartResource.KLineToolbar.MaxMinWindow;
this.TitleWindow=g_JSChartResource.KLineToolbar.TitleWindow;
this.ExportData=g_JSChartResource.KLineToolbar.ExportData; //是否显示'导出数据'菜单
this.SelBorderColor=g_JSChartResource.SelFrameBorderColor;
this.ModifyIndexEvent; //改参数 点击事件
this.ToolbarRect=null; //保存工具条的位置
this.ReDrawToolbar=false;
this.LastCalculateStatus={ Width:0, XPointCount:0 }; //最后一次计算宽度的状态
this.CustomHorizontalInfo=[]; //定制Y轴刻度
this.IsDrawTitleBG=false;
this.IsShowNameArrow=false;
this.CustomVerticalInfo=[]; //定制X轴刻度 Type:0, Date:, Time: , Line:{ Color:线段颜色, Type:线段类型 0 直线 1 虚线 }
// Type:1, Space: 第几个空白间距, Line:{ Color:线段颜色, Type:线段类型 0 直线 1 虚线 }
this.DrawCustomVerticalEvent;
this.RightSpaceCount=0;
this.Logarithmic=null; //{Up:上部 , Donw:下部 , OpenPrice:第一个开盘价}
this.CustomToolbar=[]; //自定义toolbar按钮 { ID:, Html:, Click } 2.0版本 { ID, Style:{ 见 g_JSChartResource.Buttons.CloseWindow}}
this.ToolbarType=0;
this.DrawToolbar=function()
{
if (this.ToolbarButtonStyle==1) return;
if (g_JSChartResource.IsDOMFrameToolbar===true) return;
if (typeof($)=="undefined") return;
if (!this.ChartBorder.UIElement || !this.ChartBorder.UIElement.parentNode) return;
var divToolbar=document.getElementById(this.ToolbarID);
if (divToolbar && this.SizeChange==false && this.ReDrawToolbar==false) return;
if (!divToolbar)
{
divToolbar=document.createElement("div");
divToolbar.className='klineframe-toolbar';
divToolbar.id=this.ToolbarID;
divToolbar.oncontextmenu = function() { return false;}; //屏蔽右键系统菜单
//为divToolbar添加属性identify
divToolbar.setAttribute("identify",this.Identify.toString());
this.ChartBorder.UIElement.parentNode.appendChild(divToolbar);
}
if (!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex && !this.CloseIndex && !IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar))
{
if (divToolbar.style.display!='none')
divToolbar.style.display='none';
return;
}
//使用外城div尺寸 画图尺寸是被放大的
var pixelTatio = GetDevicePixelRatio();
var chartWidth=parseInt(this.ChartBorder.UIElement.parentElement.style.width.replace("px",""));
var chartHeight=parseInt(this.ChartBorder.UIElement.parentElement.style.height.replace("px",""));
//JSConsole.Chart.Log('[KLineFrame::DrawToolbar] ',chartWidth,chartHeight,pixelTatio);
var toolbarWidth=100;
var toolbarHeight=this.ChartBorder.GetTitleHeight();
var left=chartWidth-(this.ChartBorder.Right/pixelTatio)-toolbarWidth;
var top=this.ChartBorder.GetTop()/pixelTatio;
if (this.ToolbarRect)
{
//尺寸变动移动才重新设置DOM
if (this.ToolbarRect.Left==left && this.ToolbarRect.Top==top &&
this.ToolbarRect.Width==toolbarWidth && this.ToolbarRect.Height==toolbarHeight/pixelTatio)
{
return;
}
}
this.ToolbarRect={ Left:left, Top:top, Width:toolbarWidth, Height:toolbarHeight/pixelTatio };
const modifyButton=`<span class='index_param icon iconfont icon-index_param' id='modifyindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='调整指标参数'></span>`;
const changeButton=`<span class='index_change icon iconfont icon-change_index' id='changeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='切换指标'></span>`;
const overlayButton=`<span class='index_overlay icon iconfont icon-overlay_index' id='overlayindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='叠加指标'></span>`;
const closeButton=`<span class='index_close icon iconfont icon-close' id='closeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='关闭指标窗口'></span>`;
var spanIcon=modifyButton+changeButton+overlayButton;
if (this.Identify!==0 && this.CloseIndex) //第1个窗口不能关闭
{
spanIcon+=closeButton;
}
if (IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar))
{
for(var i=0;i<this.CustomToolbar.length;++i)
{
var item=this.CustomToolbar[i];
spanIcon+=item.Html;
}
}
//var scrollPos=GetScrollPosition();
//left = left+scrollPos.Left;
//top = top+scrollPos.Top;
divToolbar.style.left = left + "px";
divToolbar.style.top = top + "px";
divToolbar.style.width=toolbarWidth+"px"; //宽度先不调整吧
divToolbar.style.height=(toolbarHeight/pixelTatio)+'px'; //只调整高度
divToolbar.innerHTML=spanIcon;
var chart=this.ChartBorder.UIElement.JSChartContainer;
var identify=this.Identify;
if (!this.ModifyIndex) //隐藏'改参数'
$("#"+divToolbar.id+" .index_param").hide();
else if (typeof(this.ModifyIndexEvent)=='function') //绑定点击事件
$("#"+divToolbar.id+" .index_param").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify
},this.ModifyIndexEvent);
if (!this.ChangeIndex) //隐藏'换指标'
{
$("#"+divToolbar.id+" .index_change").hide();
}
else if (typeof(this.ChangeIndexEvent)=='function')
{
$("#"+divToolbar.id+" .index_change").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify,
IsOverlay:false
},this.ChangeIndexEvent);
}
if (!this.OverlayIndex)
{
$("#"+divToolbar.id+" .index_overlay").hide();
}
else
{
$("#"+divToolbar.id+" .index_overlay").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify,
IsOverlay:true
},this.ChangeIndexEvent);
}
$("#"+divToolbar.id+" .index_close").click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify
},
function(event)
{
var hqChart=event.data.Chart;
var id=event.data.Identify;
hqChart.RemoveIndexWindow(id);
});
if (IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar))
{
for(var i=0;i<this.CustomToolbar.length;++i)
{
var item=this.CustomToolbar[i];
$("#"+item.ID).click(
{
Chart:this.ChartBorder.UIElement.JSChartContainer,
Identify:this.Identify,
ID:item.ID
},item.Click);
}
}
divToolbar.style.display = "block";
}
//手绘,不用DOM,使用DOM太麻烦了
this.DrawToolbarV2=function(moveonPoint, mouseStatus)
{
if (g_JSChartResource.IsDOMFrameToolbar===true) return;
this.Buttons=[];
this.LeftButtonWidth=0;
if (this.IsMinSize==true) return;
if (this.ChartBorder.TitleHeight<5) return;
var aryButton=[];
//第1个窗口不能关闭
if (this.CloseIndex && this.Identify!==0) aryButton.push( { ID:JSCHART_BUTTON_ID.CLOSE_INDEX_WINDOW, Style:this.CloseWindowButton });
if (this.MaxMinWindow && this.Identify!=0) aryButton.push({ ID:JSCHART_BUTTON_ID.MAX_MIN_WINDOW, Style:this.MaxMinWindowButton });
if (this.TitleWindow && this.Identify!=0) aryButton.push({ ID:JSCHART_BUTTON_ID.TITLE_WINDOW, Style:this.TitleWindowButton });
if (this.ExportData) aryButton.push( {ID:JSCHART_BUTTON_ID.EXPORT_DATA, Style:this.ExportDataButton});
if (this.OverlayIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.OVERLAY_INDEX, Style:this.OverlayIndexButton });
if (this.ChangeIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.CHANGE_INDEX, Style:this.ChangeIndexButton });
if (this.ModifyIndex) aryButton.push( { ID:JSCHART_BUTTON_ID.MODIFY_INDEX_PARAM, Style:this.ModifyIndexParamButton });
if (IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar))
{
for(var i=0;i<this.CustomToolbar.length;++i)
{
var item=this.CustomToolbar[i];
if (item.ID && item.Style)
{
var btnItem={ ID:item.ID, Style:item.Style, TooltipText:item.TooltipText, Data:item.Data };
if (item.IsLeft===true) //左侧按钮
{
}
else
{
aryButton.push(btnItem); //右侧按钮
}
}
}
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_RIGHT_TOOLBAR);
if (event && event.Callback)
{
var sendData={ PreventDefault:false, DefaultButton:aryButton, AryButton:null, FrameID:this.Identify };
/*
if (option)
{
if (option.Overlay) sendData.Title=option.Overlay.Title;
if (option.OverlayID) sendData.OverlayID=option.OverlayID;
}
*/
event.Callback(event, sendData, this);
if (sendData.PreventDefault)
{
this.DrawTitleButton(sendData.AryButton,moveonPoint, mouseStatus);
return;
}
}
}
this.DrawTitleButton(aryButton,moveonPoint, mouseStatus);
}
this.GetLeftToolbar=function(option)
{
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_LEFT_TOOLBAR);
if (event && event.Callback)
{
var sendData={ PreventDefault:false, AryButton:null, FrameID:this.Identify };
if (option)
{
if (option.Overlay) sendData.Title=option.Overlay.Title;
if (option.OverlayID) sendData.OverlayID=option.OverlayID;
}
event.Callback(event, sendData, this);
if (sendData.PreventDefault) return sendData.AryButton;
}
}
if (!IFrameSplitOperator.IsNonEmptyArray(this.CustomToolbar)) return null;
var aryLeftButton=[]; //左侧按钮
for(var i=0;i<this.CustomToolbar.length;++i)
{
var item=this.CustomToolbar[i];
if (item.ID && item.Style)
{
var btnItem={ ID:item.ID, Style:item.Style, TooltipText:item.TooltipText, Data:item.Data };
if (item.IsLeft===true) aryLeftButton.push(btnItem); //左侧按钮
}
}
return aryLeftButton;
}
this.DrawFrame=function()
{
if (!this.IsMinSize)
{
this.SplitXYCoordinate();
if (this.SizeChange==true)
{
this.CalculateDataWidth();
if (this.Logarithmic) this.SplitLogarithmicXYCoordinate();
}
if (this.BeforeDrawXYCallback) this.BeforeDrawXYCallback(this);
this.DrawTitleBG();
this.DrawCustomHorizontalArea(); //Y轴背景区域 在刻度前面绘制
this.DrawHorizontal();
this.DrawVertical();
}
if (this.SizeChange==true || this.ReDrawToolbar==true)
{
this.DrawToolbar(); //大小变动才画工具条
this.ReDrawToolbar=false;
}
}
//isLimit 是否限制在当前屏坐标下
this.GetXFromIndex=function(index,isLimit)
{
if (isLimit===false)
{
if (index>=0)
{
var offset=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin+this.DistanceWidth/2+this.DataWidth/2;
for(var i=1;i<=index;++i)
{
offset+=this.DistanceWidth+this.DataWidth;
}
}
else
{
var offset=(this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin)-(this.DistanceWidth/2+this.DataWidth+this.DistanceWidth);
var absIndex=Math.abs(index);
for(var i=1;i<absIndex;++i)
{
offset-=(this.DistanceWidth+this.DataWidth);
}
}
}
else
{
if (index < 0) index = 0;
if (index > this.xPointCount - 1) index = this.xPointCount - 1;
var offset=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin+this.DistanceWidth/2+this.DataWidth/2;
for(var i=1;i<=index;++i)
{
offset+=this.DistanceWidth+this.DataWidth;
}
}
return offset;
}
//X坐标转x轴数值 isLimit=是否限制在当前屏坐标下
this.GetXData=function(x,isLimit)
{
var distanceWidth=this.DistanceWidth;
var dataWidth=this.DataWidth;
var left=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin;
var maxDataCount=10000*50;
if (isLimit==false)
{
if (x<this.ChartBorder.GetLeft())
{
var index=-1;
var xPoint=this.ChartBorder.GetLeft()-(distanceWidth/2+dataWidth+distanceWidth);
while(index>-maxDataCount)
{
if (xPoint<=x)
break;
xPoint-=(dataWidth+distanceWidth);
--index;
}
return index;
}
else
{
var index=0;
var xPoint=left+distanceWidth/2+dataWidth+distanceWidth;
while(index<maxDataCount) //自己算x的数值
{
if (xPoint>=x) break;
xPoint+=(dataWidth+distanceWidth);
++index;
}
return index;
}
}
else
{
if (x<=this.ChartBorder.GetLeft()) return 0;
if (x>=this.ChartBorder.GetRight()) return this.XPointCount-1;
var right=this.ChartBorder.GetRight()-g_JSChartResource.FrameRightMargin;
var index=0;
var xPoint=left+distanceWidth/2+dataWidth+distanceWidth;
while(xPoint<right && index<maxDataCount && index+1<this.XPointCount) //自己算x的数值
{
if (xPoint>=x) break;
xPoint+=(dataWidth+distanceWidth);
++index;
}
//var test=(x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth());
return index;
}
}
//计算数据宽度
this.CalculateDataWidth=function()
{
if (this.XPointCount<2) return;
//JSConsole.Chart.Log(`[KLineFrame::CalculateDataWidth] ZoomIndex=${this.ZoomIndex}, XPointCount=${this.XPointCount}, DataWidth=${this.DataWidth}, DistanceWidth=${this.DistanceWidth}`);
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
if (this.ZoomIndex>=0 && this.LastCalculateStatus.Width==width && this.LastCalculateStatus.XPointCount==this.XPointCount) //宽度没变 尝试使用原来的柱子宽度
{
var caclWidth=(this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin)+(this.DataWidth + this.DistanceWidth)*(this.XPointCount-1);
var caclWidth2=(this.DataWidth + this.DistanceWidth) * this.XPointCount;
if (this.DataWidth<2)
{
if (caclWidth2<= width) //当前的柱子宽度够用 就不调整了
return;
}
else
{
if (caclWidth<= width) //当前的柱子宽度够用 就不调整了
return;
}
}
this.LastCalculateStatus.Width=width;
this.LastCalculateStatus.XPointCount=this.XPointCount;
for(var i=0;i<ZOOM_SEED.length;++i)
{
if((ZOOM_SEED[i][0] + ZOOM_SEED[i][1]) * this.XPointCount < width)
{
this.ZoomIndex=i;
this.DataWidth = ZOOM_SEED[i][0];
this.DistanceWidth = ZOOM_SEED[i][1];
this.TrimKLineDataWidth(width);
JSConsole.Chart.Log('[KLineFrame::CalculateDataWidth] ZOOM_SEED, DataWidth, DistanceWidth, XPointCount', ZOOM_SEED[this.ZoomIndex], this.DataWidth,this.DistanceWidth,this.XPointCount);
return;
}
}
//太多了 就平均分了
this.ZoomIndex=ZOOM_SEED.length-1;
this.DataWidth=width/this.XPointCount;
this.DistanceWidth=0;
}
this.OnSize=function(obj)
{
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
var xPointCount=0;
var y=this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin+(this.DataWidth+this.DistanceWidth);
for(;y<width; y+=(this.DataWidth+this.DistanceWidth), ++xPointCount)
{
}
obj.CurCount=this.XPointCount;
obj.CalcCount=xPointCount;
obj.DataWidth=this.DataWidth;
obj.DistanceWidth=this.DistanceWidth;
obj.Changed=false;
this.LastCalculateStatus.Width=width;
if (obj.CurCount==obj.CalcCount) return obj;
this.XPointCount=xPointCount;
this.LastCalculateStatus.XPointCount=this.XPointCount;
if (this.Data)
{
this.Data.DataOffset+=(obj.CurCount-obj.CalcCount);
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
obj.Changed=true;
}
return obj;
}
this.SetDataWidth=function(dataWidth)
{
var zoomIndex=ZOOM_SEED.length-1;
for(var i in ZOOM_SEED)
{
var item=ZOOM_SEED[i];
if (item[0]<=dataWidth)
{
zoomIndex=parseInt(i)-1;
break;
}
}
this.ZoomIndex=zoomIndex;
this.DataWidth=ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth=ZOOM_SEED[this.ZoomIndex][1];
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
var xPointCount=0;
var y=this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin+(this.DataWidth+this.DistanceWidth);
for(;y<=width; y+=(this.DataWidth+this.DistanceWidth), ++xPointCount) { }
this.XPointCount=xPointCount;
this.LastCalculateStatus.XPointCount=this.XPointCount;
this.LastCalculateStatus.Width=width;
var obj={ XPointCount:this.XPointCount, DataWidth:this.DataWidth, DistanceWidth:this.DistanceWidth };
return obj;
}
this.TrimKLineDataWidth=function(width)
{
var dataWidth=ZOOM_SEED[this.ZoomIndex][0];
var distanceWidth=ZOOM_SEED[this.ZoomIndex][1];
if (dataWidth==1 && distanceWidth==0)
{
this.DataWidth=width/this.XPointCount;
return;
}
while(true)
{
if((this.DistanceWidth + this.DataWidth) * this.XPointCount + this.DistanceWidth > width)
{
this.DistanceWidth -= 0.01;
break;
}
this.DistanceWidth += 0.01;
}
}
//当前坐标信息 是否覆盖最大 最小值输出
this.IsOverlayMaxMin=function(obj)
{
if (!this.ChartKLine) return false;
if (!this.ChartKLine.Max || !this.ChartKLine.Min) return false;
var textWidth=this.Canvas.measureText(obj.Text.Value).width+4; //刻度文字宽度
if (obj.Text.TextAlign==='right') obj.X-=textWidth;
var max=this.ChartKLine.Max, min=this.ChartKLine.Min;
var isOverlayMax=false, isOverlayMin=false;
const textHeight=20; //字体高度
if (max.X>=obj.X && max.X<=obj.X+textWidth) //最大值X 坐标不在 刻度文字范围内
{
var y1=max.Y+textHeight, y2=max.Y-textHeight;
if ( (y1>=obj.Y-textHeight && y1<=obj.Y+textHeight) || (y2>=obj.Y-textHeight && y2<=obj.Y+textHeight))
isOverlayMax=true;
}
if (isOverlayMax==true) return true;
if (min.X>=obj.X && min.X<=obj.X+textWidth)
{
var y1=min.Y+textHeight, y2=min.Y-textHeight;
if ( (y1>=obj.Y-textHeight && y1<=obj.Y+textHeight) || (y2>=obj.Y-textHeight && y2<=obj.Y+textHeight))
isOverlayMin=true;
}
return isOverlayMax || isOverlayMin;
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false)
{
if (this.XSplit)
{
if (this.XSplitOperator) this.XSplitOperator.Operator();
}
if (this.YCustomSplit)
{
//计算自定义刻度
if (this.YSplitOperator && this.YSplitOperator.CustomCoordinate)
this.YSplitOperator.CustomCoordinate();
}
return;
}
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
if (this.XSplitOperator!=null) this.XSplitOperator.Operator();
if (this.Logarithmic) this.SplitLogarithmicXYCoordinate();
}
this.SplitLogarithmicXYCoordinate=function()
{
var up=this.Logarithmic.Up;
var down=this.Logarithmic.Down;
var logHeight=0; //对数额外高度
var count=0;
var maxCount=Math.max(up.length, down.length);
var aryLogHeight=[];
for(var i=0;i<maxCount;++i)
{
aryLogHeight[i]=i*2;
}
for(var i=0, j=aryLogHeight.length-1; i<up.length; ++i,--j)
{
var item=up[i];
item.LogHeight=aryLogHeight[j];
logHeight+=item.LogHeight;
++count;
}
for(var i=0, j=aryLogHeight.length-1;i<down.length; ++i,--j)
{
var item=down[i];
item.LogHeight=aryLogHeight[j];
logHeight+=item.LogHeight;
++count;
}
var heightRate=2*GetDevicePixelRatio();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var height=(bottom-top);
var perHeight=(height-logHeight*heightRate)/count;
if (perHeight<0)
{
perHeight=0;
heightRate=height/logHeight;
}
if (this.CoordinateType==1) //反转坐标
{
var itemTop=top;
for(var i=down.length-1;i>=0;--i) //上部
{
var item=down[i];
item.Height=perHeight+(heightRate*item.LogHeight);
item.Top=itemTop;
item.Bottom=item.Top+item.Height;
itemTop=item.Bottom;
}
var itemBottom=bottom;
for(var i=up.length-1;i>=0;--i) //下部
{
var item=up[i];
item.Height=perHeight+(heightRate*item.LogHeight)
item.Bottom=itemBottom;
item.Top=itemBottom-item.Height;
itemBottom=item.Top;
}
}
else
{
var itemTop=top;
for(var i=up.length-1;i>=0;--i)
{
var item=up[i];
item.Height=perHeight+(heightRate*item.LogHeight);
item.Top=itemTop;
item.Bottom=item.Top+item.Height;
itemTop=item.Bottom;
}
var itemBottom=bottom;
for(var i=down.length-1;i>=0;--i)
{
var item=down[i];
item.Height=perHeight+(heightRate*item.LogHeight)
item.Bottom=itemBottom;
item.Top=itemBottom-item.Height;
itemBottom=item.Top;
}
}
JSConsole.Chart.Log("[KLineFrame::SplitLogarithmicXYCoordinate]", this.Logarithmic);
}
this.GetYLogarithmicFromData=function(value, isLimit)
{
if (this.CoordinateType==1)
{
if(value<=this.HorizontalMin) return this.ChartBorder.GetTopEx();
if(value>=this.HorizontalMax) return this.ChartBorder.GetBottomEx();
if (value>this.Logarithmic.OpenPrice)
{
var up=this.Logarithmic.Up;
for(var i in up)
{
var item=up[i];
if (value>=item.Start && value<=item.End)
{
var itemHeight=item.Bottom-item.Top;
var height=itemHeight*(value-item.Start)/(item.End-item.Start);
return item.Top+height;
}
}
}
else
{
var down=this.Logarithmic.Down;
for(var i in down)
{
var item=down[i];
if (value>=item.Start && value<=item.End)
{
var itemHeight=item.Bottom-item.Top;
var height=itemHeight*(value-item.Start)/(item.End-item.Start);
return item.Top+height;
}
}
}
}
else
{
if(value<=this.HorizontalMin) return this.ChartBorder.GetBottomEx();
if(value>=this.HorizontalMax) return this.ChartBorder.GetTopEx();
if (value>this.Logarithmic.OpenPrice)
{
var up=this.Logarithmic.Up;
for(var i in up)
{
var item=up[i];
if (value>=item.Start && value<=item.End)
{
var itemHeight=item.Bottom-item.Top;
var height=itemHeight*(value-item.Start)/(item.End-item.Start);
return item.Bottom-height;
}
}
}
else
{
var down=this.Logarithmic.Down;
for(var i in down)
{
var item=down[i];
if (value>=item.Start && value<=item.End)
{
var itemHeight=item.Bottom-item.Top;
var height=itemHeight*(value-item.Start)/(item.End-item.Start);
return item.Bottom-height;
}
}
}
}
}
this.GetYLogarithmicData=function(y)
{
if (this.CoordinateType==1) //反转坐标
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMin;
if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMax;
var up=this.Logarithmic.Up;
for(var i in up)
{
var item=up[i];
if (y>=item.Top && y<=item.Bottom)
{
return (y-item.Top)/item.Height*(item.End-item.Start)+item.Start;
}
}
var down=this.Logarithmic.Down;
for(var i in down)
{
var item=down[i];
if (y>=item.Top && y<=item.Bottom)
{
return (y-item.Top)/item.Height*(item.End-item.Start)+item.Start;
}
}
}
else
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMax;
if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMin;
var up=this.Logarithmic.Up;
for(var i in up)
{
var item=up[i];
if (y>=item.Top && y<=item.Bottom)
{
return (item.Bottom-y)/item.Height*(item.End-item.Start)+item.Start;
}
}
var down=this.Logarithmic.Down;
for(var i in down)
{
var item=down[i];
if (y>=item.Top && y<=item.Bottom)
{
return (item.Bottom-y)/item.Height*(item.End-item.Start)+item.Start;
}
}
}
}
this.CalculateCount=function(zoomIndex)
{
var dataWidth=ZOOM_SEED[zoomIndex][0];
var distanceWidth=ZOOM_SEED[zoomIndex][1];
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin-distanceWidth/2;
return parseInt(width/(dataWidth + distanceWidth));
}
this.ZoomUp=function(cursorIndex)
{
if (this.ZoomIndex<=0) return false;
if (this.Data.DataOffset<0) return false;
var dataCount=this.Data.Data.length;
var maxDataCount=dataCount+this.RightSpaceCount;
var rightSpaceCount=0;
var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引
var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
if (lastDataIndex>=dataCount)
{
rightSpaceCount=lastDataIndex-(this.Data.Data.length-1); //计算右边预留空间
lastDataIndex=this.Data.Data.length-1;
if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
}
var xPointCount=this.CalculateCount(this.ZoomIndex-1);
JSConsole.Chart.Log(`[KLineFrame::ZoomUp] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} rightSpaceCount=${rightSpaceCount}`);
var isShowAll=false;
--this.ZoomIndex;
if (cursorIndex.IsLockRight==true) //固定右边
{
var rightDataIndex=this.Data.DataOffset + this.XPointCount; //最右边的数据索引
if (xPointCount>rightDataIndex)
{
xPointCount=rightDataIndex;
this.XPointCount=xPointCount;
this.Data.DataOffset=0;
}
else
{
var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
this.XPointCount=xPointCount;
this.Data.DataOffset=dataOffset;
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
}
}
else if (xPointCount>=maxDataCount)
{
//xPointCount=maxDataCount;
//this.XPointCount=xPointCount;
this.Data.DataOffset=0;
this.XPointCount=xPointCount;
isShowAll=true;
JSConsole.Chart.Log(`[KLineFrame::ZoomUp] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
}
else
{
var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
if (cursorIndex.ZoomType==1) //以十字光标为中心左右放大
{
var moveOffset=(this.XPointCount-xPointCount)+1;
var leftOffset=parseInt(cursorIndex.Index/this.XPointCount*moveOffset);
var rightOffset=moveOffset-leftOffset;
var offset=this.Data.DataOffset+leftOffset;
if (offset<dataCount) dataOffset=this.Data.DataOffset+leftOffset;
}
this.XPointCount=xPointCount;
this.Data.DataOffset=dataOffset;
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
JSConsole.Chart.Log(`[KLineFrame::ZoomUp] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
}
this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
if (!isShowAll)
{
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
this.TrimKLineDataWidth(width);
}
this.LastCalculateStatus.XPointCount=this.XPointCount;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
return true;
}
this.SetXShowCount=function(showCount)
{
var index=-1;
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
for(var i=0; i<ZOOM_SEED.length; ++i)
{
var item=ZOOM_SEED[i];
var dataWidth=item[0];
var distanceWidth=item[1];
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin-distanceWidth/2;
var value=parseInt((width-distanceWidth/2)/(dataWidth + distanceWidth));
if (value>=showCount)
{
index=i;
this.XPointCount=showCount;
this.ZoomIndex=index;
this.DataWidth=dataWidth;
this.DistanceWidth=distanceWidth;
if (dataWidth<=1 && distanceWidth==0)
this.DataWidth=width/this.XPointCount;
this.LastCalculateStatus.XPointCount=this.XPointCount;
this.LastCalculateStatus.Width=width;
return;
}
}
//太多了 就平均分了
this.XPointCount=showCount;
this.ZoomIndex=ZOOM_SEED.length-1;
this.DataWidth=width/this.XPointCount;
this.DistanceWidth=0;
this.LastCalculateStatus.XPointCount=this.XPointCount;
this.LastCalculateStatus.Width=width;
}
this.XCoordinateZoom=function(isMoveLeft)
{
var oldXPointCount=this.XPointCount;
if (isMoveLeft) //放大 右边固定
{
if (this.ZoomIndex<=0) return false;
if (this.Data.DataOffset<0) return false;
var zoomIndex=this.ZoomIndex-1;
var xPointCount=this.CalculateCount(zoomIndex);
var dataCount=this.Data.Data.length;
var moveOffset=oldXPointCount-xPointCount;
if (moveOffset<=0) return false;
this.Data.DataOffset+=moveOffset;
if (this.Data.DataOffset>dataCount) this.Data.DataOffset=0;
}
else //缩小
{
if (this.ZoomIndex+1>=ZOOM_SEED.length) return false;
if (this.Data.DataOffset<0) return false;
var zoomIndex=this.ZoomIndex+1;
var xPointCount=this.CalculateCount(zoomIndex);
var moveOffset=xPointCount-oldXPointCount;
this.Data.DataOffset-=moveOffset;
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
}
//JSConsole.Chart.Log(`[KLineFrame::XCoordinateZoom] old (XPointCount=${oldXPointCount} ZoomIndex=${this.ZoomIndex}) DataCount= ${this.Data.Data.length} `);
this.XPointCount=xPointCount;
this.ZoomIndex=zoomIndex;
this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
this.TrimKLineDataWidth(width);
this.LastCalculateStatus.XPointCount=this.XPointCount;
return true;
//var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
}
this.ZoomDown=function(cursorIndex, option) //缩小
{
if (this.ZoomIndex+1>=ZOOM_SEED.length) return false;
if (this.Data.DataOffset<0) return false;
if (this.Data.DataOffset<=0 && cursorIndex.IsLockRight==true) return false;
var dataCount=this.Data.Data.length;
var maxDataCount=dataCount+this.RightSpaceCount;
//if (this.XPointCount>=maxDataCount) return false;
var rightSpaceCount=0;
var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引
if (lastDataIndex>=this.Data.Data.length)
{
rightSpaceCount=lastDataIndex-(this.Data.Data.length-1); //计算右边预留空间
lastDataIndex=this.Data.Data.length-1;
if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
}
var xPointCount=this.CalculateCount(this.ZoomIndex+1);
var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
JSConsole.Chart.Log(`[KLineFrame::ZoomDown] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} lastCursorIndex=${lastCursorIndex} rightSpaceCount=${rightSpaceCount}`);
var isShowAll=false;
++this.ZoomIndex;
if (cursorIndex.IsLockRight==true) //固定右边
{
var rightDataIndex=this.Data.DataOffset + this.XPointCount; //最右边的数据索引
if (xPointCount>rightDataIndex)
{
xPointCount=rightDataIndex;
this.XPointCount=xPointCount;
this.Data.DataOffset=0;
}
else
{
var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
this.XPointCount=xPointCount;
this.Data.DataOffset=dataOffset;
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
}
}
else if (xPointCount>=maxDataCount) //所有数据无法显示完一屏
{
//xPointCount=maxDataCount;
this.XPointCount=xPointCount;
this.Data.DataOffset=0;
//isShowAll=true; //数据铺满全屏, 不需要调整宽度
JSConsole.Chart.Log(`[KLineFrame::ZoomDown] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
if (xPointCount-this.RightSpaceCount>dataCount)
{
if (option && option.ZoomDownloadDataCallback)
{
option.ZoomDownloadDataCallback({ PageSize:xPointCount, DataCount:dataCount, RightSpaceCount:this.RightSpaceCount, Count:xPointCount-dataCount });
}
}
}
else
{
var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
if (cursorIndex.ZoomType==1) //当前十字光标位置左右同时缩小
{
var moveOffset=(xPointCount-this.XPointCount)+1;
var leftOffset=parseInt(cursorIndex.Index/this.XPointCount*moveOffset);
var rightOffset=moveOffset-leftOffset;
var dataOffset=this.Data.DataOffset-leftOffset;
if (dataOffset+(xPointCount-this.RightSpaceCount)>=dataCount) dataOffset=this.Data.DataOffset-moveOffset;
}
this.XPointCount=xPointCount;
this.Data.DataOffset=dataOffset;
if (this.Data.DataOffset<0) this.Data.DataOffset=0;
JSConsole.Chart.Log(`[KLineFrame::ZoomDown] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
}
this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
if (!isShowAll)
{
var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
this.TrimKLineDataWidth(width);
}
this.LastCalculateStatus.XPointCount=this.XPointCount;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
return true;
}
this.GetFrameWidth=function()
{
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
return border.BottomEx-border.TopEx;
//return this.ChartBorder.GetHeight();
}
else
{
var border=this.ChartBorder.GetBorder();
return border.RightEx-border.LeftEx;
//return this.ChartBorder.GetWidth();
}
}
this.DrawCustomHorizontal=function() //Y轴刻度定制显示
{
if (this.IsMinSize) return;
if (this.ChartBorder.IsShowTitleOnly) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.CustomHorizontalInfo)) return;
var aryHorizontal=this.CustomHorizontalInfo.slice();
aryHorizontal.sort((left, right)=>{ return right.Value-left.Value; });
var mapTextRect=new Map(); //key=position(1=左外 2=左内, 3=右外 4=右内), value:{ Rect:, Item: }
for(var i=0; i<aryHorizontal.length; ++i)
{
var item=aryHorizontal[i];
switch(item.Type)
{
case 0: //最新价格刻度
case 1: //固定价格刻度
this.DrawCustomItem(item, mapTextRect);
break;
case 2: //当前屏最后一个K线价格刻度
case 3: //主图K线涨幅刻度
case 4: //叠加K线涨幅刻度
case 10://自定义的
this.DrawCustomItem(item, mapTextRect);
break;
}
}
}
//Y轴面积背景
this.DrawCustomHorizontalArea=function()
{
if (this.IsMinSize) return;
if (this.ChartBorder.IsShowTitleOnly) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.CustomHorizontalInfo)) return;
for(var i=0;i<this.CustomHorizontalInfo.length;++i)
{
var item=this.CustomHorizontalInfo[i];
if (item.Type==5) this.DrawCustomAreaItem(item);
}
}
this.DrawCustomVerticalItem=function(item)
{
this.Canvas.save();
if (item.Data.Line.Type==1) this.Canvas.setLineDash([5,5]); //虚线
this.Canvas.strokeStyle=item.Data.Line.Color;
this.Canvas.beginPath();
if (item.IsHScreen)
{
this.Canvas.moveTo(item.Top,ToFixedPoint(item.X));
this.Canvas.lineTo(item.Bottom,ToFixedPoint(item.X));
}
else
{
this.Canvas.moveTo(ToFixedPoint(item.X),item.Top);
this.Canvas.lineTo(ToFixedPoint(item.X),item.Bottom);
}
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawCustomVertical=function() //X轴定制刻度显示
{
if (!this.CustomVerticalInfo) return;
if (this.CustomVerticalInfo.length<=0) return;
if (!this.Data) return;
var isHScreen=this.IsHScreen;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var dataWidth=this.DataWidth;
var distanceWidth=this.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen)
{
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
top=this.ChartBorder.GetLeftEx();
bottom=this.ChartBorder.GetRightEx();
}
var j=0;
for(var i=this.Data.DataOffset;i<this.Data.Data.length && j<this.XPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var kItem=this.Data.Data[i];
for(var k in this.CustomVerticalInfo)
{
var item=this.CustomVerticalInfo[k];
if (item.Type!=0) continue;
if (IFrameSplitOperator.IsNumber(item.Time))
{
if (kItem.Date!=item.Date || kItem.Time!=item.Time) continue;
}
else
{
if (kItem.Date!=item.Date) continue;
}
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var DrawData={X:x, Top:top, Bottom:bottom, Data:item , IsHScreen:isHScreen};
this.DrawCustomVerticalItem(DrawData);
if (this.DrawCustomVerticalEvent)
this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this);
break;
}
}
for(var i=1;j<this.XPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
for(var k in this.CustomVerticalInfo)
{
var item=this.CustomVerticalInfo[k];
if (item.Type!=1) continue;
if (item.Space!=i) continue;
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var DrawData={X:x, Top:top, Bottom:bottom, Data:item,IsHScreen:isHScreen };
this.DrawCustomVerticalItem(DrawData);
if (this.DrawCustomVerticalEvent)
this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this);
break;
}
}
}
this.DrawSelectedBorder=function(option)
{
if (this.Identify===0) return;
var border=this.IsHScreen==true?this.ChartBorder.GetHScreenBorder():this.ChartBorder.GetBorder();
var left=ToFixedPoint(border.Left);
var top=ToFixedPoint(border.Top);
var right=ToFixedPoint(border.Right);
var bottom=ToFixedPoint(border.Bottom);
var height=bottom-top;
this.Canvas.strokeStyle=this.SelBorderColor;
if (option.Mode==1)
{
var xRight=ToFixedPoint(border.ChartWidth);
this.Canvas.strokeRect(right,top,xRight-right-1,height); //少一个像素让边框显示出来
}
else
{
this.Canvas.strokeRect(left,top,right-left-1,height); //少一个像素让边框显示出来
}
}
//是否在X轴坐标上
//this.PtInVertical=function(x,y) { return false; }
//缓存X轴坐标刻度
this.GetVerticalXCache=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.VerticalInfo)) return null;
var dataWidth=this.DataWidth;
var distanceWidth=this.DistanceWidth;
var xPointCount=this.XPointCount;
var setIndex=new Set();
for(var i=0; i<this.VerticalInfo.length; ++i)
{
var item=this.VerticalInfo[i];
setIndex.add(item.Value);
}
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
var mapX=new Map();
for(var i=0;i<xPointCount;++i, xOffset+=(dataWidth+distanceWidth))
{
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
if (setIndex.has(i))
{
mapX.set(i, x);
}
}
return mapX;
}
}
function OverlayKLineFrame()
{
this.newMethod=KLineFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='OverlayKLineFrame';
this.MainFrame=null; //主框架
this.IsShareY=false; //使用和主框架公用Y轴
this.IsShowMainFrame=0; //是否显示在主框架坐标上 1=左边 2=右边
this.IsCalculateYMaxMin=true; //是否计算Y最大最小值
this.RightOffset=50;
this.PenBorder=g_JSChartResource.OverlayFrame.BolderPen; //'rgb(0,0,0)'
this.IsShow=g_JSChartResource.KLineToolbar.IsShowOverlayFrame; //坐标是否显示
this.IsShowToolbar=g_JSChartResource.KLineToolbar.IsShowOverlayToolbar; //是否显示工具条
this.Title=null;
this.TitleColor=g_JSChartResource.OverlayFrame.TitleColor;
this.TitleFont=g_JSChartResource.OverlayFrame.TitleFont;
this.IsShowTitle=true;
this.IsYDrawMainFrame=false; //Y轴自定刻度绘制在主图框架上
this.BlankWidth=0;
this.Style=0; //0=Y轴在BlankWidth 1=Y轴在左边
this.YLineExtend=[ { Width:2 }, null]; //[0]=左 [1]=右 { Width:5, Color:颜色, }
this.Buttons=[];
this.CloseButton=CloneData(g_JSChartResource.Buttons.CloseOverlayIndex);
this.ModifyIndexParamButton=CloneData(g_JSChartResource.Buttons.ModifyIndexParam);
this.DrawSelectedBorder=null;
this.KLineFrame_ReloadResource=this.ReloadResource;
this.ReloadResource=function(resource)
{
this.KLineFrame_ReloadResource(resource);
if (!resource)
{
this.CloseButton=CloneData(g_JSChartResource.Buttons.CloseOverlayIndex);
this.ModifyIndexParamButton=CloneData(g_JSChartResource.Buttons.ModifyIndexParam);
this.PenBorder=g_JSChartResource.OverlayFrame.BolderPen; //'rgb(0,0,0)'
this.TitleColor=g_JSChartResource.OverlayFrame.TitleColor;
this.TitleFont=g_JSChartResource.OverlayFrame.TitleFont;
}
}
this.Draw=function()
{
this.Buttons=[];
if (this.ChartBorder.IsShowTitleOnly) return;
this.SplitXYCoordinate();
if (this.IsShow)
{
this.DrawVertical();
this.DrawHorizontal();
this.DrawTitle();
}
this.SizeChange=false;
this.XYSplit=false;
this.XSplit=false;
this.YCustomSplit=false; //自定义Y轴分割线
}
//Y轴刻度线 x坐标
this.GetXHorizontal=function()
{
var border=this.ChartBorder.GetBorder();
var x=border.Right;
x+=this.RightOffset;
if (this.Style==1)
{
}
else
{
x+=this.BlankWidth;
}
return x;
}
this.GetHorizontalWidth=function()
{
var width=null;
if (this.YRightTextInfo && IFrameSplitOperator.IsNumber(this.TextWidthIndex))
width=this.YRightTextInfo.AryOverlayWidth[this.TextWidthIndex];
return width;
}
this.DrawTitle=function() //画标题
{
if (!this.IsShowTitle) return;
if (!this.Title) return;
var border=this.ChartBorder.GetBorder();
var top = this.ChartBorder.GetTopTitle();
var bottom = border.Bottom;
var xText=this.GetXHorizontal();
var leftLine=null, rightLine=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.YLineExtend))
{
rightLine=this.YLineExtend[1];
leftLine=this.YLineExtend[0];
}
if (this.Style==1)
{
this.Canvas.textBaseline="bottom";
if (rightLine && rightLine.Width>0) xText+=rightLine.Width+1;
else xText+=1;
}
else
{
this.Canvas.textBaseline="top";
if (leftLine && leftLine.Width>0) xText-=leftLine.Width;
else xText-=2;
}
var yText=top+(bottom-top)/2;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.font=this.TitleFont;
this.Canvas.textAlign="center";
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.Title, 0, 0);
this.Canvas.restore();
}
this.GetScaleTextWidth=function()
{
if (!this.IsShow) return null;
var border=this.ChartBorder.GetBorder();
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
if (this.IsHScreen)
{
var borderBottom=this.ChartBorder.Bottom;
var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
}
else
{
var borderRight=this.ChartBorder.Right;
var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
}
if (!isDrawRight) return null;
var width={ Left:null, Right:0 };
for(var i=0;i<this.HorizontalInfo.length;++i)
{
var textWidth=null;
var item=this.HorizontalInfo[i];
if (!item) continue;
if (item.Message[1]!=null && isDrawRight)
{
if (item.Font!=null) this.Canvas.font=item.Font;
textWidth=this.Canvas.measureText(item.Message[1]).width;
if (this.YTextPadding && IFrameSplitOperator.IsNumber(this.YTextPadding[1]))
textWidth+=this.YTextPadding[1];
if (width.Right<textWidth) width.Right=textWidth;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(this.YLineExtend))
{
var line=this.YLineExtend[1];
if (line && line.Width>0) width.Right+=line.Width;
}
return { TextWidth:width };
}
//同步主图坐标
this.SyncMainHorizontalInfo=function()
{
if (!this.MainFrame) return false;
if (this.MainFrame.YMaxMin)
{
this.YMaxMin.Max=this.MainFrame.YMaxMin.Max;
this.YMaxMin.Min=this.MainFrame.YMaxMin.Min;
}
this.HorizontalMax=this.MainFrame.HorizontalMax;
this.HorizontalMin=this.MainFrame.HorizontalMin;
this.HorizontalInfo=[];
for(var i=0;i<this.MainFrame.HorizontalInfo.length; ++i)
{
var item=this.MainFrame.HorizontalInfo[i];
this.HorizontalInfo.push(item);
}
this.CoordinateType=this.MainFrame.CoordinateType;
return true;
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false) return;
if (this.IsShareY) //和主图指标共享Y轴坐标
{
this.SyncMainHorizontalInfo();
}
else //独立Y轴坐标
{
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
}
}
//画Y轴
this.DrawHorizontal=function()
{
var border=this.ChartBorder.GetBorder();
var left=border.Left;
var right=border.Right;
var bottom = border.Bottom;
var top = this.ChartBorder.GetTopTitle();
var borderRight=this.ChartBorder.Right;
right+=this.RightOffset;
var xLine=this.GetXHorizontal();
if (IFrameSplitOperator.IsNumber(this.BlankWidth)) right+=this.BlankWidth;
var rightExtendText=null; //右侧文字设置
if (IFrameSplitOperator.IsNonEmptyArray(this.YTextExtend))
{
rightExtendText=this.YTextExtend[1];
}
var leftLine=null, rightLine=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.YLineExtend))
{
rightLine=this.YLineExtend[1];
leftLine=this.YLineExtend[0];
}
var rightWidth=this.GetHorizontalWidth(); //右侧宽度
var yPrev=null; //上一个坐标y的值
for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从上往下画分割线
{
var item=this.HorizontalInfo[i];
var y=this.GetYFromData(item.Value);
if (y!=null && Math.abs(y-yPrev)<this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom';
else if (y <= top + 2) this.Canvas.textBaseline = 'top';
else this.Canvas.textBaseline = "middle";
if (leftLine && leftLine.Width>0) //左边
{
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(xLine-leftLine.Width,ToFixedPoint(y));
this.Canvas.lineTo(xLine,ToFixedPoint(y));
this.Canvas.stroke();
}
if (rightLine && rightLine.Width>0)
{
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(xLine+rightLine.Width,ToFixedPoint(y));
this.Canvas.lineTo(xLine,ToFixedPoint(y));
this.Canvas.stroke();
}
//坐标信息 右边 间距小于10 不画坐标
if (item.Message[1]!=null && borderRight>10)
{
if (item.Font!=null) this.Canvas.font=item.Font;
var text=item.Message[1];
if (Array.isArray(item.Message[1])) text=item.Message[1][0];
if (rightExtendText && rightExtendText.Align)
{
var textWidth=rightWidth;
this.Canvas.textAlign="right";
var xRight=border.Right+this.RightOffset+textWidth-this.YTextPadding[1];
this.Canvas.fillText(text,xRight,y);
}
else
{
var xText=right+2;
if (rightLine && rightLine.Width>0) xText+=rightLine.Width;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="left";
this.Canvas.fillText(text,xText,y);
}
}
yPrev=y;
}
}
//画X轴
this.DrawVertical=function()
{
var border=this.ChartBorder.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
var right=this.GetXHorizontal();
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top));
this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom));
this.Canvas.stroke();
}
this.DrawToolbar=function(moveonPoint, isMinSize, mouseStatus)
{
this.Buttons=[];
if (isMinSize==true) return;
if (this.ChartBorder.IsShowTitleOnly) return;
if (this.ChartBorder.TitleHeight<5) return;
if (!this.IsShowToolbar) return;
var aryButton=[];
aryButton.push( { ID:JSCHART_BUTTON_ID.MODIFY_OVERLAY_INDEX_PARAM, Style:this.ModifyIndexParamButton });
aryButton.push( { ID:JSCHART_BUTTON_ID.CLOSE_OVERLAY_INDEX, Style:this.CloseWindowButton });
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_OVERLAY_TOOLBAR);
if (event && event.Callback)
{
var sendData={ PreventDefault:false, DefaultButton:aryButton, AryButton:null, Guid:this.Guid };
event.Callback(event, sendData, this);
if (sendData.PreventDefault)
{
this.DrawToolbarButton(sendData.AryButton,moveonPoint, mouseStatus);
return;
}
}
}
this.DrawToolbarButton(aryButton, moveonPoint, mouseStatus);
}
this.DrawToolbarButton=function(aryButton, moveonPoint, mouseStatus)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryButton)) return;
var border=this.ChartBorder.GetBorder();
var yButton=border.Top+this.ChartBorder.TitleHeight/2;
var rightWidth=this.GetHorizontalWidth();
var xBotton=border.Right+this.RightOffset+rightWidth-this.CloseButton.MerginLeft;
for(var i=aryButton.length-1;i>=0;--i)
{
var item=aryButton[i];
var size=item.Style.Size;
var font=`${size}px ${item.Style.Family}`;
var rtButton={ Left:xBotton-size-item.Style.MerginLeft, Top:yButton-size/2, Right:xBotton, Bottom:yButton+size/2, Width:size+item.Style.MerginLeft, Height:size };
var color=this.CloseButton.Color;
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
color=item.Style.MoveOnColor;
if (mouseStatus)
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:item, Frame:this, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
this.Canvas.fillStyle=color;
this.Canvas.font=font;
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Style.Text, xBotton, yButton);
this.Buttons.push({ ID:item.ID, Rect:rtButton });
xBotton=rtButton.Left;
}
}
this.DrawCustomItem=function(item, mapTextRect) //显示自定义Y刻度
{
if (!this.IsShow && !this.IsYDrawMainFrame) return;
if (!item.Message[1] && !item.Message[0]) return;
if (item.Value>this.HorizontalMax || item.Value<this.HorizontalMin)
{
//this.DrawOutRangeCustomItem(item, mapTextRect);
this.SendDrawCountDownEvent( { IsShow:false } );
return;
}
var border=this.GetBorder();
var left=border.Left;
var right=border.Right+this.RightOffset;
if (this.IsYDrawMainFrame) right=border.Right
var bottom=border.Bottom;
var top=border.Top;
var borderRight = this.ChartBorder.Right;
var borderLeft = this.ChartBorder.Left;
var titleHeight = this.ChartBorder.TitleHeight;
if (this.IsHScreen)
{
borderLeft=this.ChartBorder.Top;
borderRight=this.ChartBorder.Bottom;
top=border.Top;
bottom=border.Bottom;
}
var pixelTatio = GetDevicePixelRatio();
var defaultTextHeight=18*pixelTatio;
var textHeight=defaultTextHeight;
var y = this.GetYFromData(item.Value);
var position=0;
var emptyBGColor;
if (item.ExtendData && item.ExtendData.Custom)
{
var customItem=item.ExtendData.Custom;
if (IFrameSplitOperator.IsNumber(customItem.Position)) position=customItem.Position;
if (customItem.EmptyBGColor) emptyBGColor=customItem.EmptyBGColor;
}
if (item.Message[0]) // 左
{
if (borderLeft<10 || position==1)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=top;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var textLeft=left + 1*pixelTatio
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
if (i==0) this.DrawLine(textLeft+itemText.Width,right,yText,item.LineColor,item.LineType,item);
yText+=textHeight+1*pixelTatio;
}
}
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "right";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
if (i==0) var bgTop=top-itemText.Width;
else var bgTop=top-textWidth;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
if (i==0)
{
var rectLeft=left-itemText.Width;
var textLeft=left;
}
else
{
var rectLeft=left-textWidth;
var textLeft=left-(textWidth-itemText.Width);
}
if (emptyBGColor)
{
this.Canvas.fillStyle=emptyBGColor;
this.Canvas.fillRect(rectLeft-1,bgTop,itemText.Width+1,textHeight);
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.strokeRect(ToFixedPoint(rectLeft-1),ToFixedPoint(bgTop),ToFixedPoint(itemText.Width+1),ToFixedPoint(textHeight));
this.Canvas.fillStyle = item.LineColor;
this.Canvas.fillText(itemText.Text, textLeft - 1*pixelTatio, yText);
}
else
{
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(rectLeft,bgTop,itemText.Width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft - 1*pixelTatio, yText);
}
if (i==0) this.DrawLine(left,right,yText,item.LineColor,item.LineType,item);
yText+=textHeight+1*pixelTatio;
}
}
}
}
else if (item.Message[1]) //右
{
if (borderRight<10 || position==1)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
var yText=y;
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=bottom-itemText.Width;
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
if (this.GetEventCallback)
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var sendData=
{
Top:bgTop, Right:right, Height:null,
IsShow:true, BGColor:item.LineColor, TextColor:item.TextColor, PixelTatio:pixelTatio, Position:"Right", IsInside:true
};
if (this.SendDrawCountDownEvent(sendData))
{
if (IFrameSplitOperator.IsPlusNumber(sendData.Height))
yText+=textHeight+1*pixelTatio;
}
}
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var textLeft=right-itemText.Width;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textWidth,textHeight); //文本背景区域
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
if (i==0) this.DrawLine(left,textLeft,yText,item.LineColor,item.LineType,item);
yText+=textHeight+1*pixelTatio;
}
}
}
if (item.Type==3 || item.Type==4)
{
if (item.Title)
{
var width=this.Canvas.measureText(item.Title).width+2*pixelTatio;
if (this.IsHScreen)
{
var bgTop=bottom-itemText.Width-width;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,width);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Title, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=right-textWidth-width-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Title, textLeft + 1*pixelTatio, y);
}
}
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
var textWidth=textInfo.MaxWidth;
var fontHeight=this.GetFontHeight();
textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
var preTextRect=null;
if (mapTextRect && mapTextRect.has(3)) preTextRect=mapTextRect.get(3);
var yText=y;
var rtText={ };
for(var i=0;i<textInfo.Text.length;++i)
{
var itemText=textInfo.Text[i];
if (this.IsHScreen)
{
var bgTop=bottom;
//bgTop+=(textWidth-itemText.Width);
var textLeft=yText-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (i==0) this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType,item);
yText-=textHeight+1*pixelTatio;
}
else
{
if (itemText.Type===1)
{
if (this.GetEventCallback)
{
var bgTop=yText-textHeight/2-1*pixelTatio;
var sendData=
{
Top:bgTop, Left:right, Right:this.ChartBorder.GetChartWidth(), Height:null,
IsShow:true, BGColor:item.LineColor, TextColor:item.TextColor, PixelTatio:pixelTatio, Position:"Right", IsInside:false
};
if (this.SendDrawCountDownEvent(sendData))
{
if (IFrameSplitOperator.IsPlusNumber(sendData.Height))
yText+=textHeight+1*pixelTatio;
}
}
}
else
{
var bgTop=yText-textHeight/2-1*pixelTatio;
if (i==0)
{
var textLeft=right;
rtText.Left=textLeft;
if (preTextRect && bgTop<preTextRect.Rect.Bottom)
{
yText=preTextRect.Rect.Bottom;
bgTop=yText-textHeight/2-1*pixelTatio;
}
}
else
{
var textLeft=right+textWidth-itemText.Width;
}
if (emptyBGColor)
{
this.Canvas.fillStyle=emptyBGColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width+1,textHeight);
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.strokeRect(ToFixedPoint(textLeft),ToFixedPoint(bgTop),ToFixedRect(itemText.Width+1),ToFixedRect(textHeight));
this.Canvas.fillStyle = item.LineColor;
this.Canvas.fillText(itemText.Text, textLeft + 2*pixelTatio, yText);
}
else
{
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
}
if (i==0) this.DrawLine(left,right,y,item.LineColor,item.LineType,item);
yText+=textHeight+1*pixelTatio;
rtText.Bottom=yText;
}
}
}
if (mapTextRect && IFrameSplitOperator.IsNumber(rtText.Left) && IFrameSplitOperator.IsNumber(rtText.Bottom))
{
mapTextRect.set(3, { Rect:rtText, Item:item });
}
if (item.Type==3 || item.Type==4)
{
if (item.Title)
{
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
var width=this.Canvas.measureText(item.Title).width+2*pixelTatio;
if (this.IsHScreen)
{
var bgTop=bottom-width;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,textHeight,width);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Title, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=right-width-1*pixelTatio;
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(textLeft,bgTop,width,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Title, textLeft + 1*pixelTatio, y);
}
}
}
}
}
}
}
//K线横屏框架
function KLineHScreenFrame()
{
this.newMethod=KLineFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='KLineHScreenFrame';
this.IsHScreen=true; //是否是横屏
this.DrawSelectedBorder=null;
//画标题背景色
this.DrawTitleBG=function()
{
if (this.ChartBorder.TitleHeight<=0) return;
var border=this.ChartBorder.GetHScreenBorder();
var left=ToFixedPoint(border.RightTitle);
var top=ToFixedPoint(border.Top);
var bottom=ToFixedPoint(border.Bottom);
var width=this.ChartBorder.TitleHeight;
var height=bottom-top;
this.Canvas.fillStyle=this.TitleBGColor;
this.Canvas.fillRect(left,top,width,height);
}
this.DrawToolbar=function()
{
return;
}
this.GetYFromData=function(value,isLimit)
{
var border=this.ChartBorder.GetHScreenBorder();
if (isLimit===false)
{
var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return border.LeftEx+width;
}
else
{
if(value<=this.HorizontalMin) return border.LeftEx;
if(value>=this.HorizontalMax) return border.RightEx;
var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return border.LeftEx+width;
}
}
//画Y轴
this.DrawHorizontal=function()
{
var border=this.ChartBorder.GetHScreenBorder();
var top=border.Top;
var bottom=border.Bottom;
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var left=border.Left;
var right=border.Right;
var yPrev=null; //上一个坐标y的值
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var isDrawLeft=borderTop>10*pixelTatio && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从左往右画分割线
{
var item=this.HorizontalInfo[i];
var y=this.GetYFromData(item.Value);
if (y!=null && Math.abs(y-yPrev)<this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y!=left)
{
if (item.LineType==2)
{
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.setLineDash([5*pixelTatio,5*pixelTatio]); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(y),top);
this.Canvas.lineTo(ToFixedPoint(y),bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else if (item.LineType>0)
{
this.Canvas.strokeStyle=item.LineColor;
if (g_JSChartResource.FrameYLineDash)
{
this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(y),top);
this.Canvas.lineTo(ToFixedPoint(y),bottom);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(y),top);
this.Canvas.lineTo(ToFixedPoint(y),bottom);
this.Canvas.stroke();
}
}
}
//坐标信息 左边 间距小于10 不画坐标
if (item.Message[0]!=null && isDrawLeft)
{
if (item.Font!=null) this.Canvas.font=item.Font;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
var xText=y,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[0], -2, 0);
this.Canvas.restore();
}
//坐标信息 右边 间距小于10 不画坐标
if (item.Message[1]!=null && isDrawRight)
{
if (item.Font!=null) this.Canvas.font=item.Font;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
var text;
if (Array.isArray(item.Message[1])) //横屏只支持单行
{
text=item.Message[1][0];
}
else
{
text=item.Message[1];
}
var xText=y,yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text, 2, 0);
this.Canvas.restore();
}
yPrev=y;
}
}
//Y刻度画在左边内部
this.DrawInsideHorizontal = function ()
{
if (this.IsMinSize) return;
if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;
var left = this.ChartBorder.GetLeft();
var right = this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var titleHeight = this.ChartBorder.TitleHeight;
var pixelTatio = GetDevicePixelRatio();
var isDrawLeft= (borderTop<10*pixelTatio || this.YTextPosition[0]==2) && this.IsShowYText[0]===true;
var isDrawRight= (borderBottom<10*pixelTatio || this.YTextPosition[1]==2) && this.IsShowYText[1]===true;
if ( isDrawLeft || isDrawRight )
{
var pixelTatio = GetDevicePixelRatio();
var yPrev = null; //上一个坐标y的值
for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线
{
var item = this.HorizontalInfo[i];
var y = this.GetYFromData(item.Value);
if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了
//坐标信息 左边 间距小于10 画在内部
if (item.Message[0] != null && isDrawLeft)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
else this.Canvas.textBaseline = "middle";
var textObj={ X:left, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[0]}} ;
var xText=y,yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Message[0], -2, 0);
this.Canvas.restore();
}
if (item.Message[1] != null && isDrawRight)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
else this.Canvas.textBaseline = "middle";
if (Array.isArray(item.Message[1])) var text=item.Message[1][0];
else var text=item.Message[1];
var textWidth = this.Canvas.measureText(text).width;
var textObj={ X:right-textWidth, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:text}} ;
var xText=y,yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text, -2, 0);
this.Canvas.restore();
}
yPrev = y;
}
}
}
this.GetXFromIndex=function(index,isLimit)
{
if (isLimit===false)
{
var border=this.ChartBorder.GetHScreenBorder();
if (index>=0)
{
var offset=border.TopEx+ g_JSChartResource.FrameLeftMargin + this.DistanceWidth/2+this.DataWidth/2;
for(var i=1;i<=index;++i)
{
offset+=this.DistanceWidth+this.DataWidth;
}
}
else
{
var offset=border.TopEx-(this.DistanceWidth/2+this.DataWidth+this.DistanceWidth);
var absIndex=Math.abs(index);
for(var i=1;i<absIndex;++i)
{
offset-=(this.DistanceWidth+this.DataWidth);
}
}
}
else
{
if (index < 0) index = 0;
if (index > this.xPointCount - 1) index = this.xPointCount - 1;
var border=this.ChartBorder.GetHScreenBorder();
var offset=border.TopEx+ g_JSChartResource.FrameLeftMargin + this.DistanceWidth/2+this.DataWidth/2;
for(var i=1;i<=index;++i)
{
offset+=this.DistanceWidth+this.DataWidth;
}
}
return offset;
}
//画X轴
this.DrawVertical=function()
{
var mapX=null;
if (this.GetVerticalXCache) mapX=this.GetVerticalXCache();
var border=this.ChartBorder.GetHScreenBorder();
var left=border.Left;
var right=border.RightTitle;
var bottom=border.Bottom;
var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率
var xPrev=null; //上一个坐标x的值
for(var i=0; i<this.VerticalInfo.length; ++i)
{
var item=this.VerticalInfo[i];
var x=null;
if (mapX && mapX.has(item.Value)) x=mapX.get(item.Value);
else x=this.GetXFromIndex(item.Value);
if (x>=bottom) break;
if (xPrev!=null && Math.abs(x-xPrev)<80) continue;
if (item.LineType==2)
{
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(x));
this.Canvas.lineTo(right,ToFixedPoint(x));
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else if (item.LineType>0)
{
this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
if (g_JSChartResource.FrameXLineDash)
{
this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(x));
this.Canvas.lineTo(right,ToFixedPoint(x));
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
else //实线
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(x));
this.Canvas.lineTo(right,ToFixedPoint(x));
this.Canvas.stroke();
}
}
if (this.VerticalInfo[i].Message[0]!=null)
{
if (this.VerticalInfo[i].Font!=null)
this.Canvas.font=this.VerticalInfo[i].Font;
this.Canvas.fillStyle=this.VerticalInfo[i].TextColor;
var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width;
if (x<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
}
else
{
this.Canvas.textAlign="center";
this.Canvas.textBaseline="top";
}
var xText=left,yText=x;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.VerticalInfo[i].Message[0], 0, this.XBottomOffset);
this.Canvas.restore();
}
xPrev=x;
}
}
//Y坐标转y轴数值
this.GetYData=function(x,isLimit)
{
var border=this.ChartBorder.GetHScreenBorder();
if (isLimit===false)
{
var width=border.RightEx-border.LeftEx;
return (x-border.LeftEx)/width*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
else
{
if (x<border.LeftEx) return this.HorizontalMin;
if (x>border.RightEx) return this.HorizontalMax;
var width=border.RightEx-border.LeftEx;
return (x-border.LeftEx)/width*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
}
//X坐标转x轴数值
this.GetXData=function(y,isLimit)
{
var border=this.ChartBorder.GetHScreenBorder();
var left=border.TopEx+g_JSChartResource.FrameLeftMargin;
var right=border.BottomEx;
var distanceWidth=this.DistanceWidth;
var dataWidth=this.DataWidth;
var maxDataCount=10000*10;
if (isLimit==false)
{
if (y<left)
{
var index=-1;
var xPoint=left-(distanceWidth/2+dataWidth+distanceWidth);
while(index>-maxDataCount)
{
if (xPoint<=y)
break;
xPoint-=(dataWidth+distanceWidth);
--index;
}
return index;
}
else
{
var index=0;
var xPoint=left+distanceWidth/2+dataWidth+distanceWidth;
while(index<maxDataCount) //自己算x的数值
{
if (xPoint>=y) break;
xPoint+=(dataWidth+distanceWidth);
++index;
}
return index;
}
}
else
{
if (y<=border.TopEx) return 0;
if (y>=border.BottomEx) return this.XPointCount-1;
var index=0;
var xPoint=left+distanceWidth/2+ dataWidth+distanceWidth;
while(xPoint<right && index<maxDataCount && index+1<this.XPointCount) //自己算x的数值
{
if (xPoint>y) break;
xPoint+=(dataWidth+distanceWidth);
++index;
}
return index;
}
//return (y-this.ChartBorder.GetTop())*(this.XPointCount*1.0/this.ChartBorder.GetHeight());
}
this.DrawBottons=function()
{
}
//计算数据宽度
/*
this.CalculateDataWidth=function()
{
if (this.XPointCount<2) return;
var width=this.ChartBorder.GetHeight()-g_JSChartResource.FrameMargin;
for(var i=0;i<ZOOM_SEED.length;++i)
{
if((ZOOM_SEED[i][0] + ZOOM_SEED[i][1]) * this.XPointCount < width)
{
this.ZoomIndex=i;
this.DataWidth = ZOOM_SEED[i][0];
this.DistanceWidth = ZOOM_SEED[i][1];
if (i == 0) break; // 如果是最大的缩放因子,不再调整数据宽度
this.TrimKLineDataWidth(width);
return;
}
}
}
*/
/*
this.ZoomUp=function(cursorIndex)
{
if (this.ZoomIndex<=0) return false;
if (this.Data.DataOffset<0) return false;
var dataCount=this.Data.Data.length;
var maxDataCount=dataCount+this.RightSpaceCount;
if (this.XPointCount>=dataCount) return false;
var rightSpaceCount=0;
var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引
var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
if (lastDataIndex>=dataCount)
{
rightSpaceCount=lastDataIndex-(dataCount-1); //计算右边预留空间
lastDataIndex=dataCount-1;
if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
}
var xPointCount=this.CalculateCount(this.ZoomIndex-1);
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} rightSpaceCount=${rightSpaceCount}`);
--this.ZoomIndex;
if (xPointCount>=maxDataCount)
{
xPointCount=maxDataCount;
this.XPointCount=xPointCount;
this.Data.DataOffset=0;
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
}
else
{
this.XPointCount=xPointCount;
this.Data.DataOffset = lastDataIndex - (this.XPointCount-rightSpaceCount)+1;
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
}
this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
var width=this.ChartBorder.GetHeight()-g_JSChartResource.FrameMargin;
this.TrimKLineDataWidth(width);
this.LastCalculateStatus.XPointCount=this.XPointCount;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
return true;
}
this.ZoomDown=function(cursorIndex)
{
if (this.ZoomIndex+1>=ZOOM_SEED.length) return false;
if (this.Data.DataOffset<0) return false;
var dataCount=this.Data.Data.length;
var maxDataCount=dataCount+this.RightSpaceCount;
if (this.XPointCount>=dataCount) return false;
var rightSpaceCount=0;
var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引
if (lastDataIndex>=this.Data.Data.length)
{
rightSpaceCount=lastDataIndex-(this.Data.Data.length-1); //计算右边预留空间
lastDataIndex=this.Data.Data.length-1;
if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
}
var xPointCount=this.CalculateCount(this.ZoomIndex+1);
var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} lastCursorIndex=${lastCursorIndex} rightSpaceCount=${rightSpaceCount}`);
++this.ZoomIndex;
if (xPointCount>=maxDataCount)
{
xPointCount=maxDataCount;
this.XPointCount=xPointCount;
this.Data.DataOffset=0;
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
}
else
{
this.XPointCount=xPointCount;
this.Data.DataOffset = lastDataIndex - (this.XPointCount-rightSpaceCount)+1;
JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
}
this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
var width=this.ChartBorder.GetHeight()-g_JSChartResource.FrameMargin;
this.TrimKLineDataWidth(width);
this.LastCalculateStatus.XPointCount=this.XPointCount;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
return true;
}
*/
}
function OverlayKLineHScreenFrame()
{
this.newMethod=KLineHScreenFrame; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='OverlayKLineHScreenFrame';
this.MainFrame=null; //主框架
this.IsShareY=false; //使用和主框架公用Y轴
this.IsCalculateYMaxMin=true; //是否计算Y最大最小值
this.RightOffset=50;
this.PenBorder=g_JSChartResource.OverlayFrame.BolderPen; //'rgb(0,0,0)'
this.IsShow=true; //坐标是否显示
this.Title=null;
this.TitleColor=g_JSChartResource.OverlayFrame.TitleColor;
this.TitleFont=g_JSChartResource.OverlayFrame.TitleFont;
this.Draw=function()
{
this.SplitXYCoordinate();
if (this.IsShow)
{
this.DrawVertical();
this.DrawHorizontal();
this.DrawTitle();
}
this.SizeChange=false;
this.XYSplit=false;
this.XSplit=false;
this.YCustomSplit=false; //自定义Y轴分割线
}
this.DrawTitle=function() //画标题
{
/*
if (!this.Title) return;
var top = this.ChartBorder.GetTopTitle();
var bottom = this.ChartBorder.GetBottom();
var right=this.ChartBorder.GetRight();
right+=this.RightOffset;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.font=this.TitleFont;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="top";
var xText=right-2,yText=top+(bottom-top)/2;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.Title, 0, 0);
this.Canvas.restore();
*/
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false) return;
if (this.IsShareY) //和主图指标共享Y轴坐标
{
this.HorizontalMax=this.MainFrame.HorizontalMax;
this.HorizontalMin=this.MainFrame.HorizontalMin;
this.HorizontalInfo=[];
for(var i in this.MainFrame.HorizontalInfo)
{
var item=this.MainFrame.HorizontalInfo[i];
this.HorizontalInfo.push(item);
}
}
else
{
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
}
// if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
}
//画Y轴
this.DrawHorizontal=function()
{
/*
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var bottom = this.ChartBorder.GetBottom();
var top = this.ChartBorder.GetTopTitle();
var borderRight=this.ChartBorder.Right;
right+=this.RightOffset;
var yPrev=null; //上一个坐标y的值
for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从上往下画分割线
{
var item=this.HorizontalInfo[i];
var y=this.GetYFromData(item.Value);
if (y!=null && Math.abs(y-yPrev)<this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom';
else if (y <= top + 2) this.Canvas.textBaseline = 'top';
else this.Canvas.textBaseline = "middle";
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(right-2,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
//坐标信息 右边 间距小于10 不画坐标
if (item.Message[1]!=null && borderRight>10)
{
if (item.Font!=null) this.Canvas.font=item.Font;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.textAlign="left";
this.Canvas.fillText(item.Message[1],right+2,y);
}
yPrev=y;
}
*/
}
//画X轴
this.DrawVertical=function()
{
/*
var top=this.ChartBorder.GetTopEx();
//var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var bottom=this.ChartBorder.GetBottomEx();
right+=this.RightOffset;
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top));
this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom));
this.Canvas.stroke();
*/
}
this.GetScaleTextWidth=function()
{
return { TextWidth:0 };
}
}
function SubFrameItem()
{
this.Frame;
this.Height;
this.OverlayIndex=[]; //叠加指标
//this.Interval=60; //子坐标间间距
}
function OverlayIndexItem()
{
this.Frame;
this.ChartPaint=[];
this.Identify=Guid();
this.Scprit; //脚本
this.UpdateFrameMaxMin=function() //调整坐标最大 最小值
{
var value={ Max:null, Min:null }
if (this.Frame.IsShareY) //共享Y轴坐标
{
this.Frame.XYSplit=true;
return;
}
if (this.Frame.YSpecificMaxMin) //固定坐标
{
value.Max=this.Frame.YSpecificMaxMin.Max;
value.Min=this.Frame.YSpecificMaxMin.Min;
}
else
{
for(var i=0;i<this.ChartPaint.length;++i)
{
var paint=this.ChartPaint[i];
if (paint.IsShow==false) continue; //隐藏的图形不计算
var range=paint.GetMaxMin();
if (range==null || range.Max==null || range.Min==null) continue;
if (IFrameSplitOperator.IsNumber(range.Max))
{
if (value.Max==null || value.Max<range.Max) value.Max=range.Max;
}
if (IFrameSplitOperator.IsNumber(range.Min))
{
if (value.Min==null || value.Min>range.Min) value.Min=range.Min;
}
}
}
if (!IFrameSplitOperator.IsNumber(this.Frame.YMaxMin.Max) || this.Frame.YMaxMin.Max!=value.Max)
{
this.Frame.YMaxMin.Max=value.Max;
this.Frame.XYSplit=true;
}
if (!IFrameSplitOperator.IsNumber(this.Frame.YMaxMin.Min) || this.Frame.YMaxMin.Min!=value.Min)
{
this.Frame.YMaxMin.Min=value.Min;
this.Frame.XYSplit=true;
}
if (this.Frame.XYSplit)
{
var max=10, min=0;
if (value.Max!=null) max=value.Max;
if (value.Min!=null) min=value.Min;
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
else
{
this.Frame.XYSplit=true;
}
}
}
//行情框架
function HQTradeFrame()
{
this.SubFrame=new Array(); //SubFrameItem 数组
this.SizeChange=true; //大小是否改变
this.ChartBorder;
this.Canvas; //画布
this.ScreenImageData; //截图
this.Data; //主数据
this.Position; //画布的位置
this.SizeChange=true;
this.MinSubFrameHeight=g_JSChartResource.DragSubFrameBorder.MinFrameHeight;
this.DragBorderHeight=g_JSChartResource.DragSubFrameBorder.TopBorderHeight; //拖拽边框高度
this.AutoLeftBorder=null; //{ Blank:10 留白宽度, MinWidth:最小宽度 }
this.AutoRightBorder=null; //{ Blank:10 留白宽度, MinWidth:最小宽度 }
this.OverlayBlankWidth=30;
this.AuotRightWidth; //右边主坐标刻度宽度 (自动模式)
//固定模式右侧宽度
this.FixedRightWidth={ Main:60, Overlay:80 };
this.ZoomWindowsInfo=null; //附图指标缩放,备份信息
this.ZoomStartWindowIndex=1; //允许缩放窗口起始位置
this.GetExtendChartByClassName;
this.GetEventCallback;
this.OnMoveFromeBorder=function(index, yMove)
{
if (this.SubFrame.length<=0) return false;
var topFrame=this.SubFrame[index];
var bottomFrame=null;
for(var i=index+1;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (item.Height>0)
{
bottomFrame=item;
break;
}
}
if (!topFrame || !bottomFrame) return false;
var bottomBackup=topFrame.Frame.ChartBorder.Bottom;
var topBackup=bottomFrame.Frame.ChartBorder.Top;
topFrame.Frame.ChartBorder.Bottom-=yMove;
bottomFrame.Frame.ChartBorder.Top+=yMove;
var height=topFrame.Frame.ChartBorder.GetHeightEx();
var height2=bottomFrame.Frame.ChartBorder.GetHeightEx();
//缩小的时候 小于最小高度 不处理
if ((height<this.MinSubFrameHeight && yMove<0) || (height2<this.MinSubFrameHeight && yMove>0))
{
topFrame.Frame.ChartBorder.Bottom=bottomBackup;
bottomFrame.Frame.ChartBorder.Top=topBackup;
return false;
}
return true;
}
this.ReDrawToolbar=function()
{
for(var i in this.SubFrame)
{
this.SubFrame[i].Frame.ReDrawToolbar=true;
}
}
this.SetFrameBorderSizeChange=function()
{
var firstFrame=this.SubFrame[0];
if (!firstFrame || !firstFrame.Frame) return;
var splitOper=firstFrame.Frame.YSplitOperator;
if (!splitOper) return;
if (splitOper.CoordinateType==2) //对数坐标 需要重新计算Y轴分割
{
firstFrame.Frame.XYSplit=true;
}
}
this.CancelZoomUpDownFrameY=function(obj)
{
var index=obj.Index;
if (this.SubFrame.length<=0) return false;
if (!this.SubFrame[index]) return false;
var subFrame=this.SubFrame[index];
var frame=subFrame.Frame;
if (obj.IsOverlay)
{
var overlayItem=subFrame.OverlayIndex[obj.OverlayIndex];
if (!overlayItem) return false;
if (!overlayItem.Frame.IsShareY) frame=overlayItem.Frame;
}
var splitOper=frame.YSplitOperator;
if (splitOper.FixedYMaxMin)
{
splitOper.FixedYMaxMin=null;
splitOper.EnableZoomUpDown=false;
frame.XYSplit=true;
for(var i in subFrame.OverlayIndex)
{
var item=subFrame.OverlayIndex[i];
if (item.Frame.IsShareY) item.Frame.XYSplit=true;
}
JSConsole.Chart.Log(`[HQTradeFrame::CancelZoomUpDownFrameY]`);
return true;
}
return false;
}
this.OnZoomUpDownFrameY=function(obj, yMove)
{
var index=obj.Index;
if (this.SubFrame.length<=0) return false;
if (!this.SubFrame[index]) return false;
var subFrame=this.SubFrame[index];
var frame=subFrame.Frame;
if (obj.IsOverlay)
{
var overlayItem=subFrame.OverlayIndex[obj.OverlayIndex];
if (!overlayItem) return false;
if (!overlayItem.Frame.IsShareY) frame=overlayItem.Frame;
}
var top=frame.ChartBorder.GetTopEx();
var bottom=frame.ChartBorder.GetBottomEx();
var maxValue=frame.HorizontalMax;
var minValue=frame.HorizontalMin;
var moveStep=(maxValue-minValue)*Math.abs(yMove)/(bottom-top);
var splitOper=frame.YSplitOperator;
var newFixedYMaxMin={ Max:maxValue, Min:minValue };
if (obj.Position==1)
{
var step=yMove>0 ? -moveStep:moveStep;
newFixedYMaxMin.Max+=step;
}
else if (obj.Position==2)
{
var step=yMove>0 ? -moveStep:moveStep;
newFixedYMaxMin.Min+=step;
}
else if (obj.Position==0)
{
var step=yMove>0 ? moveStep:-moveStep;
newFixedYMaxMin.Max+=step;
newFixedYMaxMin.Min-=step;
}
else
{
return false;
}
if (newFixedYMaxMin.Max>newFixedYMaxMin.Min)
{
splitOper.FixedYMaxMin=newFixedYMaxMin;
splitOper.EnableZoomUpDown=true;
frame.XYSplit=true;
for(var i=0;i<subFrame.OverlayIndex.length;++i)
{
var item=subFrame.OverlayIndex[i];
if (item.Frame.IsShareY) item.Frame.XYSplit=true;
}
JSConsole.Chart.Log(`[HQTradeFrame::OnZoomUpDownFrameY] Max=${newFixedYMaxMin.Max}, Min=${newFixedYMaxMin.Min}`);
return true;
}
return false;
}
this.OnUpDonwFrameY=function(obj, yMove)
{
var index=obj.Index;
if (this.SubFrame.length<=0) return false;
if (!this.SubFrame[index]) return false;
var subFrame=this.SubFrame[index];
var frame=subFrame.Frame;
var top=frame.ChartBorder.GetTopEx();
var bottom=frame.ChartBorder.GetBottomEx();
var splitOper=frame.YSplitOperator;
if (!splitOper) return false;
var maxValue=frame.HorizontalMax;
var minValue=frame.HorizontalMin;
var moveStep=(maxValue-minValue)*Math.abs(yMove)/(bottom-top);
var step=yMove>0 ? -moveStep:moveStep;
var newFixedYMaxMin={ Max:maxValue, Min:minValue };
newFixedYMaxMin.Max-=step;
newFixedYMaxMin.Min-=step;
splitOper.FixedYMaxMin=newFixedYMaxMin;
splitOper.EnableZoomUpDown=true;
frame.XYSplit=true;
for(var i in subFrame.OverlayIndex)
{
var item=subFrame.OverlayIndex[i];
if (item.Frame.IsShareY) item.Frame.XYSplit=true;
}
JSConsole.Chart.Log(`[HQTradeFrame::OnUpDonwFrameY] Max=${newFixedYMaxMin.Max}, Min=${newFixedYMaxMin.Min}, yMove=${yMove}, moveStep=${moveStep}`);
return true;
}
this.ClearUpDonwFrameYData=function(option) //清空上下拖拽的数据
{
if (this.SubFrame.length<=0) return;
if (option)
{
var index=option.Index;
if (index<0 || index>=this.SubFrame.length) return;
var item=this.SubFrame[index];
if (!item || !item.Frame || !item.Frame.YSplitOperator) return;
var splitOper=item.Frame.YSplitOperator;
if (splitOper.EnableZoomUpDown==true) splitOper.FixedYMaxMin=null;
}
else
{
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (!item || !item.Frame || !item.Frame.YSplitOperator) continue;
var splitOper=item.Frame.YSplitOperator;
if (splitOper.EnableZoomUpDown==true) splitOper.FixedYMaxMin=null;
}
}
}
this.ClearCoordinateText=function(option) //清空X,Y轴刻度文字, 线段保留
{
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (!item.Frame) continue;
item.Frame.ClearCoordinateText(option);
}
}
this.RestoreIndexWindows=function()
{
if (!this.ZoomWindowsInfo) return false;
var subFrame=this.SubFrame[this.ZoomWindowsInfo.FrameID];
for(var i=this.ZoomStartWindowIndex;i<this.ZoomWindowsInfo.Data.length; ++i)
{
var restoreItem=this.ZoomWindowsInfo.Data[i];
var frameItem=this.SubFrame[i];
frameItem.Height=restoreItem.Height;
frameItem.Frame.IsMinSize=false;
frameItem.Frame.ReDrawToolbar=true;
frameItem.Frame.XSplitOperator.ShowText=restoreItem.ShowXText;
frameItem.Frame.XYSplit=true;
for(var j=0; j<frameItem.OverlayIndex.length; ++j)
{
var overlayItem=frameItem.OverlayIndex[j];
overlayItem.Frame.IsMinSize=false;
}
}
this.ZoomWindowsInfo=null;
return true;
}
this.ZoomIndexWindow=function(frameID, option)
{
var subFrame=this.SubFrame[frameID];
if (!subFrame) return false;
subFrame.Frame.ChartBorder.IsShowTitleOnly=false;
if (this.ZoomWindowsInfo) //还原
{
return this.RestoreIndexWindows();
}
else //放大
{
var zoomInfo={ FrameID:frameID, Data:[] }; //备份下放大前各个窗口的高度
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
zoomInfo.Data[i]={ Height:item.Height, ShowXText:item.Frame.XSplitOperator.ShowText };
}
this.ZoomWindowsInfo=zoomInfo;
var totalHeight=0;
for(var i=this.ZoomStartWindowIndex;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
var frame=item.Frame;
frame.XYSplit=true;
totalHeight+=item.Height;
if (i!=frameID)
{
item.Height=0;
frame.IsMinSize=true; //最小化
frame.HideToolbar();
frame.XSplitOperator.ShowText=false;
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.IsMinSize=true;
}
}
}
subFrame.Height=totalHeight;
subFrame.Frame.XSplitOperator.ShowText=true;
return true;
}
}
//保存高度比例
this.SaveSubFrameHeightRate=function()
{
var height=this.ChartBorder.GetHeight();
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var subHeight=item.Frame.ChartBorder.GetHeight();
var rate=(subHeight/height)*100;
item.Height=rate;
}
}
this.ShowIndexTitleOnly=function(frameID, option)
{
var item=this.SubFrame[frameID];
if (!item && !item.Frame) return false;
var frame=item.Frame;
if (!frame.ChartBorder) return false;
var subChartBorder=frame.ChartBorder;
if (subChartBorder.TitleHeight<10) return false;
this.RestoreIndexWindows();
if (subChartBorder.IsShowTitleOnly)
{
subChartBorder.IsShowTitleOnly=false;
}
else
{
subChartBorder.IsShowTitleOnly=true;
}
return true;
}
this.CalculateChartBorder=function() //计算每个子框架的边框信息
{
if (this.SubFrame.length<=0) return;
var top=this.ChartBorder.GetTop();
var height=this.ChartBorder.GetHeight();
var totalHeight=0;
var totalTitleHeight=0;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var frame=item.Frame;
if (frame && frame.ChartBorder && frame.ChartBorder.IsShowTitleOnly && item.Height>0)
totalTitleHeight+=frame.ChartBorder.TitleHeight;
else
totalHeight+=item.Height;
}
height-=totalTitleHeight;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var frame=item.Frame;
item.Frame.ChartBorder.Top=top;
item.Frame.ChartBorder.Left=this.ChartBorder.Left;
item.Frame.ChartBorder.Right=this.ChartBorder.Right;
item.Frame.ChartBorder.LeftExtendWidth=this.ChartBorder.LeftExtendWidth;
item.Frame.ChartBorder.RightExtendWidth=this.ChartBorder.RightExtendWidth;
if (frame && frame.ChartBorder && frame.ChartBorder.IsShowTitleOnly && item.Height>0)
{
var frameHeight=item.Frame.ChartBorder.Top+frame.ChartBorder.TitleHeight;
item.Frame.ChartBorder.Bottom=this.ChartBorder.GetChartHeight()-frameHeight;
top=frameHeight;
}
else
{
var frameHeight=height*(item.Height/totalHeight)+top;
item.Frame.ChartBorder.Bottom=this.ChartBorder.GetChartHeight()-frameHeight;
top=frameHeight;
}
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SIZE_FRAME);
if (event && event.Callback)
{
var sendData={ SubFrame:this.SubFrame };
event.Callback(event, sendData, this);
}
}
}
this.SetExtendWidth=function(obj)
{
if (!obj) return;
var leftWidth=null, rightWidth=null;
if (IFrameSplitOperator.IsNumber(obj.Left))
{
leftWidth=obj.Left;
this.ChartBorder.LeftExtendWidth=leftWidth;
}
if (IFrameSplitOperator.IsNumber(obj.Right))
{
rightWidth=obj.Right;
this.ChartBorder.RightExtendWidth=rightWidth;
}
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
if (leftWidth!=null) item.Frame.ChartBorder.LeftExtendWidth=leftWidth;
if (rightWidth!=null) item.Frame.ChartBorder.RightExtendWidth=rightWidth;
}
}
this.CalculateChartBorder2=function() //计算每个子框架的边框信息(思维导图用)
{
if (this.SubFrame.length<=0) return;
var top=this.ChartBorder.Top;
var bottom=this.ChartBorder.Bottom;
var height=this.ChartBorder.GetHeight();
var totalHeight=0;
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
totalHeight+=item.Height;
}
var tempHeight=0;
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
item.Frame.ChartBorder.Top=top;
item.Frame.ChartBorder.Left=this.ChartBorder.Left;
item.Frame.ChartBorder.Right=this.ChartBorder.Right;
item.Frame.ChartBorder.X=this.ChartBorder.X;
item.Frame.ChartBorder.Y=this.ChartBorder.Y;
item.Frame.ChartBorder.Width=this.ChartBorder.Width;
item.Frame.ChartBorder.Height=this.ChartBorder.Height;
var frameHeight=height*(item.Height/totalHeight);
tempHeight+=frameHeight;
bottom=this.ChartBorder.Bottom+(height-tempHeight);
item.Frame.ChartBorder.Bottom=bottom;
top+=frameHeight;
}
}
this.GetScaleTextWidth=function()
{
var width={ Left:null, Right:null, OverlayRight:0 };
var aryOverlayWidth=[];// 叠加坐标
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue;
var frame=item.Frame;
if (!frame) continue;
if (!frame.XSplitOperator) continue;
var maxValue=frame.HorizontalMax; //最大最小要还原
var minValue=frame.HorizontalMin;
frame.YSplitOperator.Operator();
var value=frame.GetScaleTextWidth();
//数据原始范围存储在YMaxMin, 不需要还原HorizontalMax,HorizontalMin
//frame.HorizontalMax=maxValue;
//frame.HorizontalMin=minValue;
if (value && value.TextWidth)
{
var widthItem=value.TextWidth;
if (IFrameSplitOperator.IsNumber(widthItem.Left))
{
if (width.Left==null || width.Left<widthItem.Left) width.Left=widthItem.Left;
}
if (IFrameSplitOperator.IsNumber(widthItem.Right))
{
if (width.Right==null || width.Right<widthItem.Right) width.Right=widthItem.Right;
}
}
//右侧叠加指标
if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
{
for(var j=0, k=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (!overlayItem.Frame) continue;
if (overlayItem.Frame.IsShareY)
{
if (overlayItem.Frame.SyncMainHorizontalInfo)
overlayItem.Frame.SyncMainHorizontalInfo();
var value=overlayItem.Frame.GetScaleTextWidth();
}
else
{
var maxValue=overlayItem.Frame.HorizontalMax; //最大最小要还原
var minValue=overlayItem.Frame.HorizontalMin;
overlayItem.Frame.YSplitOperator.Operator();
var value=overlayItem.Frame.GetScaleTextWidth();
//数据原始范围存储在YMaxMin, 不需要还原HorizontalMax,HorizontalMin
//overlayItem.Frame.HorizontalMax=maxValue;
//overlayItem.Frame.HorizontalMin=minValue;
}
overlayItem.RightWidth={ Index:-1, Width:0 };
if (!value || !value.TextWidth) continue;
var widthItem=value.TextWidth;
if (!IFrameSplitOperator.IsNumber(widthItem.Right)) continue;
overlayItem.RightWidth.Index=k;
overlayItem.RightWidth.Width=widthItem.Right;
if (aryOverlayWidth[k])
{
aryOverlayWidth[k][i]=overlayItem.RightWidth;
}
else
{
aryOverlayWidth[k]=[];
aryOverlayWidth[k][i]=overlayItem.RightWidth;
}
++k;
}
}
}
var overlayWidth=[];
for(var i=0; i<aryOverlayWidth.length; ++i)
{
var colItem=aryOverlayWidth[i];
var max=0;
for(var j=0; j<colItem.length; ++j)
{
if (!colItem[j]) continue;
var item=colItem[j].Width;
if (max<item) max=item;
}
if (max>0) max+=this.OverlayBlankWidth
for(var j=0; j<colItem.length; ++j)
{
if (!colItem[j]) continue;
colItem[j].Width=max;
}
overlayWidth[i]=max;
}
for(var i=0;i<overlayWidth.length;++i)
{
var value=overlayWidth[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
width.OverlayRight+=value;
}
width.AryOverlayWidth=overlayWidth;
return width;
}
this.IsFrameXYSplit=function()
{
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
if (item.Frame.XYSplit) return true;
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Frame.XYSplit) return true;
}
}
return false;
}
this.Draw=function(option)
{
if (this.SizeChange===true)
{
this.CalculateChartBorder();
}
var isSplash=false; //是否过场动画
if (option && option.IsEnableSplash===true) isSplash=true;
if (isSplash==false && (this.AutoLeftBorder || this.AutoRightBorder) && this.IsFrameXYSplit())
{
this.AutoRightOverlayWidth=[];
var textWidth=this.GetScaleTextWidth();
var bSizeChange=false;
if (IFrameSplitOperator.IsNumber(textWidth.Left) && this.AutoLeftBorder)
{
var blank=0;
if (IFrameSplitOperator.IsNumber(this.AutoLeftBorder.Blank)) blank=this.AutoLeftBorder.Blank;
var value=textWidth.Left+blank;
if (IFrameSplitOperator.IsNumber(this.AutoLeftBorder.MinWidth))
{
if (this.AutoLeftBorder.MinWidth>value) value=this.AutoLeftBorder.MinWidth;
}
if (this.IsHScreen) this.ChartBorder.Top=value;
else this.ChartBorder.Left=value;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (this.IsHScreen) item.Frame.ChartBorder.Top=value;
else item.Frame.ChartBorder.Left=value;
}
}
if (IFrameSplitOperator.IsNumber(textWidth.Right))
{
if (this.AutoRightBorder) //自动调整右侧间距
{
var rightTextInfo={ };
var blank=0;
if (IFrameSplitOperator.IsNumber(this.AutoRightBorder.Blank)) blank=this.AutoRightBorder.Blank;
var value=textWidth.Right+blank;
if (IFrameSplitOperator.IsNumber(this.AutoRightBorder.MinWidth))
{
if (this.AutoRightBorder.MinWidth>value) value=this.AutoRightBorder.MinWidth;
}
this.AuotRightWidth=value;
rightTextInfo.MainTextWidth=value; //主图坐标宽度
if (IFrameSplitOperator.IsNonEmptyArray(textWidth.AryOverlayWidth)) rightTextInfo.AryOverlayWidth=textWidth.AryOverlayWidth;
if (IFrameSplitOperator.IsPlusNumber(textWidth.OverlayRight))
{
this.AuotRightWidth=value;
value+=textWidth.OverlayRight;
}
if (this.GetExtendChartRightWidth)
{
var extendWidth=this.GetExtendChartRightWidth();
if (this.GetExtendChartByClassName)
{
var finder=this.GetExtendChartByClassName("StockChip");
if (finder && finder.Chart)
{
finder.Chart.Left=value;
}
}
value+=extendWidth;
}
if (this.IsHScreen)
{
if (this.ChartBorder.Bottom!=value) bSizeChange=true;
this.ChartBorder.Bottom=value;
}
else
{
if (this.ChartBorder.Right!=value) bSizeChange=true;
this.ChartBorder.Right=value;
}
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (this.IsHScreen) item.Frame.ChartBorder.Bottom=value;
else item.Frame.ChartBorder.Right=value;
item.Frame.ReDrawToolbar=true;
item.Frame.YRightTextInfo=rightTextInfo;
for(var j=0;j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.YRightTextInfo=rightTextInfo;
}
}
}
else
{
var rightTextInfo={ };
rightTextInfo.MainTextWidth=this.FixedRightWidth.Main;
if (textWidth.OverlayRight==0) //无叠加直接最右边
{
if (this.IsHScreen)
rightTextInfo.MainTextWidth=this.ChartBorder.Bottom;
else
rightTextInfo.MainTextWidth=this.ChartBorder.Right;
}
else if (IFrameSplitOperator.IsNonEmptyArray(textWidth.AryOverlayWidth))
{
for(var i=0;i<textWidth.AryOverlayWidth.length;++i)
textWidth.AryOverlayWidth[i]=this.FixedRightWidth.Overlay;
rightTextInfo.AryOverlayWidth=textWidth.AryOverlayWidth;
}
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
item.Frame.ReDrawToolbar=true;
item.Frame.YRightTextInfo=rightTextInfo;
for(var j=0;j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.YRightTextInfo=rightTextInfo;
}
}
}
}
this.SetSizeChage(true);
}
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue;
item.Frame.Draw();
if (this.AutoRightBorder)
{
var rightOffset=this.AuotRightWidth;
for(var j=0, index=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
//把主坐标部分设置给子坐标下来
overlayItem.Frame.DataWidth=item.Frame.DataWidth;
overlayItem.Frame.DistanceWidth=item.Frame.DistanceWidth;
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.RightOffset=rightOffset;
overlayItem.Frame.BlankWidth=0;
overlayItem.Frame.TextWidthIndex=index;
if (IFrameSplitOperator.IsNumber(this.OverlayBlankWidth)) overlayItem.Frame.BlankWidth=this.OverlayBlankWidth;
overlayItem.Frame.Draw();
if (overlayItem.RightWidth) rightOffset+=overlayItem.RightWidth.Width;
if (overlayItem.Frame.IsShow) ++index;
}
}
else
{
var rightOffset=this.FixedRightWidth.Main;
if (item.Frame.RightTextMaxWidth>rightOffset) rightOffset=item.Frame.RightTextMaxWidth;
for(var j =0, index=0; j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
//把主坐标部分设置给子坐标下来
overlayItem.Frame.DataWidth=item.Frame.DataWidth;
overlayItem.Frame.DistanceWidth=item.Frame.DistanceWidth;
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.RightOffset=rightOffset;
overlayItem.Frame.BlankWidth=0;
overlayItem.Frame.TextWidthIndex=index;
if (IFrameSplitOperator.IsNumber(this.OverlayBlankWidth)) overlayItem.Frame.BlankWidth=this.OverlayBlankWidth;
overlayItem.Frame.Draw();
if (overlayItem.Frame.IsShow)
{
rightOffset+=this.FixedRightWidth.Overlay;
++index;
}
}
}
}
this.SizeChange=false;
}
this.DrawOveraly=function(bDrawFirst)
{
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue; //高度是0 不画
for(var j=0;j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
for(var k=0; k<overlayItem.ChartPaint.length; ++k)
{
var chartItem=overlayItem.ChartPaint[k];
if (chartItem.IsShow)
{
if (bDrawFirst)
{
if (chartItem.IsDrawFirst) chartItem.Draw();
}
else
{
if (!chartItem.IsDrawFirst) chartItem.Draw();
}
}
}
}
}
}
this.DrawOveralySelectedStatus=function(selectedInfo)
{
if (!selectedInfo.MoveOn.Identify && !selectedInfo.Selected.Identify) return;
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
for(var k in overlayItem.ChartPaint)
{
var chart=overlayItem.ChartPaint[k];
if (!chart.IsShow) continue;
if (!chart.Identify) continue;
if (chart.Identify!=selectedInfo.MoveOn.Identify && chart.Identify!=selectedInfo.Selected.Identify) continue;
if (chart.DrawSelectedStatus)
chart.DrawSelectedStatus();
}
}
}
}
this.PtInOveralyChart=function(x,y)
{
var result=null;
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
for(var k in overlayItem.ChartPaint)
{
var chart=overlayItem.ChartPaint[k];
if (!chart.IsShow) continue;
if (chart.IsHideScriptIndex()) continue;
if (chart.PtInChart)
{
result=chart.PtInChart(x,y);
if (result)
return result;
}
}
}
}
return null;
}
this.DrawPictureCoordinate=function(drawPicture, option)
{
if (!drawPicture || !drawPicture.Frame) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(drawPicture.Point)) return false;
if (!drawPicture.GetXYCoordinate) return false;
var range=drawPicture.GetXYCoordinate();
if (range && range.IsShowYCoordinate===false) //隐藏Y轴刻度信息
{
}
else
{
drawPicture.Frame.DrawPictureYCoordinate(drawPicture, range, option);
}
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (!item || !item.Frame) continue;
if (!item.Frame.XSplitOperator.ShowText) continue;
item.Frame.DrawPictureXCoordinate(drawPicture, range, option);
break;
}
return true;
}
this.DrawLock=function()
{
for (var i in this.SubFrame)
{
var item = this.SubFrame[i];
item.Frame.DrawLock();
}
}
this.DrawLogo=function()
{
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (item.Frame.DrawLogo)
{
item.Frame.DrawLogo();
break;
}
}
}
this.CalculateLock=function()
{
for (var i in this.SubFrame)
{
var item = this.SubFrame[i];
item.Frame.CalculateLock();
}
}
this.DrawInsideHorizontal = function ()
{
for (var i in this.SubFrame)
{
var item = this.SubFrame[i];
if (item.Height<=0) continue;
if (item.Frame.DrawInsideHorizontal) item.Frame.DrawInsideHorizontal();
}
}
this.DrawCustomHorizontal=function() //定制Y轴自定义刻度
{
for (var i in this.SubFrame)
{
var item = this.SubFrame[i];
if (item.Frame.DrawCustomHorizontal) item.Frame.DrawCustomHorizontal();
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Frame && overlayItem.Frame.DrawCustomHorizontal)
overlayItem.Frame.DrawCustomHorizontal();
}
}
}
this.DrawEx=function(option)
{
for(var i in this.SubFrame)
{
var item = this.SubFrame[i];
if ((item.Frame.ClassName=="MinuteFrame"||item.Frame.ClassName=="MinuteHScreenFrame") && i==1)
{
item.Frame.DrawVolTitle(option.Symbol);
}
}
}
this.DrawCustomVertical=function(event)
{
for (var i=0; i<this.SubFrame.length; ++i)
{
var item = this.SubFrame[i];
item.Frame.DrawCustomVerticalEvent=event;
if (item.Frame.DrawCustomVertical) item.Frame.DrawCustomVertical();
}
}
this.DrawToolbar=function(mouseStatus)
{
var moveonPoint=null;
if (mouseStatus && mouseStatus.MoveOnPoint) moveonPoint=mouseStatus.MoveOnPoint;
for (var i=0; i<this.SubFrame.length; ++i)
{
var item = this.SubFrame[i];
if (item.Height<=0) continue;
var frame=item.Frame;
if (!frame) continue;
if (frame.ToolbarButtonStyle==1)
{
if (frame.DrawToolbarV2) frame.DrawToolbarV2(moveonPoint, mouseStatus);
}
for(var j=0;j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
var overlayFrame=overlayItem.Frame;
if (!overlayFrame.IsShow) continue;
if (overlayFrame.DrawToolbar) overlayFrame.DrawToolbar(moveonPoint, frame.IsMinSize, mouseStatus);
}
}
}
this.SetSizeChage=function(sizeChange)
{
this.SizeChange=sizeChange;
for(var i in this.SubFrame)
{
var item=this.SubFrame[i];
item.Frame.SizeChange=sizeChange;
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Frame) overlayItem.Frame.SizeChange=sizeChange;
}
}
//画布的位置
if (this.ChartBorder.UIElement)
{
this.Position={
X:this.ChartBorder.UIElement.offsetLeft,
Y:this.ChartBorder.UIElement.offsetTop,
W:this.ChartBorder.UIElement.clientWidth,
H:this.ChartBorder.UIElement.clientHeight
};
}
}
this.SetBeforeDrawXYCallback=function(callback)
{
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
item.Frame.BeforeDrawXYCallback=callback;
}
}
//图形快照
this.Snapshot=function()
{
this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight());
}
this.GetXData=function(x)
{
return this.SubFrame[0].Frame.GetXData(x);
}
this.GetYData=function(y,outObject) //outObject 可以保存返回的额外数据
{
var frame;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var left=item.Frame.ChartBorder.GetLeft();
var top=item.Frame.ChartBorder.GetTopEx();
var width=item.Frame.ChartBorder.GetWidth();
var height=item.Frame.ChartBorder.GetHeightEx();
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(left,top,width,height);
if (item.Frame.Canvas.isPointInPath(left,y))
{
frame=item.Frame;
if (outObject) outObject.FrameID=i;
break;
}
}
if (frame!=null)
{
if (frame.RightFrame) outObject.RightYValue=frame.RightFrame.GetYData(y); //右侧子坐标
var yValue=frame.GetYData(y);
if (frame.YSplitOperator.CoordinateType==1) //百分比坐标 右边显示百分比信息
{
var firstOpenPrice=frame.YSplitOperator.GetFirstOpenPrice();
outObject.RightYValue=((yValue-firstOpenPrice)/firstOpenPrice*100).toFixed(2)+'%';
}
if (frame.GetMainOverlayFrame)
{
var aryOverlayFrame=frame.GetMainOverlayFrame();
if (aryOverlayFrame)
{
if (aryOverlayFrame[0]) //左侧
{
var leftFrame=aryOverlayFrame[0];
var value=leftFrame.GetYData(y);
outObject.RightYValue=yValue;
yValue=value;
}
if (aryOverlayFrame[1]) //右侧
{
var rightFrame=aryOverlayFrame[1];
var value=rightFrame.GetYData(y);
outObject.RightYValue=value;
}
}
}
return yValue;
}
}
this.PtInFrame=function(x,y) //鼠标哪个指标窗口
{
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var left=item.Frame.ChartBorder.GetLeft();
var top=item.Frame.ChartBorder.GetTop();
var width=item.Frame.ChartBorder.GetWidth();
var height=item.Frame.ChartBorder.GetHeight();
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(left,top,width,height);
if (item.Frame.Canvas.isPointInPath(x,y))
{
return i; //转成整形
}
}
var bottom=this.ChartBorder.GetBottom();
var chartHeight=this.ChartBorder.GetChartHeight();
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
//底部
if (x>=left && x<=right && y>bottom && y<chartHeight)
return -3;
return -1;
}
this.PtInChartFrame=function(x,y) //鼠标在图形区域, 取出上下空白
{
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var left=item.Frame.ChartBorder.GetLeft();
var top=item.Frame.ChartBorder.GetTopEx();
var width=item.Frame.ChartBorder.GetWidth();
var height=item.Frame.ChartBorder.GetHeightEx();
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(left,top,width,height);
if (item.Frame.Canvas.isPointInPath(x,y))
{
return i; //转成整形
}
}
return -1;
}
//Y轴刻度标签
this.PtInHorizontalLabel=function(x,y)
{
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue;
var label=item.Frame.PtInHorizontalLabel(x,y);
if (label)
{
label.Frame=item.Frame;
label.FrameID=i;
return label;
}
}
return null;
}
this.PtInButtons=function(x,y)
{
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue;
var button=item.Frame.PtInButtons(x,y);
if (button)
{
button.Frame=item.Frame;
button.FrameID=i;
return button;
}
for(var j=0;j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
var overlayFrame=overlayItem.Frame;
if (!overlayFrame || !overlayFrame.PtInButtons) continue;
var button=overlayFrame.PtInButtons(x,y);
if (button)
{
button.IndexID=overlayItem.Identify;
button.FrameID=i;
button.OverlayFrame=overlayFrame;
button.Frame=item.Frame;
return button;
}
}
}
return null
}
//是否在X轴坐标上
this.PtInFrameBottom=function(x,y)
{
var left=this.ChartBorder.GetLeft();
var top=this.ChartBorder.GetBottom();
var width=this.ChartBorder.GetWidth();
var height=this.ChartBorder.Bottom;
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
if (this.Canvas.isPointInPath(x,y)) return true;
return false;
}
this.PtInFrameVertical=function(x, y)
{
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (item.Height<=0) continue;
if (!item.Frame.PtInVertical) continue;
if (item.Frame.PtInVertical(x, y))
{
return { Frame:item.Frame };
}
}
return null;
}
this.GetXFromIndex=function(index)
{
return this.SubFrame[0].Frame.GetXFromIndex(index);
}
this.GetYFromData=function(value)
{
return this.SubFrame[0].Frame.GetYFromData(value);
}
this.ZoomUp=function(cursorIndex)
{
var result=this.SubFrame[0].Frame.ZoomUp(cursorIndex);
this.UpdateAllFrame();
return result;
}
this.ZoomDown=function(cursorIndex, option)
{
var result=this.SubFrame[0].Frame.ZoomDown(cursorIndex, option);
this.UpdateAllFrame();
return result;
}
this.SetXShowCount=function(showCount)
{
var result=this.SubFrame[0].Frame.SetXShowCount(showCount);
this.UpdateAllFrame();
return result;
}
this.GetXShowCount=function()
{
var xPointcount=-1;
if (!IFrameSplitOperator.IsNonEmptyArray(this.SubFrame)) return xPointcount;
var subFrame=this.SubFrame[0];
if (!subFrame.Frame) return xPointcount;
xPointcount=subFrame.Frame.XPointCount;
return xPointcount;
}
this.XCoordinateZoom=function(step, isMoveLeft)
{
var result=this.SubFrame[0].Frame.XCoordinateZoom(step, isMoveLeft);
this.UpdateAllFrame();
return result;
}
//设置重新计算刻度坐标
this.ResetXYSplit=function()
{
for(let i in this.SubFrame)
{
this.SubFrame[i].Frame.XYSplit=true;
}
}
this.ResetXSplit=function()
{
for(let i in this.SubFrame)
{
this.SubFrame[i].Frame.XSplit=true;
}
}
this.ResetYCustomSplit=function(windowIndex)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.SubFrame)) return;
if (IFrameSplitOperator.IsNumber(windowIndex) && windowIndex>=0)
{
var item=this.SubFrame[windowIndex];
if (item.Frame) item.Frame.YCustomSplit=true;
}
else
{
for(var i=0;i<this.SubFrame.length;++i)
{
this.SubFrame[i].Frame.YCustomSplit=true;
}
}
}
//清空Y轴坐标的最大最小值
this.ClearYCoordinateMaxMin=function(windowIndex)
{
if (IFrameSplitOperator.IsNumber(windowIndex))
{
var subItem=this.SubFrame[windowIndex];
if (!subItem || !subItem.Frame) return;
var frame=subItem.Frame;
if (frame.YMaxMin)
{
frame.YMaxMin.Max=null;
frame.YMaxMin.Min=null;
}
}
else
{
for(var i=0;i<this.SubFrame.length;++i)
{
var subItem=this.SubFrame[i];
var frame=subItem.Frame;
if (frame.YMaxMin)
{
frame.YMaxMin.Max=null;
frame.YMaxMin.Min=null;
}
}
}
}
this.SetLanguage=function(languageID)
{
for(let i in this.SubFrame)
{
var item=this.SubFrame[i];
if (item && item.Frame )
{
if (item.Frame.YSplitOperator) item.Frame.YSplitOperator.LanguageID=languageID;
if (item.Frame.XSplitOperator) item.Frame.XSplitOperator.LanguageID=languageID;
}
}
}
this.GetCurrentPageSize=function() //获取当前页显示的数据个数
{
if (this.SubFrame.length<=0) return null;
var item=this.SubFrame[0];
if (!item || !item.Frame) return null;
return item.Frame.XPointCount;
}
this.OnSize=function()
{
var obj={};
this.SubFrame[0].Frame.OnSize(obj);
this.UpdateAllFrame();
return obj;
}
this.SetDataWidth=function(dataWidth)
{
var obj=this.SubFrame[0].Frame.SetDataWidth(dataWidth);
this.UpdateAllFrame();
return obj;
}
this.UpdateAllFrame=function()
{
var mainFrame=this.SubFrame[0].Frame;
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (i>0) //第1个窗口主坐标已经算好了
{
item.Frame.XPointCount= mainFrame.XPointCount;
item.Frame.ZoomIndex= mainFrame.ZoomIndex;
item.Frame.DataWidth= mainFrame.DataWidth;
item.Frame.DistanceWidth= mainFrame.DistanceWidth;
item.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width;
item.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount;
}
for(var j in item.OverlayIndex)
{
var overlayItem=this.SubFrame[i].OverlayIndex[j];
overlayItem.Frame.XPointCount= mainFrame.XPointCount;
overlayItem.Frame.ZoomIndex= mainFrame.ZoomIndex;
overlayItem.Frame.DataWidth= mainFrame.DataWidth;
overlayItem.Frame.DistanceWidth= mainFrame.DistanceWidth;
overlayItem.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width;
overlayItem.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount;
}
}
}
//鼠标是否在边框上
this.PtInFrameBorder=function(x,y)
{
var height=this.DragBorderHeight;
for(var i=0;i<this.SubFrame.length-1;++i)
{
var item=this.SubFrame[i];
if (item.Frame.Heigh<=0) continue;
var bottom=item.Frame.ChartBorder.GetBottom();
var left=item.Frame.ChartBorder.GetLeft();
var right=item.Frame.ChartBorder.GetRight();
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(left,bottom-height/2,(right-left),height);
if (item.Frame.Canvas.isPointInPath(x,y))
{
return { Index:i, Bottom:true };
}
}
return null;
}
this.IsEnableDragY=function(index)
{
if (!this.SubFrame) return false;
var item=this.SubFrame[index];
if (!item || !item.Frame || !item.Frame.YSplitOperator) return false;
var split=item.Frame.YSplitOperator;
if (typeof(split.IsEnableDragY)!='function') return false;
return split.IsEnableDragY();
}
this.IsEnableOverlayDragY=function(index, overlayIndex)
{
if (!this.SubFrame) return false;
var item=this.SubFrame[index];
var overlayItem=item.OverlayIndex[overlayIndex];
if (!overlayItem || !overlayItem.Frame) return false;
var split=overlayItem.Frame.YSplitOperator;
if (overlayItem.Frame.IsShareY)
split=overlayItem.Frame.MainFrame.YSplitOperator;
if (!split || typeof(split.IsEnableDragY)!='function') return false;
return split.IsEnableDragY();
}
this.PtInFrameY=function(x,y)
{
var rightExtendWith=0;
if (this.GetExtendChartByClassName)
{
var finder=this.GetExtendChartByClassName("StockChip");
if (finder && finder.Chart) rightExtendWith=finder.Chart.Width;
}
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (item.Frame.Heigh<=0) continue;
var rightWidth=item.Frame.ChartBorder.Right;
rightWidth-=rightExtendWith;
var border=item.Frame.ChartBorder.GetBorder();
var bottom=border.Bottom;
var top=border.TopTitle;
var left=border.Left;
var right=border.Right;
var maxTopHegith=30;
var barHegith=(bottom-top);
if (barHegith/3>maxTopHegith)
{
var barTop=top+maxTopHegith;
var barBottom=bottom-maxTopHegith;
}
else
{
var internal=barHegith/3;
var barTop=top+internal;
var barBottom=bottom-internal;
}
var position=0;
if (y<barTop) position=1;
else if (y>barBottom) position=2;
if (rightWidth>=10)
{
if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
{
var overlayItem=item.OverlayIndex[0];
var rightOffset=overlayItem.Frame.RightOffset;
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(right,top,rightOffset,(bottom-top));
if (item.Frame.Canvas.isPointInPath(x,y))
{
return { Index:i, Right:true, Left:false, Position:position, IsOverlay:false }; //Position 1=上面 2 下面 0=中间(TODO)
}
var overlayRight=right+rightOffset;
for(var j=0;j<item.OverlayIndex.length;++j)
{
var overlayItem=item.OverlayIndex[j];
if (!overlayItem.RightWidth || !IFrameSplitOperator.IsNumber(overlayItem.RightWidth.Width)) continue;
var overlayWidth=overlayItem.RightWidth.Width;
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(overlayRight,top,overlayWidth,(bottom-top));
if (item.Frame.Canvas.isPointInPath(x,y))
{
return { Index:i, Right:true, Left:false , Position:position, IsOverlay:true, OverlayIndex:j }; //Position 1=上面 2 下面 0=中间(TODO)
}
overlayRight+=overlayWidth;
}
}
else
{
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(right,top,rightWidth,(bottom-top));
if (item.Frame.Canvas.isPointInPath(x,y))
{
return { Index:i, Right:true, Left:false , Position:position, IsOverlay:false }; //Position 1=上面 2 下面 0=中间(TODO)
}
}
}
var leftWidth=item.Frame.ChartBorder.Left;
if (leftWidth>=10)
{
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(0,top,leftWidth,(bottom-top));
if (item.Frame.Canvas.isPointInPath(x,y))
{
return { Index:i, Right:false, Left:true, Position:position,IsOverlay:false };
}
}
}
return null;
}
this.SetDayCount=function(dayCount)
{
this.ChartBorder.MultiDayMinute.Count=dayCount;
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (!item.Frame) continue;
item.Frame.DayCount=dayCount;
item.Frame.ChartBorder.MultiDayMinute.Count=dayCount;
}
}
//设置多日分时宽度
this.SetMultiDayMinuteWidth=function(obj)
{
if (!obj) return;
if (IFrameSplitOperator.IsNumber(obj.Left)) this.ChartBorder.MultiDayMinute.Left=obj.Left;
if (IFrameSplitOperator.IsNumber(obj.Right)) this.ChartBorder.MultiDayMinute.Right=obj.Right;
for(var i=0;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (!item.Frame) continue;
if (IFrameSplitOperator.IsNumber(obj.Left)) item.Frame.ChartBorder.MultiDayMinute.Left=obj.Left;
if (IFrameSplitOperator.IsNumber(obj.Right)) item.Frame.ChartBorder.MultiDayMinute.Right=obj.Right;
}
}
}
//行情框架横屏
function HQTradeHScreenFrame()
{
this.newMethod=HQTradeFrame; //派生
this.newMethod();
delete this.newMethod;
this.IsHScreen=true; //是否是横屏
this.CalculateChartBorder=function() //计算每个子框架的边框信息
{
if (this.SubFrame.length<=0) return;
var border=this.ChartBorder.GetHScreenBorder();
var right=this.ChartBorder.Right;
var left=border.Right;
var width=border.Right-border.Left;
var totalHeight=0;
var totalTitleHeight=0;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var frame=item.Frame;
if (frame && frame.ChartBorder && frame.ChartBorder.IsShowTitleOnly && item.Height>0)
totalTitleHeight+=frame.ChartBorder.TitleHeight;
else
totalHeight+=item.Height;
}
width-=totalTitleHeight;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var frame=item.Frame;
item.Frame.ChartBorder.Top=this.ChartBorder.Top;
item.Frame.ChartBorder.Bottom=this.ChartBorder.Bottom;
item.Frame.ChartBorder.LeftExtendWidth=this.ChartBorder.LeftExtendWidth;
item.Frame.ChartBorder.RightExtendWidth=this.ChartBorder.RightExtendWidth;
if (frame && frame.ChartBorder && frame.ChartBorder.IsShowTitleOnly && item.Height>0)
{
var frameWidth=frame.ChartBorder.TitleHeight;
item.Frame.ChartBorder.Right=right;
item.Frame.ChartBorder.Left=left-frameWidth;
right+=frameWidth;
left-=frameWidth;
}
else
{
var frameWidth=width*(item.Height/totalHeight);
item.Frame.ChartBorder.Right=right;
item.Frame.ChartBorder.Left=left-frameWidth;
right+=frameWidth;
left-=frameWidth;
}
}
}
this.GetYData=function(x,outObject)
{
var frame;
for(var i=0; i<this.SubFrame.length; ++i)
{
var item=this.SubFrame[i];
var left=item.Frame.ChartBorder.GetLeftEx();
var top=item.Frame.ChartBorder.GetTop();
var width=item.Frame.ChartBorder.GetWidthEx();
var height=item.Frame.ChartBorder.GetHeight();
item.Frame.Canvas.beginPath();
item.Frame.Canvas.rect(left,top,width,height);
if (item.Frame.Canvas.isPointInPath(x,top))
{
frame=item.Frame;
if (outObject) outObject.FrameID=i;
break;
}
}
if (frame!=null)
{
var xValue= frame.GetYData(x);
if (frame.GetMainOverlayFrame)
{
var aryOverlayFrame=frame.GetMainOverlayFrame();
if (aryOverlayFrame)
{
if (aryOverlayFrame[0]) //左侧
{
var leftFrame=aryOverlayFrame[0];
var value=leftFrame.GetYData(x);
outObject.RightYValue=xValue;
xValue=value;
}
if (aryOverlayFrame[1]) //右侧
{
var rightFrame=aryOverlayFrame[1];
var value=rightFrame.GetYData(x);
outObject.RightYValue=value;
}
}
}
return xValue;
}
}
}
//深度图框架
function DepthChartFrame()
{
this.newMethod=AverageWidthFrame; //派生
this.newMethod();
delete this.newMethod;
this.ScreenImageData; //截图
this.Position; //画布的位置
this.ClassName="DepthChartFrame";
//X轴价格 最大,最小
this.VerticalRange={ Max:88, Min:8, Center:null, MaxDiffer:null, Differ:null, Step:0.05 };
this.AskPrice;
this.BidPrice;
this.MinZoom=0.05; //最小缩放
this.SetPriceList=function(aryAskPrice, aryBidPrice)
{
this.AskPrice=aryAskPrice;
this.BidPrice=aryBidPrice;
}
this.DrawFrame=function()
{
this.SplitXYCoordinate();
this.DrawHorizontal();
this.DrawVertical();
}
this.GetXFromIndex=function(value)
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var width=this.ChartBorder.GetWidth();
var offset=width*(value-this.VerticalRange.Min)/(this.VerticalRange.Max-this.VerticalRange.Min);
return left+offset;
}
this.GetXData=function(x)
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var width=this.ChartBorder.GetWidth();
return (x-left)/width*(this.VerticalRange.Max-this.VerticalRange.Min)+this.VerticalRange.Min;
}
this.GetXFromPrice=function(price)
{
var isAskPrice=false;
var find=this.GetPrice(this.BidPrice, price);
if (find==null)
{
find=this.GetPrice(this.AskPrice, price);
isAskPrice=true;
}
if (find==null)
{
if (this.BidPrice && Array.isArray(this.BidPrice) && this.BidPrice.length>0)
{
var minPrice=this.BidPrice[0];
if (price<minPrice)
{
isAskPrice=false;
find= minPrice;
}
}
}
if (find==null)
{
if (this.AskPrice && Array.isArray(this.AskPrice) && this.AskPrice.length>0)
{
var maxPrice=this.AskPrice[this.AskPrice.length-1];
if (price>maxPrice)
{
isAskPrice=true;
find=maxPrice;
}
}
}
if (find==null) return null;
var x=this.GetXFromIndex(find);
return { X:x, Price:find, IsAsk:isAskPrice };
}
this.GetPrice=function(aryPrice, price)
{
if (!aryPrice || !Array.isArray(aryPrice) || aryPrice.length<=0) return null;
if (price<aryPrice[0] || price>aryPrice[aryPrice.length-1]) return null;
var lastPrice=null;
for(var i in aryPrice)
{
var item=aryPrice[i];
if (price==item)
{
return item;
}
if (price<item)
return lastPrice;
lastPrice=item;
}
}
//分割x,y轴坐标信息
this.SplitXYCoordinate=function()
{
if (this.XYSplit==false) return;
if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
if (this.XSplitOperator!=null) this.XSplitOperator.Operator();
}
//图形快照
this.Snapshot=function()
{
this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight());
}
this.SetSizeChage=function(sizeChange)
{
this.SizeChange=sizeChange;
//画布的位置
this.Position={
X:this.ChartBorder.UIElement.offsetLeft,
Y:this.ChartBorder.UIElement.offsetTop,
W:this.ChartBorder.UIElement.clientWidth,
H:this.ChartBorder.UIElement.clientHeight
};
}
this.PtInFrame=function(x,y) //鼠标哪个指标窗口
{
var left=this.ChartBorder.GetLeft();
var top=this.ChartBorder.GetTop();
var width=this.ChartBorder.GetWidth();
var height=this.ChartBorder.GetHeight();
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
if (this.Canvas.isPointInPath(x,y))
return 0;
return -1;
}
this.PtInFrameBorder=function(x,y)
{
return null;
}
this.ZoomUp=function() //放大
{
var xRange=this.VerticalRange;
var differ=xRange.Differ;
var minDiffer=xRange.MaxDiffer*this.MinZoom;
if (differ<minDiffer) return false;
var offsetDiffer=xRange.Differ*xRange.Step;
differ-=offsetDiffer;
xRange.Differ=differ;
xRange.Min=xRange.Center-xRange.Differ;
xRange.Max=xRange.Center+xRange.Differ;
return true;
}
this.ZoomDown=function() //缩小
{
var xRange=this.VerticalRange;
var differ=xRange.Differ;
if (differ==xRange.MaxDiffer) return false;
var offsetDiffer=xRange.Differ*xRange.Step;
differ+=offsetDiffer;
if (differ>xRange.MaxDiffer) differ=xRange.MaxDiffer;
xRange.Differ=differ;
xRange.Min=xRange.Center-xRange.Differ;
xRange.Max=xRange.Center+xRange.Differ;
return true;
}
}
//历史K线数据
function HistoryData()
{
this.Date;
this.YClose;
this.Open;
this.Close;
this.High;
this.Low;
this.Vol;
this.Amount;
this.Time; //mmhh 或者 mmhhss
this.FlowCapital=null; //流通股本
this.Position=null; //持仓量
this.IsVirtual=false; //是否为虚拟数据
this.IsNonTrade=false; //非交易日
//期货
this.YFClose=null; //前结算价
this.FClose=null; //结算价
//指数才有的数据
this.Stop; //停牌家数
this.Up; //上涨
this.Down; //下跌
this.Unchanged; //平盘
this.ExtendData; //扩展数据
this.BFactor; //前复权
this.AFactor; //后复权
this.RightSeed; //本地计算的复权系数
/*
{
PriceOffset: 每个单元的价格间距,
High: [ { Price:, Value:, Text: Color ,Font:{ Weight:}}, ..... ],
Low:[ { Price:, Value:, Text: Color , Font:{ Weight:}}, ..... ] ,
Order: //订单信息
[
{
Price:,
Ask:{ Color:, Value: , Text:, BG:, Font:{ Weight:} }
Bid:{ Color:, Value:, Text:, BG:, Font:{ Weight:} },
//横线柱子 Width K线宽度比值, Height:高度 Type:0=长度由Width决定, 1=当收盘价小于Price后,线就不需要在继续延伸 2=当收盘价大于Price后,线就不需要在继续延伸了
HBar:{ Color:, Width, Height: 1, Type:0,1,2 },
Vol:{ Value:, BG:, Text:, Color: }
},
........
]
}
*/
this.OrderFlow; //订单流
this.ColorData; //自定义颜色 {Type:0=空心 1=实心, Line:{ Color:'上下线颜色'}, Border:{Color:柱子边框颜色}, BarColor:柱子颜色};
/*
{
PriceOffset:每个单元的价格间距,
Order:
[
{ Price:价格, Color:颜色, Value: }
]
}
*/
this.HeatMap;
}
//数据复制
HistoryData.Copy=function(data)
{
var newData=new HistoryData();
newData.Date=data.Date;
if (IFrameSplitOperator.IsNumber(data.Time)) newData.Time=data.Time;
newData.YClose=data.YClose;
newData.Open=data.Open;
newData.Close=data.Close;
newData.High=data.High;
newData.Low=data.Low;
newData.Vol=data.Vol;
newData.Amount=data.Amount;
if (IFrameSplitOperator.IsNumber(data.FlowCapital)) newData.FlowCapital=data.FlowCapital;
if (IFrameSplitOperator.IsNumber(data.Position)) newData.Position=data.Position;
if (IFrameSplitOperator.IsNumber(data.YFClose)) newData.YFClose=data.YFClose;
if (IFrameSplitOperator.IsNumber(data.FClose)) newData.FClose=data.FClose;
//指数涨停家数
if (IFrameSplitOperator.IsNumber(data.Stop)) newData.Stop=data.Stop;
if (IFrameSplitOperator.IsNumber(data.Up)) newData.Up=data.Up;
if (IFrameSplitOperator.IsNumber(data.Down)) newData.Down=data.Down;
if (IFrameSplitOperator.IsNumber(data.Unchanged)) newData.Unchanged=data.Unchanged;
//复权因子
if (IFrameSplitOperator.IsNumber(data.BFactor)) newData.BFactor=data.BFactor;
if (IFrameSplitOperator.IsNumber(data.AFactor)) newData.AFactor=data.AFactor;
if (IFrameSplitOperator.IsBool(data.IsVirtual)) newData.IsVirtual=data.IsVirtual;
if (IFrameSplitOperator.IsBool(data.IsNonTrade)) newData.IsNonTrade=data.IsNonTrade;
if (data.OrderFlow) newData.OrderFlow=data.OrderFlow;
if (data.ColorData) newData.ColorData=data.ColorData;
if (data.ExtendData) newData.ExtendData=data.ExtendData;
if (data.HeatMap) newData.HeatMap=data.HeatMap;
return newData;
}
//把数据 src 复制到 dest中
HistoryData.CopyTo=function(dest,src)
{
dest.Date=src.Date;
if (IFrameSplitOperator.IsNumber(src.Time)) dest.Time=src.Time;
dest.YClose=src.YClose;
dest.Open=src.Open;
dest.Close=src.Close;
dest.High=src.High;
dest.Low=src.Low;
dest.Vol=src.Vol;
dest.Amount=src.Amount;
if (IFrameSplitOperator.IsNumber(src.FlowCapital)) dest.FlowCapital=src.FlowCapital;
if (IFrameSplitOperator.IsNumber(src.Position)) dest.Position=src.Position;
if (IFrameSplitOperator.IsNumber(src.YFClose)) dest.YFClose=src.YFClose;
if (IFrameSplitOperator.IsNumber(src.FClose)) dest.FClose=src.FClose;
if (IFrameSplitOperator.IsNumber(src.Stop)) dest.Stop=src.Stop;
if (IFrameSplitOperator.IsNumber(src.Up)) dest.Up=src.Up;
if (IFrameSplitOperator.IsNumber(src.Down)) dest.Down=src.Down;
if (IFrameSplitOperator.IsNumber(src.Unchanged)) dest.Unchanged=src.Unchanged;
if (IFrameSplitOperator.IsNumber(src.BFactor)) dest.BFactor=src.BFactor;
if (IFrameSplitOperator.IsNumber(src.AFactor)) dest.AFactor=src.AFactor;
if (IFrameSplitOperator.IsBool(src.IsVirtual)) dest.IsVirtual=src.IsVirtual;
if (IFrameSplitOperator.IsBool(src.IsNonTrade)) dest.IsNonTrade=src.IsNonTrade;
if (src.OrderFlow) dest.OrderFlow=src.OrderFlow;
if (src.ColorData) dest.ColorData=src.ColorData;
if (src.HeatMap) dest.HeatMap=src.HeatMap;
if (src.ExtendData) dest.ExtendData=src.ExtendData;
}
//数据复权拷贝
HistoryData.CopyRight=function(data,seed)
{
var newData=new HistoryData();
newData.Date=data.Date;
if (IFrameSplitOperator.IsNumber(data.Time)) newData.Time=data.Time;
newData.YClose=data.YClose*seed;
newData.Open=data.Open*seed;
newData.Close=data.Close*seed;
newData.High=data.High*seed;
newData.Low=data.Low*seed;
newData.Vol=data.Vol;
newData.Amount=data.Amount;
newData.FlowCapital=data.FlowCapital;
newData.Position=data.Position;
newData.YFClose=data.YFClose;
newData.FClose=data.FClose;
if (data.ColorData) newData.ColorData=data.ColorData; //K线颜色
if (data.ExtendData) newData.ExtendData=data.ExtendData; //扩张数据
return newData;
}
function MinuteData()
{
this.Close;
this.Open;
this.High;
this.Low;
this.Vol; //量
this.Amount; //金额
this.DateTime;
this.Increase; //涨幅
this.Risefall; //涨跌
this.AvPrice; //均价
this.Lead=null; //领先指标
this.Time; //时间
this.Date; //日期
this.Position=null; //持仓量
this.YClearing; //昨结算价
this.YClose; //昨收价
this.ExtendData; //扩展数据
}
//盘前集合竞价
function BeforeOpenData()
{
this.Time;
this.Date;
this.Price; //匹配的价格
this.AvPrice; //均价
this.Vol=[]; //[0]=匹配量 [1]=未匹配量
this.ColorID; //0=平盘 1=红 2=绿 3 ...自定义颜色
this.YClose; //昨收价
}
//收盘集合竞价
function AfterCloseData()
{
this.Time;
this.Date;
this.Price; //匹配的价格
this.AvPrice; //均价
this.Vol=[]; //[0]=匹配量 [1]=未匹配量
this.ColorID; //0=平盘 1=红 2=绿 3 ...自定义颜色
this.YClose; //昨收价
}
//单指标数据
function SingleData()
{
this.Date; //日期
this.Time; //时间
this.Value; //数据 (可以是一个数组)
}
var KLINE_INFO_TYPE=
{
INVESTOR:1, //互动易
ANNOUNCEMENT:2, //公告
PFORECAST:3, //业绩预告
ANNOUNCEMENT_QUARTER_1:4, //一季度报
ANNOUNCEMENT_QUARTER_2:5, //半年报
ANNOUNCEMENT_QUARTER_3:6, //2季度报
ANNOUNCEMENT_QUARTER_4:7, //年报
RESEARCH:8, //调研
BLOCKTRADING:9, //大宗交易
TRADEDETAIL:10, //龙虎榜
//公告预留类型
ANNOUNCEMENT_EX_START:100,
ANNOUNCEMENT_EX_END:200,
}
function KLineInfoData()
{
this.ID;
this.Date;
this.Time; //时间
this.Title;
this.InfoType;
this.ExtendData; //扩展数据
}
//外部数据计算方法接口
function DataPlus ()
{
this.PeriodCallback=new Map(); //key=周期id value={ Period, Callback(period,data,self): }
this.GetPeriodCallback=function(period)
{
if (!this.PeriodCallback.has(period)) return null;
return this.PeriodCallback.get(period);
}
this.AddPeriodCallback=function(obj)
{
if (!IFrameSplitOperator.IsNumber(obj.Period) || !obj.Callback) return;
var item={ Period:obj.Period, Callback:obj.Callback };
this.PeriodCallback.set(obj.Period, item);
}
this.RemovePeriodCallback=function(obj)
{
if (!this.PeriodCallback.has(obj.ID)) return;
this.PeriodCallback.delete(obj.ID);
}
};
var g_DataPlus=new DataPlus();
function ChartData()
{
this.Data=new Array();
this.DataOffset=0; //数据偏移
this.Period=0; //周期 0 日线 1 周线 2 月线 3年线
this.Right=0; //复权 0 不复权 1 前复权 2 后复权
this.Symbol; //股票代码
this.Data2=new Array(); //第1组数据 走势图:历史分钟数据
this.GetCloseMA=function(dayCount)
{
var result=new Array();
for (var i = 0, len = this.Data.length; i < len; i++)
{
if (i < dayCount)
{
result[i]=null;
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++)
{
sum += this.Data[i - j].Close;
}
result[i]=sum / dayCount;
}
return result;
}
this.GetVolMA=function(dayCount)
{
var result=new Array();
for (var i = 0, len = this.Data.length; i < len; i++)
{
if (i < dayCount)
{
result[i]=null;
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++)
{
sum += this.Data[i - j].Vol;
}
result[i]=sum / dayCount;
}
return result;
}
this.GetAmountMA=function(dayCount)
{
var result=new Array();
for (var i = 0, len = this.Data.length; i < len; i++)
{
if (i < dayCount)
{
result[i]=null;
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++)
{
sum += this.Data[i - j].Amount;
}
result[i]=sum / dayCount;
}
return result;
}
//获取收盘价
this.GetClose=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Close;
}
return result;
}
this.GetYClose=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].YClose;
}
return result;
}
this.GetHigh=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].High;
}
return result;
}
this.GetLow=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Low;
}
return result;
}
this.GetOpen=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Open;
}
return result;
}
this.GetVol=function(unit)
{
var value=1;
if (IFrameSplitOperator.IsNumber(unit)) value=unit;
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Vol/value;
}
return result;
}
this.GetAmount=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Amount;
}
return result;
}
this.GetPosition=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Position;
}
return result;
}
this.GetSettlementPrice=function() //结算价
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].FClose;
}
return result;
}
this.GetIsEqual=function()
{
var result=[];
for(var i in this.Data)
{
var item=this.Data[i];
result[i]=(item.Close==item.Open? 1:0);
}
return result;
}
this.GetIsUp=function()
{
var result=[];
for(var i in this.Data)
{
var item=this.Data[i];
result[i]=(item.Close>item.Open? 1:0);
}
return result;
}
this.GetIsDown=function()
{
var result=[];
for(var i in this.Data)
{
var item=this.Data[i];
result[i]=(item.Close<item.Open? 1:0);
}
return result;
}
this.GetLead=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Lead;
}
return result;
}
this.GetDate=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Date;
}
return result;
}
this.GetTime=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Time;
}
return result;
}
this.GetUp=function() //上涨家数
{
var result=[];
for(var i in this.Data)
{
result[i]=this.Data[i].Up;
}
return result;
}
this.GetDown=function() //下跌家数
{
var result=[];
for(var i in this.Data)
{
result[i]=this.Data[i].Down;
}
return result;
}
this.GetYear=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=parseInt(this.Data[i].Date/10000);
}
return result;
}
this.GetMonth=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=parseInt(this.Data[i].Date%10000/100);
}
return result;
}
//分时图均价
this.GetAvPrice=function()
{
var result=new Array();
for(var i in this.Data)
{
var value=this.Data[i].AvPrice;
if (IFrameSplitOperator.IsNumber(value))
result[i]=value;
else
result[i]=0;
}
return result;
}
//获取数据日期和时间范围
this.GetDateRange=function()
{
if (!this.Data || this.Data.length<=0) return null;
var start=this.Data[0];
var end=this.Data[this.Data.length-1];
var range={ Start:{Date:start.Date}, End:{Date:end.Date} };
if (IFrameSplitOperator.IsNumber(start.Time)) range.Start.Time=start.Time;
if (IFrameSplitOperator.IsNumber(end.Time)) range.End.Time=end.Time;
return range;
}
this.GetDateList=function()
{
if (!this.Data || this.Data.length<=0) return null;
var aryDate=[];
var setDate=new Set();
for(var i=0;i<this.Data.length; ++i)
{
var item=this.Data[i];
if (!IFrameSplitOperator.IsNumber(item.Date)) continue;
if (setDate.has(item.Date)) continue;
setDate.add(item.Date);
aryDate.push(item.Date);
}
return aryDate;
}
//计算分钟
this.GetMinutePeriodData=function(period)
{
var result = new Array();
var periodDataCount = 5;
if (period == 5)
periodDataCount = 5;
else if (period == 6)
periodDataCount = 15;
else if (period == 7)
periodDataCount = 30;
else if (period == 8)
periodDataCount = 60;
else if (period==11)
periodDataCount=120;
else if (period==12)
periodDataCount=240;
else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)
{
periodDataCount=period-CUSTOM_MINUTE_PERIOD_START;
return this.GetMinuteCustomPeriodData(periodDataCount);
}
else
return this.Data;
var bFirstPeriodData = false;
var newData = null;
var preTime=null; //上一次的计算时间
for (var i = 0; i < this.Data.length; )
{
bFirstPeriodData = true;
for (var j = 0; j < periodDataCount && i < this.Data.length; ++i)
{
if (bFirstPeriodData)
{
newData = new HistoryData();
result.push(newData);
bFirstPeriodData = false;
}
var minData = this.Data[i];
if (minData == null)
{
++j;
continue;
}
if (minData.Time==925 && (preTime==null || preTime!=924)) //9:25, 9:30 不连续就不算个数
{
}
else if (minData.Time == 930 && (preTime==null || preTime!=929) )
{
}
else if (minData.Time == 1300 && (preTime==null || preTime!=1259) ) //1点的数据 如果不是连续的 就不算个数
{
}
else
++j;
newData.Date = minData.Date;
newData.Time = minData.Time;
preTime=newData.Time;
if (minData.Open==null || minData.Close==null)
continue;
if (newData.Open==null || newData.Close==null)
{
newData.Open=minData.Open;
newData.High=minData.High;
newData.Low=minData.Low;
newData.YClose=minData.YClose;
newData.Close=minData.Close;
newData.Vol=minData.Vol;
newData.Amount=minData.Amount;
newData.FlowCapital=minData.FlowCapital;
newData.Position=minData.Position;
newData.YFClose=minData.YFClose;
newData.FClose=minData.FClose;
}
else
{
if (newData.High<minData.High)
newData.High=minData.High;
if (newData.Low>minData.Low)
newData.Low=minData.Low;
newData.Close=minData.Close;
newData.Vol+=minData.Vol;
if (minData.Amount!=null) newData.Amount+=minData.Amount;
newData.Position=minData.Position;
newData.FlowCapital=minData.FlowCapital;
newData.FClose=minData.FClose;
}
if (i+1 < this.Data.length) //判断下一个数据是否是不同日期的
{
var nextItem=this.Data[i+1];
if (nextItem && nextItem.Date!=minData.Date) //不同日期的, 周期结束
{
++i;
break;
}
}
}
}
return result;
}
//自定义分钟
this.GetMinuteCustomPeriodData=function(count)
{
var result = new Array();
var periodDataCount = count;
var bFirstPeriodData = false;
var newData = null;
for (var i = 0; i < this.Data.length; )
{
bFirstPeriodData = true;
for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j)
{
if (bFirstPeriodData)
{
newData = new HistoryData();
result.push(newData);
bFirstPeriodData = false;
}
var minData = this.Data[i];
if (minData == null) continue;
newData.Date = minData.Date;
newData.Time = minData.Time;
if (minData.Open==null || minData.Close==null) continue;
if (newData.Open==null || newData.Close==null)
{
newData.Open=minData.Open;
newData.High=minData.High;
newData.Low=minData.Low;
newData.YClose=minData.YClose;
newData.Close=minData.Close;
newData.Vol=minData.Vol;
newData.Amount=minData.Amount;
newData.FlowCapital=minData.FlowCapital;
newData.Position=minData.Position;
newData.YFClose=minData.YFClose;
newData.FClose=minData.FClose;
}
else
{
if (newData.High<minData.High) newData.High=minData.High;
if (newData.Low>minData.Low) newData.Low=minData.Low;
newData.Close=minData.Close;
newData.Vol+=minData.Vol;
if (minData.Amount!=null) newData.Amount+=minData.Amount; //null数据不相加
newData.Position=minData.Position;
newData.FlowCapital=minData.FlowCapital;
newData.FClose=minData.FClose;
}
}
}
return result;
}
//计算周,月,年
this.GetDayPeriodData=function(period)
{
if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)
return this.GetDayCustomPeriodData(period-CUSTOM_DAY_PERIOD_START);
var isBit=MARKET_SUFFIX_NAME.IsBIT(this.Symbol);
var result=new Array();
var index=0;
var startDate=0;
var weekCount=2;
var newData=null;
for(var i in this.Data)
{
var isNewData=false;
var dayData=this.Data[i];
switch(period)
{
case 1: //周线
if (isBit) var fridayDate=ChartData.GetSunday(dayData.Date); //数字货币全年的
else var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
isNewData=true;
startDate=fridayDate;
}
break;
case 21: //双周
if (isBit) var fridayDate=ChartData.GetSunday(dayData.Date); //数字货币全年的
else var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
++weekCount;
if (weekCount>=2)
{
isNewData=true;
weekCount=0;
}
startDate=fridayDate;
}
break;
case 2: //月线
if (parseInt(dayData.Date/100)!=parseInt(startDate/100))
{
isNewData=true;
startDate=dayData.Date;
}
break;
case 3: //年线
if (parseInt(dayData.Date/10000)!=parseInt(startDate/10000))
{
isNewData=true;
startDate=dayData.Date;
}
break;
case 22://半年:
var halfYear=ChartData.GetHalfYear(dayData.Date);
if (halfYear!=startDate)
{
isNewData=true;
startDate=halfYear;
}
break;
case 9: //季线
var now=ChartData.GetQuarter(dayData.Date);
now=parseInt(dayData.Date/10000)*10+now;
var last=ChartData.GetQuarter(startDate);
last=parseInt(startDate/10000)*10+last;
if (now!=last)
{
isNewData=true;
startDate=dayData.Date;
}
break;
}
if (isNewData)
{
newData=new HistoryData();
newData.Date=dayData.Date;
result.push(newData);
if (dayData.Open==null || dayData.Close==null) continue;
newData.Open=dayData.Open;
newData.High=dayData.High;
newData.Low=dayData.Low;
newData.YClose=dayData.YClose;
newData.Close=dayData.Close;
newData.Vol=dayData.Vol;
newData.Amount=dayData.Amount;
newData.FlowCapital=dayData.FlowCapital;
newData.Position=dayData.Position;
newData.YFClose=dayData.YFClose;
newData.FClose=dayData.FClose;
}
else
{
if (newData==null) continue;
if (dayData.Open==null || dayData.Close==null) continue;
if (newData.Open==null || newData.Close==null)
{
newData.Open=dayData.Open;
newData.High=dayData.High;
newData.Low=dayData.Low;
newData.YClose=dayData.YClose;
newData.Close=dayData.Close;
newData.Vol=dayData.Vol;
newData.Amount=dayData.Amount;
newData.FlowCapital=dayData.FlowCapital;
newData.Position=dayData.Position;
newData.YFClose=dayData.YFClose;
newData.FClose=dayData.FClose;
}
else
{
if (newData.High<dayData.High) newData.High=dayData.High;
if (newData.Low>dayData.Low) newData.Low=dayData.Low;
newData.Close=dayData.Close;
newData.Vol+=dayData.Vol;
if (dayData.Amount!=null) newData.Amount+=dayData.Amount;
newData.Position=dayData.Position;
newData.FlowCapital=dayData.FlowCapital;
newData.Date=dayData.Date;
newData.FClose=dayData.FClose;
}
}
}
return result;
}
this.GetDayCustomPeriodData=function(count)
{
var result = [];
var periodDataCount = count;
var bFirstPeriodData = false;
var newData = null;
for (var i = 0; i < this.Data.length; )
{
bFirstPeriodData = true;
for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j)
{
if (bFirstPeriodData)
{
newData = new HistoryData();
result.push(newData);
bFirstPeriodData = false;
}
var dayData = this.Data[i];
if (dayData == null) continue;
newData.Date = dayData.Date;
if (dayData.Open==null || dayData.Close==null) continue;
if (newData.Open==null || newData.Close==null)
{
newData.Open=dayData.Open;
newData.High=dayData.High;
newData.Low=dayData.Low;
newData.YClose=dayData.YClose;
newData.Close=dayData.Close;
newData.Vol=dayData.Vol;
newData.Amount=dayData.Amount;
newData.FlowCapital=dayData.FlowCapital;
newData.Position=dayData.Position;
newData.YFClose=dayData.YFClose;
newData.FClose=dayData.FClose;
}
else
{
if (newData.High<dayData.High) newData.High=dayData.High;
if (newData.Low>dayData.Low) newData.Low=dayData.Low;
newData.Close=dayData.Close;
newData.Vol+=dayData.Vol;
if (dayData.Amount!=null) newData.Amount+=dayData.Amount;
newData.Position=dayData.Position;
newData.FlowCapital=dayData.FlowCapital;
newData.FClose=dayData.FClose;
}
}
}
return result;
}
//周期数据 1=周 2=月 3=年
this.GetPeriodData=function(period)
{
//外部自定义周期计算函数
var itemCallback=g_DataPlus.GetPeriodCallback(period);
if (itemCallback) return itemCallback.Callback(period,this.Data,this);
if (MARKET_SUFFIX_NAME.IsBIT(this.Symbol))
{
if (period==5 || period==6 || period==7 || period==8 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) //分钟K线
{
var periodDataCount = 5;
if (period == 5)
periodDataCount = 5;
else if (period == 6)
periodDataCount = 15;
else if (period == 7)
periodDataCount = 30;
else if (period == 8)
periodDataCount = 60;
else if (period==11)
periodDataCount = 120;
else if (period==12)
periodDataCount = 240;
else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)
periodDataCount=period-CUSTOM_MINUTE_PERIOD_START;
return this.GetMinuteCustomPeriodData(periodDataCount);
}
}
//if (period==1 || period==2 || period==3 || period==9 || period==21 || period==22 || (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END))
if (ChartData.IsDayPeriod(period,false)) return this.GetDayPeriodData(period);
//if (period==5 || period==6 || period==7 || period==8 || period==11 || period==12 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) return this.GetMinutePeriodData(period);
if (ChartData.IsMinutePeriod(period,false)) return this.GetMinutePeriodData(period);
}
//复权 0 不复权 1 前复权 2 后复权
this.GetRightData=function(right, option)
{
var result=[];
if (this.Data.length<=0) return result;
if (option && option.AlgorithmType==1) //使用复权因子计算
{
for(var i=0;i<this.Data.length;++i)
{
var item=this.Data[i];
var seed=(right==1?item.BFactor:item.AFactor);
result[i]=HistoryData.CopyRight(item,seed);
}
return result;
}
if (right==1)
{
var index=this.Data.length-1;
var seed=1; //复权系数
var yClose=this.Data[index].YClose;
result[index]=HistoryData.Copy(this.Data[index]);
result[index].RightSeed=seed;
for(--index; index>=0; --index)
{
if (yClose!=this.Data[index].Close) break;
var newItem=HistoryData.Copy(this.Data[index]);
newItem.RightSeed=seed;
result[index]=newItem;
yClose=this.Data[index].YClose;
}
for(; index>=0; --index)
{
var value=this.Data[index].Close;
if(yClose!=value && value!=0)
seed *= yClose/value;
var newItem=HistoryData.CopyRight(this.Data[index],seed);
newItem.RightSeed=seed;
result[index]=newItem
yClose=this.Data[index].YClose;
}
}
else if (right==2)
{
var index=0;
var seed=1;
var close=this.Data[index].Close;
result[index]=HistoryData.Copy(this.Data[index]);
result[index].RightSeed=seed;
for(++index;index<this.Data.length;++index)
{
if (close!=this.Data[index].YClose) break;
var newItem=HistoryData.Copy(this.Data[index]);
newItem.RightSeed=seed;
result[index]=newItem;
close=this.Data[index].Close;
}
for(;index<this.Data.length;++index)
{
if(close!=this.Data[index].YClose)
seed *= close/this.Data[index].YClose;
var newItem=HistoryData.CopyRight(this.Data[index],seed);
newItem.RightSeed=seed;
result[index]=newItem;
close=this.Data[index].Close;
}
}
return result;
}
this.GetRightDate=this.GetRightData;
//叠加数据和主数据拟合,去掉主数据没有日期的数据
this.GetOverlayData=function(overlayData, bApiPeriod)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=overlayData.length)
{
result[i]=new HistoryData();
result[i].Date=date;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
if (overlayDate==date)
{
result[i]=new HistoryData();
result[i].Date=overlayData[j].Date;
result[i].YClose=overlayData[j].YClose;
result[i].Open=overlayData[j].Open;
result[i].High=overlayData[j].High;
result[i].Low=overlayData[j].Low;
result[i].Close=overlayData[j].Close;
result[i].Vol=overlayData[j].Vol;
result[i].Amount=overlayData[j].Amount;
//涨跌家数数据
result[i].Stop=overlayData[j].Stop;
result[i].Up=overlayData[j].Up;
result[i].Down=overlayData[j].Down;
result[i].Unchanged=overlayData[j].Unchanged;
++j;
++i;
}
else if (overlayDate<date)
{
++j;
}
else
{
result[i]=new HistoryData();
result[i].Date=date;
++i;
}
}
return result;
}
this.GetOverlayMinuteData=function(overlayData, bApiPeriod)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=overlayData.length)
{
result[i]=new HistoryData();
result[i].Date=date;
result[i].Time=time;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
var overlayTime=overlayData[j].Time;
if (overlayDate==date && overlayTime==time)
{
result[i]=new HistoryData();
result[i].Date=overlayData[j].Date;
result[i].Time=overlayData[j].Time;
result[i].YClose=overlayData[j].YClose;
result[i].Open=overlayData[j].Open;
result[i].High=overlayData[j].High;
result[i].Low=overlayData[j].Low;
result[i].Close=overlayData[j].Close;
result[i].Vol=overlayData[j].Vol;
result[i].Amount=overlayData[j].Amount;
//涨跌家数数据
result[i].Stop=overlayData[j].Stop;
result[i].Up=overlayData[j].Up;
result[i].Down=overlayData[j].Down;
result[i].Unchanged=overlayData[j].Unchanged;
++j;
++i;
}
else if (overlayDate<date || (overlayDate==date && overlayTime<time))
{
++j;
}
else
{
result[i]=new HistoryData();
result[i].Date=date;
result[i].Time=time;
++i;
}
}
return result;
}
/*
技术指标数据方法
*/
//以主图数据 拟合,返回 SingleData 数组
this.GetFittingData=function(overlayData)
{
var result=new Array();
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=overlayData.length)
{
result[i]=null;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
if (overlayDate==date)
{
var item=new SingleData();
item.Date=overlayData[j].Date;
item.Value=overlayData[j].Value;
result[i]=item;
++j;
++i;
}
else if (overlayDate<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
++i;
}
}
return result;
}
// 缺省数据使用 emptyValue填充
this.GetFittingData2=function(overlayData,emptyValue)
{
var result=new Array();
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=overlayData.length)
{
result[i]=new SingleData();
result[i].Date=date;
result[i].Value=emptyValue;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
if (overlayDate==date)
{
var item=new SingleData();
item.Date=overlayData[j].Date;
item.Value=overlayData[j].Value;
result[i]=item;
++j;
++i;
}
else if (overlayDate<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
result[i].Value=emptyValue;
++i;
}
}
return result;
}
//日期转化 对应数据索引
this.GetDateIndex=function(data)
{
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=data.length) break;
var dateItem=data[j];
if (dateItem.Date==date)
{
dateItem.Index=i;
++j;
}
else if (dateItem.Date<date)
{
++j;
}
else
{
++i;
}
}
}
//日期 时间转化 对应数据索引
this.GetDateTimeIndex=function(data)
{
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=data.length) break;
var dateTimeItem=data[j];
if (dateTimeItem.Date==date && dateTimeItem.Time==time)
{
dateTimeItem.Index=i;
++j;
}
else if (dateTimeItem.Date<date || (dateTimeItem.Date==date && dateTimeItem.Time<time))
{
++j;
}
else
{
++i;
}
}
}
/*
this.GetMinuteFittingData=function(overlayData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=overlayData.length)
{
result[i]=null;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
var overlayTime=overlayData[j].Time;
const overlayItem=overlayData[j];
if (overlayDate==date && overlayTime==time)
{
var item=new SingleData();
item.Date=overlayItem.Date;
item.Time=overlayItem.Time;
item.Value=overlayItem.Value;
result[i]=item;
++j;
++i;
}
else if (overlayDate<date || (overlayDate==date && overlayTime<time))
{
++j;
}
else
{
var item=new SingleData();
item.Date=date;
item.Time=time;
result[i]=item;
++i;
}
}
return result;
}
*/
//分钟数据拟合 精确匹配
this.GetMinuteFittingData=function(overlayData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=overlayData.length)
{
result[i]=null;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
var overlayTime=overlayData[j].Time;
const overlayItem=overlayData[j];
if (overlayDate==date && overlayTime==time)
{
var item=new SingleData();
item.Date=overlayItem.Date;
item.Time=overlayItem.Time;
item.Value=overlayItem.Value;
result[i]=item;
++j;
++i;
}
else if (overlayDate<date || (overlayDate==date && overlayTime<time))
{
++j;
}
else
{
var item=new SingleData();
item.Date=date;
item.Time=time;
result[i]=item;
++i;
}
}
return result;
}
//分钟数据拟合 数据顺延
this.GetMinuteFittingDataV2=function(overlayData)
{
var result=[];
var latestItem=null;
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=overlayData.length)
{
result[i]=null;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
var overlayTime=overlayData[j].Time;
const overlayItem=overlayData[j];
if (overlayDate==date && overlayTime==time)
{
var item=new SingleData();
item.Date=overlayItem.Date;
item.Time=overlayItem.Time;
item.Value=overlayItem.Value;
result[i]=item;
latestItem=overlayItem;
++j;
++i;
}
else if (overlayDate<date || (overlayDate==date && overlayTime<time))
{
//数据更新到最新数据上
var index=result.length-1;
if (index>=0)
{
var item=result[index];
if (item)
{
if (overlayDate<item.Date || ((overlayDate==item.Date && overlayTime<item.Time)))
item.Value=overlayItem.Value;
}
}
latestItem=overlayItem;
++j;
}
else
{
var item=new SingleData();
item.Date=date;
item.Time=time;
if (latestItem) item.Value=latestItem.Value;
result[i]=item;
++i;
}
}
return result;
}
//把财报数据拟合到主图数据,返回 SingleData 数组
this.GetFittingFinanceData=function(financeData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j<financeData.length)
{
var fDate=financeData[j].Date;
if (date<fDate)
{
++i;
continue;
}
}
if (j+1<financeData.length)
{
if (financeData[j].Date<date && financeData[j+1].Date<=date)
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
if (j<financeData.length)
{
item.Value=financeData[j].Value;
item.FinanceDate=financeData[j].Date; //财务日期 调试用
}
else
{
item.Value=null;
item.FinanceDate=null;
}
result[i]=item;
++i;
}
return result;
}
//财务数据拟合到分钟数据上 返回 SingleData 数组
this.GetMinuteFittingFinanceData=function(financeData)
{
var result=[];
if (!Array.isArray(financeData) || financeData.length<=0) return result;
var i=0;
var firstItem=financeData[0];
for(i=0;i<this.Data.length;++i)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (date>firstItem.Date || (date==firstItem.Date && time>=firstItem.Time))
{
break;
}
}
for(var j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j+1<financeData.length)
{
if ((financeData[j].Date<date && financeData[j+1].Date<=date) ||
(financeData[j].Date==date && financeData[j].Time<time && financeData[j+1].Time<=time) )
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.Time=time;
if (j<financeData.length)
{
item.Value=financeData[j].Value;
item.FinanceDate=financeData[j].Date; //财务日期 调试用
item.FinanceTime=financeData[j].Time; //财务日期 调试用
}
else
{
item.Value=null;
item.FinanceDate=null;
item.FinanceTime=null;
}
result[i]=item;
++i;
}
return result;
}
//日线拟合交易数据, 不做平滑处理
this.GetFittingTradeData=function(tradeData, nullValue, bExactMatch)
{
var result=[];
var bMatch=false;
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j<tradeData.length)
{
if (tradeData[j].Date>date)
{
var item=new SingleData();
item.Date=date;
item.Value=nullValue;
result[i]=item;
++i;
continue;
}
}
if (j+1<tradeData.length)
{
if (tradeData[j].Date<date && tradeData[j+1].Date<=date)
{
++j;
bMatch=false;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.Value=nullValue;
item.FinanceDate=null;
if (j<tradeData.length)
{
var tradeItem=tradeData[j];
if (this.Period==0 && bExactMatch===true) //日线完全匹配
{
if (tradeItem.Date==item.Date)
{
item.Value=tradeItem.Value;
item.FinanceDate=tradeItem.Date; //财务日期 调试用
bMatch=true;
}
}
else //其他日线周期
{
if (bMatch==false)
{
item.Value=tradeItem.Value;
item.FinanceDate=tradeItem.Date; //财务日期 调试用
bMatch=true;
}
}
}
result[i]=item;
++i;
}
return result;
}
this.GetMinuteFittingTradeData=function(tradeData, nullValue,bExactMatch)
{
var result=[];
var bMatch=false;
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j<tradeData.length)
{
if (tradeData[j].Date>date || (tradeData[j].Date==date && tradeData[j].Time>time))
{
var item=new SingleData();
item.Date=date;
item.Time=time;
item.Value=nullValue;
result[i]=item;
++i;
continue;
}
}
if (j+1<tradeData.length)
{
if ( (tradeData[j].Date<date && tradeData[j+1].Date<=date) ||
(tradeData[j].Date==date && tradeData[j].Time<time && tradeData[j+1].Time<=time) )
{
++j;
bMatch=false;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.FinanceDate=null;
item.Time=time;
item.Value=nullValue;
if (j<tradeData.length)
{
var tradeItem=tradeData[j];
if (this.Period==4 && bExactMatch===true) //1分钟线完全匹配
{
if (tradeItem.Date==item.Date && tradeItem.Time==item.Time) //完全匹配
{
item.Value=tradeItem.Value;
item.FinanceDate=tradeItem.Date; //财务日期 调试用
item.FinanceTime=tradeItem.Time;
bMatch=true;
}
}
else //其他日线周期
{
if (bMatch==false)
{
item.Value=tradeItem.Value;
item.FinanceDate=tradeItem.Date; //财务日期 调试用
item.FinanceTime=tradeItem.Time;
bMatch=true;
}
}
}
result[i]=item;
++i;
}
return result;
}
//市值计算 financeData.Value 是股数
this.GetFittingMarketValueData=function(financeData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var price=this.Data[i].Close;
if (j+1<financeData.length)
{
if (financeData[j].Date<date && financeData[j+1].Date<=date)
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.Value=financeData[j].Value*price; //市值计算 收盘价*股数
item.FinanceDate=financeData[j].Date; //财务日期 调试用
result[i]=item;
++i;
}
return result;
}
//月线数据拟合
this.GetFittingMonthData=function(overlayData)
{
var result=new Array();
var preDate=null;
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=overlayData.length)
{
result[i]=null;
++i;
continue;;
}
var overlayDate=overlayData[j].Date;
if (overlayDate==date)
{
var item=new SingleData();
item.Date=overlayData[j].Date;
item.Value=overlayData[j].Value;
item.Text=overlayData[j].Text;
result[i]=item;
++j;
++i;
}
else if (preDate!=null && preDate<overlayDate && date>overlayDate)
{
var item=new SingleData();
item.Date=date;
item.OverlayDate=overlayData[j].Date;
item.Value=overlayData[j].Value;
item.Text=overlayData[j].Text;
result[i]=item;
++j;
++i;
}
else if (overlayDate<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
++i;
}
preDate=date;
}
return result;
}
this.GetValue=function()
{
var result=[];
for(var i in this.Data)
{
if (this.Data[i] && this.Data[i].Value!=null)
{
var item=this.Data[i].Value;
if (!isNaN(item))
result[i]=item;
else if (item instanceof Array) //支持数组
result[i]=item;
else
result[i]=null;
}
else
result[i]=null;
}
return result;
}
this.GetObject=function()
{
var result=[];
for(var i in this.Data)
{
if (this.Data[i] && this.Data[i].Value)
{
var item=this.Data[i].Value;
result[i]=item;
}
else
result[i]=null;
}
return result;
}
this.GetPeriodSingleData=function(period)
{
var result=new Array();
var index=0;
var startDate=0;
var weekCount=2;
var newData=null;
for(var i in this.Data)
{
var isNewData=false;
var dayData=this.Data[i];
if (dayData==null || dayData.Date==null) continue;
switch(period)
{
case 1: //周线
var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
isNewData=true;
startDate=fridayDate;
}
break;
case 21: //双周
var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
++weekCount;
if (weekCount>=2)
{
isNewData=true;
weekCount=0;
}
startDate=fridayDate;
}
break;
case 2: //月线
if (parseInt(dayData.Date/100)!=parseInt(startDate/100))
{
isNewData=true;
startDate=dayData.Date;
}
break;
case 3: //年线
if (parseInt(dayData.Date/10000)!=parseInt(startDate/10000))
{
isNewData=true;
startDate=dayData.Date;
}
break;
case 9: //季线
var now=ChartData.GetQuarter(dayData.Date);
now=parseInt(dayData.Date/10000)*10+now;
var last=ChartData.GetQuarter(startDate);
last=parseInt(startDate/10000)*10+last;
if (now!=last)
{
isNewData=true;
startDate=dayData.Date;
}
break;
}
if (isNewData)
{
newData=new SingleData();
newData.Date=dayData.Date;
newData.Value=dayData.Value;
result.push(newData);
}
else
{
if (newData==null) continue;
if (dayData.Value==null || isNaN(dayData.Value)) continue;
if (newData.Value==null || isNaN(newData.Value)) newData.Value=dayData.Value;
}
}
return result;
}
/*
分钟数据方法
this.GetClose() 每分钟价格
this.GetVol() 每分钟成交量
*/
//分钟均线
this.GetMinuteAvPrice=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].AvPrice;
}
return result;
}
this.MergeMinuteData=function(data) //合并数据
{
if (!this.Data || this.Data.length<=0)
{
this.Data=data;
return true;
}
var sourceFirstItem=this.Data[0];
var firstItemID=0;
var firstItem=null;
for(var i=0;i<data.length;++i) //查找比原始数据起始位置大的数据位置
{
var item=data[i];
if (item.Date>sourceFirstItem.Date)
{
firstItemID=i;
firstItem=item;
break;
}
if (item.Date==sourceFirstItem.Date && item.Time>=sourceFirstItem.Time)
{
firstItemID=i;
firstItem=item;
break;
}
}
if (firstItem==null) return false;
var index=null;
var bFind=false; //第1个数据是否完全匹配
for(var i=this.Data.length-1; i>=0;--i)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (firstItem.Date>date || (firstItem.Date==date && firstItem.Time>=time) )
{
index=i;
if (firstItem.Date==date && firstItem.Time==time) bFind=true;
break;
}
}
if (index==null) return false;
var j=index; //原始数据插入位置
var i=firstItemID; //合并数据起始位置
if (bFind==true) //第1个数据匹配,覆盖
{
var item=data[i];
if (j-1>0)
{
var preItem=this.Data[j-1];
if (!item.YClose) item.YClose=preItem.Close; //前收盘如果没有就是上一记录的收盘
//流通股使用上一个数据的
if (!IFrameSplitOperator.IsNumber(item.FlowCapital) && IFrameSplitOperator.IsNumber(preItem.FlowCapital))
item.FlowCapital=preItem.FlowCapital;
}
var newItem=HistoryData.Copy(item);
this.Data[j]=newItem;
++j;
++i;
}
else //从下一个数据开始插入
{
++j;
}
for(;i<data.length; )
{
var item=data[i];
if (j>=this.Data.length-1)
{
if (j-1>0)
{
var preItem=this.Data[j-1];
if (!item.YClose) item.YClose=preItem.Close; //前收盘如果没有就是上一记录的收盘
//流通股使用上一个数据的
if (!IFrameSplitOperator.IsNumber(item.FlowCapital) && IFrameSplitOperator.IsNumber(preItem.FlowCapital))
item.FlowCapital=preItem.FlowCapital;
}
//if (j-1>0 && !item.YClose) item.YClose=this.Data[j-1].YClose; //前收盘如果没有就是上一记录的收盘
//if (j-1>0 && !IFrameSplitOperator.IsNumber(item.FlowCapital) && IFrameSplitOperator.IsNumber(this.Data[j-1].FlowCapital)) item.FlowCapital=this.Data[j-1].FlowCapital;
var newItem=HistoryData.Copy(item);
this.Data[j]=newItem;
++j;
++i;
}
else
{
var oldItem=this.Data[j];
if (oldItem.Date==item.Date && oldItem.Time==item.Time) //更新数据
{
HistoryData.CopyTo(oldItem,item);
++j;
++i;
}
else
{
++j;
}
}
}
//JSConsole.Chart.Log('[ChartData::MergeMinuteData] ', this.Data, data);
return true;
}
//跨周期转化
this.ConverPeriod=function(data, curPeriod, changePeriod) //把数据用data, 日期时间不变, curPeriod=当前周期 changePeriod=需要转换周期
{
var result=[];
var tempItem=null;
var isMinute=ChartData.IsMinutePeriod(curPeriod,true);
var isMinute2=ChartData.IsMinutePeriod(changePeriod,true);
var isMimToMin=isMinute && isMinute2;
var isMinToDay=isMinute && !isMinute2;
var isDayToDay=!isMinute && !isMinute2;
for(var i=0,j=0; i<this.Data.length; ++i)
{
var item=this.Data[i]; //原始数据
for(;j<data.length;++j)
{
var periodItem=data[j];
if (isMimToMin) //都是分钟数据
{
if ( (periodItem.Date>item.Date) || (periodItem.Date==item.Date && periodItem.Time>=item.Time) )
{
tempItem=periodItem;
break;
}
}
else if (isMinToDay || isDayToDay) //分钟 => 日线, 日线 => 日线
{
if (periodItem.Date>=item.Date)
{
tempItem=periodItem;
break;
}
}
}
var newItem=null;
if (tempItem)
{
newItem=HistoryData.Copy(tempItem);
newItem.PDate=tempItem.Date;
newItem.PTime=tempItem.Time;
}
else newItem=new HistoryData();
newItem.Date=item.Date;
if (isMimToMin || isMinToDay) newItem.Time=item.Time;
result.push(newItem);
}
JSConsole.Chart.Log('[ChartData::ConverPeriod] result', result);
return result;
}
this.GetRef=function(n)
{
let result=[];
for(var i=0 ;i<this.Data.length; ++i )
{
result[i]=null;
var itemDate=this.Data[i]; //原始数据
if (i-n<0)
{
var newData=new HistoryData();
newData.Date=itemDate.Date;
newData.Time=itemDate.Time;
result[i]=newData;
continue;
}
var itemData=this.Data[i-n];
var newData=HistoryData.Copy(itemData);
newData.Date=itemDate.Date;
newData.Time=itemDate.Time;
result[i]=newData;
}
return result;
}
//拟合其他K线数据指标
this.FitKLineIndex=function(kLineData, outVar, peirod, indexPeriod)
{
var count=this.Data.length; //原始K线数据
var indexCount=kLineData.length; //拟合K线数据
var isMinutePeriod=[ChartData.IsMinutePeriod(peirod,true), ChartData.IsMinutePeriod(indexPeriod,true) ]; //0=原始K线 1=需要拟合的K线
var isDayPeriod=[ChartData.IsDayPeriod(peirod,true), ChartData.IsDayPeriod(indexPeriod,true) ]; //0=原始K线 1=需要拟合的K线
var firstItem=ChartData.GetKLineDataTime(this.Data[0]);
//计算拟合以后的数据索引
var aryFixDataID=[];
var indexStart=indexCount;
for(var i=0;i<indexCount;++i)
{
var item=ChartData.GetKLineDataTime(kLineData[i]);
if ( (isDayPeriod[0] && isDayPeriod[1]) || (isMinutePeriod[0] && isDayPeriod[1]) ) //日线(拟合) => 日线(原始) 日线(拟合 => 分钟(原始)
{
if (item.Date>=firstItem.Date)
{
indexStart = i;
break;
}
}
else if (isMinutePeriod[0] && isMinutePeriod[1]) //分钟(拟合 => 分钟(原始)
{
if (item.Date>firstItem.Date)
{
indexStart = i;
break;
}
if (item.Date == firstItem.Date && item.Time >= firstItem.Time )
{
indexStart = i;
break;
}
}
}
for(var i=0, j=indexStart; i<count; )
{
var item=ChartData.GetKLineDataTime(this.Data[i]);
if (j>=indexCount)
{
var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
aryFixDataID[i]=fitItem;
++i;
continue;
}
var destItem=ChartData.GetKLineDataTime(kLineData[j]);
if ( (isDayPeriod[0] && isDayPeriod[1]) || (isMinutePeriod[0] && isDayPeriod[1]) ) //日线(拟合) => 日线(原始) 日线(拟合 => 分钟(原始)
{
if (destItem.Date == item.Date)
{
var fitItem={ Date:item.Date, Time:item.Time, Index:j, Data2:destItem.Date, Time2:destItem.Time };
aryFixDataID[i]=fitItem;
++i;
}
else
{
if (j+1<indexCount)
{
var nextDestItem=ChartData.GetKLineDataTime(kLineData[j+1]);
if ( destItem.Date<=item.Date && nextDestItem.Date>item.Date )
{
var fitItem={ Date:item.Date, Time:item.Time, Index:j+1, Data2:nextDestItem.Date, Time2:nextDestItem.Time };
aryFixDataID[i]=fitItem;
++i;
}
else if (nextDestItem.Date <= item.Date )
{
++j;
}
else
{
var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
aryFixDataID[i]=fitItem;
++i;
}
}
else
{
++j;
}
}
}
else if (isMinutePeriod[0] && isMinutePeriod[1]) //分钟(拟合 => 分钟(原始)
{
if (destItem.Date == item.Date && destItem.Time == item.Time)
{
var fitItem={ Date:item.Date, Time:item.Time, Index:j, Data2:destItem.Date, Time2:destItem.Time };
aryFixDataID[i]=fitItem;
++i;
}
else
{
if (j+1<indexCount)
{
var nextDestItem=ChartData.GetKLineDataTime(kLineData[j+1]);
if ( (destItem.Date<item.Date && nextDestItem.Date>item.Date) ||
(destItem.Date == item.Date && destItem.Time < item.Time && nextDestItem.Date == item.Date && nextDestItem.Time > item.Time) ||
(destItem.Date == item.Date && destItem.Time < item.Time && nextDestItem.Date > item.Date) ||
(destItem.Date < item.Date && nextDestItem.Date == item.Date && nextDestItem.Time > item.Time) )
{
var fitItem={ Date:item.Date, Time:item.Time, Index:j+1, Data2:nextDestItem.Date, Time2:nextDestItem.Time };
aryFixDataID[i]=fitItem;
++i;
}
else if (nextDestItem.Date < item.Date || (nextDestItem.Date == item.Date && nextDestItem.Time <= item.Time) )
{
++j;
}
else
{
var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
aryFixDataID[i]=fitItem;
++i;
}
}
else
{
++j;
}
}
}
}
//拟合数据
var result=[];
for(var i in outVar)
{
var item=outVar[i];
if (Array.isArray(item.Data))
{
var data=[];
result[i]={ Data:data, Name:item.Name } ;
for(var j=0;j<aryFixDataID.length;++j)
{
var dataItem=aryFixDataID[j];
data[j]=null;
if ( dataItem && dataItem.Index>=0 && dataItem.Index<item.Data.length )
data[j]=item.Data[dataItem.Index];
}
}
else
{
result[i]={ Data:item.Data, Name:item.Name} ;
}
}
return result;
}
//获取数据索引
this.FindDataIndexByDateTime=function(aryDateTime) //aryDateTime=[ { Date:, Time:, Index:-1 }, ......]
{
var findCount=0;
for(var i in aryDateTime)
{
aryDateTime[i].Index=-1;
}
for(var i in this.Data)
{
var item=this.Data[i];
for(var j in aryDateTime)
{
var findItem=aryDateTime[j];
if (findItem.Index>=0) continue;
if (IFrameSplitOperator.IsNumber(findItem.Time))
{
if (findItem.Date==item.Date && findItem.Time==item.Time)
{
findItem.Index=parseInt(i);
++findCount;
break;
}
}
else
{
if (findItem.Date==item.Date)
{
findItem.Index=parseInt(i);
++findCount;
break;
}
}
if (findCount>=aryDateTime.length) break;
}
}
}
//深拷贝数据
this.CloneData=function(className)
{
var result=[];
if (className=="HistoryData")
{
for(var i in this.Data)
{
var item=this.Data[i];
var newItem=HistoryData.Copy(item);
result.push(newItem);
}
}
return result;
}
this.GetAPIDataIndex=function(date,time)
{
var result=[];
if (date && time)
{
var count=this.Data.length; //原始K线数据
var indexCount=date.length; //拟合数据
var firstItem=ChartData.GetKLineDataTime(this.Data[0]);
var indexStart=indexCount; //拟合数据的起始位置
var indexStart=indexCount; //拟合数据的起始位置
for(var i=0;i<indexCount;++i)
{
var itemDate=date[i];
var itemTime=time[i];
if (itemDate>firstItem.Date || (itemDate == firstItem.Date && itemTime >= firstItem.Time))
{
indexStart = i;
break;
}
}
for(var i=0, j=indexStart; i<count; )
{
var item=this.Data[i];
if (j>=indexCount)
{
var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:-1 };
result[i]=fitItem;
++i;
continue;
}
var itemDate=date[j];
var itemTime=time[j];
if (itemDate == item.Date && itemTime == item.Time)
{
var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:j, Data:itemDate, Time:itemTime };
result[i]=fitItem;
++i;
}
else
{
if (j+1<indexCount)
{
var nextItemDate=date[j+1];
var nextItemTime=time[j+1];
if ( (itemDate<item.Date && nextItemDate>item.Date) ||
(itemDate == item.Date && itemTime < item.Time && nextItemDate == item.Date && nextItemTime > item.Time) ||
(itemDate == item.Date && itemTime < item.Time && nextItemDate > item.Date) ||
(itemDate < item.Date && nextItemDate == item.Date && nextItemTime > item.Time) )
{
var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:j, Data:itemDate, Time:itemTime };
result[i]=fitItem;
++i;
}
else if (nextItemDate < item.Date || (nextItemDate == item.Date && nextItemTime <= item.Time) )
{
++j;
}
else
{
var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:-1 };
result[i]=fitItem;
++i;
}
}
else
{
++j;
}
}
}
}
else if (date)
{
var count=this.Data.length; //原始K线数据
var indexCount=date.length; //拟合数据
var firstItem=ChartData.GetKLineDataTime(this.Data[0]);
var indexStart=indexCount; //拟合数据的起始位置
for(var i=0;i<indexCount;++i)
{
var item=date[i];
if (item>=firstItem.Date)
{
indexStart = i;
break;
}
}
for(var i=0, j=indexStart; i<count; )
{
var item=this.Data[i];
if (j>=indexCount)
{
var fitItem={ KDate:item.Date, KIndex:i, Index:-1 };
result[i]=fitItem;
++i;
continue;
}
var destDate=date[j];
if (destDate == item.Date)
{
var fitItem={ KDate:item.Date, KIndex:i, Index:j, Data:destDate };
result[i]=fitItem;
++i;
}
else
{
if (j+1<indexCount)
{
var nextDestDate=date[j+1];
if ( destDate<=item.Date && nextDestDate>item.Date )
{
var fitItem={ KDate:item.Date, KIndex:i, Index:j, Data:destDate };
result[i]=fitItem;
++i;
}
else if (nextDestDate <= item.Date )
{
++j;
}
else
{
var fitItem={ KDate:item.Date, KIndex:i, Index:-1 };
result[i]=fitItem;
++i;
}
}
else
{
++j;
}
}
}
}
return result;
}
//K线数据拟合
this.FixKData=function(aryKData, period)
{
if (ChartData.IsDayPeriod(period,true))
{
return this.FixKData_Day(aryKData);
}
else if (ChartData.IsMinutePeriod(period,true))
{
return this.FixKData_Minute(aryKData);
}
return null;
}
this.FixKData_Day=function(aryKData)
{
var result=[];
var nOverlayDataCount=aryKData.length;
for(var i=0,j=0; i<this.Data.length;)
{
var kItem=this.Data[i];
if (j<nOverlayDataCount)
{
var fItem=aryKData[j];
if (fItem.Date>kItem.Date)
{
++i;
continue;
}
}
if (j+1<nOverlayDataCount)
{
var fItem = aryKData[j];
var fItem2 = aryKData[j + 1];
if (fItem.Date < kItem.Date && fItem2.Date <= kItem.Date)
{
++j;
continue;
}
}
var item=new HistoryData();
item.Date=kItem.Date;
var index=j<nOverlayDataCount ? j : nOverlayDataCount-1;
var fItem=aryKData[index];
item.Close = fItem.Close;
item.High = fItem.High;
item.Low = fItem.Low;
item.Open = fItem.Open;
item.YClose = fItem.YClose;
item.Amount = fItem.Amount;
item.Vol = fItem.Vol;
item.ExDate = fItem.Date; //对应叠加数据的日期 调试用
result[i]=item;
++i;
}
return result;
}
this.FixKData_Minute=function(aryKData)
{
var result=[];
var nOverlayDataCount=aryKData.length;
for(var i=0,j=0; i<this.Data.length;)
{
var kItem=this.Data[i];
var kDateTime=ChartData.DateTimeToNumber(kItem);
if (j<nOverlayDataCount)
{
var fItem=aryKData[j];
var fDateTime=ChartData.DateTimeToNumber(fItem);
if (fDateTime>kDateTime)
{
++i;
continue;
}
}
if (j+1<nOverlayDataCount)
{
var fItem = aryKData[j];
var fItem2 = aryKData[j + 1];
var fDateTime=ChartData.DateTimeToNumber(fItem);
var fDateTime2=ChartData.DateTimeToNumber(fItem2);
if (fDateTime < kDateTime && fDateTime2 <= kDateTime)
{
++j;
continue;
}
}
var item=new HistoryData();
item.Date=kItem.Date;
item.Time=kItem.Time;
var index=j<nOverlayDataCount ? j : nOverlayDataCount-1;
var fItem=aryKData[index];
item.Close = fItem.Close;
item.High = fItem.High;
item.Low = fItem.Low;
item.Open = fItem.Open;
item.YClose = fItem.YClose;
item.Amount = fItem.Amount;
item.Vol = fItem.Vol;
item.ExDate = fItem.Date; //对应叠加数据的日期 调试用
item.ExTime=fItem.Time; //对应叠加数据的日期 调试用
result[i]=item;
++i;
}
return result;
}
//获取K线的索引范围 start={ Date, Time };
this.GetDataRange=function(start, end)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var range={ }; //{Start:{Date, Time, Index,}, End:{Date, Time, Index}}
for(var i=0; i<this.Data.length; ++i)
{
var item=this.Data[i];
if (item.Date==start.Date)
{
if (IFrameSplitOperator.IsNumber(start.Time))
{
if (item.Time==start.Time) range.Start={ Index:i, Date:item.Date, Time:item.Time };
}
else
{
range.Start={ Index:i, Date:item.Date };
}
}
if (item.Date=end.Date)
{
if (IFrameSplitOperator.IsNumber(end.Time))
{
if (item.Time==end.Time) range.End={ Index:i, Date:item.Date, Time:item.Time };
}
else
{
range.End={ Index:i, Date:item.Date };
}
}
if (range.Start && range.End) return range;
}
return null;
}
//导出单数组数据
this.ExportArrayData=function(aryKData,option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var start=0, end=this.Data.length-1;
//限制范围
if (option && option.Start && option.End && IFrameSplitOperator.IsNumber(option.Start.Index) && IFrameSplitOperator.IsNumber(option.End.Index))
{
start=option.Start.Index;
end=option.End.Index;
}
var aryData=[];
for(var i=start; i<=end && i<this.Data.length; ++i)
{
aryData[i]=this.Data[i];
}
return aryData;
}
this.ExportBoolData=function(aryKData,option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var start=0, end=this.Data.length-1;
//限制范围
if (option && option.Start && option.End && IFrameSplitOperator.IsNumber(option.Start.Index) && IFrameSplitOperator.IsNumber(option.End.Index))
{
start=option.Start.Index;
end=option.End.Index;
}
var aryValue=[];
for(var i=start; i<=end && i<this.Data.length; ++i)
{
var item=this.Data[i];
aryValue[i]=false;
if (!IFrameSplitOperator.IsPlusNumber(item)) continue;
aryValue[i]=true;
}
return aryValue;
}
//导出K线数据
this.ExportKLineData=function(option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var start=0, end=this.Data.length-1;
//限制范围
if (option && option.Start && option.End && IFrameSplitOperator.IsNumber(option.Start.Index) && IFrameSplitOperator.IsNumber(option.End.Index))
{
start=option.Start.Index;
end=option.End.Index;
}
var aryDate=[], aryOpen=[], aryHigh=[], aryLow=[], aryVol=[], aryAmount=[], aryClose=[], aryTime=[];
for(var i=start; i<=end && i<this.Data.length; ++i)
{
var item=this.Data[i];
aryDate[i]=item.Date;
aryOpen[i]=item.Open;
aryHigh[i]=item.High;
aryLow[i]=item.Low;
aryClose[i]=item.Close;
aryVol[i]=item.Vol;
aryAmount[i]=item.Amount;
aryTime[i]=item.Time;
}
if (option)
{
if (option.IsOverlay) //叠加股票不返回时间,日期
{
var result=
[
{Name:"Open", Data:aryOpen }, {Name:"High", Data:aryHigh }, {Name:"Low", Data:aryLow}, {Name:"Close", Data:aryClose },
{Name:"Vol", Data:aryVol}, { Name:"Amount", Data:aryAmount}
];
return result;
}
}
var result=[ {Name:"Date", Data:aryDate} ];
if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period))
result.push({ Name:"Time", Data:aryTime} );
result.push
(
{Name:"Open", Data:aryOpen }, {Name:"High", Data:aryHigh }, {Name:"Low", Data:aryLow}, {Name:"Close", Data:aryClose },
{Name:"Vol", Data:aryVol}, { Name:"Amount", Data:aryAmount}
);
return result;
}
//导出分时图数据
this.ExportMinuteData=function(option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var aryDate=[], aryOpen=[], aryHigh=[], aryLow=[], aryVol=[], aryAmount=[], aryClose=[], aryTime=[];
var aryPosition=[], aryAvPrice=[];
var start=0, end=this.Data.length-1;
//限制范围
if (option && option.Start && option.End && IFrameSplitOperator.IsNumber(option.Start.Index) && IFrameSplitOperator.IsNumber(option.End.Index))
{
start=option.Start.Index;
end=option.End.Index;
}
for(var i=start;i<=end && i<this.Data.length;++i)
{
var item=this.Data[i];
aryDate[i]=item.Date;
aryOpen[i]=item.Open;
aryHigh[i]=item.High;
aryLow[i]=item.Low;
aryClose[i]=item.Close;
aryVol[i]=item.Vol;
aryAmount[i]=item.Amount;
aryTime[i]=item.Time;
aryAvPrice[i]=item.AvPrice;
aryPosition[i]=item.Position
}
var result=
[
{Name:"Open", Data:aryOpen }, {Name:"High", Data:aryHigh }, {Name:"Low", Data:aryLow}, {Name:"Close", Data:aryClose },
{Name:"Vol", Data:aryVol}, { Name:"Amount", Data:aryAmount}, {Name:"AvPrice", Data:aryAvPrice}, {Name:"Position", Data: aryPosition}
];
if (option)
{
if (option.IsOverlay) //叠加股票不返回时间,日期
return result;
}
result.splice(0,0,{Name:"Date", Data:aryDate}, { Name:"Time", Data:aryTime});
return result;
}
}
ChartData.DateTimeToNumber=function(kItem)
{
return kItem.Date*10000+kItem.Time;
}
ChartData.GetKLineDataTime=function(kLineItem) //获取K线的 日期和时间 如果时间没有就用0
{
var result={ Date:kLineItem.Date, Time:0 };
if (IFrameSplitOperator.IsNumber(kLineItem.Time)) result.Time=kLineItem.Time;
return result;
}
ChartData.GetFirday=function(value)
{
var date=new Date(parseInt(value/10000),(value/100%100-1),value%100);
var day=date.getDay();
if (day==5) return value;
var timestamp=date.getTime();
if (day<5)
{
var prevTimestamp=(24*60*60*1000)*(5-day);
timestamp+=prevTimestamp;
}
else
{
var prevTimestamp=(24*60*60*1000)*(day-5);
timestamp-=prevTimestamp;
}
date.setTime(timestamp);
var fridayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate();
var week=date.getDay();
return fridayDate;
}
ChartData.GetSunday=function(value)
{
var date=new Date(parseInt(value/10000),(value/100%100-1),value%100);
var day=date.getDay();
if (day==0) return value;
var timestamp=date.getTime();
if (day>0)
{
var prevTimestamp=(24*60*60*1000)*(7-day);
timestamp+=prevTimestamp;
}
date.setTime(timestamp);
var sundayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate();
var week=date.getDay();
return sundayDate;
}
ChartData.GetQuarter=function(value)
{
var month=parseInt(value%10000/100);
if (month==1 || month==2 || month==3) return 1;
else if (month==4 || month==5 || month==6) return 2;
else if (month==7 || month==8 || month==9) return 3;
else if (month==10 || month==11 || month==12) return 4;
else return 0;
}
ChartData.GetHalfYear=function(value)
{
var year=parseInt(value/10000);
var day=value%10000;
if (day<=630) return year*10000+630;
return year*10000+1231;
}
//是否是日线周期 0=日线 1=周线 2=月线 3=年线 9=季线 21=双周 22=半年 [40001-50000) 自定义日线 (isIncludeBase 是否包含基础日线周期)
var CUSTOM_DAY_PERIOD_START=40000, CUSTOM_DAY_PERIOD_END=49999;
ChartData.IsDayPeriod=function(period, isIncludeBase)
{
if (period==1 || period==2 || period==3 || period==9 || period==21 || period==22) return true;
if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END) return true;
if (period==0 && isIncludeBase==true) return true;
return false;
}
//是否是分钟周期 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 11=120分钟 12=240分钟 [20001-30000) 自定义分钟 (isIncludeBase 是否包含基础1分钟周期)
var CUSTOM_MINUTE_PERIOD_START=20000, CUSTOM_MINUTE_PERIOD_END=29999;
ChartData.IsMinutePeriod=function(period,isIncludeBase)
{
if (period==5 || period==6 || period==7 || period==8 ||period==11 || period==12) return true;
if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) return true;
if (period==4 && isIncludeBase==true) return true;
return false;
}
//是否是秒周期 [30001-32000)
var CUSTOM_SECOND_PERIOD_START=30000, CUSTOM_SECOND_PERIOD_END=32000;
ChartData.IsSecondPeriod=function(period)
{
if (period>CUSTOM_SECOND_PERIOD_START && period<=CUSTOM_SECOND_PERIOD_END) return true;
return false;
}
var CUSTOM_MILLISECOND_PERIOD_START=50000, CUSTOM_MILLISECOND_PERIOD_END=60000;
ChartData.IsMilliSecondPeriod=function(period)
{
if (period>CUSTOM_MILLISECOND_PERIOD_START && period<=CUSTOM_MILLISECOND_PERIOD_END) return true;
return false;
}
//是否是分笔图 10=分笔
ChartData.IsTickPeriod=function(period)
{
return period==10;
}
//获取周期名字
ChartData.GetPeriodName=function(period)
{
var mapName=new Map(
[
[0, '日线'],[1, '周线'],[2, '月线'],[3, '年线'],[9, '季线'], [21,'双周'],[22,"半年"],
[4, '1分'], [5, '5分'], [6, '15分'],[7, '30分'],[8, '60分'],[11, '2小时'],[12, '4小时'],
[10, '分笔']
]);
if (mapName.has(period)) return mapName.get(period);
return '';
}
function TooltipData() //提示信息
{
this.ChartPaint;
this.Data;
this.Type=0;
}
function Rect(x,y,width,height)
{
this.X=x,
this.Y=y;
this.Width=width;
this.Height=height;
}
//图形外部挂接
function ChartPaintFactory()
{
//[key:name, { Create:function(option) { return new class(); }} ]
this.DataMap=new Map(
[
["ChartKLine", { Create:function(option) { return new ChartKLine(); } }], //K线图
["ChartMinuteVolumBar",{ Create:function(option) { return new ChartMinuteVolumBar(); } }], //分时成交量柱子
["ChartMinutePriceLine",{ Create:function(option) { return new ChartMinutePriceLine();} }]
]);
this.Create=function(name, option)
{
if (!this.DataMap.has(name))
{
JSConsole.Warn(`[ChartPaintFactory::Create] can't find class=${name}.`);
return null;
}
var item=this.DataMap.get(name);
return item.Create(option);
}
this.Add=function(name, option)
{
this.DataMap.set(name, { Create:option.Create } );
}
}
var g_ChartPaintFactory=new ChartPaintFactory();
//图新画法接口类
function IChartPainting()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='IChartPainting'; //类名
this.Data=new ChartData(); //数据区
this.Script; //图形对应的指标脚本 (只有指标图形才有)
this.NotSupportMessage=null;
this.MessageFont=g_JSChartResource.Index.NotSupport.Font;
this.MessageColor=g_JSChartResource.Index.NotSupport.TextColor;
this.IsDrawFirst=false;
this.IsShow=true;
this.IsVisible=true; //是否显示 (预留给外部单独设置线段显隐)
this.GetEventCallback;
this.SelectedLineWidth=g_JSChartResource.SelectedChart.LineWidth;
this.SelectedLineColor=g_JSChartResource.SelectedChart.LineColor;
this.SelectedRadius=g_JSChartResource.SelectedChart.Radius;
this.SelectedPointMinSpace=g_JSChartResource.SelectedChart.MinSpace; //点和点间最小间距
this.SelectedBGColor=g_JSChartResource.SelectedChart.BGColor;
this.DrawSelectedStatus; //function() { } //选中状态
this.PtInChart; //function(x,y) { }
this.IsFullRangeMaxMin=false; //this.GetMaxMin() true=计算全部的最大最小值 false=计算可视范围的最大最小值
this.IsExcludeYValue=false; //不参与Y轴计算
this.Draw=function()
{
}
//数据导出 数据格式 [{ Title:数据名称, Data:[] }]
//this.ExportData=function(aryKData) { }
this.GetBorder=function()
{
if (this.ChartFrame.IsHScreen) return this.ChartBorder.GetHScreenBorder();
return this.ChartBorder.GetBorder();
}
this.ClipClient=function(isHScreen) //裁剪客户端
{
if (isHScreen==true)
{
var left=this.ChartBorder.GetLeftEx();
var right=this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
}
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
}
this.GetYFromData=function(value,isLimit)
{
return this.ChartFrame.GetYFromData(value,isLimit);
}
this.IsMinuteFrame=function()
{
var isMinute=(this.ChartFrame.ClassName=="MinuteFrame" || this.ChartFrame.ClassName=="MinuteHScreenFrame" ||
this.ChartFrame.ClassName=="OverlayMinuteFrame" || this.ChartFrame.ClassName=="OverlayMinuteHScreenFrame" );
return isMinute
}
this.DrawNotSupportmessage=function()
{
this.Canvas.font=this.MessageFont;
this.Canvas.fillStyle=this.MessageColor;
var left=this.ChartBorder.GetLeft();
var width=this.ChartBorder.GetWidth();
var top=this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx();
var x=left+width/2;
var y=top+height/2;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(this.NotSupportMessage,x,y);
}
this.GetTooltipData=function(x,y,tooltip)
{
return false;
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || isNaN(value)) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
return range;
}
this.GetDynamicFont=function(dataWidth, distanceWidth, maxSize, minSize, zoom, fontname) //根据宽度自动获取对应字体
{
var pixelTatio = GetDevicePixelRatio();
maxSize*=pixelTatio;
minSize*=pixelTatio;
if (maxSize==minSize) //固定大小
{
var font=`${maxSize.toFixed(0)}px ${fontname}` ;
return font;
}
var fontSize=(dataWidth+distanceWidth);
if (zoom)
{
if (zoom.Type==0)
{
if (zoom.Value>0) fontSize=(dataWidth*zoom.Value);
}
else if (zoom.Type==1)
{
if (zoom.Value>0) fontSize=(dataWidth+distanceWidth)*zoom.Value;
}
else if (zoom.Type==2)
{
if (IFrameSplitOperator.IsNumber(zoom.Value))
fontSize=(dataWidth+distanceWidth) + (2*zoom.Value)*pixelTatio;
}
}
if (fontSize<minSize) fontSize=minSize;
else if (fontSize>maxSize) fontSize=maxSize;
var font=`${fontSize.toFixed(0)}px ${fontname}` ;
/*
if (dataWidth < 5) font =4*pixelTatio + 'px Arial'; //字体根据数据宽度动态调整
else if (dataWidth < 7) font = 6*pixelTatio +'px Arial';
else if (dataWidth < 9) font = 8*pixelTatio +'px Arial';
else if (dataWidth < 11) font =10*pixelTatio +'px Arial';
else if (dataWidth < 13) font =12*pixelTatio +'px Arial';
else if (dataWidth < 15) font =14*pixelTatio + 'px Arial';
else font =16*pixelTatio + 'px Arial';
*/
return font;
}
this.GetLockRect=function()
{
return this.ChartFrame.GetLockRect();
}
this.SetFillStyle=function(color, x0, y0, x1, y1)
{
if (Array.isArray(color))
{
let gradient = this.Canvas.createLinearGradient(x0, y0, x1, y1);
var offset=1/(color.length-1);
for(var i=0; i<color.length; ++i)
{
var value=i*offset;
gradient.addColorStop(value, color[i]);
}
this.Canvas.fillStyle=gradient;
}
else
{
this.Canvas.fillStyle=color;
}
}
this.GetDynamicIconSize=function(dataWidth, distanceWidth, maxSize, minSize, zoom)
{
var pixelTatio = GetDevicePixelRatio();
maxSize*=pixelTatio;
minSize*=pixelTatio;
if (maxSize==minSize) return maxSize;
var iconSize=(dataWidth+distanceWidth)-2*pixelTatio;
if (zoom)
{
if (zoom.Type==0)
{
if (zoom.Value>0) iconSize=(dataWidth*zoom.Value);
}
else if (zoom.Type==1)
{
if (zoom.Value>0) iconSize=(dataWidth+distanceWidth)*zoom.Value;
}
else if (zoom.Type==2)
{
if (IFrameSplitOperator.IsNumber(zoom.Value))
iconSize=(dataWidth+distanceWidth) + (2*zoom.Value)*pixelTatio;
}
}
if (iconSize<minSize) iconSize=minSize;
else if (iconSize>maxSize) iconSize=maxSize;
return iconSize;
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
//选中图形画点
this.DrawLinePoint=function(option)
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
if (bHScreen) return;
if (!this.IsShow) return;
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
var pixelRatio=GetDevicePixelRatio();
this.Canvas.save();
this.ClipClient(bHScreen);
this.Canvas.lineWidth=this.SelectedLineWidth*pixelRatio;
this.Canvas.strokeStyle=this.SelectedLineColor;
if (this.SelectedBGColor) this.Canvas.fillStyle=this.SelectedBGColor;
var radius=this.SelectedRadius;
var pointSpace=Math.ceil(this.SelectedPointMinSpace/(dataWidth+distanceWidth));
if (pointSpace<=0) pointSpace=1;
if (isMinute)
{
var barWidth=(border.Right-border.Left)/xPointCount;
pointSpace=Math.ceil(this.SelectedPointMinSpace/barWidth);
}
var valueType=0;
var firstOpen=null, firstOverlayOpen=null;
if (option)
{
if (option.KLineClose) valueType=1; //K线收盘价
else if (option.MinuteVolBar)
{
valueType=2; //分时图柱子
}
else if (option.MinuteOverlayPrice) //叠加分时图价格
{
if (option.OverlayType==1) valueType=1;
else valueType=3;
}
else if (option.OverlayKLine)
{
valueType=4; //叠加K线
firstOpen=this.GetFirstOpen();
}
else if (option.StackedBar) valueType=5; //叠加柱子
}
for(var i=this.Data.DataOffset,j=0,k=0;i<this.Data.Data.length && j<xPointCount;++i,++j,++k,xOffset+=(dataWidth+distanceWidth))
{
var value=null;
if (valueType==1) //K线收盘价
{
var kItem=this.Data.Data[i];
if (IFrameSplitOperator.IsNumber(kItem.Close)) value=kItem.Close
}
else if (valueType==2)
{
var kItem=this.Data.Data[i];
if (IFrameSplitOperator.IsNumber(kItem.Vol)) value=kItem.Vol
}
else if (valueType==3)
{
var minItem=this.Data.Data[i];
var mainItem=this.MainData.Data[i];
if (!minItem || !IFrameSplitOperator.IsNumber(minItem.Close) || !IFrameSplitOperator.IsNumber(minItem.YClose)) continue;
if (!mainItem || !IFrameSplitOperator.IsNumber(mainItem.Close) || !IFrameSplitOperator.IsNumber(mainItem.YClose)) continue;
var price=minItem.Close;
var value=price/minItem.YClose*mainItem.YClose;
}
else if (valueType==4)
{
var data=this.Data.Data[i];
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
value=data.Close/firstOverlayOpen*firstOpen;
}
else if (valueType==5)
{
var bars=this.Data.Data[i];
if (!IFrameSplitOperator.IsNonEmptyArray(bars)) continue;
var maxValue=0, minValue=0;
for(var k=0;k<bars.length;++k)
{
var barValue=bars[k];
if (!IFrameSplitOperator.IsNumber(barValue)) continue;
if (barValue==0) continue;
if (barValue>0) maxValue+=barValue;
else if (barValue<0) minValue+=barValue;
}
value=(maxValue+minValue)/2;
}
else
{
value=this.Data.Data[i];
}
if (value==null) continue;
if (k<pointSpace) continue;
k=0
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y=this.GetYFromData(value,false);
if (x>chartright) break;
this.Canvas.beginPath();
this.Canvas.arc(x,y,radius,0,360,false);
this.Canvas.closePath();
if (this.SelectedBGColor) this.Canvas.fill();
this.Canvas.stroke();
}
this.Canvas.restore();
}
//点是否在线段上
this.PtInLine=function(x, y, option)
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
if (bHScreen) return;
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
if (x<xOffset || x>chartright) return null;
if (y>border.BottomEx || y<border.TopEx) return null;
var ptStart={}, ptEnd={};
var valueType=0;
if (option)
{
if (option.KLineClose)
{
valueType=1; //K线收盘价
}
else if (option.MinuteOverlayPrice) //走势图叠加线
{
if (option.OverlayType==1) valueType=1; //价格线
else valueType=3; //百分比
}
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=null;
if (valueType==1) //K线收盘价
{
var kItem=this.Data.Data[i];
if (IFrameSplitOperator.IsNumber(kItem.Close)) value=kItem.Close
}
else if (valueType==3)
{
var minItem=this.Data.Data[i];
var mainItem=this.MainData.Data[i];
if (!minItem || !IFrameSplitOperator.IsNumber(minItem.Close) || !IFrameSplitOperator.IsNumber(minItem.YClose)) continue;
if (!mainItem || !IFrameSplitOperator.IsNumber(mainItem.Close) || !IFrameSplitOperator.IsNumber(mainItem.YClose)) continue;
var price=minItem.Close;
var value=price/minItem.YClose*mainItem.YClose;
}
else
{
value=this.Data.Data[i];
}
if (value==null) continue;
if (isMinute)
{
var xLine=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var xLine=left+(right-left)/2;
}
var yLine=this.GetYFromData(value,false);
if (xLine<x)
{
ptStart.X=xLine;
ptStart.Y=yLine;
}
else if (xLine==x)
{
ptStart.X=ptEnd.X=xLine;
ptStart.Y=ptEnd.Y=yLine;
break;
}
else
{
ptEnd.X=xLine;
ptEnd.Y=yLine;
break;
}
if (x>chartright) break;
}
if (!IFrameSplitOperator.IsNumber(ptStart.X) || !IFrameSplitOperator.IsNumber(ptStart.Y)) return null;
if (!IFrameSplitOperator.IsNumber(ptEnd.X) || !IFrameSplitOperator.IsNumber(ptEnd.Y)) return null;
if (x==ptStart.X && y==ptStart.Y)
return { Identify:this.Identify, Chart:this };
if (x==ptEnd.X && y==ptEnd.Y)
return { Identify:this.Identify, Chart:this };
var lineWidth=5;
this.Canvas.beginPath();
if (ptStart.X==ptEnd.X) //竖线
{
this.Canvas.moveTo(ptStart.X-lineWidth,ptStart.Y);
this.Canvas.lineTo(ptStart.X+lineWidth,ptStart.Y);
this.Canvas.lineTo(ptEnd.X+lineWidth,ptEnd.Y);
this.Canvas.lineTo(ptEnd.X-lineWidth,ptEnd.Y);
}
else
{
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
}
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return { Identify:this.Identify, Chart:this };
return null;
}
//option={ BarWidth:柱子宽度(空为K线宽度) }
this.PtInBar=function(x, y, option)
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return null;
var bHScreen=(this.ChartFrame.IsHScreen===true);
if (bHScreen) return null;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Left;
if (x<xOffset || x>chartright) return null;
if (y>border.BottomEx || y<border.TopEx) return null;
var isMinute=this.IsMinuteFrame();
var yBottom=this.ChartFrame.GetYFromData(0);
var barWidth=null;
var isMinuteVolBar=false;
var isStackedBar=false;
if (option)
{
if (option.BarWidth>0) barWidth=option.BarWidth;
if (option.MinuteVolBar==true)
{
isMinuteVolBar=true;
barWidth=4;
}
else if (option.StackedBar==true)
{
isStackedBar=true;
}
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
if (isMinute)
{
var xLine=this.ChartFrame.GetXFromIndex(j);
var left=xLine-barWidth/2;
var right=left+barWidth;
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
}
if (isMinuteVolBar)
{
if (!IFrameSplitOperator.IsNumber(value.Vol)) continue;
var yBar=this.ChartFrame.GetYFromData(value.Vol);
var barTop=yBar, barBottom=yBottom;
}
else if (isStackedBar)
{
var maxValue=0, minValue=0;
if (!IFrameSplitOperator.IsNonEmptyArray(value)) continue;
for(var k=0;k<value.length;++k)
{
var barValue=value[k];
if (!IFrameSplitOperator.IsNumber(barValue)) continue;
if (barValue==0) continue;
if (barValue>0) maxValue+=barValue;
else if (barValue<0) minValue+=barValue;
}
var barTop=this.ChartFrame.GetYFromData(maxValue);
var barBottom=this.ChartFrame.GetYFromData(minValue);
}
else
{
var yBar=this.ChartFrame.GetYFromData(value);
var barTop=yBar, barBottom=yBottom;
}
if (barTop>barBottom)
{
barTop=yBottom;
barBottom=yBar;
}
var barLeft=left, barRight=right;
if (barWidth>0)
{
barLeft=left+(right-left)/2-barWidth/2;
barRight=barLeft+barWidth;
}
if (x>=barLeft && x<=barRight && y>=barTop && y<=barBottom)
return { Identify:this.Identify, Chart:this };
if (right>x) break;
}
return null;
}
this.PtInKBar=function(x,y,option)
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return null;
var isHScreen=(this.ChartFrame.IsHScreen===true);
if (isHScreen) return null;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
if (x<xOffset || x>chartright) return null;
if (y>border.BottomEx || y<border.TopEx) return null;
var firstOverlayOpen=null;
var kBarType=0;
var firstOpen=null;
if (option && option.OverlayKLine)
{
kBarType=1; //叠加K线
firstOpen=this.GetFirstOpen();
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
if (x>=left && x<=right)
{
if (kBarType==1)
{
var yLow=this.GetYFromData(data.Low/firstOverlayOpen*firstOpen,false);
var yHigh=this.GetYFromData(data.High/firstOverlayOpen*firstOpen,false);
}
else
{
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
}
if (y<=yLow && y>=yHigh)
return { Identify:this.Identify, Chart:this };
}
if (right>x) break;
}
}
this.IsShowIndexTitleOnly=function()
{
if (this.ChartFrame && this.ChartFrame.ChartBorder && this.ChartFrame.ChartBorder.IsShowTitleOnly) return true;
return false;
}
//是否隐藏指标
this.IsHideScriptIndex=function()
{
if (this.Script && this.Script.IsShow==false) return true;
return false;
}
//导出单数组数据
this.ExportArrayData=function(aryKData, option)
{
var data=this.Data.ExportArrayData(aryKData, option);
return [ { Name:this.Name, Data:data }];
}
this.ExportBoolData=function(aryKData, option)
{
var data=this.Data.ExportBoolData(aryKData, option);
return [ { Name:this.Name, Data:data }];
}
//获取单数组的数据某一个数据 indexData={ Index:数据索引 }
this.GetArrayItemData=function(indexData)
{
if (!indexData) return null;
if (!IFrameSplitOperator.IsNumber(indexData.Index)) return null;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var index=indexData.Index;
if (index<0 || index>=this.Data.Data.length) return null;
var item=this.Data.Data[index];
return [ { Value:item, Color:this.Color, Name: this.Name } ];
}
}
//缩放因子
/*
var ZOOM_SEED=
[
[49,10], [46,9], [43,8],
[41,7.5], [39,7], [37,6],
[31,5.5], [27,5], [23,4.5],
[21,4], [18,3.5], [16,3],
[13,2.5], [11,2], [8,1.5],
[6,1], [3,0.6], [2.2,0.5],
//太多了卡,
//[1.1,0.3],
//[0.9,0.2], [0.7,0.15],
//[0.6,0.12], [0.5,0.1], [0.4,0.08],
//[0.3,0.06], [0.2,0.04], [0.1,0.02]
];
*/
var ZOOM_SEED= //0=柱子宽度 1=间距
[
[48,10], [44,10],
[40,9], [36,9],
[32,8], [28,8],
[24,7], [20,7],
[18,6], [16,6],
[15,5], [13,5],
[9,4], [7,4], [5,4],
[3,3],
[3,1], [2,1], [1,1], [1,0],
//[0.5,0],[0.4,0],[0.3,0],[0.2,0],[0.1,0]
];
//K线画法 支持横屏
function ChartKLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartKLine'; //类名
this.Symbol; //股票代码
this.DrawType=0; // 0=实心K线柱子 1=收盘价线 2=美国线 3=空心K线柱子 4=收盘价面积图 5=订单流 6=空心K线柱子2(全部空心) 7=订单流样式2 8=订单流样式3
// 9=自定义颜色K线
// 10=renko
// 11=Heikin Ashi
// 12=line break
// 13=high low
// 14=外部自定义图
// 15=HLC Area
// 16=kagi
// 17=订单流样式4
// 18=订单流样式5
this.CloseLineColor=g_JSChartResource.CloseLineColor;
this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor;
this.CloseLineWidth=g_JSChartResource.CloseLineWidth;
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.UnchagneColor=g_JSChartResource.UnchagneBarColor; //平盘
this.ColorData; //五彩K线颜色 >0:g_JSChartResource.UpBarColor 其他:g_JSChartResource.DownBarColor
this.TradeData; //交易系统 包含买卖数据{Buy:, Sell:, Name:指标名称 }
this.TradeIcon=g_JSChartResource.KLine.TradeIcon;
this.TooltipRect=[]; //2位数组 0 数据序号 1 区域
this.InfoTooltipRect=[]; //2维数组 0 数据, 1 区域
this.TradeIconTooltipRect=[]; //2维数组 0 数据, 1 区域
this.IsShowMaxMinPrice=true; //是否显示最大最小值
this.IsShowKTooltip=true; //是否显示K线tooltip
this.TextFont=g_JSChartResource.KLine.MaxMin.Font;
this.TextColor=g_JSChartResource.KLine.MaxMin.Color;
this.InfoData; //信息地雷 key=日期 value=信息数据
this.InfoPosition=0; // 0=K线上 1 底部
this.PtMax; //最大值的位置
this.PtMin; //最小值的位置
this.TickSymbol='╳'; //分笔显示的图标
this.TickFontName='arial';
this.Period; //周期
this.ShowRange={ }; //K线显示范围 { Start:, End:, DataCount:, ShowCount: }
this.CustomKLine; //自定义K线, key=date*1000000+time, key={ Color:, DrawType: }
this.DrawKRange={ Start:null, End:null }; //当前屏K线的索引{ Start: , End:}
this.IsThinAKBar=true; //美国线 柱子是否是线段 (false=柱子)
this.OneLimitBarType=0; //一字板颜色类型 4个价格全部都在同一个价位上 0=使用平盘颜色 1=跟昨收比较
this.HighLowBarColor=g_JSChartResource.HighLowBarColor;
this.HighLowTextConfig=
{
FontName:g_JSChartResource.HighLowText.FontName,
MaxSize:g_JSChartResource.HighLowText.MaxSize,
MinSize:g_JSChartResource.HighLowText.MinSize,
Color:g_JSChartResource.HighLowText.Color, //未用
MaxText:g_JSChartResource.HighLowText.MaxText
};
this.HLCAreaConfig=
{
HighLineColor:g_JSChartResource.HLCArea.HighLineColor,
LowLineColor:g_JSChartResource.HLCArea.LowLineColor,
CloseLineColor:g_JSChartResource.HLCArea.CloseLineColor,
LineWidth:g_JSChartResource.HLCArea.LineWidth,
UpAreaColor:g_JSChartResource.HLCArea.UpAreaColor,
DownAreaColor:g_JSChartResource.HLCArea.DownAreaColor,
}
//虚线柱子
this.VirtualBarConfig={ Color:g_JSChartResource.VirtualKLine.Color, LineDash:g_JSChartResource.VirtualKLine.LineDash };
//DrawType==14 自定义图形
this.FFKChart;
/*
this.CustomKLine=new Map([
[20210415*1000000, { Color:'rgb(255,0,255)', DrawType:3, BGColor:"rgba(135,206,250,0.5)" }],
[20210412*1000000, { DrawType:3 }],
[20210108*1000000, { DrawType:3,BGColor:"rgba(135,206,250,0.5)" }],
[20210122*1000000, {Color:'rgb(122,135,155)'}]
]);
*/
//订单流配置
this.OrderFlow=
{
UpColor:{BG:g_JSChartResource.OrderFlow.UpColor.BG, Border:g_JSChartResource.OrderFlow.UpColor.Border },
DownColor:{ BG:g_JSChartResource.OrderFlow.DownColor.BG, Border:g_JSChartResource.OrderFlow.DownColor.Border },
UnchagneColor: { BG:g_JSChartResource.OrderFlow.UnchagneColor.BG, Border:g_JSChartResource.OrderFlow.UnchagneColor.Border },
Text:{ Color: g_JSChartResource.OrderFlow.Text.Color , Family:g_JSChartResource.OrderFlow.Text.Family, FontMaxSize:g_JSChartResource.OrderFlow.Text.FontMaxSize, MaxValue:g_JSChartResource.OrderFlow.Text.MaxValue },
Line:{ UpDownColor: g_JSChartResource.OrderFlow.Line.UpDownColor, MiddleColor:g_JSChartResource.OrderFlow.Line.MiddleColor },
POCGBColor:g_JSChartResource.OrderFlow.POCGBColor,
ShowType:0, //显示类型 0, 1
AskBarColor:g_JSChartResource.OrderFlow.AskBarColor,
BidBarColor:g_JSChartResource.OrderFlow.BidBarColor,
AlwaysShowOrderText:g_JSChartResource.OrderFlow.AlwaysShowOrderText,
IsShowAskText:true,
IsShowAskBar:false, //是否显示横向柱子
IsShowBidText:true,
IsShowBidBar:false, //是否显示横向柱子
IsShowPOCBG:true,
}
this.OrderFlow_Style2=
{
BarWidth:g_JSChartResource.OrderFlow_Style2.BarWidth,
//柱子颜色
UpColor:g_JSChartResource.OrderFlow_Style2.UpColor,
DownColor:g_JSChartResource.OrderFlow_Style2.DownColor,
UnchagneColor:g_JSChartResource.OrderFlow_Style2.UnchagneColor,
}
this.OrderFlow_Style3=
{
BarWidth:g_JSChartResource.OrderFlow_Style3.BarWidth,
//柱子颜色
UpColor:g_JSChartResource.OrderFlow_Style3.UpColor,
DownColor:g_JSChartResource.OrderFlow_Style3.DownColor,
UnchagneColor:g_JSChartResource.OrderFlow_Style3.UnchagneColor,
}
this.OrderFlow_Style4=
{
//柱子颜色
UpColor:g_JSChartResource.OrderFlow_Style4.UpColor,
DownColor:g_JSChartResource.OrderFlow_Style4.DownColor,
UnchagneColor:g_JSChartResource.OrderFlow_Style4.UnchagneColor,
KBarType:1, //0=不显示K线柱子 1=左侧显示K线
VolBarSpace:g_JSChartResource.OrderFlow_Style4.VolBarSpace, //间距
KBarWidth:g_JSChartResource.OrderFlow_Style4.KBarWidth,
LeftMargin:g_JSChartResource.OrderFlow_Style4.LeftMargin,
RightMargin:g_JSChartResource.OrderFlow_Style4.RightMargin,
}
this.OrderFlow_Style5=
{
AskBarColor:g_JSChartResource.OrderFlow_Style5.AskBarColor, //左
BidBarColor:g_JSChartResource.OrderFlow_Style5.BidBarColor, //右
LeftMargin:g_JSChartResource.OrderFlow_Style5.LeftMargin,
RightMargin:g_JSChartResource.OrderFlow_Style5.RightMargin,
}
this.IsShowOrderText=false;
this.AryOrderFlowBorder=[]; //订单流边框 临时变量
this.ChartHeatMap; //=new ChartHeatMap();
//未回补的价格缺口
this.PriceGap={ Enable:false, Count:1 };
this.PriceGapStyple=
{
Line:{ Color:g_JSChartResource.PriceGapStyple.Line.Color },
Text:{ Color:g_JSChartResource.PriceGapStyple.Text.Color, Font: g_JSChartResource.PriceGapStyple.Text.Font }
};
this.AryPriceGapCache=[]; //缺口数据 { }
this.ReloadResource=function(resource)
{
this.TextFont=g_JSChartResource.KLine.MaxMin.Font;
this.TextColor=g_JSChartResource.KLine.MaxMin.Color;
this.CloseLineColor=g_JSChartResource.CloseLineColor;
this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor;
this.CloseLineWidth=g_JSChartResource.CloseLineWidth;
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.UnchagneColor=g_JSChartResource.UnchagneBarColor; //平盘
this.HighLowBarColor=g_JSChartResource.HighLowBarColor;
this.OrderFlow.UpColor={BG:g_JSChartResource.OrderFlow.UpColor.BG, Border:g_JSChartResource.OrderFlow.UpColor.Border };
this.OrderFlow.DownColor={ BG:g_JSChartResource.OrderFlow.DownColor.BG, Border:g_JSChartResource.OrderFlow.DownColor.Border };
this.OrderFlow.UnchagneColor= { BG:g_JSChartResource.OrderFlow.UnchagneColor.BG, Border:g_JSChartResource.OrderFlow.UnchagneColor.Border };
this.OrderFlow.Text={ Color: g_JSChartResource.OrderFlow.Text.Color , Family:g_JSChartResource.OrderFlow.Text.Family, FontMaxSize:g_JSChartResource.OrderFlow.Text.FontMaxSize, MaxValue:g_JSChartResource.OrderFlow.Text.MaxValue };
this.OrderFlow.Line={ UpDownColor: g_JSChartResource.OrderFlow.Line.UpDownColor, MiddleColor:g_JSChartResource.OrderFlow.Line.MiddleColor };
}
this.ClearCustomKLine=function()
{
this.CustomKLine=null;
}
this.GetCustomKLine=function(kItem)
{
if (!this.CustomKLine) return null;
if (!kItem) return null;
var key=kItem.Date*1000000;
if (IFrameSplitOperator.IsNumber(kItem.Time)) key+=kItem.Time;
if (!this.CustomKLine.has(key)) return null;
var value=this.CustomKLine.get(key);
return value;
}
this.DrawHeatMap=function()
{
if (!this.ChartHeatMap) return;
this.ChartHeatMap.Canvas=this.Canvas;
this.ChartHeatMap.ChartBorder=this.ChartBorder;
this.ChartHeatMap.ChartFrame=this.ChartFrame;
this.ChartHeatMap.Data=this.Data;
this.ChartHeatMap.Draw();
}
this.ClearHeatMap=function()
{
this.ChartHeatMap=null;
}
this.CreateHeatMap=function()
{
this.ChartHeatMap=new ChartHeatMap();
}
this.DrawAKLine=function() //美国线
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var upColor=this.UpColor;
var downColor=this.DownColor;
var unchagneColor=this.UnchagneColor;
var ptMax={X:null,Y:null,Value:null,Align:'left'};
var ptMin={X:null,Y:null,Value:null,Align:'left'};
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
var eventUnchangeKLine=null; //定制平盘K线颜色事件
if (this.GetEventCallback)
{
eventUnchangeKLine=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_UNCHANGE_KLINE_COLOR);
}
var preKItemInfo=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
var yOpen=this.GetYFromData(data.Open,false);
var yClose=this.GetYFromData(data.Close,false);
this.DrawKRange.End=i;
var kItemInfo={ Data:data, Coordinate:{ X:x, Low:yLow, High:yHigh, Close:yClose, Open:yOpen, Left:left, Right:right }};
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
unchagneColor=this.UnchagneColor;
if (data.Open<data.Close)
{
this.Canvas.strokeStyle=this.UpColor; //阳线
}
else if (data.Open>data.Close)
{
this.Canvas.strokeStyle=this.DownColor; //阳线
}
else
{
if (eventUnchangeKLine && eventUnchangeKLine.Callback)
{
var sendData={ KItem:data, DataIndex:i, DefaultColor:unchagneColor, BarColor:null };
eventUnchangeKLine.Callback(eventUnchangeKLine, sendData, this);
if (sendData.BarColor) unchagneColor=sendData.BarColor;
}
this.Canvas.strokeStyle=unchagneColor; //平线
}
if (this.ColorData) ///五彩K线颜色设置
{
if (i<this.ColorData.length)
upColor=downColor=unchagneColor=(this.ColorData[i]>0?this.UpColor:this.DownColor);
else
upColor=downColor=unchagneColor=this.DownColor;
}
if (this.IsThinAKBar==false && dataWidth>=9)
{
var coordinateInfo={YLow:yLow, YHigh:yHigh, YOpen:yOpen, YClose:yClose, X:x, Left:left, Right:right };
var colorInfo={ UpColor:upColor, DownColor:downColor, UnchangeColor:unchagneColor };
this.DrawAKBar(data, dataWidth, isHScreen, coordinateInfo, colorInfo);
}
else
{
this.Canvas.beginPath(); //最高-最低
if (isHScreen)
{
if (data.High==data.Low && dataWidth<4)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow-1,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
}
else
{
if (data.High==data.Low && dataWidth<4)
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow+1);
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
}
this.Canvas.stroke();
if (dataWidth>=4)
{
this.Canvas.beginPath(); //开盘
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yOpen),left);
this.Canvas.lineTo(ToFixedPoint(yOpen),x);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(yOpen));
this.Canvas.lineTo(x,ToFixedPoint(yOpen));
}
this.Canvas.stroke();
this.Canvas.beginPath(); //收盘
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yClose),right);
this.Canvas.lineTo(ToFixedPoint(yClose),x);
}
else
{
this.Canvas.moveTo(right,ToFixedPoint(yClose));
this.Canvas.lineTo(x,ToFixedPoint(yClose));
}
this.Canvas.stroke();
}
}
if(this.Data.DataType==0)
{
var infoItem={Xleft:left,XRight:right, YMax:yHigh, XCenter:x, YMin:yLow, DayData:data, Index:j};
this.DrawInfo(infoItem);
}
if (this.PriceGap.Enable && preKItemInfo)
{
this.CheckPriceGap(kItemInfo);
var value=this.IsPriceGap(kItemInfo,preKItemInfo);
if (value>0)
this.AryPriceGapCache.push({ Data:[preKItemInfo, kItemInfo], Type:value });
}
preKItemInfo=kItemInfo;
}
this.PtMax=ptMax;
this.PtMin=ptMin;
}
this.DrawAKBar=function(data, dataWidth, isHScreen, coordinateInfo, colorInfo)
{
var barWidth=dataWidth/3;
var left=ToFixedRect(coordinateInfo.Left);
var aryX=[left, ToFixedRect(left+barWidth), ToFixedRect(left+barWidth*2), ToFixedRect(left+barWidth*3)];
var yHigh=coordinateInfo.YHigh, yLow=coordinateInfo.YLow, yOpen=coordinateInfo.YOpen, yClose=coordinateInfo.YClose;
if (data.Open<data.Close)
{
this.Canvas.strokeStyle=colorInfo.UpColor; //阳线
this.Canvas.fillStyle=colorInfo.UpColor;
}
else if (data.Open>data.Close)
{
this.Canvas.strokeStyle=colorInfo.DownColor; //阳线
this.Canvas.fillStyle=colorInfo.DownColor;
}
else
{
this.Canvas.strokeStyle=colorInfo.UnchangeColor; //平线
this.Canvas.fillStyle=colorInfo.UnchangeColor;
}
//最高-最低
if (isHScreen)
{
if (data.High==data.Low)
{
var yTop=yHigh-barWidth/2;
this.Canvas.fillRect(yTop,aryX[1],barWidth,aryX[2]-aryX[1]);
}
else
{
this.Canvas.fillRect(yHigh,aryX[1],(yLow-yHigh),aryX[2]-aryX[1]);
}
}
else
{
if (data.High==data.Low)
{
var yTop=yHigh-barWidth/2;
this.Canvas.fillRect(aryX[1],yTop,aryX[2]-aryX[1],barWidth);
}
else
{
this.Canvas.fillRect(aryX[1],yHigh,aryX[2]-aryX[1],(yLow-yHigh));
}
}
//开盘
var yTop=yOpen-barWidth/2;
if (isHScreen)
{
this.Canvas.fillRect(yTop,aryX[0],(barWidth),aryX[1]-aryX[0]);
}
else
{
this.Canvas.fillRect(aryX[0],yTop,aryX[1]-aryX[0],(barWidth));
}
//收盘
var yTop=yClose-barWidth/2;
if (isHScreen)
{
this.Canvas.fillRect(yTop,aryX[2],(barWidth),aryX[3]-aryX[2]);
}
else
{
this.Canvas.fillRect(aryX[2],yTop,aryX[3]-aryX[2],(barWidth));
}
}
this.DrawCloseArea=function() //收盘价面积图
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var borderLeft=border.TopEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var borderLeft=border.LeftEx;
}
var bFirstPoint=true;
var firstPoint=null;
this.Canvas.beginPath();
this.Canvas.strokeStyle=this.CloseLineColor;
if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
var ptLast=null;
if (this.Data.DataOffset>0) //把最左边的一个点连上
{
var data=this.Data.Data[this.Data.DataOffset-1];
if (data && IFrameSplitOperator.IsNumber(data.Close))
{
var x=borderLeft;
var yClose=this.GetYFromData(data.Close,false);
if (isHScreen)
{
this.Canvas.moveTo(yClose,x);
firstPoint={ X:yClose, Y:x };
}
else
{
this.Canvas.moveTo(x,yClose);
firstPoint={ X:x, Y:yClose };
}
bFirstPoint=false;
}
}
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
var preKItemInfo=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yClose=this.GetYFromData(data.Close,false);
this.DrawKRange.End=i;
if (bFirstPoint)
{
if (isHScreen)
{
this.Canvas.moveTo(yClose,x);
firstPoint={ X:yClose, Y:x };
}
else
{
this.Canvas.moveTo(x,yClose);
firstPoint={ X:x, Y:yClose };
}
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(yClose,x);
else this.Canvas.lineTo(x,yClose);
}
if (i==this.Data.Data.length-1)
{
ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
}
if (this.PriceGap.Enable )
{
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var kItemInfo={ Data:data, Coordinate:{ X:x, Low:yLow, High:yHigh, Close:yClose, Open:yOpen, Left:left, Right:right }};
if (preKItemInfo)
{
this.CheckPriceGap(kItemInfo);
var value=this.IsPriceGap(kItemInfo,preKItemInfo);
if (value>0) this.AryPriceGapCache.push({ Data:[preKItemInfo, kItemInfo], Type:value });
}
preKItemInfo=kItemInfo;
}
}
this.DrawLastPointEvent(ptLast); //通知外部绘制最后一个点
if (bFirstPoint) return;
this.Canvas.stroke();
if (isHScreen)
{
this.Canvas.lineTo(border.Left,x);
this.Canvas.lineTo(border.Left,firstPoint.Y);
}
else
{
this.Canvas.lineTo(x,border.Bottom);
this.Canvas.lineTo(firstPoint.X,border.Bottom);
}
this.Canvas.closePath();
if (Array.isArray(this.CloseLineAreaColor))
{
if (isHScreen)
{
let gradient = this.Canvas.createLinearGradient(this.ChartBorder.GetRightEx(),this.ChartBorder.GetTop(), this.ChartBorder.GetLeft(),this.ChartBorder.GetTop());
gradient.addColorStop(0, this.CloseLineAreaColor[0]);
gradient.addColorStop(1, this.CloseLineAreaColor[1]);
this.Canvas.fillStyle=gradient;
}
else
{
let gradient = this.Canvas.createLinearGradient(firstPoint.X,this.ChartBorder.GetTopEx(), firstPoint.X,this.ChartBorder.GetBottom());
gradient.addColorStop(0, this.CloseLineAreaColor[0]);
gradient.addColorStop(1, this.CloseLineAreaColor[1]);
this.Canvas.fillStyle=gradient;
}
}
else
{
this.Canvas.fillStyle=this.CloseLineAreaColor;
}
this.Canvas.fill();
}
this.DrawCloseLine=function() //收盘价线
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var bFirstPoint=true;
this.Canvas.beginPath();
this.Canvas.strokeStyle=this.CloseLineColor;
if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
var preKItemInfo=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yClose=this.GetYFromData(data.Close,false);
this.DrawKRange.End=i;
if (bFirstPoint)
{
if (isHScreen) this.Canvas.moveTo(yClose,x);
else this.Canvas.moveTo(x,yClose);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(yClose,x);
else this.Canvas.lineTo(x,yClose);
}
if (this.PriceGap.Enable )
{
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var kItemInfo={ Data:data, Coordinate:{ X:x, Low:yLow, High:yHigh, Close:yClose, Open:yOpen, Left:left, Right:right }};
if (preKItemInfo)
{
this.CheckPriceGap(kItemInfo);
var value=this.IsPriceGap(kItemInfo,preKItemInfo);
if (value>0) this.AryPriceGapCache.push({ Data:[preKItemInfo, kItemInfo], Type:value });
}
preKItemInfo=kItemInfo;
}
}
if (bFirstPoint==false) this.Canvas.stroke();
}
this.DrawKBar=function() //蜡烛头
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var ptMax={X:null,Y:null,Value:null,Align:'left'};
var ptMin={X:null,Y:null,Value:null,Align:'left'};
var upColor=this.UpColor;
var downColor=this.DownColor;
var unchagneColor=this.UnchagneColor;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
var ptLast=null;
this.DrawKRange.Start=this.Data.DataOffset;
var eventUnchangeKLine=null; //定制平盘K线颜色事件
if (this.GetEventCallback)
{
eventUnchangeKLine=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_UNCHANGE_KLINE_COLOR);
}
var preKItemInfo=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
var kItemInfo={ Data:data, Coordinate:{ X:x, Low:yLow, High:yHigh, Close:yClose, Open:yOpen, Left:left, Right:right }};
this.DrawKRange.End=i;
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
if (this.ColorData) ///五彩K线颜色设置
{
if (i<this.ColorData.length)
upColor=downColor=unchagneColor=(this.ColorData[i]>0?this.UpColor:this.DownColor);
else
upColor=downColor=unchagneColor=this.DownColor;
}
var kLineOption=this.GetCustomKLine(data);
if (data.IsNonTrade) //非交易日 绘制虚线柱子
{
this.DrawVirtualBar(data, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
else if (kLineOption)
{
var barColor=kLineOption.Color;
if (!barColor)
{
if (data.Open<data.Close) barColor=upColor;
else if (data.Open>data.Close) barColor=downColor;
else barColor=unchagneColor;
}
var drawType=this.DrawType;
if (IFrameSplitOperator.IsNumber(kLineOption.DrawType)) drawType=kLineOption.DrawType;
this.DrawKBar_Custom(data, dataWidth, barColor, drawType, kLineOption, x, y, left, right, yLow, yHigh, yOpen, yClose, border, isHScreen);
}
else if (this.DrawType==9 && data.ColorData)
{
this.DrawColorKBar(data, data.ColorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
else if (data.Open<data.Close) //阳线
{
this.DrawKBar_Up(data, dataWidth, upColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
else if (data.Open>data.Close) //阴线
{
this.DrawKBar_Down(data, dataWidth, downColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
else // 平线
{
var barColor=unchagneColor;
if (eventUnchangeKLine && eventUnchangeKLine.Callback)
{
var sendData={ KItem:data, DataIndex:i, DefaultColor:barColor, BarColor:null };
eventUnchangeKLine.Callback(eventUnchangeKLine, sendData, this);
if (sendData.BarColor) barColor=sendData.BarColor;
}
this.DrawKBar_Unchagne(data, dataWidth, barColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域
{
var yTop=Math.min(yOpen,yClose);
var yBottom=Math.max(yOpen,yClose);
if (Math.abs(yOpen-yClose)<5) //高度太小了, 上下各+5px
{
yTop=Math.min(yHigh,yTop-5);
yBottom=Math.max(yLow,yBottom+5);
}
if (data.IsNonTrade)
{
yTop=yHigh;
yBottom=yLow;
}
var rect=new Rect(left,yTop,dataWidth,yBottom-yTop);
//this.Canvas.fillStyle="rgb(0,0,100)";
//this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height);
this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域
}
if(this.Data.DataType==0 || this.Data.DataType==1)
{
var infoItem={Xleft:left,XRight:right, XCenter:x, YMax:yHigh, YMin:yLow, DayData:data, Index:j};
this.DrawInfo(infoItem);
}
if (i==this.Data.Data.length-1)
{
ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
}
if (this.PriceGap.Enable && preKItemInfo)
{
this.CheckPriceGap(kItemInfo);
var value=this.IsPriceGap(kItemInfo,preKItemInfo);
if (value>0)
this.AryPriceGapCache.push({ Data:[preKItemInfo, kItemInfo], Type:value });
}
preKItemInfo=kItemInfo;
}
this.DrawLastPointEvent(ptLast); //通知外部绘制最后一个点
this.PtMax=ptMax;
this.PtMin=ptMin;
}
this.DrawKBar_Up=function(data, dataWidth, upColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //阳线
{
var isEmptyBar=(drawType==3 || drawType==6);
if (dataWidth>=4)
{
if (isEmptyBar)
{
if ((dataWidth%2)!=0) dataWidth-=1;
}
this.Canvas.strokeStyle=upColor;
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(drawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(Math.min(yClose,yOpen)));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yClose));
}
}
this.Canvas.stroke();
y=yClose;
}
else
{
y=yClose;
}
this.Canvas.fillStyle=upColor;
if (isHScreen)
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
}
}
}
else
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y)));
}
}
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(drawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(Math.max(yClose,yOpen)));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.strokeStyle=upColor;
this.Canvas.stroke();
}
}
this.DrawKBar_Down=function(data, dataWidth, downColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //阴线
{
var isEmptyBar=(drawType==6);
if (dataWidth>=4)
{
if (isEmptyBar)
{
if ((dataWidth%2)!=0) dataWidth-=1;
}
this.Canvas.strokeStyle=downColor;
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(Math.min(yClose,yOpen)));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen));
}
}
this.Canvas.stroke();
y=yOpen;
}
else
{
y=yOpen
}
this.Canvas.fillStyle=downColor;
if (isHScreen)
{
if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth));
}
else
{
if (Math.abs(yClose-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(Math.min(y,yClose)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yClose-y)));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yClose)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yClose-y)));
}
}
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(Math.max(yClose,yOpen)));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.strokeStyle=downColor;
this.Canvas.stroke();
}
}
this.DrawKBar_Unchagne=function(data, dataWidth, unchagneColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //平线
{
if (this.OneLimitBarType===1&& this.IsOneLimitBar(data)) //一字板
{
unchagneColor=this.GetOneLimitBarColor(data);
}
if (dataWidth>=4)
{
if ((dataWidth%2)!=0) dataWidth-=1;
this.Canvas.strokeStyle=unchagneColor;
this.Canvas.beginPath();
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yOpen,ToFixedPoint(x));
}
else
{
var xFixed=ToFixedPoint(left+dataWidth/2);
this.Canvas.moveTo(xFixed,y);
this.Canvas.lineTo(xFixed,yOpen);
}
y=yOpen;
}
else
{
y=yOpen;
}
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left));
this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right));
}
else
{
this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(left+dataWidth),ToFixedPoint(y));
}
if (data.Open>data.Low) //下影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
var xFixed=ToFixedPoint(left+dataWidth/2);
this.Canvas.moveTo(xFixed,ToFixedPoint(y));
this.Canvas.lineTo(xFixed,ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
if (data.High==data.Low)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow-1,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
}
else
{
if (data.High==data.Low)
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow+1);
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
}
this.Canvas.strokeStyle=unchagneColor;
this.Canvas.stroke();
}
}
//是否是一字板
this.IsOneLimitBar=function(kItem)
{
if (kItem.Open==kItem.Close && kItem.High==kItem.Low && kItem.Open==kItem.High) return true;
return false;
}
//一字板颜色 和昨收比较
this.GetOneLimitBarColor=function(kItem)
{
if (!kItem || !IFrameSplitOperator.IsNumber(kItem.YClose)) return this.UnchagneColor;
if (kItem.Close>kItem.YClose) return this.UpColor;
else if (kItem.Close<kItem.YClose) return this.DownColor;
else return this.UnchagneColor;
}
this.DrawKBar_Custom=function(data, dataWidth, barColor, drawType, option, x, y, left, right, yLow, yHigh, yOpen, yClose, border, isHScreen)
{
if (option.BGColor) //画背景色
{
this.Canvas.fillStyle=option.BGColor;
var distanceWidth=this.ChartFrame.DistanceWidth;
if (isHScreen)
{
var yLeft=left-(distanceWidth/2);
var yRight=right+(distanceWidth/2);
var xTop=border.RightEx;
var xBottom=border.LeftEx;
this.Canvas.fillRect(ToFixedRect(xBottom),ToFixedRect(yLeft),ToFixedRect(xTop-xBottom),ToFixedRect(yRight-yLeft));
}
else
{
var xLeft=left-(distanceWidth/2);
var xRight=right+(distanceWidth/2);
var yTop=border.TopEx;
var yBottom=border.BottomEx;
this.Canvas.fillRect(ToFixedRect(xLeft),ToFixedRect(yTop),ToFixedRect(xRight-xLeft),ToFixedRect(yBottom-yTop));
}
}
if (dataWidth>=4)
{
this.Canvas.strokeStyle=barColor;
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(drawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(drawType==3?Math.min(yClose,yOpen):yClose));
}
this.Canvas.stroke();
y=yClose;
}
else
{
y=yClose;
}
this.Canvas.fillStyle=barColor;
if (isHScreen)
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
}
else
{
if (drawType==3) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
}
}
}
else
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (drawType==3) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y)));
}
}
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(drawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(drawType==3?Math.max(yClose,yOpen):y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.strokeStyle=barColor;
this.Canvas.stroke();
}
}
//绘制自定义K线
this.DrawColorKBar=function(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (Math.abs(yClose-yOpen)<1)
this.DrawColorKBar_Line(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
else if (colorData.Border || colorData.Type===0)
this.DrawColorKBar_Border(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
else
this.DrawColorKBar_NoBorder(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
//带边框柱子
this.DrawColorKBar_Border=function(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (dataWidth>=4)
{
if ((dataWidth%2)!=0) dataWidth-=1;
var topPrice=Math.max(data.Close,data.Open);
var bottomPrice=Math.min(data.Close,data.Open);
if (isHScreen)
{
var yBarTop=Math.max(yClose,yOpen);
var yBarBottom=Math.min(yClose,yOpen);
}
else
{
var yBarTop=Math.min(yClose,yOpen);
var yBarBottom=Math.max(yClose,yOpen);
}
var yBarHeight=Math.abs(yClose-yOpen);
//上影线
if (data.High>topPrice && colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yHigh),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yBarTop),ToFixedPoint(x));
}
else
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(yHigh));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yBarTop));
}
this.Canvas.stroke();
}
//下影线
if (bottomPrice>data.Low && colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yBarBottom),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(yBarBottom));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
//中心柱子
if (isHScreen)
{
var pathBar=new Path2D();
pathBar.rect(ToFixedPoint(yBarBottom),ToFixedPoint(left),ToFixedRect(yBarHeight),ToFixedRect(dataWidth));
}
else
{
var pathBar=new Path2D();
pathBar.rect(ToFixedPoint(left),ToFixedPoint(yBarTop),ToFixedRect(dataWidth),ToFixedRect(yBarHeight));
}
if (colorData.Type==0) //空心柱子
{
if (colorData.BarColor) //边框
{
this.Canvas.strokeStyle=colorData.BarColor;
this.Canvas.stroke(pathBar);
}
if (colorData.Border)
{
this.Canvas.strokeStyle=colorData.Border.Color;
this.Canvas.stroke(pathBar);
}
}
else if (colorData.Type==1) //实心
{
if (colorData.BarColor) //内部填充
{
this.Canvas.fillStyle=colorData.BarColor;
this.Canvas.fill(pathBar);
}
if (colorData.Border) //边框
{
this.Canvas.strokeStyle=colorData.Border.Color;
this.Canvas.stroke(pathBar);
}
}
}
else
{
this.DrawColorKBar_MinBar(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
}
//不带边框柱子
this.DrawColorKBar_NoBorder=function(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (dataWidth>=4)
{
var topPrice=Math.max(data.Close,data.Open);
var bottomPrice=Math.min(data.Close,data.Open);
if (isHScreen)
{
var yBarTop=Math.max(yClose,yOpen);
var yBarBottom=Math.min(yClose,yOpen);
}
else
{
var yBarTop=Math.min(yClose,yOpen);
var yBarBottom=Math.max(yClose,yOpen);
}
var yBarHeight=Math.abs(yClose-yOpen);
//上影线
if (data.High>topPrice && colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yHigh),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yBarTop),ToFixedPoint(x));
}
else
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(yHigh));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yBarTop));
}
this.Canvas.stroke();
}
//下影线
if (bottomPrice>data.Low && colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yBarBottom),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(yBarBottom));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
//中心柱子
if (isHScreen)
{
var pathBar=new Path2D();
pathBar.rect(ToFixedRect(yBarBottom),ToFixedRect(left),ToFixedRect(yBarHeight),ToFixedRect(dataWidth));
}
else
{
var pathBar=new Path2D();
pathBar.rect(ToFixedRect(left),ToFixedRect(yBarTop),ToFixedRect(dataWidth),ToFixedRect(yBarHeight));
}
if (colorData.Type==1) //实心
{
if (colorData.BarColor) //内部填充
{
this.Canvas.fillStyle=colorData.BarColor;
this.Canvas.fill(pathBar);
}
}
}
else
{
this.DrawColorKBar_MinBar(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
}
this.DrawColorKBar_MinBar=function(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yHigh),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yHigh));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
/*
var barColor;
if (colorData.Type==0) //空心柱子
{
if (colorData.Border) barColor=colorData.Border.Color;
else if (colorData.BarColor) barColor=colorData.BarColor;
}
else if (colorData.Type==1) //实心
{
if (colorData.Border) barColor=colorData.Border.Color;
else if (colorData.BarColor) barColor=colorData.BarColor;
}
if (barColor)
{
this.Canvas.strokeStyle=barColor;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yOpen),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yClose),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yOpen));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yClose));
}
this.Canvas.stroke();
}
*/
}
//十字线
this.DrawColorKBar_Line=function(data, colorData, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (dataWidth>=4)
{
if (colorData.Line)
{
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yHigh),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yHigh));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
var barColor;
if (colorData.Type==0) //空心柱子
{
if (colorData.Border) barColor=colorData.Border.Color;
else if (colorData.BarColor) barColor=colorData.BarColor;
}
else if (colorData.Type==1) //实心
{
if (colorData.Border) barColor=colorData.Border.Color;
else if (colorData.BarColor) barColor=colorData.BarColor;
}
if (barColor)
{
this.Canvas.strokeStyle=barColor;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yOpen),ToFixedPoint(left));
this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(right));
}
else
{
this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(yOpen));
this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(yOpen));
}
this.Canvas.stroke();
}
}
else
{
if (colorData.Line)
{
var xFixed=left+dataWidth/2;
this.Canvas.strokeStyle=colorData.Line.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yHigh),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yHigh));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
}
}
this.DrawVirtualBar=function(data, dataWidth, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
var yTop=Math.min(yHigh,yLow), yBottom=Math.max(yHigh,yLow);
this.Canvas.strokeStyle=this.VirtualBarConfig.Color;
this.Canvas.setLineDash(this.VirtualBarConfig.LineDash);
if (isHScreen)
{
if (dataWidth>=4)
{
this.Canvas.strokeRect(ToFixedPoint(yTop),ToFixedPoint(left),ToFixedRect(yBottom-yTop),ToFixedRect(dataWidth));
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(yTop,ToFixedPoint(x));
this.Canvas.lineTo(yBottom,ToFixedPoint(x));
this.Canvas.stroke();
}
}
else
{
if (dataWidth>=4)
{
//this.Canvas.beginPath();
this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(yTop),ToFixedRect(dataWidth),ToFixedRect(yBottom-yTop));
//this.Canvas.stroke();
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x),yTop);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
this.Canvas.stroke();
}
}
this.Canvas.setLineDash([]);
}
this.DrawRenkoCandle=function() //砖型K线
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var ptMax={X:null,Y:null,Value:null,Align:'left'};
var ptMin={X:null,Y:null,Value:null,Align:'left'};
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
this.DrawKRange.End=i;
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
if (data.YClose<data.Close)
{
this.Canvas.strokeStyle=this.UpColor; //阳线
this.Canvas.fillStyle=this.UpColor;
}
else if (data.YClose>data.Close)
{
this.Canvas.strokeStyle=this.DownColor; //阴线
this.Canvas.fillStyle=this.DownColor;
}
if (dataWidth>=4)
{
if (isHScreen)
{
this.Canvas.fillRect(ToFixedRect(yLow),ToFixedRect(left),ToFixedRect(Math.abs(yLow-yHigh)),ToFixedRect(dataWidth));
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(yHigh),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yLow-yHigh)));
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
}
}
this.PtMax=ptMax;
this.PtMin=ptMin;
}
this.DrawLineBreak=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var halfDistanceWidth=distanceWidth/2;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin-halfDistanceWidth;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin-halfDistanceWidth;
var chartright=border.RightEx;
}
var ptMax={X:null,Y:null,Value:null,Align:'left'};
var ptMin={X:null,Y:null,Value:null,Align:'left'};
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth+distanceWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
this.DrawKRange.End=i;
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
if (data.YClose<data.Close)
{
this.Canvas.strokeStyle=this.UpColor; //阳线
this.Canvas.fillStyle=this.UpColor;
}
else if (data.YClose>data.Close)
{
this.Canvas.strokeStyle=this.DownColor; //阴线
this.Canvas.fillStyle=this.DownColor;
}
if (dataWidth>=4)
{
if (isHScreen)
{
this.Canvas.fillRect(ToFixedRect(yLow),ToFixedRect(left),ToFixedRect(Math.abs(yLow-yHigh)),ToFixedRect(dataWidth+distanceWidth));
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(yHigh),ToFixedRect(dataWidth+distanceWidth),ToFixedRect(Math.abs(yLow-yHigh)));
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
}
}
this.PtMax=ptMax;
this.PtMin=ptMin;
}
this.DrawKagi=function() //卡吉图
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var left=border.TopEx+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var left=border.Left+g_JSChartResource.FrameLeftMargin;
}
var ptMax={X:null,Y:null,Value:null,Align:'left'};
var ptMin={X:null,Y:null,Value:null,Align:'left'};
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
var lineWidth=2*GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
var preItem={ Item:null, X:left, Y:null };
var index=this.Data.DataOffset-1;
if (index>=0 && index<this.Data.Data.length)
{
var item=this.Data.Data[index];
preItem.Item=item;
if (item.Direction==1) //上
{
preItem.Y=this.GetYFromData(item.High,false);
}
else if (item.Direction==2)
{
preItem.Y=this.GetYFromData(item.Low,false);
}
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
this.DrawKRange.End=i;
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
var xFixed=ToFixedPoint2(lineWidth,x);
if (preItem.Item)
{
this.Canvas.beginPath();
var yFixed=ToFixedPoint2(lineWidth,preItem.Y);
this.Canvas.moveTo(preItem.X, yFixed);
this.Canvas.lineTo(xFixed, yFixed);
var prePrice=null;
if (preItem.Item.Direction==1) prePrice=preItem.Item.Low;
else if (preItem.Item.Direction==2) prePrice=preItem.Item.High;
if (data.Direction==1)
{
if (data.High<prePrice)
{
this.Canvas.lineTo(xFixed, yHigh);
this.Canvas.strokeStyle=this.DownColor;
this.Canvas.stroke();
}
else
{
var yPrePrice=this.GetYFromData(prePrice,false);
this.Canvas.lineTo(xFixed, yPrePrice);
this.Canvas.strokeStyle=this.DownColor;
this.Canvas.stroke();
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed, yPrePrice);
this.Canvas.lineTo(xFixed, yHigh);
this.Canvas.strokeStyle=this.UpColor;
this.Canvas.stroke();
}
}
else if (data.Direction==2)
{
if (data.Low>prePrice)
{
this.Canvas.lineTo(xFixed, yLow);
this.Canvas.strokeStyle=this.DownColor; //阳线
this.Canvas.stroke();
}
else
{
var yPrePrice=this.GetYFromData(prePrice,false);
this.Canvas.lineTo(xFixed, yPrePrice);
this.Canvas.strokeStyle=this.DownColor; //阳线
this.Canvas.stroke();
this.Canvas.beginPath();
this.Canvas.moveTo(xFixed, yPrePrice);
this.Canvas.lineTo(xFixed, yLow);
this.Canvas.strokeStyle=this.UpColor;
this.Canvas.stroke();
}
}
}
else
{
this.Canvas.beginPath();
if (data.Direction==1)
{
this.Canvas.moveTo(xFixed, yLow);
this.Canvas.lineTo(xFixed, yHigh);
}
else if (data.Direction==2)
{
this.Canvas.moveTo(xFixed, yHigh);
this.Canvas.lineTo(xFixed, yLow);
}
this.Canvas.stroke();
}
/*
if (data.YClose<data.Close)
{
this.Canvas.strokeStyle=this.UpColor; //阳线
this.Canvas.fillStyle=this.UpColor;
}
else if (data.YClose>data.Close)
{
this.Canvas.strokeStyle=this.DownColor; //阴线
this.Canvas.fillStyle=this.DownColor;
}
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint2(lineWidth,x),yHigh);
this.Canvas.lineTo(ToFixedPoint2(lineWidth,x),yLow);
}
this.Canvas.stroke();
*/
preItem.Item=data;
preItem.X=x;
if (data.Direction==1) preItem.Y=yHigh; //上
else if (data.Direction==2) preItem.Y=yLow //下
}
this.PtMax=ptMax;
this.PtMin=ptMin;
}
this.DrawTrade=function() //交易系统
{
if (!this.TradeData) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
chartright=this.ChartBorder.GetBottom();
}
var sellData=this.TradeData.Sell;
var buyData=this.TradeData.Buy;
var arrowWidth=dataWidth;
if (arrowWidth>10) arrowWidth=10;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var buy=false,sell=false;
if (sellData && i<sellData.length) sell=sellData[i]>0;
if (buyData && i<buyData.length) buy=buyData[i]>0;
if (!sell && !buy) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
var yOpen=this.GetYFromData(data.Open,false);
var yClose=this.GetYFromData(data.Close,false);
var y=yHigh;
if (buy)
{
this.Canvas.fillStyle=this.UpColor;
this.Canvas.strokeStyle=this.UnchagneColor;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yLow-1,x);
this.Canvas.lineTo(yLow-arrowWidth-1,x-arrowWidth/2);
this.Canvas.lineTo(yLow-arrowWidth-1,x+arrowWidth/2);
}
else
{
this.Canvas.moveTo(x,yLow+1);
this.Canvas.lineTo(x-arrowWidth/2,yLow+arrowWidth+1);
this.Canvas.lineTo(x+arrowWidth/2,yLow+arrowWidth+1);
}
this.Canvas.closePath();
this.Canvas.fill();
this.Canvas.stroke();
}
if (sell)
{
this.Canvas.fillStyle=this.DownColor;
this.Canvas.strokeStyle=this.UnchagneColor;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh+1,x);
this.Canvas.lineTo(yHigh+arrowWidth+1,x-arrowWidth/2);
this.Canvas.lineTo(yHigh+arrowWidth+1,x+arrowWidth/2);
}
else
{
this.Canvas.moveTo(x,yHigh-1);
this.Canvas.lineTo(x-arrowWidth/2,yHigh-arrowWidth-1);
this.Canvas.lineTo(x+arrowWidth/2,yHigh-arrowWidth-1);
}
this.Canvas.closePath();
this.Canvas.fill();
this.Canvas.stroke();
}
}
}
this.DrawTick=function() //分笔图
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var fontSize=parseInt(dataWidth);
if (fontSize<=1) fontSize=2;
else if (fontSize>=18) fontSize=18;
var bFirstPoint=true;
var pixelRatio=GetDevicePixelRatio();
var textSize=fontSize*pixelRatio;
this.Canvas.beginPath();
this.Canvas.font=fontSize*pixelRatio+'px '+this.TickFontName;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yClose=this.ChartFrame.GetYFromData(data.Close,false);
this.DrawKRange.End=i;
if (data.Flag===0) this.Canvas.fillStyle=this.UpColor;
else if (data.Flag==1) this.Canvas.fillStyle=this.DownColor;
else this.Canvas.fillStyle=this.UnchagneColor;
this.Canvas.textAlign='center'
this.Canvas.textBaseline='middle';
if (isHScreen) this.Canvas.fillText(this.TickSymbol,yClose,x);
else this.Canvas.fillText(this.TickSymbol,x,yClose);
if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域
{
var rect=new Rect(x-textSize/2,yClose-textSize/2,textSize,textSize);
//this.Canvas.fillStyle="rgb(0,0,100)";
//this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height);
this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域
}
}
}
this.DrawHLCArea=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var borderLeft=border.TopEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var borderLeft=border.LeftEx;
}
var lowPath=new Path2D();
var highPath=new Path2D();
var closePath=new Path2D();
var upArea=new Path2D();
var downArea=new Path2D();
var aryHighPoint=[];
var aryLowPoint=[];
var aryClosePoint=[];
var bFirstPoint=true;
if (this.Data.DataOffset>0) //把最左边的一个点连上
{
var data=this.Data.Data[this.Data.DataOffset-1];
if (data && IFrameSplitOperator.IsNumber(data.Close) && IFrameSplitOperator.IsNumber(data.High) && IFrameSplitOperator.IsNumber(data.Low))
{
var x=borderLeft;
var yClose=this.GetYFromData(data.Close,false);
var yHigh=this.GetYFromData(data.High,false);
var yLow=this.GetYFromData(data.Low,false);
if (isHScreen)
{
closePath.moveTo(yClose,x);
highPath.moveTo(yHigh,x);
lowPath.moveTo(yLow,x);
upArea.moveTo(yHigh,x);
downArea.moveTo(yLow,x);
aryClosePoint.push({ X:yClose, Y:x });
aryHighPoint.push({ X:yHigh, Y:x });
aryLowPoint.push({ X:yLow, Y:x });
}
else
{
closePath.moveTo(x,yClose);
highPath.moveTo(x,yHigh);
lowPath.moveTo(x,yLow);
upArea.moveTo(x,yHigh);
downArea.moveTo(x,yLow);
aryClosePoint.push({ X:x, Y:yClose });
aryHighPoint.push({ X:x, Y:yHigh });
aryLowPoint.push({ X:x, Y:yLow });
}
bFirstPoint=false;
}
}
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (!data || !IFrameSplitOperator.IsNumber(data.Close) || !IFrameSplitOperator.IsNumber(data.High) || !IFrameSplitOperator.IsNumber(data.Low)) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yClose=this.GetYFromData(data.Close,false);
var yHigh=this.GetYFromData(data.High,false);
var yLow=this.GetYFromData(data.Low,false);
this.DrawKRange.End=i;
if (bFirstPoint)
{
if (isHScreen)
{
closePath.moveTo(yClose,x);
highPath.moveTo(yHigh,x);
lowPath.moveTo(yLow,x);
upArea.moveTo(yHigh,x);
downArea.moveTo(yLow,x);
}
else
{
closePath.moveTo(x,yClose);
highPath.moveTo(x,yHigh);
lowPath.moveTo(x,yLow);
upArea.moveTo(x,yHigh);
downArea.moveTo(x,yLow);
}
bFirstPoint=false;
}
else
{
if (isHScreen)
{
closePath.lineTo(yClose,x);
highPath.lineTo(yHigh,x);
lowPath.lineTo(yLow,x);
upArea.lineTo(yHigh,x);
downArea.lineTo(yLow,x);
}
else
{
closePath.lineTo(x,yClose);
highPath.lineTo(x,yHigh);
lowPath.lineTo(x,yLow);
upArea.lineTo(x,yHigh);
downArea.lineTo(x,yLow);
}
}
if (isHScreen)
{
aryClosePoint.push({ X:yClose, Y:x });
aryHighPoint.push({ X:yHigh, Y:x });
aryLowPoint.push({ X:yLow, Y:x });
}
else
{
aryClosePoint.push({ X:x, Y:yClose });
aryHighPoint.push({ X:x, Y:yHigh });
aryLowPoint.push({ X:x, Y:yLow });
}
}
if (bFirstPoint) return;
for(var i=aryClosePoint.length-1; i>=0;--i)
{
var item=aryClosePoint[i];
upArea.lineTo(item.X, item.Y);
downArea.lineTo(item.X, item.Y);
}
upArea.closePath();
downArea.closePath();
this.Canvas.fillStyle=this.HLCAreaConfig.UpAreaColor;
this.Canvas.fill(upArea);
this.Canvas.fillStyle=this.HLCAreaConfig.DownAreaColor;
this.Canvas.fill(downArea);
if (IFrameSplitOperator.IsNumber(this.HLCAreaConfig.LineWidth)) this.Canvas.lineWidth=this.HLCAreaConfig.LineWidth;
this.Canvas.strokeStyle=this.HLCAreaConfig.CloseLineColor;
this.Canvas.stroke(closePath);
this.Canvas.strokeStyle=this.HLCAreaConfig.HighLineColor;
this.Canvas.stroke(highPath);
this.Canvas.strokeStyle=this.HLCAreaConfig.LowLineColor;
this.Canvas.stroke(lowPath);
}
this.ClipTickClient=function(isHScreen)
{
var border=this.GetBorder();
if (isHScreen==true)
{
var left=this.ChartBorder.GetLeftEx();
var right=this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=border.Left;
var right=border.Right;
var top=border.TopTitle;
var bottom=border.Bottom;
}
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
this.Canvas.clip();
}
this.ClipWindow=function(isHScreen)
{
if (isHScreen==true)
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottom();
}
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
}
this.ClipClient=function(isHScreen) //裁剪客户端
{
if (isHScreen==true)
{
var left=this.ChartBorder.GetLeftEx();
var right=this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
if (this.ChartBorder.BottomSpace>0) bottom+=1;
if (this.DrawType==13) //需要显示文字,裁剪要大点
{
top=this.ChartBorder.GetTopTitle();
bottom=this.ChartBorder.GetBottom();
}
}
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
this.IsShowOrderText=false;
this.TooltipRect=[];
this.InfoTooltipRect=[];
this.TradeIconTooltipRect=[];
this.PtMax={X:null,Y:null,Value:null,Align:'left'}; //清空最大
this.PtMin={X:null,Y:null,Value:null,Align:'left'}; //清空最小
this.DrawKRange={ Start:null, End:null };
this.AryPriceGapCache=[];
this.ChartFrame.ChartKLine={Max:null, Min:null }; //保存K线上 显示最大最小值坐标
this.DrawHeatMap();
if (!this.IsShow) return;
if (this.ChartFrame.IsMinSize && this.Name=="Self Kline") return;
if (ChartData.IsTickPeriod(this.Period)) //分笔图
{
this.Canvas.save();
if (this.DrawType==1)
{
this.ClipClient(this.ChartFrame.IsHScreen);
this.DrawCloseLine();
}
else if (this.DrawType==4)
{
this.ClipClient(this.ChartFrame.IsHScreen);
this.DrawCloseArea();
}
else
{
this.ClipTickClient(this.ChartFrame.IsHScreen);
this.DrawTick();
}
this.Canvas.restore();
return;
}
this.Canvas.save();
this.ClipClient(this.ChartFrame.IsHScreen);
if (this.DrawType==1)
{
this.DrawCloseLine();
this.Canvas.restore();
if (this.PriceGap.Enable) this.DrawPriceGap();
return;
}
else if (this.DrawType==2)
{
this.DrawAKLine();
}
else if (this.DrawType==4)
{
this.DrawCloseArea();
}
else if (this.DrawType==5)
{
this.DrawOrderFlow();
}
else if (this.DrawType==7)
{
this.DrawOrderFlow_Style2();
}
else if (this.DrawType==8)
{
this.DrawOrderFlow_Style3();
}
else if (this.DrawType==9)
{
this.DrawKBar();
}
else if (this.DrawType==10)
{
this.DrawRenkoCandle();
}
else if (this.DrawType==12)
{
this.DrawLineBreak();
}
else if (this.DrawType==13)
{
this.DrawHighLow();
}
else if (this.DrawType==14)
{
if (this.FFKChart && this.FFKChart.Draw)
{
this.FFKChart.Draw(this);
}
}
else if (this.DrawType==15)
{
this.DrawHLCArea();
}
else if (this.DrawType==16)
{
this.DrawKagi();
}
else if (this.DrawType==17)
{
this.DrawOrderFlow_Style4();
}
else if (this.DrawType==18)
{
this.DrawOrderFlow_Style5();
}
else
{
this.DrawKBar();
}
if (this.TradeIcon) this.DrawTradeIcon()
else this.DrawTrade();
this.Canvas.restore();
if (this.PriceGap.Enable) this.DrawPriceGap();
if (this.IsShowMaxMinPrice) //标注最大值最小值
{
if (this.ChartFrame.IsHScreen===true) this.HScreenDrawMaxMinPrice(this.PtMax,this.PtMin);
else this.DrawMaxMinPrice(this.PtMax,this.PtMin);
}
if (this.DrawType==14) //自定义图形 标注最大最小值
{
if (this.FFKChart && this.FFKChart.DrawMaxMinPrice)
{
this.FFKChart.DrawMaxMinPrice();
}
}
}
this.OnFormatHighLowTitle=function(ptMax, ptMin)
{
if (!ptMax || !ptMin) return null;
if (!IFrameSplitOperator.IsNumber(ptMax.Value) || !IFrameSplitOperator.IsNumber(ptMin.Value)) return null;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol); //小数位数
var title=
{
High:ptMax.Value.toFixed(defaultfloatPrecision),
Low:ptMin.Value.toFixed(defaultfloatPrecision)
};
if (!this.GetEventCallback) return title;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_KLINE_HIGH_LOW_TITLE);
if (!event || !event.Callback) return title;
var data={ Max:ptMax, Min:ptMin, Symbol:this.Symbol, Title:{ High:title.High, Low:title.Low }, Decimal:defaultfloatPrecision, PreventDefault:false };
event.Callback(event, data, this);
if (data.PreventDefault) return data.Title; //使用外部回调的数值
return title;
}
this.DrawMaxMinPrice=function(ptMax,ptMin)
{
if (ptMax.X==null || ptMax.Y==null || ptMax.Value==null) return;
if (ptMin.X==null || ptMin.Y==null || ptMin.Value==null) return;
var title=this.OnFormatHighLowTitle(ptMax,ptMin);
if (!title) return;
var leftArrow=g_JSChartResource.KLine.MaxMin.LeftArrow;
var rightArrow=g_JSChartResource.KLine.MaxMin.RightArrow;
var highYOffset=g_JSChartResource.KLine.MaxMin.HighYOffset;
var lowYOffset=g_JSChartResource.KLine.MaxMin.LowYOffset;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
this.Canvas.font=this.TextFont;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var ptTop=ptMax;
var text=title.High;
var textColor=this.TextColor;
if (this.ChartFrame.CoordinateType==1) //反转坐标
{
if (ptMax.Y<ptMin.Y) ptTop=ptMin;
this.Canvas.textBaseline='top';
var text=title.Low;
if (title.LowColor) textColor=title.LowColor;
}
else
{
if (ptMax.Y>ptMin.Y) ptTop=ptMin;
this.Canvas.textBaseline='bottom';
if (title.HighColor) textColor=title.HighColor;
}
this.Canvas.fillStyle=textColor;
this.Canvas.textAlign=ptTop.Align;
var left=ptTop.Align=='left'?ptTop.X:ptTop.X;
if (IFrameSplitOperator.IsNumber(highYOffset)) ptTop.Y+=highYOffset;
//var text=ptTop.Value.toFixed(defaultfloatPrecision);
if (ptTop.Align=='left') text=leftArrow+text;
else text=text+rightArrow;
if (ptTop.Y>(top-2))
{
this.Canvas.fillText(text,left,ptTop.Y);
this.ChartFrame.ChartKLine.Max={X:left, Y:ptTop.Y, Text: { BaseLine:'bottom'}};
}
var ptBottom=ptMin;
var text=title.Low;
var textColor=this.TextColor;
if (this.ChartFrame.CoordinateType==1)
{
if (ptMin.Y>ptMax.Y) ptBottom=ptMax;
this.Canvas.textBaseline='bottom';
var text=title.High;
if (title.HighColor) textColor=title.HighColor;
}
else
{
if (ptMax.Y>ptMin.Y) ptTop=ptMin;
this.Canvas.textBaseline='top';
if (title.LowColor) textColor=title.LowColor;
}
this.Canvas.fillStyle=textColor;
this.Canvas.textAlign=ptBottom.Align;
var left=ptBottom.Align=='left'?ptBottom.X:ptBottom.X;
if (IFrameSplitOperator.IsNumber(lowYOffset)) ptBottom.Y+=lowYOffset;
//var text=ptMin.Value.toFixed(defaultfloatPrecision);
if (ptBottom.Align=='left') text=leftArrow+text;
else text=text+rightArrow;
if (ptBottom.Y<(bottom+1))
{
this.Canvas.fillText(text,left,ptBottom.Y);
this.ChartFrame.ChartKLine.Min={X:left, Y:ptBottom.Y, Text:{ BaseLine:'top'}};
}
}
this.HScreenDrawMaxMinPrice=function(ptMax,ptMin) //横屏模式下显示最大最小值
{
if (ptMax.X==null || ptMax.Y==null || ptMax.Value==null) return;
if (ptMin.X==null || ptMin.Y==null || ptMin.Value==null) return;
var title=this.OnFormatHighLowTitle(ptMax,ptMin);
if (!title) return;
var leftArrow=g_JSChartResource.KLine.MaxMin.LeftArrow;
var rightArrow=g_JSChartResource.KLine.MaxMin.RightArrow;
var highYOffset=g_JSChartResource.KLine.MaxMin.HighYOffset;
var lowYOffset=g_JSChartResource.KLine.MaxMin.LowYOffset;
//var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
var xText=ptMax.Y;
var yText=ptMax.X;
if (IFrameSplitOperator.IsNumber(highYOffset)) xText+=highYOffset;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
var text=title.High;
this.Canvas.font=this.TextFont;
if (title.HighColor) this.Canvas.fillStyle=title.HighColor;
else this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign=ptMax.Align;
this.Canvas.textBaseline='bottom';
//var text=ptMax.Value.toFixed(defaultfloatPrecision);
if (ptMax.Align=='left') text=leftArrow+text;
else text=text+rightArrow;
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
var xText=ptMin.Y;
var yText=ptMin.X;
if (IFrameSplitOperator.IsNumber(lowYOffset)) xText+=lowYOffset;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
var text=title.Low;
this.Canvas.font=this.TextFont;
if (title.LowColor) this.Canvas.fillStyle=title.LowColor;
else this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign=ptMin.Align;
this.Canvas.textBaseline='top';
//var text=ptMin.Value.toFixed(defaultfloatPrecision);
if (ptMin.Align=='left') text=leftArrow+text;
else text=text+rightArrow;
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
//画某一天的信息地雷
this.DrawInfo=function(item)
{
if (!this.InfoData || this.InfoData.size<=0) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var bottom=this.ChartBorder.GetBottom();
var top=this.ChartBorder.GetTop();
var key=`${item.DayData.Date}`;
if (this.Data.DataType==1) key=`${item.DayData.Date}-${item.DayData.Time}`;
if (!this.InfoData.has(key)) return;
var infoData=this.InfoData.get(key);
if (!infoData || infoData.Data.length<=0) return;
this.Canvas.restore();
this.Canvas.save();
this.ClipWindow(isHScreen);
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var iconSize=dataWidth+distanceWidth;
var minIconSize=18*pixelTatio;
var bShowNum=true;
if (iconSize<=15) bShowNum=false;
if (iconSize<minIconSize) iconSize=minIconSize;
var text='', title='';
var mapImage=new Map();
var iconTop=item.YMax+1*pixelTatio;
var iconBottom=item.YMin+1*pixelTatio+iconSize;
var drawTop=true;
var yOffset=0;
for(var i in infoData.Data)
{
var infoItem=infoData.Data[i];
var imageInfo=mapImage.get(infoItem.InfoType);
if (!imageInfo)
{
var icon=JSKLineInfoMap.GetIconFont(infoItem.InfoType);
this.Canvas.fillStyle=icon.Color;
this.Canvas.font=iconSize+'px '+icon.Family;
if (isHScreen)
{
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
this.Canvas.fillText(icon.HScreenText,iconTop,item.XCenter,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,iconTop-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:iconTop, Y:item.XCenter} };
mapImage.set(infoItem.InfoType,infoCache);
iconTop+=iconSize;
}
else
{
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="center";
if (this.InfoPosition===1)
{
var yBottom=bottom+yOffset;
this.Canvas.fillText(icon.Text,item.XCenter,yBottom,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,yBottom-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:yBottom} };
mapImage.set(infoItem.InfoType,infoCache);
yOffset-=iconSize;
}
else
{
if (drawTop)
{
this.Canvas.fillText(icon.Text,item.XCenter,iconTop,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,iconTop-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:iconTop} };
mapImage.set(infoItem.InfoType,infoCache);
iconTop-=iconSize;
if (iconTop-iconSize<top ) drawTop=false;
}
else //上面显示不下,就显示在下面
{
this.Canvas.fillText(icon.Text,item.XCenter,iconBottom,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,iconBottom-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:iconBottom} };
mapImage.set(infoItem.InfoType,infoCache);
iconBottom+=iconSize;
}
}
}
}
else
{
imageInfo.Data.push(infoItem);
}
}
var numText;
if (g_JSChartResource.KLine.NumIcon)
{
if (isHScreen) numText=g_JSChartResource.KLine.NumIcon.HScreenText;
else numText=g_JSChartResource.KLine.NumIcon.Text;
}
for(var item of mapImage)
{
var value=item[1];
if (value.Data.length>=2 && numText && bShowNum) //太小了 就不显示了
{
var iconID=value.Data.length;
if (iconID>=numText.length) iconID=0;
this.Canvas.fillStyle=g_JSChartResource.KLine.NumIcon.Color;
var text=numText[iconID];
this.Canvas.fillText(text,value.TextRect.X,value.TextRect.Y,iconSize);
}
if (!isHScreen) this.InfoTooltipRect.push(value); //横屏没有tooltip
}
this.Canvas.restore();
this.Canvas.save();
this.ClipClient(isHScreen);
}
//画交易图标
this.DrawTradeIcon=function()
{
if (!this.TradeData) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
chartright=this.ChartBorder.GetBottom();
}
var sellData=this.TradeData.Sell;
var buyData=this.TradeData.Buy;
var iconSize=dataWidth+distanceWidth;
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var iconSizeMax=24*pixelTatio,iconSizeMin=12*pixelTatio;
if (iconSize<iconSizeMin) iconSize=iconSizeMin;
else if (iconSize>iconSizeMax) iconSize=iconSizeMax;
this.Canvas.font=iconSize+'px '+this.TradeIcon.Family;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var buy=false,sell=false;
if (sellData && i<sellData.length) sell=sellData[i]>0;
if (buyData && i<buyData.length) buy=buyData[i]>0;
if (!sell && !buy) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
var yOpen=this.GetYFromData(data.Open,false);
var yClose=this.GetYFromData(data.Close,false);
var y=yHigh;
if (buy)
{
this.Canvas.fillStyle=this.TradeIcon.Buy.Color;
if (isHScreen)
{
this.Canvas.textAlign='right';
this.Canvas.textBaseline='middle';
this.Canvas.fillText(this.TradeIcon.Buy.HScreenText,yLow,x);
}
else
{
this.Canvas.textAlign='center';
this.Canvas.textBaseline='top';
this.Canvas.fillText(this.TradeIcon.Buy.Text,x,yLow);
var iconRect=new Rect(x-iconSize/2,yLow,iconSize,iconSize);
var iconData={ Data:{ Type:1, KData:data, Name:this.TradeData.Name, Param:this.TradeData.Param }, Rect:iconRect, TextRect:{X:x, Y:yLow} };
this.TradeIconTooltipRect.push(iconData);
}
}
if (sell)
{
this.Canvas.fillStyle=this.TradeIcon.Sell.Color;
if (isHScreen)
{
this.Canvas.textAlign='left';
this.Canvas.textBaseline='middle';
this.Canvas.fillText(this.TradeIcon.Sell.HScreenText,yHigh,x);
}
else
{
this.Canvas.textAlign='center';
this.Canvas.textBaseline='bottom';
this.Canvas.fillText(this.TradeIcon.Sell.Text,x,yHigh);
var iconRect=new Rect(x-iconSize/2,yHigh-iconSize,iconSize,iconSize);
var iconData={ Data:{ Type:2, KData:data, Name:this.TradeData.Name,Param:this.TradeData.Param }, Rect:iconRect, TextRect:{X:x, Y:yHigh} };
this.TradeIconTooltipRect.push(iconData);
}
}
}
}
this.GetTooltipData=function(x,y,tooltip)
{
if (!this.IsShow) return false;
for(var i in this.TradeIconTooltipRect)
{
var item=this.TradeIconTooltipRect[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
JSConsole.Chart.Log('[ChartKLine::GetTooltipData] trade icon ', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=2; //指标
return true;
}
}
for(var i in this.InfoTooltipRect)
{
var item=this.InfoTooltipRect[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
//JSConsole.Chart.Log('[ChartKLine::GetTooltipData] info ', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=1; //信息地雷
return true;
}
}
for(var i in this.TooltipRect)
{
var rect=this.TooltipRect[i][1];
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
var index=this.TooltipRect[i][0];
tooltip.Data=this.Data.Data[index];
tooltip.ChartPaint=this;
tooltip.Type=0; //K线信息
return true;
}
}
return false;
}
//计算当天显示数据的最大最小值
this.GetMaxMin=function()
{
if (this.DrawType==14)
{
if (this.FFKChart && this.FFKChart.GetMaxMin)
{
return this.FFKChart.GetMaxMin(this);
}
}
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
var range={ Max:null, Min:null };
if (this.DrawType==1 || this.DrawType==4 ) // 1=收盘价线 4=收盘价面积图
{
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(data.Close)) continue;
if (range.Max==null) range.Max=data.Close;
if (range.Min==null) range.Min=data.Close;
if (range.Max<data.Close) range.Max=data.Close;
if (range.Min>data.Close) range.Min=data.Close;
}
}
else
{
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (this.DrawType==5 && data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset))
{
var high=data.High;
var low=data.Low;
if (IFrameSplitOperator.IsNonEmptyArray(data.OrderFlow.High))
{
for(var k=0;k<data.OrderFlow.High.length;++k)
{
var item=data.OrderFlow.High[k];
if (high<item.Price) high=item.Price;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(data.OrderFlow.Low))
{
for(var k=0;k<data.OrderFlow.Low.length;++k)
{
var item=data.OrderFlow.Low[k];
if (low>item.Price) low=item.Price;
}
}
high+=data.OrderFlow.PriceOffset;
low-=data.OrderFlow.PriceOffset;
if (range.Max==null) range.Max=high;
if (range.Min==null) range.Min=low;
if (range.Max<high) range.Max=high;
if (range.Min>low) range.Min=low;
}
else
{
if (range.Max==null) range.Max=data.High;
if (range.Min==null) range.Min=data.Low;
if (range.Max<data.High) range.Max=data.High;
if (range.Min>data.Low) range.Min=data.Low;
}
}
}
return range;
}
//获取所有的价格
this.GetAllPrice=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var setPrice=new Set();
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var value=data.Close;
setPrice.add(value);
}
var aryPrice=[];
for(var item of setPrice)
{
aryPrice.push(item);
}
aryPrice.sort(function(a,b) { return a-b; }); //排序 升序
return aryPrice;
}
this.DrawLastPointEvent=function(ptLast)
{
if (!this.GetEventCallback) return;
//通知外部绘制最后一个点
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_KLINE_LAST_POINT);
if (event)
{
var kWidth={ Data: this.ChartFrame.DataWidth, Distance:this.ChartFrame.DistanceWidth };
if (ptLast) var data={ LastPoint:{ X:ptLast.X, Y:ptLast.Y, XLeft:ptLast.XLeft, XRight:ptLast.XRight }, KItem:ptLast.KItem, DrawType:this.DrawType, KWidth:kWidth, ChartRight:ptLast.ChartRight };
else var data={ LastPoint:null, KItem:null, KWidth:kWidth };
event.Callback(event,data,this);
}
}
this.DrawOrderFlow=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var upColor=this.UpColor;
var downColor=this.DownColor;
var unchagneColor=this.UnchagneColor;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
var ptLast=null;
this.DrawOrderFlowHBar(); //横向柱子
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
this.DrawKRange.End=i;
var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
var xKLine={ Left:left, Center:x, Right:right, DataWidth:dataWidth };
this.DrawOrderFlowBar(data.OrderFlow, data, xKLine, yKline, isHScreen);
if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域
{
var yTop=Math.min(yOpen,yClose);
var yBottom=Math.max(yOpen,yClose);
if (Math.abs(yOpen-yClose)<5) //高度太小了, 上下各+5px
{
yTop=Math.min(yHigh,yTop-5);
yBottom=Math.max(yLow,yBottom+5);
}
var rect=new Rect(left,yTop,dataWidth,yBottom-yTop);
//this.Canvas.fillStyle="rgb(0,0,100)";
//this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height);
this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域
}
if(this.Data.DataType==0)
{
var infoItem={Xleft:left,XRight:right, XCenter:x, YMax:yHigh, YMin:yLow, DayData:data, Index:j};
this.DrawInfo(infoItem);
}
if (i==this.Data.Data.length-1)
{
ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
}
}
}
this.DrawOrderFlowBar=function(orderFlow, kItem, xKLine, yKline, isHScreen)
{
var top=Math.min(yKline.Open, yKline.Close)
var bottom=Math.max(yKline.Open, yKline.Close);
var barHeight=Math.abs(yKline.Open-yKline.Close);
var cellHeight=0;
if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2);
this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);
if (this.OrderFlow.AlwaysShowOrderText) this.IsShowOrderText=true;
var kColor;
if (kItem.Open<kItem.Close) kColor=this.OrderFlow.UpColor;
else if (kItem.Open>kItem.Close) kColor=this.OrderFlow.DownColor;
else kColor=this.OrderFlow.UnchagneColor;
var isSmallKLine=(xKLine.DataWidth<4);
if (isSmallKLine)
{
this.Canvas.strokeStyle=kColor.Border;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
this.Canvas.stroke();
}
else
{
this.Canvas.fillStyle=kColor.BG;
this.Canvas.fillRect(ToFixedRect(xKLine.Left),ToFixedRect(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
}
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='center';
this.Canvas.font=textFont;
var textWidth=xKLine.DataWidth/2;
var textXOffset=textWidth/2;
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
{
var totalAsk=0, totalBid=0, maxTotalIndex=null;
if (this.OrderFlow.IsShowAskBar || this.OrderFlow.IsShowBidBar || this.OrderFlow.IsShowPOCBG)
{
var maxTotal=0, value=0;
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
value=0;
if (item.Ask && IFrameSplitOperator.IsNumber(item.Ask.Value))
{
totalAsk+=item.Ask.Value;
value+=item.Ask.Value;
}
if (item.Bid && IFrameSplitOperator.IsNumber(item.Bid.Value))
{
totalBid+=item.Bid.Value;
value+=item.Bid.Value;
}
if (maxTotal<value)
{
maxTotal=value;
maxTotalIndex=i;
}
}
}
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
var yPrice=this.GetYFromData(item.Price, false);
var rect={ Left:xKLine.Left, Right:xKLine.Center, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (item.Ask.BG)
{
this.Canvas.fillStyle=item.Ask.BG;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (this.OrderFlow.IsShowPOCBG && maxTotalIndex==i)
{
this.Canvas.fillStyle=this.OrderFlow.POCGBColor;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (this.OrderFlow.IsShowAskBar && IFrameSplitOperator.IsNumber(item.Ask.Value) && totalAsk>0)
{
var barWidh=rect.Width*(item.Ask.Value/totalAsk);
if (barWidh<1) barWidh=1;
this.Canvas.fillStyle=this.OrderFlow.AskBarColor;
this.Canvas.fillRect(ToFixedRect(rect.Right),ToFixedRect(rect.Top),ToFixedRect(-barWidh),ToFixedRect(rect.Height));
}
var text=null;
if (IFrameSplitOperator.IsString(item.Ask.Text)) text=item.Ask.Text;
else if (IFrameSplitOperator.IsNumber(item.Ask.Value)) text=item.Ask.Value.toString();
if (text && this.IsShowOrderText && this.OrderFlow.IsShowAskText)
{
if (item.Ask.Color) this.Canvas.fillStyle=item.Ask.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
if (item.Ask.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Ask.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
}
}
var rect={ Left:xKLine.Center, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (item.Bid.BG)
{
this.Canvas.fillStyle=item.Bid.BG;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (this.OrderFlow.IsShowPOCBG && maxTotalIndex==i)
{
this.Canvas.fillStyle=this.OrderFlow.POCGBColor;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (this.OrderFlow.IsShowBidBar && IFrameSplitOperator.IsNumber(item.Bid.Value) && totalBid>0)
{
var barWidh=rect.Width*(item.Bid.Value/totalBid);
if (barWidh<1) barWidh=1;
this.Canvas.fillStyle=this.OrderFlow.BidBarColor;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(barWidh),ToFixedRect(rect.Height));
}
var text=null;
if (IFrameSplitOperator.IsString(item.Bid.Text)) text=item.Bid.Text;
else if (IFrameSplitOperator.IsNumber(item.Bid.Value)) text=item.Bid.Value.toString();
if (text && this.IsShowOrderText && this.OrderFlow.IsShowBidText)
{
if (item.Bid.Color) this.Canvas.fillStyle=item.Bid.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
if (item.Bid.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Bid.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
}
}
}
}
if (yKline.High<top || yKline.Low>bottom)
{
this.Canvas.strokeStyle=this.OrderFlow.Line.UpDownColor;
if (yKline.High<top)
{
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),yKline.High-cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
this.Canvas.stroke();
}
if (yKline.Low>bottom)
{
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),yKline.Low+cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
this.Canvas.stroke();
}
}
if (!isSmallKLine && Math.abs(yKline.Open-yKline.Close)>1) //K线中间竖线
{
this.Canvas.strokeStyle=this.OrderFlow.Line.MiddleColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
this.Canvas.stroke();
}
//K线边框
if (!isSmallKLine)
{
this.Canvas.beginPath();
this.Canvas.strokeStyle=kColor.Border;
this.Canvas.rect(ToFixedPoint(xKLine.Left),ToFixedPoint(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
this.Canvas.stroke();
}
//var fontHeight=this.Canvas.measureText("擎").width+2;
var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth);
//上下文字
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.High) && this.IsShowOrderText)
{
for(var i=0;i<orderFlow.High.length;++i)
{
var item=orderFlow.High[i];
var text;
if (IFrameSplitOperator.IsString(item.Text)) text=item.Text;
else if (IFrameSplitOperator.IsNumber(item.Value)) text=item.Value.toString();
if (!text) continue;
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
var yPrice=this.GetYFromData(item.Price, false);
if (item.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth, item.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Center,yPrice);
}
}
}
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Low) && this.IsShowOrderText)
{
for(var i=0;i<orderFlow.Low.length;++i)
{
var item=orderFlow.Low[i];
var text;
if (IFrameSplitOperator.IsString(item.Text)) text=item.Text;
else if (IFrameSplitOperator.IsNumber(item.Value)) text=item.Value.toString();
if (!text) continue;
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
var yPrice=this.GetYFromData(item.Price, false);
if (item.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth, item.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Center,yPrice);
}
}
}
}
this.GetPriceYOffset=function(value)
{
var frame=this.ChartFrame;
var y=frame.ChartBorder.GetHeightEx()*(value)/(frame.HorizontalMax-frame.HorizontalMin);
return y;
}
this.GetDynamicOrderFlowFont=function(cellHeight, width, fontOption)
{
var fontSize=parseInt(cellHeight)-2;
if (cellHeight<5) fontSize=parseInt(cellHeight); //高度太小了就不要上下间距了
if (fontSize>this.OrderFlow.Text.FontMaxSize) fontSize=this.OrderFlow.Text.FontMaxSize;
else if (fontSize<=0) fontSize=1;
var font=this.FormatFontString(fontSize, this.OrderFlow.Text.Family, fontOption);
for(var i=fontSize; i>0; i-=2)
{
var font=this.FormatFontString(i, this.OrderFlow.Text.Family, fontOption);
this.Canvas.font=font;
var textWidth=this.Canvas.measureText(this.OrderFlow.Text.MaxValue).width+2;
if (textWidth<width) break;
}
return font;
}
this.FormatFontString=function(fontSize, family, option)
{
var font;
if (!option)
{
font=`${fontSize}px ${family}`;
}
else
{
if (option.Weight) font=`${option.Weight} ${fontSize}px ${family}`;
}
return font;
}
this.DrawOrderFlowHBar=function()
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var horizontalMax=this.ChartFrame.HorizontalMax, horizontalMin=this.ChartFrame.HorizontalMin;
var startOffset=this.Data.DataOffset, endOffset=this.Data.DataOffset+xPointCount
for(var i=0; i<this.Data.Data.length;++i) //绘制横线柱子
{
var kItem=this.Data.Data[i];
if (!kItem || !kItem.OrderFlow) continue;
if (!IFrameSplitOperator.IsNonEmptyArray(kItem.OrderFlow.Order)) continue;
for(var j=0;j<kItem.OrderFlow.Order.length;++j)
{
var orderItem=kItem.OrderFlow.Order[j];
if (!orderItem.HBar) continue;
if (!IFrameSplitOperator.IsNumber(orderItem.HBar.Width)) continue;
if (!IFrameSplitOperator.IsNumber(orderItem.Price)) continue;
if (orderItem.Price>horizontalMax || orderItem.Price<horizontalMin) continue;
var value=Math.ceil((i+orderItem.HBar.Width));
var start=Math.min(i,value);
var end=Math.max(i,value);
if (end<startOffset || start>endOffset) continue;
this.DrawOrderFlowHBarItem(i, kItem.OrderFlow, orderItem, dataWidth, distanceWidth);
}
}
}
this.DrawOrderFlowHBarItem=function(index, orderFlow, orderItem, dataWidth, distanceWidth)
{
var offset=this.ShowRange.Start;
var endOffset=this.ShowRange.Start+this.ShowRange.ShowCount;
var yPrice=this.GetYFromData(orderItem.Price, false);
var value=parseInt(index+orderItem.HBar.Width);
var start=index-offset;
var end=value-offset;
if (start<0) start=0;
if (end<0) end=0;
if (start<=end)
{
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
var dataOffset=offset;
var cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var xStart=this.ChartFrame.GetXFromIndex(start)-dataWidth/2;
if (orderItem.HBar.Type==1)
{
for(var i=0, j=index+1; i<orderItem.HBar.Width && j<this.Data.Data.length ; ++i, ++j)
{
var data=this.Data.Data[j];
if (data.Close<orderItem.Price)
{
end=(j-1)-dataOffset;
break;
}
}
}
else if (orderItem.HBar.Type==2)
{
for(var i=0, j=index+1; i<orderItem.HBar.Width && j<this.Data.Data.length ; ++i, ++j)
{
var data=this.Data.Data[j];
if (data.Close>orderItem.Price)
{
end=(j-1)-dataOffset;
break;
}
}
}
if (end<0) return;
var xEnd=this.ChartFrame.GetXFromIndex(end)+dataWidth/2;
var yTop=yPrice-cellHeight/2;
var yHeight=cellHeight+0.5
if (IFrameSplitOperator.IsNumber(orderItem.HBar.Height))
yHeight=orderItem.HBar.Height*cellHeight+0.1;
var fValue=orderItem.HBar.Width-parseInt(orderItem.HBar.Width);
if (fValue>0.000001) xEnd+=(dataWidth+distanceWidth)*fValue;
this.Canvas.fillStyle=orderItem.HBar.Color;
this.Canvas.fillRect(ToFixedRect(xStart),ToFixedRect(yTop),ToFixedRect(xEnd-xStart),ToFixedRect(yHeight)); //高度适当加上,否则行间有空隙
}
}
this.PtInChart=function(x,y)
{
if (this.DrawType==1 || this.DrawType==4)
{
return this.PtInLine(x,y, {KLineClose:true});
}
return this.PtInKBar(x,y);
}
this.DrawSelectedStatus=function()
{
this.DrawLinePoint({KLineClose:true});
}
//////////////////////////////////////////////////////////////
//订单流样式2
this.DrawOrderFlow_Style2=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
this.AryOrderFlowBorder=[];
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var upColor=this.OrderFlow_Style2.UpColor;
var downColor=this.OrderFlow_Style2.DownColor;
var unchagneColor=this.OrderFlow_Style2.UnchagneColor;
var barWidth=ToFixedRect(this.OrderFlow_Style2.BarWidth);
var textWidth=dataWidth-barWidth;
if (textWidth/7<barWidth) barWidth=textWidth/7;
if (barWidth<=1) barWidth=2;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
this.DrawOrderFlowHBar(); //横向柱子
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
this.DrawKRange.End=i;
var barTop=Math.min(yOpen,yClose);
var barBottom=Math.max(yOpen,yClose);
var barLeft=ToFixedRect(left);
var barRight=barLeft+barWidth
if (data.Open<data.Close) this.Canvas.fillStyle=upColor;
else if (data.Open>data.Close) this.Canvas.fillStyle=downColor;
else this.Canvas.fillStyle=unchagneColor;
var cellHeight=0;
if (data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(data.OrderFlow.PriceOffset);
this.Canvas.fillRect(barLeft,ToFixedRect(barTop-cellHeight/2),barWidth,ToFixedRect(barBottom-barTop+cellHeight));
var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
var xKLine={ Left:barRight, Center:x, Right:right, DataWidth:(right-barRight) };
xKLine.Center=xKLine.Left+xKLine.DataWidth/2;
this.DrawOrderFlowBar_Style2(data.OrderFlow, data, xKLine, yKline, isHScreen);
}
//最后绘制边框
if (dataWidth-barWidth>5)
{
for(var i=0;i<this.AryOrderFlowBorder.length;++i)
{
var item=this.AryOrderFlowBorder[i];
if (!item || !item.Rect || !item.Color) continue;
var rect=item.Rect;
this.Canvas.strokeStyle=item.Color;
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(rect.Left),ToFixedPoint(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
this.Canvas.stroke();
}
}
this.AryOrderFlowBorder=[];
}
/////////////////////////////////////////////////////////////
//订单流样式3
this.DrawOrderFlow_Style3=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
this.AryOrderFlowBorder=[];
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var upColor=this.OrderFlow_Style3.UpColor;
var downColor=this.OrderFlow_Style3.DownColor;
var unchagneColor=this.OrderFlow_Style3.UnchagneColor;
var barWidth=ToFixedRect(this.OrderFlow_Style3.BarWidth);
if (dataWidth/4<barWidth) barWidth=dataWidth/4;
if (barWidth<=1) barWidth=2;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
this.DrawOrderFlowHBar(); //横向柱子
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
this.DrawKRange.End=i;
var barTop=Math.min(yOpen,yClose);
var barBottom=Math.max(yOpen,yClose);
var barLeft=ToFixedRect(left);
var barRight=barLeft+barWidth
if (data.Open<data.Close) this.Canvas.fillStyle=upColor;
else if (data.Open>data.Close) this.Canvas.fillStyle=downColor;
else this.Canvas.fillStyle=unchagneColor;
var cellHeight=0;
if (data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(data.OrderFlow.PriceOffset);
this.Canvas.fillRect(barLeft,ToFixedRect(barTop-cellHeight/2),barWidth,ToFixedRect(barBottom-barTop+cellHeight));
var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
var xKLine={ Left:barRight, Right:right, DataWidth:(right-barRight) };
this.DrawOrderFlowBar_Style3(data.OrderFlow, data, xKLine, yKline, isHScreen);
}
//最后绘制边框
if (dataWidth-barWidth>5)
{
for(var i=0;i<this.AryOrderFlowBorder.length;++i)
{
var item=this.AryOrderFlowBorder[i];
if (!item || !item.Rect || !item.Color) continue;
var rect=item.Rect;
this.Canvas.strokeStyle=item.Color;
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(rect.Left),ToFixedPoint(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
this.Canvas.stroke();
}
}
this.AryOrderFlowBorder=[];
}
this.DrawOrderFlowBar_Style2=function(orderFlow, kItem, xKLine, yKline, isHScreen)
{
var top=Math.min(yKline.Open, yKline.Close)
var bottom=Math.max(yKline.Open, yKline.Close);
var barHeight=Math.abs(yKline.Open-yKline.Close);
var cellHeight=0;
if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2);
this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);
if (this.OrderFlow.AlwaysShowOrderText) this.IsShowOrderText=true;
/* 背景暂时不用
var kColor;
if (kItem.Open<kItem.Close) kColor=this.OrderFlow.UpColor;
else if (kItem.Open>kItem.Close) kColor=this.OrderFlow.DownColor;
else kColor=this.OrderFlow.UnchagneColor;
var isSmallKLine=(xKLine.DataWidth<4);
if (isSmallKLine)
{
this.Canvas.strokeStyle=kColor.Border;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
this.Canvas.stroke();
}
else
{
this.Canvas.fillStyle=kColor.BG;
this.Canvas.fillRect(ToFixedRect(xKLine.Left),ToFixedRect(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
}
*/
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.font=textFont;
var textWidth=xKLine.DataWidth/2;
var textXOffset=2;
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
{
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
var yPrice=this.GetYFromData(item.Price, false);
var rect={ Left:xKLine.Left, Right:xKLine.Center, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (item.Ask.BG)
{
this.Canvas.fillStyle=item.Ask.BG;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (item.Ask.BorderColor)
{
var borderItem={Rect:rect, Color:item.Ask.BorderColor};
this.AryOrderFlowBorder.push(borderItem);
}
var text=null;
if (IFrameSplitOperator.IsString(item.Ask.Text)) text=item.Ask.Text;
else if (IFrameSplitOperator.IsNumber(item.Ask.Value)) text=item.Ask.Value.toString();
if (text && this.IsShowOrderText)
{
if (item.Ask.Color) this.Canvas.fillStyle=item.Ask.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
if (item.Ask.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Ask.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
}
}
var rect={ Left:xKLine.Center, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (item.Bid.BG)
{
this.Canvas.fillStyle=item.Bid.BG;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (item.Bid.BorderColor)
{
var borderItem={Rect:rect, Color:item.Bid.BorderColor};
this.AryOrderFlowBorder.push(borderItem);
}
var text=null;
if (IFrameSplitOperator.IsString(item.Bid.Text)) text=item.Bid.Text;
else if (IFrameSplitOperator.IsNumber(item.Bid.Value)) text=item.Bid.Value.toString();
if (text && this.IsShowOrderText)
{
if (item.Bid.Color) this.Canvas.fillStyle=item.Bid.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
if (item.Bid.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Bid.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
}
}
}
}
}
this.DrawOrderFlowBar_Style3=function(orderFlow, kItem, xKLine, yKline, isHScreen)
{
var top=Math.min(yKline.Open, yKline.Close)
var bottom=Math.max(yKline.Open, yKline.Close);
var barHeight=Math.abs(yKline.Open-yKline.Close);
var itemWidth=xKLine.DataWidth-4;
var cellHeight=0;
if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var textFont=this.GetDynamicOrderFlowFont(cellHeight, itemWidth);
this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);
if (this.OrderFlow.AlwaysShowOrderText) this.IsShowOrderText=true;
/* 背景暂时不用
var kColor;
if (kItem.Open<kItem.Close) kColor=this.OrderFlow.UpColor;
else if (kItem.Open>kItem.Close) kColor=this.OrderFlow.DownColor;
else kColor=this.OrderFlow.UnchagneColor;
var isSmallKLine=(xKLine.DataWidth<4);
if (isSmallKLine)
{
this.Canvas.strokeStyle=kColor.Border;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
this.Canvas.stroke();
}
else
{
this.Canvas.fillStyle=kColor.BG;
this.Canvas.fillRect(ToFixedRect(xKLine.Left),ToFixedRect(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
}
*/
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.font=textFont;
var textXOffset=2;
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
{
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
var yPrice=this.GetYFromData(item.Price, false);
var rect={ Left:xKLine.Left, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (item.Item.BG)
{
this.Canvas.fillStyle=item.Item.BG;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
}
if (item.Item.BorderColor)
{
var borderItem={Rect:rect, Color:item.Item.BorderColor};
this.AryOrderFlowBorder.push(borderItem);
}
var text=null;
if (IFrameSplitOperator.IsString(item.Item.Text)) text=item.Item.Text;
else if (IFrameSplitOperator.IsNumber(item.Item.Value)) text=item.Item.Value.toString();
if (text && this.IsShowOrderText)
{
if (item.Item.Color) this.Canvas.fillStyle=item.Item.Color;
else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
if (item.Item.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, itemWidth, item.Item.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
//订单流样式4
this.DrawOrderFlow_Style4=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
this.AryOrderFlowBorder=[];
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var upColor=this.OrderFlow_Style4.UpColor;
var downColor=this.OrderFlow_Style4.DownColor;
var unchagneColor=this.OrderFlow_Style4.UnchagneColor;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
this.DrawOrderFlowHBar(); //横向柱子
var kBarWidth=this.OrderFlow_Style4.KBarWidth;
if (dataWidth+distanceWidth<kBarWidth*3) kBarWidth=1;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
this.DrawKRange.End=i;
var barLeft=left+this.OrderFlow_Style4.LeftMargin;
var barRight=right+distanceWidth-this.OrderFlow_Style4.RightMargin;
if (this.OrderFlow_Style4.KBarType==1)
{
var kbarTop=Math.min(yOpen,yClose);
var kbarBottom=Math.max(yOpen,yClose);
var kbarLeft=ToFixedRect(left)+this.OrderFlow_Style4.LeftMargin;
var kbarRight=barLeft+kBarWidth;
if (data.Open<data.Close) this.Canvas.fillStyle=upColor;
else if (data.Open>data.Close) this.Canvas.fillStyle=downColor;
else this.Canvas.fillStyle=unchagneColor;
var cellHeight=0;
if (data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(data.OrderFlow.PriceOffset);
this.Canvas.fillRect(kbarLeft,ToFixedRect(kbarTop-cellHeight/2),kBarWidth,ToFixedRect(kbarBottom-kbarTop+cellHeight));
barLeft=kbarRight+1;
}
var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
var xKLine={ Left:barLeft, Center:x, Right:barRight, DataWidth:(barRight-barLeft) };
xKLine.Center=xKLine.Left+xKLine.DataWidth/2;
this.DrawOrderFlowBar_Style4(data.OrderFlow, data, xKLine, yKline, isHScreen);
}
}
this.DrawOrderFlowBar_Style4=function(orderFlow, kItem, xKLine, yKline, isHScreen)
{
var top=Math.min(yKline.Open, yKline.Close)
var bottom=Math.max(yKline.Open, yKline.Close);
var barHeight=Math.abs(yKline.Open-yKline.Close);
var cellHeight=0;
if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2);
this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);
if (this.OrderFlow.AlwaysShowOrderText) this.IsShowOrderText=true;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.font=textFont;
var volBarSpace=this.OrderFlow_Style4.VolBarSpace;
if (cellHeight<=4) volBarSpace=0; //太细了 间距就不要了
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
{
if (!orderFlow.Summary) orderFlow.Summary={ };
if (!orderFlow.Summary.VolMaxMin) //计算最大最小值
{
var volMaxMin={ Max:null, Min:null };
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order.length[i];
if (volMaxMin.Max==null || volMaxMin.Max<item.Vol.Value) volMaxMin.Max=item.Vol.Value;
if (volMaxMin.Min==null || volMaxMin.Min>item.Vol.Value) volMaxMin.Min=item.Vol.Value;
}
orderFlow.Summary.VolMaxMin=volMaxMin;
}
var preItem=null; //上一个矩形框
var max=orderFlow.Summary.VolMaxMin.Max, min=orderFlow.Summary.VolMaxMin.Min;
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
var yPrice=this.GetYFromData(item.Price, false);
if (!item.Vol) continue;
if (IFrameSplitOperator.IsNonEmptyArray(item.AryVol))
{
var barWidth=xKLine.Right-xKLine.Left;
var xVolLeft=xKLine.Left;
var xVolRight=xVolLeft;
var totalVol=0;
var rtDraw={ Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
for(var j=0;j<item.AryVol.length;++j)
{
var itemVol=item.AryVol[j];
if (!IFrameSplitOperator.IsNumber(itemVol.Value)) continue;
totalVol+=itemVol.Value;
xVolRight=barWidth*(totalVol-min)/(max-min)+xKLine.Left;
var rtBar={ Left:xVolLeft, Right:xVolRight, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
if (preItem && item.Price>preItem.Price)
{
rtBar.Bottom=preItem.Rect.Top-volBarSpace;
}
rtBar.Width=rtBar.Right-rtBar.Left;
rtBar.Height=rtBar.Bottom-rtBar.Top;
rtDraw={ Left:ToFixedRect(rtBar.Left), Top:ToFixedRect(rtBar.Top), Width:ToFixedRect(rtBar.Width), Height:ToFixedRect(rtBar.Height) };
rtDraw.Bottom=rtDraw.Top+rtDraw.Height;
rtDraw.Right=rtDraw.Left+rtDraw.Width;
if (rtDraw.Width<1) rtDraw.Width=1;
if (itemVol.BG) //背景色
{
this.Canvas.fillStyle=itemVol.BG;
this.Canvas.fillRect(rtDraw.Left, rtDraw.Top, rtDraw.Width, rtDraw.Height);
}
xVolLeft=rtDraw.Right;
}
rtDraw.Left=xKLine.Left;
rtDraw.Width=rtDraw.Right-rtDraw.Left;
if (item.Vol.Text && this.IsShowOrderText) //文字
{
this.Canvas.fillStyle=item.Vol.Color;
if (item.Vol.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, barWidth/2, item.Vol.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(item.Vol.Text,rtDraw.Left+2,yPrice);
}
}
preItem={ Price: item.Price, Rect:rtDraw };
}
else if (IFrameSplitOperator.IsNumber(item.Vol.Value))
{
var barWidth=xKLine.Right-xKLine.Left;
var volWidth=barWidth*(item.Vol.Value-min)/(max-min);
var rect={ Left:xKLine.Left, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Right=rect.Left+volWidth;
if (preItem && item.Price>preItem.Price)
{
rect.Bottom=preItem.Rect.Top-volBarSpace;
}
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
var rtDraw={ Left:ToFixedRect(rect.Left), Top:ToFixedRect(rect.Top), Width:ToFixedRect(rect.Width), Height:ToFixedRect(rect.Height) };
rtDraw.Bottom=rtDraw.Top+rtDraw.Height;
rtDraw.Right=rtDraw.Left+rtDraw.Width;
if (rtDraw.Width<1) rtDraw.Width=1;
if (item.Vol.BG) //背景色
{
this.Canvas.fillStyle=item.Vol.BG;
this.Canvas.fillRect(rtDraw.Left, rtDraw.Top, rtDraw.Width, rtDraw.Height);
}
if (item.Vol.BorderColor) //边框
{
this.Canvas.strokeStyle = item.Vol.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtDraw.Left), ToFixedPoint(rtDraw.Top), rtDraw.Width, rtDraw.Height);
}
if (item.Vol.Text && this.IsShowOrderText) //文字
{
this.Canvas.fillStyle=item.Vol.Color;
if (item.Vol.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, barWidth/2, item.Vol.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(item.Vol.Text,rtDraw.Left+2,yPrice);
}
}
preItem={ Price: item.Price, Rect:rtDraw };
}
else
{
continue;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
//订单流样式5
this.DrawOrderFlow_Style5=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
this.AryOrderFlowBorder=[];
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
var upColor=this.OrderFlow_Style2.UpColor;
var downColor=this.OrderFlow_Style2.DownColor;
var unchagneColor=this.OrderFlow_Style2.UnchagneColor;
var barWidth=ToFixedRect(this.OrderFlow_Style2.BarWidth);
var textWidth=dataWidth-barWidth;
if (textWidth/7<barWidth) barWidth=textWidth/7;
if (barWidth<=1) barWidth=2;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
this.DrawOrderFlowHBar(); //横向柱子
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
this.DrawKRange.End=i;
var barTop=Math.min(yOpen,yClose);
var barBottom=Math.max(yOpen,yClose);
var barLeft=ToFixedRect(left);
var barRight=barLeft+barWidth
if (data.Open<data.Close) this.Canvas.fillStyle=upColor;
else if (data.Open>data.Close) this.Canvas.fillStyle=downColor;
else this.Canvas.fillStyle=unchagneColor;
var cellHeight=0;
if (data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(data.OrderFlow.PriceOffset);
this.Canvas.fillRect(barLeft,ToFixedRect(barTop-cellHeight/2),barWidth,ToFixedRect(barBottom-barTop+cellHeight));
var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
var xKLine={ Left:barRight, Center:x, Right:right, DataWidth:(right-barRight) };
xKLine.Center=xKLine.Left+xKLine.DataWidth/2;
this.DrawOrderFlowBar_Style5(data.OrderFlow, data, xKLine, yKline, isHScreen);
}
}
this.DrawOrderFlowBar_Style5=function(orderFlow, kItem, xKLine, yKline, isHScreen)
{
var top=Math.min(yKline.Open, yKline.Close)
var bottom=Math.max(yKline.Open, yKline.Close);
var barHeight=Math.abs(yKline.Open-yKline.Close);
var cellHeight=0;
if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2);
this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);
if (this.OrderFlow.AlwaysShowOrderText) this.IsShowOrderText=true;
this.Canvas.textBaseline='middle';
this.Canvas.font=textFont;
var textWidth=xKLine.DataWidth/2;
if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
{
var maxValue=orderFlow.MaxValue;
for(var i=0;i<orderFlow.Order.length;++i)
{
var item=orderFlow.Order[i];
var yPrice=this.GetYFromData(item.Price, false);
var rect={ Left:xKLine.Left, Right:xKLine.Center, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (IFrameSplitOperator.IsNumber(item.Ask.Value))
{
var color=this.OrderFlow_Style5.AskBarColor;
if (item.Ask.BG) color=item.Ask.BG;
this.Canvas.fillStyle=color;
var barWidth=rect.Width*item.Ask.Value/maxValue;
this.Canvas.fillRect(ToFixedRect(rect.Right),ToFixedRect(rect.Top),ToFixedRect(-barWidth),ToFixedRect(rect.Height));
var text=null;
if (IFrameSplitOperator.IsString(item.Ask.Text)) text=item.Ask.Text;
else text=item.Ask.Value.toString();
if (text && this.IsShowOrderText)
{
var textColor=this.OrderFlow.Text.Color;
if (item.Ask.Color) textColor=item.Ask.Color;
this.Canvas.fillStyle=textColor;
this.Canvas.textAlign='right';
var xText=rect.Right-this.OrderFlow_Style5.LeftMargin;
if (item.Ask.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Ask.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xText,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xText,yPrice);
}
}
}
var rect={ Left:xKLine.Center, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
if (IFrameSplitOperator.IsNumber(item.Bid.Value))
{
var color=this.OrderFlow_Style5.BidBarColor;
if (item.Bid.BG) color=item.Bid.BG;
this.Canvas.fillStyle=color;
var barWidth=rect.Width*item.Bid.Value/maxValue;
this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(barWidth),ToFixedRect(rect.Height));
var text=null;
if (IFrameSplitOperator.IsString(item.Bid.Text)) text=item.Bid.Text;
else text=item.Bid.Value.toString();
if (text && this.IsShowOrderText)
{
var textColor=this.OrderFlow.Text.Color;
if (item.Bid.Color)textColor=item.Bid.Color;
this.Canvas.fillStyle=textColor;
this.Canvas.textAlign='left';
var xText=rect.Left+this.OrderFlow_Style5.RightMargin
if (item.Bid.Font)
{
var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Bid.Font);
this.Canvas.font=itemFont;
this.Canvas.fillText(text,xText,yPrice);
this.Canvas.font=textFont;
}
else
{
this.Canvas.fillText(text,xText,yPrice);
}
}
}
}
}
}
//////////////////////////////////////////////////////////////
// high low bar
//
///////////////////////////////////////////////////////////////
this.DrawHighLow=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.DrawKRange.Start=this.Data.DataOffset;
this.Canvas.fillStyle=this.HighLowBarColor;
this.Canvas.strokeStyle=this.HighLowBarColor;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
var font=this.GetHighLowTextFont(dataWidth,distanceWidth);
var bShowText=false;
if (font)
{
bShowText=true;
this.Canvas.font=font;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
this.ShowRange.End=i;
if (data.Open==null || data.High==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low,false);
var yHigh=this.GetYFromData(data.High,false);
this.DrawKRange.End=i;
var yBarTop=yLow;
var barHeight=yHigh-yLow;
if (Math.abs(barHeight)<1) barHeight=1; //高度小于1,统一使用高度1
if (dataWidth>=4)
{
if (isHScreen)
{
this.Canvas.fillRect(ToFixedRect(yBarTop),ToFixedRect(left),ToFixedRect(barHeight),ToFixedRect(dataWidth));
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(yBarTop),ToFixedRect(dataWidth),ToFixedRect(barHeight));
if (bShowText) this.DrawHighLowText(yHigh, yLow, x, data, defaultfloatPrecision);
//TODO:文字输出
}
}
else //竖线
{
var x=left+(right-left)/2;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yLow),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yHigh),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yLow));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yHigh));
}
this.Canvas.stroke();
}
if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域
{
var yTop=Math.min(yLow,yHigh);
var yBottom=Math.max(yLow,yHigh);
if (Math.abs(yTop-yBottom)<5) //高度太小了, 上下各+5px
{
yTop=Math.min(yHigh,yTop-5);
yBottom=Math.max(yLow,yBottom+5);
}
var rect=new Rect(left,yTop,dataWidth,yBottom-yTop);
//this.Canvas.fillStyle="rgb(0,0,100)";
//this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height);
this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域
}
}
}
this.DrawHighLowText=function(yHigh, yLow, x, kItem, floatPrecision)
{
this.Canvas.textAlign="center";
var text=kItem.High.toFixed(floatPrecision);
this.Canvas.textBaseline="bottom";
this.Canvas.fillText(text,x,yHigh-2);
var text=kItem.Low.toFixed(floatPrecision);
this.Canvas.textBaseline="top";
this.Canvas.fillText(text,x,yLow+3);
}
this.GetHighLowTextFont=function(dataWidth, distanceWidth)
{
var barWidth=dataWidth+distanceWidth;
var text=this.HighLowTextConfig.MaxText;
var min=Math.min(this.HighLowTextConfig.MaxSize,this.HighLowTextConfig.MinSize);
var max=Math.max(this.HighLowTextConfig.MaxSize,this.HighLowTextConfig.MinSize);
for(var i=max; i>=min; --i)
{
var font=`${i*GetDevicePixelRatio()}px ${this.HighLowTextConfig.FontName}`;
this.Canvas.font=font;
var textWidth=this.Canvas.measureText(text).width;
if (textWidth<=barWidth)
return font;
}
return null;
}
//////////////////////////////////////////////////////////////
//标识缺口
//
/////////////////////////////////////////////////////////////
this.DrawPriceGap=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryPriceGapCache)) return;
if (this.PriceGap.Count<=0) return;
var index=this.AryPriceGapCache.length-this.PriceGap.Count;
if (index<0) index=0;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var border=null;
if (isHScreen) border=this.ChartBorder.GetHScreenBorder();
else border=this.ChartBorder.GetBorder();
this.Canvas.font=this.PriceGapStyple.Text.Font;
this.Canvas.textAlign = 'left';
this.Canvas.textBaseline = 'bottom';
var textHeight=this.Canvas.measureText("擎").width;
var decNum=GetfloatPrecision(this.Symbol);
for(var i=index;i<this.AryPriceGapCache.length;++i)
{
var item=this.AryPriceGapCache[i];
var start=item.Data[0];
var end=item.Data[1];
var rect=null, rtText=null, text=null;
if (item.Type==1) //上缺口
{
if (isHScreen)
{
rect={ Left:start.Coordinate.High, Right:end.Coordinate.Low, Top:start.Coordinate.X, Bottom: border.Bottom };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
rtText={ Left:start.Coordinate.High-textHeight-2, Top:start.Coordinate.Right+2, Height:textHeight };
rtText.Bottom=rtText.Top+rtText.Height;
}
else
{
rect={ Left:start.Coordinate.X, Right:border.Right, Top:end.Coordinate.Low, Bottom:start.Coordinate.High };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
rtText={ Left:start.Coordinate.Right+2, Top:rect.Bottom+2, Right:rect.Right, Height:textHeight };
rtText.Bottom=rtText.Top+rtText.Height;
}
text=`${start.Data.High.toFixed(decNum)}-${end.Data.Low.toFixed(decNum)}`;
}
else if (item.Type==2) //下缺口
{
if (isHScreen)
{
rect={ Left:start.Coordinate.Low, Right:end.Coordinate.High, Top:start.Coordinate.X, Bottom: border.Bottom };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
rtText={ Left:start.Coordinate.Low+2, Top:start.Coordinate.Right+2, Height:textHeight };
rtText.Bottom=rtText.Top+rtText.Height;
}
else
{
rect={ Left:start.Coordinate.X, Right:border.Right, Top:start.Coordinate.Low, Bottom:end.Coordinate.High };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
rtText={ Left:start.Coordinate.Right+2, Bottom:rect.Top, Right:rect.Right, Height:textHeight };
rtText.Top=rtText.Bottom-rtText.Height;
}
text=`${start.Data.Low.toFixed(decNum)}-${end.Data.High.toFixed(decNum)}`;
}
else
{
continue;
}
if (!rect) return;
this.Canvas.fillStyle=this.PriceGapStyple.Line.Color;
this.Canvas.fillRect(rect.Left, rect.Top,rect.Width, rect.Height);
if (rtText)
{
var textWidth=this.Canvas.measureText(text).width;
rtText.Width=textWidth;
rtText.Right=rtText.Left+rtText.Width;
this.Canvas.fillStyle=this.PriceGapStyple.Text.Color;
if (isHScreen)
{
this.Canvas.save();
this.Canvas.translate(rtText.Left, rtText.Top);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
if (rtText.Right>rect.Right)
{
rtText.Right=rect.Right;
rtText.Left=rtText.Right-rtText.Width;
}
this.Canvas.fillStyle=this.PriceGapStyple.Text.Color;
this.Canvas.fillText(text,rtText.Left,rtText.Bottom);
}
//this.Canvas.fillStyle="rgb(250,250,250)"
//this.Canvas.fillRect(rtText.Left, rtText.Top, rtText.Width, rtText.Height);
}
}
}
//是否有缺口
this.IsPriceGap=function(item, preItem)
{
if (!preItem || !item) return 0;
if (preItem.Data.Low>item.Data.High) return 2; //下缺口
if (preItem.Data.High<item.Data.Low) return 1; //上缺口
return -1;
}
//检测缺口是不回补了
this.CheckPriceGap=function(kItemInfo)
{
var kItem=kItemInfo.Data;
for(var i=0;i<this.AryPriceGapCache.length;++i)
{
var item=this.AryPriceGapCache[i];
var start=item.Data[0];
var end=item.Data[1];
if (item.Type==1) //上缺口
{
if (kItem.Low<=start.Data.High)
{
this.AryPriceGapCache.splice(i,1);
--i;
continue;
}
if (kItem.Low<end.Data.Low) item.Data[1]=kItemInfo;
}
else if (item.Type==2) //下缺口
{
if (kItem.High>=start.Data.Low)
{
this.AryPriceGapCache.splice(i,1);
--i;
continue;
}
if (kItem.High>end.Data.High) item.Data[1]=kItemInfo;
}
}
}
}
function ChartColorKline()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartColorKline'; //类名
this.Symbol; //股票代码
this.Color='rgb(0,255,44)';
this.IsEmptyBar=false;
this.DrawType=0; //0=实心K线柱子 3=空心K线柱子
this.KLineColor; //Map key=K线索引 value=设置
this.DrawName;
this.Draw=function()
{
if (!this.IsShow) return;
if (this.DrawName=="DRAWCOLORKLINE")
{
this.DrawColorBar();
}
else
{
if (!this.KLineColor) return;
this.DrawBar();
}
}
this.DrawUpBarItem=function(data, xOffset, dataWidth, option)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var yLow=this.ChartFrame.GetYFromData(data.Low);
var yHigh=this.ChartFrame.GetYFromData(data.High);
var yOpen=this.ChartFrame.GetYFromData(data.Open);
var yClose=this.ChartFrame.GetYFromData(data.Close);
var y=yHigh;
if (dataWidth>=4)
{
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose));
}
this.Canvas.stroke();
y=yClose;
}
else
{
y=yClose;
}
if (isHScreen)
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
}
else
{
if (this.DrawType==3) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
}
}
}
else
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (this.DrawType==3) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y)));
}
}
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
}
}
this.DrawDownBarItem=function(data, xOffset, dataWidth, option)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var yLow=this.ChartFrame.GetYFromData(data.Low);
var yHigh=this.ChartFrame.GetYFromData(data.High);
var yOpen=this.ChartFrame.GetYFromData(data.Open);
var yClose=this.ChartFrame.GetYFromData(data.Close);
var y=yHigh;
if (dataWidth>=4)
{
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen));
}
this.Canvas.stroke();
y=yOpen;
}
else
{
y=yOpen
}
if (isHScreen)
{
if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth));
}
else
{
if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yClose)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yClose-y)));
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
}
}
this.DrawUnChangeBarItem=function(data, xOffset, dataWidth, option)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var yLow=this.ChartFrame.GetYFromData(data.Low);
var yHigh=this.ChartFrame.GetYFromData(data.High);
var yOpen=this.ChartFrame.GetYFromData(data.Open);
var yClose=this.ChartFrame.GetYFromData(data.Close);
var y=yHigh;
if (dataWidth>=4)
{
this.Canvas.beginPath();
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yOpen,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yOpen);
}
y=yOpen;
}
else
{
y=yOpen;
}
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left));
this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right));
}
else
{
this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y));
}
if (data.Open>data.Low) //下影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
}
}
this.DrawBar=function()
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
if (this.IsHScreen)
{
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
chartright=this.ChartBorder.GetBottom();
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (!this.KLineColor.has(i)) continue;
var itemOption=this.KLineColor.get(i);
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
if (itemOption.Color)
{
this.Canvas.strokeStyle=itemOption.Color;
this.Canvas.fillStyle=itemOption.Color;
}
else
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.fillStyle=this.Color;
}
if (data.Open<data.Close) //阳线
{
this.DrawUpBarItem(data,xOffset,dataWidth,itemOption);
}
else if (data.Open>data.Close) //阴线
{
this.DrawDownBarItem(data,xOffset,dataWidth,itemOption);
}
else //平线
{
this.DrawUnChangeBarItem(data,xOffset,dataWidth,itemOption);
}
}
}
this.DrawColorBar=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (!data) continue;
if (!IFrameSplitOperator.IsNumber(data.Open) || !IFrameSplitOperator.IsNumber(data.High) ||
!IFrameSplitOperator.IsNumber(data.Low) || !IFrameSplitOperator.IsNumber(data.Close)) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low, false);
var yHigh=this.GetYFromData(data.High, false);
var yOpen=this.GetYFromData(data.Open, false);
var yClose=this.GetYFromData(data.Close, false);
var y=yHigh;
if (data.Open==data.Close)
this.DrawKBar_Unchagne(data, dataWidth, this.Color, this.IsEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
else
this.DrawKBar_Custom(data, dataWidth, this.Color, this.IsEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
}
}
this.DrawKBar_Unchagne=function(data, dataWidth, unchagneColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (dataWidth>=4)
{
if ((dataWidth%2)!=0) dataWidth-=1;
this.Canvas.strokeStyle=unchagneColor;
this.Canvas.beginPath();
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yOpen,ToFixedPoint(x));
}
else
{
var xFixed=ToFixedPoint(left+dataWidth/2);
this.Canvas.moveTo(xFixed,y);
this.Canvas.lineTo(xFixed,yOpen);
}
y=yOpen;
}
else
{
y=yOpen;
}
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left));
this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right));
}
else
{
this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(left+dataWidth),ToFixedPoint(y));
}
if (data.Open>data.Low) //下影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
var xFixed=ToFixedPoint(left+dataWidth/2);
this.Canvas.moveTo(xFixed,ToFixedPoint(y));
this.Canvas.lineTo(xFixed,ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.strokeStyle=unchagneColor;
this.Canvas.stroke();
}
}
this.DrawKBar_Custom=function(data, dataWidth, barColor, isEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
{
if (isEmptyBar)
{
if ((dataWidth%2)!=0) dataWidth-=1;
}
if (dataWidth>=4)
{
this.Canvas.strokeStyle=barColor;
if (data.High>data.Close) //上影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(isEmptyBar?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(Math.min(yClose,yOpen)));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yClose));
}
}
this.Canvas.stroke();
y=yClose;
}
else
{
y=yClose;
}
this.Canvas.fillStyle=barColor;
if (isHScreen)
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
}
}
}
else
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar) //空心柱
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y)));
}
}
}
if (data.Open>data.Low) //下影线
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(isEmptyBar?Math.min(yClose,yOpen):y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
if (isEmptyBar)
{
var xFixed=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(Math.max(yClose,yOpen)));
this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
this.Canvas.stroke();
}
}
else
{
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.strokeStyle=barColor;
this.Canvas.stroke();
}
}
this.GetMaxMin=function()
{
var range={Max:null,Min:null };
if (this.DrawName=="DRAWCOLORKLINE")
{
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (!data) continue;
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (range.Max==null) range.Max=data.High;
if (range.Min==null) range.Min=data.Low;
if (range.Max<data.High) range.Max=data.High;
if (range.Min>data.Low) range.Min=data.Low;
}
}
return range;
}
}
function ChartHeatMap()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartHeatMap'; //类名
this.Draw=function()
{
if (!this.IsShow) return;
if (this.ChartFrame.IsMinSize) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (!data.HeatMap) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var xCenter=left+(right-left)/2;
this.DrawHeatMap(left, right+distanceWidth, data.HeatMap);
}
}
this.DrawHeatMap=function(left, right, heatMap)
{
if (!IFrameSplitOperator.IsNonEmptyArray(heatMap.Order)) return;
var max=this.ChartFrame.HorizontalMax;
var min=this.ChartFrame.HorizontalMin;
var cellHeight=0;
if (IFrameSplitOperator.IsNumber(heatMap.PriceOffset)) cellHeight=this.GetPriceYOffset(heatMap.PriceOffset);
for(var i=0;i<heatMap.Order.length;++i)
{
var item=heatMap.Order[i];
if (!IFrameSplitOperator.IsNumber(item.Price)) continue;
if (!item.Color) continue;
if (item.Price>max || item.Price<min) continue;
var yPrice=this.GetYFromData(item.Price, false);
var rect={ Left:left, Right:right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
rect.Width=rect.Right-rect.Left;
rect.Height=rect.Bottom-rect.Top;
this.Canvas.fillStyle=item.Color;
this.Canvas.fillRect(rect.Left,rect.Top,rect.Width,rect.Height);
}
}
this.GetPriceYOffset=function(value)
{
var frame=this.ChartFrame;
var y=frame.ChartBorder.GetHeightEx()*(value)/(frame.HorizontalMax-frame.HorizontalMin);
return y;
}
}
//K线叠加 支持横屏
var OVERLAY_STATUS_ID=
{
STATUS_NONE_ID:0, //空闲状态
STATUS_REQUESTDATA_ID:1, //请求数据
STATUS_RECVDATA_ID:2, //接收到数据
STATUS_FINISHED_ID:3, //数据下载完成
};
function ChartOverlayKLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartOverlayKLine'; //类名
this.Color="rgb(65,105,225)";
this.MainData; //主图K线数据
this.SourceData; //叠加的原始数据
this.Title;
this.DrawType=0;
this.CustomDrawType=null; //图形类型
this.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
this.IsDelete=false; //是否已经删除
this.CloseLineWidth=g_JSChartResource.CloseLineWidth;
this.ShowRange={ }; //K线显示范围 { Start:, End:, DataCount:, ShowCount: }
this.DrawKRange={ Start:null, End:null }; //当前屏K线的索引{ Start: , End:}
this.YInfoType=4;
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsNumber(option.DrawType)) this.CustomDrawType=option.DrawType;
if (IFrameSplitOperator.IsNumber(option.YInfoType)) this.YInfoType=option.YInfoType;
}
this.DrawKBar=function(firstOpen) //firstOpen 当前屏第1个显示数据
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var drawType=this.DrawType;
if (this.CustomDrawType!=null) drawType=this.CustomDrawType;
var isFristDraw=true;
var firstOverlayOpen=null;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.ShowRange.FirstOpen=firstOpen;
this.DrawKRange.Start=this.Data.DataOffset;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
if (!data || data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null)
{
firstOverlayOpen=data.Open;
this.ShowRange.FirstOverlayOpen=data.Open;
}
if (isFristDraw)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.fillStyle=this.Color;
this.Canvas.beginPath();
isFristDraw=false;
}
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low/firstOverlayOpen*firstOpen,false);
var yHigh=this.GetYFromData(data.High/firstOverlayOpen*firstOpen,false);
var yOpen=this.GetYFromData(data.Open/firstOverlayOpen*firstOpen,false);
var yClose=this.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);
var y=yHigh;
this.DrawKRange.End=i;
if (data.Open<data.Close) //阳线
{
if (dataWidth>=4)
{
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose));
}
y=yClose;
}
else
{
y=yClose;
}
if (isHScreen)
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
}
else
{
if (drawType==3) this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); //空心柱
else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth));
}
}
else
{
if (Math.abs(yOpen-y)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (drawType==3) this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); //空心柱
else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y));
}
}
if (data.Open>data.Low)
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
}
else
{
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
}
}
else if (data.Open>data.Close) //阴线
{
if (dataWidth>=4)
{
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen));
}
y=yOpen;
}
else
{
y=yOpen
}
if (isHScreen)
{
if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1
else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth));
}
else
{
if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yClose-y));
}
if (data.Open>data.Low) //下影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
}
else
{
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
}
}
else // 平线
{
if (dataWidth>=4)
{
if (data.High>data.Close) //上影线
{
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yOpen,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yOpen);
}
y=yOpen;
}
else
{
y=yOpen;
}
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left));
this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right));
}
else
{
this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y));
}
if (data.Open>data.Low) //下影线
{
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow));
}
}
}
else
{
if (isHScreen)
{
if (data.High==data.Low)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow-1,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
}
else
{
if (data.High==data.Low)
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow+1);
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
}
}
}
//添加tooltip区域
{
var yTop=Math.min(yLow,yHigh,yOpen,yClose);
var yBottom=Math.max(yLow,yHigh,yOpen,yClose);
var rect=new Rect(left,yTop,dataWidth,yBottom-yTop);
//this.Canvas.fillStyle="rgb(0,0,100)";
//this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height);
this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域
}
}
if (isFristDraw==false) this.Canvas.stroke();
}
this.DrawAKLine=function(firstOpen) //美国线
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var firstOverlayOpen=null;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.ShowRange.FirstOpen=firstOpen;
this.DrawKRange.Start=this.Data.DataOffset;
this.Canvas.strokeStyle=this.Color;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null)
{
firstOverlayOpen=data.Open;
this.ShowRange.FirstOverlayOpen=data.Open;
}
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yLow=this.GetYFromData(data.Low/firstOverlayOpen*firstOpen,false);
var yHigh=this.GetYFromData(data.High/firstOverlayOpen*firstOpen,false);
var yOpen=this.GetYFromData(data.Open/firstOverlayOpen*firstOpen,false);
var yClose=this.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);
this.DrawKRange.End=i;
this.Canvas.beginPath(); //最高-最低
if (isHScreen)
{
this.Canvas.moveTo(yHigh,ToFixedPoint(x));
this.Canvas.lineTo(yLow,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yHigh);
this.Canvas.lineTo(ToFixedPoint(x),yLow);
}
this.Canvas.stroke();
if (dataWidth>=4)
{
this.Canvas.beginPath(); //开盘
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yOpen),left);
this.Canvas.lineTo(ToFixedPoint(yOpen),x);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(yOpen));
this.Canvas.lineTo(x,ToFixedPoint(yOpen));
}
this.Canvas.stroke();
this.Canvas.beginPath(); //收盘
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yClose),right);
this.Canvas.lineTo(ToFixedPoint(yClose),x);
}
else
{
this.Canvas.moveTo(right,ToFixedPoint(yClose));
this.Canvas.lineTo(x,ToFixedPoint(yClose));
}
this.Canvas.stroke();
}
}
}
this.DrawCloseLine=function(firstOpen) //收盘价线
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var firstOverlayOpen=null;
var bFirstPoint=true;
this.Canvas.strokeStyle=this.Color;
if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
this.ShowRange.Start=this.Data.DataOffset;
this.ShowRange.End=this.ShowRange.Start;
this.ShowRange.DataCount=0;
this.ShowRange.ShowCount=xPointCount;
this.ShowRange.FirstOpen=firstOpen;
this.DrawKRange.Start=this.Data.DataOffset;
this.Canvas.beginPath();
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null)
{
firstOverlayOpen=data.Open;
this.ShowRange.FirstOverlayOpen=data.Open;
}
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var yClose=this.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);
this.DrawKRange.End=i;
if (bFirstPoint)
{
if (isHScreen) this.Canvas.moveTo(yClose,x);
else this.Canvas.moveTo(x,yClose);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(yClose,x);
else this.Canvas.lineTo(x,yClose);
}
}
if (bFirstPoint==false) this.Canvas.stroke();
}
this.GetFirstOpen=function()
{
if (!this.MainData || !this.Data) return null;
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.MainData.Data.length && j<xPointCount;++i,++j)
{
var data=this.MainData.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
return data.Open;
}
return null;
}
this.Draw=function()
{
this.TooltipRect=[];
this.InfoTooltipRect=[];
this.DrawKRange={ Start:null, End:null };
if (!this.MainData || !this.Data) return;
var xPointCount=this.ChartFrame.XPointCount;
var firstOpen=this.GetFirstOpen(); //主线数据第1个开盘价
if (firstOpen==null) return;
var drawType=this.DrawType;
if (this.CustomDrawType!=null) drawType=this.CustomDrawType;
this.Canvas.save();
this.ClipClient(this.ChartFrame.IsHScreen);
if (drawType==1) this.DrawCloseLine(firstOpen);
else if (drawType==2) this.DrawAKLine(firstOpen);
else this.DrawKBar(firstOpen);
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Max=null;
range.Min=null;
if (!this.MainData || !this.Data) return range;
var firstOpen=null; //主线数据第1个收盘价
for(var i=this.Data.DataOffset,j=0;i<this.MainData.Data.length && j<xPointCount;++i,++j)
{
var data=this.MainData.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
firstOpen=data.Close;
break;
}
if (firstOpen==null) return range;
var firstOverlayOpen=null;
var high,low;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (!data || data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
high=data.High/firstOverlayOpen*firstOpen;
low=data.Low/firstOverlayOpen*firstOpen;
if (range.Max==null) range.Max=high;
if (range.Min==null) range.Min=low;
if (range.Max<high) range.Max=high;
if (range.Min>low) range.Min=low;
}
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
for(var i in this.TooltipRect)
{
var rect=this.TooltipRect[i][1];
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
var index=this.TooltipRect[i][0];
tooltip.Data=this.Data.Data[index];
tooltip.ChartPaint=this;
return true;
}
}
return false;
}
this.PtInChart=function(x,y)
{
var drawType=this.DrawType;
if (IFrameSplitOperator.IsNumber(this.CustomDrawType)) drawType=this.CustomDrawType;
if (drawType==1 || drawType==4) //线段,面积不支持选中
{
return null;
//return this.PtInLine(x,y, {KLineClose:true});
}
return this.PtInKBar(x,y, {OverlayKLine:true});
}
this.DrawSelectedStatus=function()
{
this.DrawLinePoint({OverlayKLine:true});
}
}
//K线表格
function ChartKLineTable()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartKlineTable'; //类名
this.Data;
this.RowName;
this.IsShowRowName=false;
this.BGColor; //背景色
this.RowCount=5; //行数
this.RowHeight=10; //行高
this.TextFontConfig=CloneData(g_JSChartResource.ChartKLineTable.TextFont);
this.ItemMergin=CloneData(g_JSChartResource.ChartKLineTable.ItemMergin);
this.TextFont;
this.TextColor='rgb(0,0,0)';
this.NameColor="rgb(0,0,0)";
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
if (isHScreen) return;
if (this.RowCount<=0) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var border=this.ChartFrame.GetBorder();
var height=border.Bottom-border.TopTitle;
this.RowHeight=height/this.RowCount;
var xOffset=border.LeftEx+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var top=border.TopTitle;
var bottom=border.Bottom;
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
var left=border.LeftEx;
var width=border.RightEx-border.LeftEx;
var height=bottom-top;
this.Canvas.fillRect(left, top, width, height);
}
var itemHeight=this.RowHeight;
var itemWidth=dataWidth+distanceWidth;
if (itemHeight-this.ItemMergin.Top-this.ItemMergin.Bottom>0) itemHeight=itemHeight-this.ItemMergin.Left-this.ItemMergin.Right;
if (itemWidth-this.ItemMergin.Left-this.ItemMergin.Right>0) itemWidth=itemWidth-this.ItemMergin.Left-this.ItemMergin.Right;
var font=this.GetDynamicTextFont(itemHeight, itemWidth);
this.TextFont=font;
this.Canvas.font=this.TextFont;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
var left=xOffset;
var right=xOffset+dataWidth+distanceWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
if (x>chartright) break;
if (j==0 && this.IsShowRowName)
{
this.DrawRowName(top, bottom, left, right);
}
else
{
this.DrawRow(item, top, bottom, left, right); //绘制一列
}
}
}
this.DrawRowName=function(top, bottom, left, right)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.RowName)) return;
var x=left,y=top, width=right-left;
for(var i=0;i<this.RowName.length;++i)
{
var item=this.RowName[i];
var rtBG={Left:x, Top:y, Right:right, Height:this.RowHeight, Width:width };
rtBG.Bottom=rtBG.Top+this.RowHeight;
if (item.Name && rtBG.Width>10)
{
this.Canvas.fillStyle=item.Color?item.Color:this.TextColor;
this.Canvas.textBaseline='middle';
if (item.TextAlign=='right')
{
this.Canvas.textAlign='right';
this.Canvas.fillText(item.Name,rtBG.Right-2,rtBG.Top+this.RowHeight/2, width-4);
}
else if (item.TextAlign=='center')
{
this.Canvas.textAlign='center';
this.Canvas.fillText(item.Name,rtBG.Left+rtBG.Width/2,rtBG.Top+this.RowHeight/2, width-4);
}
else
{
this.Canvas.textAlign='left';
this.Canvas.fillText(item.Name,rtBG.Left+2,rtBG.Top+this.RowHeight/2, width-4);
}
}
y+=this.RowHeight;
}
}
this.DrawRow=function(data, top, bottom, left, right)
{
var x=left,y=top, width=right-left;
for(var i=0;i<data.length;++i)
{
var item=data[i];
var rtBG={Left:x, Top:y, Right:right, Height:this.RowHeight, Width:width };
rtBG.Bottom=rtBG.Top+this.RowHeight;
if (item.BGColor)
{
this.Canvas.fillStyle=item.BGColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
if (item.Color && rtBG.Width>10)
{
this.Canvas.fillStyle=item.Color;
this.Canvas.textBaseline='middle';
if (item.TextAlign=='right')
{
this.Canvas.textAlign='right';
this.Canvas.fillText(item.Text,rtBG.Right-2,rtBG.Top+this.RowHeight/2, width-4);
}
else if (item.TextAlign=='center')
{
this.Canvas.textAlign='center';
this.Canvas.fillText(item.Text,rtBG.Left+rtBG.Width/2,rtBG.Top+this.RowHeight/2, width-4);
}
else
{
this.Canvas.textAlign='left';
this.Canvas.fillText(item.Text,rtBG.Left+2,rtBG.Top+this.RowHeight/2, width-4);
}
}
y+=this.RowHeight;
}
}
this.GetDynamicTextFont=function(cellHeight, width, fontOption)
{
var fontSize=parseInt(cellHeight)-2;
if (cellHeight<5) fontSize=parseInt(cellHeight); //高度太小了就不要上下间距了
if (fontSize>this.TextFontConfig.FontMaxSize) fontSize=this.TextFontConfig.FontMaxSize;
else if (fontSize<=0) fontSize=1;
var font=this.FormatFontString(fontSize, this.TextFontConfig.Family, fontOption);
return font;
}
this.FormatFontString=function(fontSize, family, option)
{
var font;
if (!option)
{
font=`${fontSize}px ${family}`;
}
else
{
if (option.Weight) font=`${option.Weight} ${fontSize}px ${family}`;
}
return font;
}
this.GetMaxMin=function()
{
return {Min:0, Max:this.RowCount};
}
}
//分钟成交量 支持横屏
function ChartMinuteVolumBar()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartMinuteVolumBar'; //类名
this.UpColor = g_JSChartResource.UpBarColor; //上涨
this.DownColor = g_JSChartResource.DownBarColor; //下跌
this.UnchangeColor=g_JSChartResource.UnchagneBarColor; //平盘
this.BarColorType=1; //柱子颜色显示类型 0=红绿 1=红绿白
this.CustomColor=g_JSChartResource.Minute.VolBarColor; //自定义颜色
this.YClose; //前收盘
this.Symbol;
this.BeforeOpenData; //盘前数据
this.AfterCloseData; //盘后数据
this.BeforeVolColor=g_JSChartResource.Minute.Before.VolColor;
this.ShareAfterVol=0;
this.MultiDayBeforeOpenData; //多日分时图 盘前数据 数组 1天一个
this.MultiDayAfterCloseData; //多日分时图 盘后数据 数组 1天一个
this.PtInChart=function(x,y)
{
var option={ MinuteVolBar:true };
return this.PtInBar(x,y,option);
}
this.DrawSelectedStatus=function()
{
return this.DrawLinePoint({ MinuteVolBar:true });
}
this.Draw=function()
{
var isHScreen = (this.ChartFrame.IsHScreen === true);
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright = border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var chartright=border.RightEx;
}
this.DrawBeforeOpen();
this.DrawMultiDayBeforeOpen();
var xPointCount=this.ChartFrame.XPointCount;
var yBottom=this.ChartFrame.GetYFromData(0);
var yPrice=this.YClose; //上一分钟的价格
var data=this.Data;
var bShowColorBar=MARKET_SUFFIX_NAME.IsShowMinuteColorVolBar(this.Symbol);
if (bShowColorBar) this.Canvas.strokeStyle=this.CustomColor;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var item = data.Data[i];
var vol=null;
if (!item) continue;
var price=null;
vol=item.Vol;
price=item.Close;
if (!vol) continue;
var y=this.ChartFrame.GetYFromData(vol);
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) break;
//价格>=上一分钟价格 红色 否则绿色
if (!bShowColorBar) this.Canvas.strokeStyle = this.GetMinuteBarColor(price, yPrice);
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yBottom,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
}
this.Canvas.stroke();
if (price) yPrice=price;
}
this.DrawAfterClose();
this.DrawMultiDayAfterClose();
}
//连续交易成交量柱子颜色
this.GetMinuteBarColor=function(price, yPrice)
{
if (this.BarColorType==1) //通达信模式
{
if (price>yPrice) return this.UpColor;
else if (price<yPrice) return this.DownColor;
else return this.UnchangeColor;
}
else //东方财富模式
{
return price >= yPrice ? this.UpColor:this.DownColor;
}
}
this.DrawBeforeOpen=function()
{
if (this.ChartBorder.LeftExtendWidth<10) return;
if (!this.BeforeOpenData) return;
this.DrawCallAuction(-1,this.BeforeOpenData,true);
}
this.DrawAfterClose=function()
{
if (this.ChartBorder.RightExtendWidth<10) return;
if (!this.AfterCloseData) return;
this.DrawCallAuction(-1,this.AfterCloseData,false);
}
this.DrawMultiDayBeforeOpen=function()
{
if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Left<=0) return;
if (!this.MultiDayBeforeOpenData) return;
var offset=0,showDayCount=this.MultiDayBeforeOpenData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
for(var i=offset,j=0; i<this.MultiDayBeforeOpenData.length && j<showDayCount; ++i,++j)
{
var dayItem=this.MultiDayBeforeOpenData[i];
this.DrawCallAuction(j, dayItem, true);
}
}
this.DrawMultiDayAfterClose=function()
{
if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Right<=0) return;
if (!this.MultiDayAfterCloseData) return;
var offset=0,showDayCount=this.MultiDayAfterCloseData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
for(var i=offset,j=0;i<this.MultiDayAfterCloseData.length && j<showDayCount; ++i,++j)
{
var dayItem=this.MultiDayAfterCloseData[i];
this.DrawCallAuction(j, dayItem, false);
}
}
this.DrawCallAuction=function(indexDay, callAutionData, isBeforeOpen)
{
if (!callAutionData) return;
callAutionData.Index=indexDay;
var border=this.GetBorder();
var isHScreen=(this.ChartFrame.IsHScreen===true);
var yPrice=this.YClose; //上一分钟的价格
var yBottom=this.ChartFrame.GetYFromData(0);
if (callAutionData.Ver==1.0)
{
for(var i in callAutionData.Data)
{
var item=callAutionData.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Vol[0])) continue;
if (isBeforeOpen)
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[0]);
}
else
{
var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[0]);
}
this.Canvas.strokeStyle = item.Price >= yPrice ? this.UpColor:this.DownColor;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yBottom,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
}
this.Canvas.stroke();
if (item.Price) yPrice=item.Price;
}
}
else if (callAutionData.Ver==2.0 || callAutionData.Ver==3.0)
{
var range={ Max: callAutionData.VolMax, Min:callAutionData.VolMin }
for(var i in callAutionData.Data)
{
var item=callAutionData.Data[i];
if (!item) continue;
if (IFrameSplitOperator.IsPlusNumber(item.Vol[0]))
{
if (isBeforeOpen)
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[0],false, { Range:range });
}
else
{
var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
if (this.ShareAfterVol==1) var y=this.ChartFrame.GetYFromData(item.Vol[0]);
else var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[0],false, { Range:range });
}
this.Canvas.strokeStyle = this.GetBarColor(item.ColorID);
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yBottom,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
}
this.Canvas.stroke();
}
if (IFrameSplitOperator.IsPlusNumber(item.Vol[1]))
{
if (isBeforeOpen)
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[1],false, { Range:range });
}
else
{
var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
if (this.ShareAfterVol==1) var y=this.ChartFrame.GetYFromData(item.Vol[1]);
else var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[1],false, { Range:range });
}
this.Canvas.strokeStyle = this.GetBarColor(item.ColorID);
this.Canvas.beginPath();
if (isHScreen)
{
y-=yBottom;
y=border.RightEx-y;
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(border.RightEx,ToFixedPoint(x));
}
else
{
y-=yBottom;
y=border.TopEx-y;
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),border.TopEx);
}
this.Canvas.stroke();
}
}
}
}
this.GetBarColor=function(id)
{
switch(id)
{
case 0:
return this.UnchangeColor;
case 1:
return this.UpColor;
case 2:
return this.DownColor;
}
if (this.BeforeVolColor && Array.isArray(this.BeforeVolColor))
{
var index=id-3;
if (index>=0 && index<this.BeforeVolColor.length)
return this.BeforeVolColor[index];
}
return this.UnchangeColor;
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange===true)
{
xPointCount=this.Data.Data.length;
start=0;
}
var range={};
range.Min=0;
range.Max=null;
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item = this.Data.Data[i];
if (!item || !item.Vol) continue;
if (range.Max == null) range.Max = item.Vol;
if (range.Max < item.Vol) range.Max = item.Vol;
}
if (this.ShareAfterVol==1)
{
this.GetAfterCloseMaxMin(range);
this.GetMultiDayAfterCloseMaxMin(range);
}
return range;
}
this.GetAfterCloseMaxMin=function(range)
{
if (this.ChartBorder.RightExtendWidth<10) return;
if (!this.AfterCloseData) return;
var callAutionData=this.AfterCloseData;
if (range.Max == null || range.Max < callAutionData.VolMax) range.Max=callAutionData.VolMax;
}
this.GetMultiDayAfterCloseMaxMin=function(range)
{
if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Right<=0) return;
if (!this.MultiDayAfterCloseData) return;
for(var i=0;i<this.MultiDayAfterCloseData.length; ++i)
{
var callAutionData=this.MultiDayAfterCloseData[i];
if (callAutionData.Ver==2.0 || callAutionData.Ver==3.0)
{
if (range.Max == null || range.Max < callAutionData.VolMax) range.Max=callAutionData.VolMax;
}
}
}
}
function ChartErrorMessage()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartErrorMessage'; //类名
this.Draw=function()
{
if (!this.IsShow) return;
if (this.NotSupportMessage) this.DrawNotSupportmessage();
}
}
//线段 支持横屏
function ChartLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.LineWidth; //线段宽度
this.DrawType=0; //画图方式 0=无效数平滑 1=无效数不画断开
this.IsDotLine=false; //虚线
this.LineDash=g_JSChartResource.DOTLINE.LineDash;
this.BreakPoint; //断开的点索引 Set();
this.DrawSelectedStatus=this.DrawLinePoint;
this.PtInChart=this.PtInLine;
this.ExportData=this.ExportArrayData;
this.GetItemData=this.GetArrayItemData;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
switch(this.DrawType)
{
case 0:
return this.DrawLine();
case 1:
return this.DrawStraightLine();
case 2:
return this.DrawSectionLine(); //分段线
}
}
this.DrawLine=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (bHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
this.Canvas.save();
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
if (this.IsDotLine) this.Canvas.setLineDash(this.LineDash); //画虚线
var bFirstPoint=true;
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.GetYFromData(value);
if (x>chartright) break;
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
//无效数不画
this.DrawStraightLine=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
this.Canvas.save();
this.ClipClient(bHScreen);
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
if (this.IsDotLine) this.Canvas.setLineDash(this.LineDash); //画虚线
var bFirstPoint=true;
var ptFirst=null;; //第1个点
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
//for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null)
{
if (drawCount>0) this.Canvas.stroke();
bFirstPoint=true;
drawCount=0;
ptFirst=null;
continue;
}
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y=this.GetYFromData(value,false);
if (x>chartright) break;
if (bFirstPoint)
{
this.Canvas.beginPath();
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={ X:x, Y:y };
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0)
{
if (drawCount==1 && ptFirst) //如果只有1个点, 画一个像素的横线
{
if (bHScreen) this.Canvas.lineTo(ptFirst.Y,ptFirst.X+1*GetDevicePixelRatio());
else this.Canvas.lineTo(ptFirst.X+1*GetDevicePixelRatio(),ptFirst.Y);
}
this.Canvas.stroke();
}
this.Canvas.restore();
}
//分段线
this.DrawSectionLine=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
this.Canvas.save();
this.ClipClient(bHScreen);
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
if (this.IsDotLine) this.Canvas.setLineDash(this.LineDash); //画虚线
var bFirstPoint=true;
var ptFirst=null;; //第1个点
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
//for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null)
{
if (drawCount>0) this.Canvas.stroke();
bFirstPoint=true;
drawCount=0;
ptFirst=null;
continue;
}
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y=this.GetYFromData(value,false);
if (x>chartright) break;
//断开
if (this.BreakPoint && this.BreakPoint.has(i))
{
if (drawCount>0) this.Canvas.stroke();
bFirstPoint=true;
drawCount=0;
ptFirst=null;
}
if (bFirstPoint)
{
this.Canvas.beginPath();
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={ X:x, Y:y };
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0)
{
if (drawCount==1 && ptFirst) //如果只有1个点, 画一个像素的横线
{
if (bHScreen) this.Canvas.lineTo(ptFirst.Y,ptFirst.X+1*GetDevicePixelRatio());
else this.Canvas.lineTo(ptFirst.X+1*GetDevicePixelRatio(),ptFirst.Y);
}
this.Canvas.stroke();
}
this.Canvas.restore();
}
}
//面积图 支持横屏
function ChartArea()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartArea'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.AreaColor; //面积颜色
this.LineWidth; //线段宽度
this.LineDash; //虚线
this.AreaDirection=0 //0=向下 1=向上
this.DrawSelectedStatus=this.DrawLinePoint;
this.PtInChart=this.PtInLine;
this.ExportData=this.ExportArrayData;
this.GetItemData=this.GetArrayItemData;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.DrawArea();
}
//无效数不画
this.DrawArea=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
this.Canvas.save();
this.ClipClient(bHScreen);
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
if (this.AreaColor) this.Canvas.fillStyle=this.AreaColor;
else this.Canvas.fillStyle=IChartDrawPicture.ColorToRGBA(this.Color,0.6);
if (IFrameSplitOperator.IsNonEmptyArray(this.LineDash)) this.Canvas.setLineDash(this.LineDas); //画虚线
var bFirstPoint=true;
var ptFirst=null, ptEnd=null //起始结束点
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value))
{
if (drawCount>0) this.Canvas.stroke();
if (ptFirst && ptEnd)
{
if (bHScreen)
{
if (this.AreaDirection==1)
{
this.Canvas.lineTo(border.RightEx,ptEnd.X);
this.Canvas.lineTo(border.RightEx,ptFirst.X);
}
else
{
this.Canvas.lineTo(border.LeftEx,ptEnd.X);
this.Canvas.lineTo(border.LeftEx,ptFirst.X);
}
this.Canvas.closePath();
this.Canvas.fill();
}
else
{
if (this.AreaDirection==1)
{
this.Canvas.lineTo(ptEnd.X, border.TopEx);
this.Canvas.lineTo(ptFirst.X, border.TopEx);
}
else
{
this.Canvas.lineTo(ptEnd.X, border.BottomEx);
this.Canvas.lineTo(ptFirst.X, border.BottomEx);
}
this.Canvas.closePath();
this.Canvas.fill();
}
}
bFirstPoint=true;
drawCount=0;
ptFirst=null;
ptEnd=null;
continue;
}
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y=this.GetYFromData(value,false);
if (x>chartright) break;
if (bFirstPoint)
{
this.Canvas.beginPath();
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={ X:x, Y:y };
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
ptEnd={ X:x, Y:y };
}
++drawCount;
}
if (drawCount>0)
{
if (drawCount==1 && ptFirst) //如果只有1个点, 画一个像素的横线
{
if (bHScreen) this.Canvas.lineTo(ptFirst.Y,ptFirst.X+1*GetDevicePixelRatio());
else this.Canvas.lineTo(ptFirst.X+1*GetDevicePixelRatio(),ptFirst.Y);
}
this.Canvas.stroke();
if (ptFirst && ptEnd)
{
if (bHScreen)
{
if (this.AreaDirection==1)
{
this.Canvas.lineTo(border.RightEx,ptEnd.X);
this.Canvas.lineTo(border.RightEx,ptFirst.X);
}
else
{
this.Canvas.lineTo(border.LeftEx,ptEnd.X);
this.Canvas.lineTo(border.LeftEx,ptFirst.X);
}
this.Canvas.closePath();
this.Canvas.fill();
}
else
{
if (this.AreaDirection==1)
{
this.Canvas.lineTo(ptEnd.X, border.TopEx);
this.Canvas.lineTo(ptFirst.X, border.TopEx);
}
else
{
this.Canvas.lineTo(ptEnd.X, border.BottomEx);
this.Canvas.lineTo(ptFirst.X, border.BottomEx);
}
this.Canvas.closePath();
this.Canvas.fill();
}
}
}
this.Canvas.restore();
}
}
//散点图
function ChartScatterPlot()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartScatterPlot'; //类名
//默认点配置
this.Color="rgb(255,193,37)"; //点颜色
this.Radius=3; //半径
//this.Data.Data [ {Value:, Radius:半径(可选), Color:颜色(可选), ColorBorder:边框颜色(可选)}, .....]
this.TooltipData=[];
this.Draw=function()
{
this.TooltipData=[];
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.DrawScatterPlot();
}
this.DrawScatterPlot=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
this.Canvas.save();
this.ClipClient(bHScreen);
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (x>chartright) break;
if (Array.isArray(item))
{
for(var j=0;j<item.length;++j)
{
this.DrawItem(item[j], x);
}
}
else
{
this.DrawItem(item, x);
}
}
this.Canvas.restore();
}
this.DrawItem=function(item, x)
{
if (!item) return;
if (!IFrameSplitOperator.IsNumber(item.Value)) return;
var y=this.GetYFromData(item.Value,false);
var radius=this.Radius;
if (item.Radius) radius=item.Radius;
if (!IFrameSplitOperator.IsNumber(radius)) return;
this.Canvas.beginPath();
this.Canvas.arc(x, y, radius, 0, 2 * Math.PI);
var color=this.Color;
if (item.Color) color=item.Color;
if (color)
{
this.Canvas.fillStyle=color;
this.Canvas.fill();
}
if (item.ColorBorder)
{
this.Canvas.strokeStyle=item.ColorBorder;
this.Canvas.stroke()
}
var itemTooltip={ X:x, Y:y, Radius:radius, Data:item };
this.TooltipData.push(itemTooltip);
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var point=this.Data.Data[i];
if (!point) continue;
if (Array.isArray(point))
{
for(var k=0;k<point.length;++k)
{
var item=point[k];
if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
if (range.Max==null) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
if (range.Max<item.Value) range.Max=item.Value;
if (range.Min>item.Value) range.Min=item.Value;
}
}
else
{
if (!IFrameSplitOperator.IsNumber(point.Value)) continue;
if (range.Max==null) range.Max=point.Value;
if (range.Min==null) range.Min=point.Value;
if (range.Max<point.Value) range.Max=point.Value;
if (range.Min>point.Value) range.Min=point.Value;
}
}
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
if (!this.IsShow) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(this.TooltipData)) return false;
for(var i=this.TooltipData.length-1; i>=0; --i)
{
var item=this.TooltipData[i];
this.Canvas.beginPath();
this.Canvas.arc(item.X, item.Y, item.Radius, 0, 2 * Math.PI);
if (this.Canvas.isPointInPath(x,y))
{
JSConsole.Chart.Log('[ChartScatterPlot::GetTooltipData] point', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=6; //散点图
return true;
}
}
}
}
//子线段
function ChartSubLine()
{
this.newMethod=ChartLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartSubLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.LineWidth; //线段宽度
this.DrawType=0; //画图方式 0=无效数平滑 1=无效数不画断开
this.IsDotLine=false; //虚线
this.SubFrame={ Max:null,Min:null };
this.Draw=function()
{
if (!this.IsShow) return;
if (!this.Data || !this.Data.Data) return;
this.CalculateDataMaxMin();
switch(this.DrawType)
{
case 0:
return this.DrawLine();
case 1:
return this.DrawStraightLine();
}
}
this.GetYFromData=function(value)
{
var bHScreen = (this.ChartFrame.IsHScreen === true);
if (bHScreen)
{
if (value <= this.SubFrame.Min) return this.ChartBorder.GetLeftEx();
if (value >= this.SubFrame.Max) return this.ChartBorder.GetRightEx();
var width = this.ChartBorder.GetWidthEx() * (value - this.SubFrame.Min) / (this.SubFrame.Max - this.SubFrame.Min);
return this.ChartBorder.GetLeftEx() + width;
}
else
{
if(value<=this.SubFrame.Min) return this.ChartBorder.GetBottomEx();
if(value>=this.SubFrame.Max) return this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx()*(value-this.SubFrame.Min)/(this.SubFrame.Max-this.SubFrame.Min);
return this.ChartBorder.GetBottomEx()-height;
}
}
this.CalculateDataMaxMin=function()
{
this.SubFrame={ Max:null,Min:null };
var bHScreen=(this.ChartFrame.IsHScreen===true);
var chartright=this.ChartBorder.GetRight();
if (bHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) break;
if (this.SubFrame.Min==null || this.SubFrame.Min>value) this.SubFrame.Min=value;
if (this.SubFrame.Max==null || this.SubFrame.Max<value) this.SubFrame.Max=value;
}
}
this.GetMaxMin=function() //数据不参与坐标轴最大最小值计算
{
var range={Min:null, Max:null};
return range;
}
}
//叠加线段
function ChartOverlayLine()
{
this.newMethod=ChartLine; //派生
this.newMethod();
delete this.newMethod;
this.MainData=new ChartData(); //主数据
this.Draw=function()
{
if (!this.Data || !this.Data.Data) return;
if (!this.MainData || !this.MainData.Data) return;
switch(this.DrawType)
{
case 0:
return this.DrawLine();
case 1:
return this.DrawStraightLine();
}
}
//获取第1个有效数据
this.GetFirstVaildIndex=function()
{
var startIndex=this.Data.DataOffset;
for(var i=startIndex, j=0 ; i<this.MainData.Data.length && i<this.Data.Data.length; ++i,++j )
{
var value=this.MainData.Data[i];
var overlayValue=this.Data.Data[i];
if (IFrameSplitOperator.IsNumber(value) && IFrameSplitOperator.IsNumber(overlayValue))
return { Index:j, DataOffset:i, OverlayValue:overlayValue, MainValue:value };
}
return null;
}
//无效数不画
this.DrawStraightLine=function()
{
var firstData=this.GetFirstVaildIndex();
if (!firstData) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (bHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (lockRect)
{
if (bHScreen) chartright=lockRect.Top;
else chartright=lockRect.Left;
}
this.Canvas.save();
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
if (this.IsDotLine) this.Canvas.setLineDash([3,5]); //画虚线
var bFirstPoint=true;
var drawCount=0,rate=0;
for(var i=firstData.DataOffset,j=firstData.Index;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null)
{
if (drawCount>0) this.Canvas.stroke();
bFirstPoint=true;
drawCount=0;
continue;
}
var x=this.ChartFrame.GetXFromIndex(j);
var diff=value-firstData.OverlayValue;
if (firstData.OverlayValue!=0) rate= 1+ diff/Math.abs(firstData.OverlayValue);
else rate=1+diff;
var fixedValue=firstData.MainValue*rate;
//var fixedValue=value/firstData.OverlayValue*firstData.MainValue;
var y=this.GetYFromData(fixedValue);
if (x>chartright) break;
if (bFirstPoint)
{
this.Canvas.beginPath();
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
var firstData=this.GetFirstVaildIndex();
if (!firstData) return range;
for(var i=firstData.DataOffset,j=firstData.Index; i<this.Data.Data.length && j<xPointCount; ++i,++j)
{
var overlayValue=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(overlayValue)) continue;
var diff=overlayValue-firstData.OverlayValue;
if (firstData.OverlayValue!=0) rate= 1+ diff/Math.abs(firstData.OverlayValue);
else rate=1+diff;
var value=firstData.MainValue*rate;
//var value=overlayValue/firstData.OverlayValue*firstData.MainValue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
return range;
}
}
//独立线段
function ChartSingleLine()
{
this.newMethod=ChartLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartSingleLine'; //类名
this.MaxMin=null; //当前的显示范围
this.Draw=function()
{
this.MaxMin=null;
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (!this.Data || !this.Data.Data) return;
this.MaxMin=this.GetCurrentMaxMin();
if (!this.MaxMin) return;
if (!IFrameSplitOperator.IsNumber(this.MaxMin.Max) || !IFrameSplitOperator.IsNumber(this.MaxMin.Min)) return;
switch(this.DrawType)
{
default:
return this.DrawStraightLine();
}
}
//获取当前页的最大最小值
this.GetCurrentMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={ Max:null, Min:null };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
return range;
}
this.GetMaxMin=function()
{
return { Max:null, Min:null };
}
this.GetYFromData=function(value)
{
var bHScreen = (this.ChartFrame.IsHScreen === true);
if (bHScreen)
{
if (value <= this.MaxMin.Min) return this.ChartBorder.GetLeftEx();
if (value >= this.MaxMin.Max) return this.ChartBorder.GetRightEx();
var width = this.ChartBorder.GetWidthEx() * (value - this.MaxMin.Min) / (this.MaxMin.Max - this.MaxMin.Min);
return this.ChartBorder.GetLeftEx() + width;
}
else
{
if(value<=this.MaxMin.Min) return this.ChartBorder.GetBottomEx();
if(value>=this.MaxMin.Max) return this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx()*(value-this.MaxMin.Min)/(this.MaxMin.Max-this.MaxMin.Min);
return this.ChartBorder.GetBottomEx()-height;
}
}
}
//彩色线段
function ChartPartLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartPartLine'; //类名
this.LineWidth; //线段宽度
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.DrawLine();
}
this.DrawLine=function()
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var xPointCount=this.ChartFrame.XPointCount;
var isMinute=this.IsMinuteFrame();
this.Canvas.save();
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var bFirstPoint=true;
var drawCount=0;
var lastColor;
var lastPoint={X:null,Y:null};
var isPerNull=false;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (item==null || item.Value==null)
{
lastPoint.X=null;
lastPoint.Y=null;
isPerNull=true;
continue;
}
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var value=item.Value;
var color=item.RGB;
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) break;
if (color!=lastColor || isPerNull==true)
{
if (lastColor && drawCount>0) this.Canvas.stroke();
drawCount=0;
lastColor=color;
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
if (lastPoint.X!=null && lastPoint.Y!=null) //接着上一个点连线
{
if (bHScreen) this.Canvas.moveTo(lastPoint.Y,lastPoint.X); //横屏坐标轴对调
else this.Canvas.moveTo(lastPoint.X,lastPoint.Y);
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
++drawCount;
}
else
{
if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
}
}
else
{
if (bHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
++drawCount;
}
lastPoint.X=x;
lastPoint.Y=y;
isPerNull=false;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item = this.Data.Data[i];
if (!item || !item.Value) continue;
if (range.Max == null || range.Max<item.Value) range.Max = item.Value;
if (range.Min == null || range.Min>item.Value) range.Min = item.Value;
}
return range;
}
this.ExportData=function(aryKData, option)
{
var aryValue=[], aryColor=[];
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
var start=0, end=this.Data.length-1;
//限制范围
if (option && option.Start && option.End && IFrameSplitOperator.IsNumber(option.Start.Index) && IFrameSplitOperator.IsNumber(option.End.Index))
{
start=option.Start.Index;
end=option.End.Index;
}
for(var i=start ;i<=end && i<this.Data.Data.length; ++i)
{
var item = this.Data.Data[i];
aryValue[i]=null;
aryColor[i]=null;
if (item && IFrameSplitOperator.IsNumber(item.Value))
{
aryValue[i]=item.Value;
aryColor[i]=item.RGB;
}
}
}
return [{ Name: `${this.Name}-Value`, Data:aryValue }, { Name: `${this.Name}-Color`, Data:aryColor }] ;
}
}
//阶梯折线图
function ChartStepLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartStepLine'; //类名
this.LineWidth=1; //线段宽度
this.DotLine;
this.IsHScreen;
this.IsDotLine=false; //虚线
this.PtInChart=function(x,y)
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
if (bHScreen) return;
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
if (lockRect) chartright=lockRect.Top;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
if (lockRect) chartright=lockRect.Left;
}
if (x<xOffset || x>chartright) return null;
if (y>border.BottomEx || y<border.TopEx) return null;
var ptStart={}, ptEnd={};
for(var i=this.Data.DataOffset; i>=0; --i)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var yPt=this.GetYFromData(value,false);
var xPt=null;
if (isMinute) xPt=this.ChartFrame.GetXFromIndex(0);
else xPt=xOffset;
ptStart.Y=yPt;
ptStart.X=xPt;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (isMinute)
{
var xLine=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var xLine=left+(right-left)/2;
}
var yLine=this.GetYFromData(value,false);
if (xLine<x)
{
ptStart.X=xLine;
ptStart.Y=yLine;
}
else if (xLine==x)
{
ptStart.X=ptEnd.X=xLine;
ptStart.Y=ptEnd.Y=yLine;
break;
}
else
{
ptEnd.X=xLine;
ptEnd.Y=yLine;
break;
}
if (x>chartright) break;
}
if (!IFrameSplitOperator.IsNumber(ptStart.X) || !IFrameSplitOperator.IsNumber(ptStart.Y)) return null;
if (!IFrameSplitOperator.IsNumber(ptEnd.X) || !IFrameSplitOperator.IsNumber(ptEnd.Y)) return null;
if (x==ptStart.X || y==ptStart.Y)
return { Identify:this.Identify, Chart:this };
if (x==ptEnd.X || y==ptEnd.Y)
return { Identify:this.Identify, Chart:this };
if (x>=ptStart.X && x<=ptEnd.X && y>=ptStart.Y-3 && y<=ptStart.Y+3)
return { Identify:this.Identify, Chart:this };
if (x>=ptEnd.X-3 && x<=ptEnd.X+3 && y>=Math.min(ptStart.Y,ptEnd.Y) && y<Math.max(ptStart.Y,ptEnd.Y))
return { Identify:this.Identify, Chart:this };
return null;
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
this.Canvas.save();
this.ClipClient(this.IsHScreen);
this.DrawLine();
this.Canvas.restore();
}
this.DrawLine=function()
{
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
if (lockRect) chartright=lockRect.Top;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
if (lockRect) chartright=lockRect.Left;
}
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线
if (this.DotLine) this.Canvas.setLineDash(this.DotLine); //画虚线
this.Canvas.strokeStyle=this.Color;
var bFirstPoint=true;
var drawCount=0;
var prePoint={ X:null, Y:null };
for(var i=this.Data.DataOffset; i>=0; --i)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var y=this.GetYFromData(value,false);
var x=null;
if (isMinute) x=this.ChartFrame.GetXFromIndex(0);
else x=xOffset;
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
prePoint.Y=y;
prePoint.X=x;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (x>chartright) break;
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var y=this.GetYFromData(value,false);
if (bFirstPoint)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
prePoint.X=x;
prePoint.Y=y;
}
else
{
if (this.IsHScreen)
{
this.Canvas.lineTo(prePoint.Y,x)
this.Canvas.lineTo(y,x);
}
else
{
this.Canvas.lineTo(x,prePoint.Y)
this.Canvas.lineTo(x,y);
}
prePoint.X=x;
prePoint.Y=y;
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
}
this.DrawSelectedStatus=function()
{
this.DrawLinePoint();
}
}
//斜率线 DRAWSL()
function ChartSlopeLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartSlopeLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.IsDotLine=false;
this.LineWidth;
this.Option; //[ { Slope:slope, Length:len, Direct:direct } ]
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.Canvas.save();
this.Canvas.strokeStyle=this.Color;
if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线
var left=this.ChartBorder.GetLeft();
var top=this.ChartBorder.GetTopEx();
var right=this.ChartBorder.GetRight();
var bottom=this.ChartBorder.GetBottom();
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
this.Canvas.clip();
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var option=this.Option[i];
if (!option) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
var z=option.Length*g_JSChartResource.DRAWSL.PixelWidth;
if (x>chartright) break;
var x2=Math.sqrt((z*z)/(1+option.Slope*option.Slope));
var y2=x2*option.Slope;
this.Canvas.beginPath();
if (option.Direct==2)
{
this.Canvas.moveTo(x-x2,y+y2);
this.Canvas.lineTo(x+x2,y-y2);
}
else if (option.Direct==1)
{
this.Canvas.moveTo(x,y);
this.Canvas.lineTo(x-x2,y+y2);
}
else
{
this.Canvas.moveTo(x,y);
this.Canvas.lineTo(x+x2,y-y2);
}
this.Canvas.stroke();
}
this.Canvas.restore();
}
}
//POINTDOT 圆点 支持横屏
/*
SAR的圈圈分成两种颜色,当股价朝向上的方向前进时,SAR位于收盘价线的下方,并且呈现红色的圈圈,
当股价朝下跌的方向前进时,SAR位于收盘价的上方,并且呈现绿色的圈圈。
我们最需要注意的是,股价向上或向下穿越SAR圈圈的讯号,而且是以收盘价的穿越有效。
当价格由下往上穿越今天绿色的SAR时,画面上立即在明天的价格位置显示一个红色的圈圈,
代表股价已经翻红,又代表明天开始,必须从事多头交易,当价格由上往下跌破今天红色的SAR时,画面上立即在明天的价格位置,
显示一个绿色的圈圈,代表股价已经翻绿,又代表明天开始必须从事空头交易。
*/
function ChartPointDot()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartPointDot'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.Radius=1; //点半径
this.EnableUpDownColor=false; //是否是红绿点
this.HistoryData;
this.ExportData=this.ExportArrayData;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (bHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
this.Canvas.save();
this.ClipClient(bHScreen);
this.Canvas.fillStyle=this.Color;
var colorDot;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value, false);
if (x>chartright) break;
if (this.EnableUpDownColor)
{
var kItem=this.HistoryData.Data[i];
if (kItem.Close>value) colorDot="rgb(255,61,61)";
else colorDot='rgb(0,199,65)';
this.Canvas.fillStyle=colorDot;
}
this.Canvas.beginPath();
if (bHScreen) this.Canvas.arc(y, x, this.Radius, 0, Math.PI*2, true);
else this.Canvas.arc(x, y, this.Radius, 0, Math.PI*2, true);
this.Canvas.closePath();
this.Canvas.fill();
}
this.Canvas.restore();
}
}
//通达信语法 STICK 支持横屏
function ChartStick()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.Color="rgb(255,193,37)"; //线段颜色
this.LineWidth; //线段宽度
this.ClassName='ChartStick';
this.ExportData=this.ExportArrayData;
this.DrawLine=function()
{
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
this.Canvas.save();
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var bFirstPoint=true;
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) break;
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawStick=function()
{
if (!this.Data || !this.Data.Data) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
var chartright=this.ChartBorder.GetRight();
if (bHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var yBottom=this.ChartBorder.GetBottom();
var xLeft=this.ChartBorder.GetLeft();
this.Canvas.save();
this.Canvas.strokeStyle=this.Color;
if (this.LineWidth) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var lineWidth=this.Canvas.lineWidth;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) break;
this.Canvas.beginPath();
if (bHScreen)
{
this.Canvas.moveTo(xLeft,x);
this.Canvas.lineTo(y,x);
this.Canvas.stroke();
}
else
{
var xFix=ToFixedPoint2(lineWidth, x);
this.Canvas.moveTo(xFix,y);
this.Canvas.lineTo(xFix,yBottom);
}
this.Canvas.stroke();
}
this.Canvas.restore();
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.DrawStick();
}
}
//通达信语法 LINESTICK 支持横屏
function ChartLineStick()
{
this.newMethod=ChartStick; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartLineStick';
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
this.DrawStick();
this.DrawLine();
}
}
//通达信语法 VOLSTICK 支持横屏
function ChartVolStick()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.HistoryData; //历史数据
this.KLineDrawType=0;
this.ClassName='ChartVolStick';
this.BarWidth; //固定宽度 目前只支持宽度为1
this.BarType; //柱子状态 1=实心 0=空心 2=涨实跌空 如果设置了这个属性, 属性KLineDrawType无效
this.BarColorType=0; //0=柱子颜色跟K线走 1=正upcolor 负downcolor
this.PtInChart=this.PtInBar;
this.DrawSelectedStatus=this.DrawLinePoint;
this.ExportData=this.ExportArrayData;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.ChartFrame.IsHScreen===true)
{
this.HScreenDraw();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Left;
var isMinute=this.IsMinuteFrame();
var yBottom=this.ChartFrame.GetYFromData(0);
this.Canvas.save();
if (dataWidth>=4 && !(this.BarWidth===1))
{
yBottom=ToFixedRect(yBottom);
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
if (value==0) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var y=this.ChartFrame.GetYFromData(value);
var barColor=this.GetBarColor(kItem,value);
var bUp=barColor.IsUp;
var height=ToFixedRect(Math.abs(yBottom-y)>=1?yBottom-y:1);//高度调整为整数, 如果小于1, 统一使用1
y=yBottom-height;
var bSolidBar=this.IsSolidBar(bUp); //实心柱子
if (bSolidBar)
{
this.Canvas.fillStyle=barColor.Color;
this.Canvas.fillRect(ToFixedRect(left),y,ToFixedRect(dataWidth),height);
}
else
{
this.Canvas.strokeStyle=barColor.Color;
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),height);
this.Canvas.stroke();
}
}
}
else //太细了直接话线
{
var preKItem=null;
var barColor=null;
this.Canvas.linewidth=1*GetDevicePixelRatio();
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var y=this.ChartFrame.GetYFromData(value);
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
}
if (x>chartright) break;
if (isMinute) barColor=this.GetMinuteBarColor(kItem,preKItem); //分时图颜色单独计算
else barColor=this.GetBarColor(kItem, value);
this.Canvas.strokeStyle=barColor.Color;
//var x=this.ChartFrame.GetXFromIndex(j);
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
this.Canvas.stroke();
preKItem=kItem;
}
}
this.Canvas.restore();
}
this.HScreenDraw=function() //横屏画法
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartBottom=border.BottomEx;
var xPointCount=this.ChartFrame.XPointCount;
var lockRect=this.GetLockRect();
if (lockRect) chartBottom=lockRect.Top;
var isMinute=this.IsMinuteFrame();
var yBottom=this.ChartFrame.GetYFromData(0);
if (dataWidth>=4)
{
yBottom=ToFixedRect(yBottom);
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartBottom) break;
var y=this.ChartFrame.GetYFromData(value);
var barColor=this.GetBarColor(kItem, value);
var bUp=barColor.IsUp;
var height=ToFixedRect(y-yBottom); //高度调整为整数
var bSolidBar=this.IsSolidBar(bUp); //实心柱子
if (bSolidBar)
{
this.Canvas.fillStyle=barColor.Color;
this.Canvas.fillRect(yBottom,ToFixedRect(left),height,ToFixedRect(dataWidth));
}
else
{
this.Canvas.strokeStyle=barColor.Color;
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(yBottom),ToFixedPoint(left),height,ToFixedRect(dataWidth));
this.Canvas.stroke();
}
}
}
else //太细了直接话线
{
var preKItem=null;
var barColor=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var y=this.ChartFrame.GetYFromData(value);
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
}
if (x>chartBottom) break;
if (isMinute) barColor=this.GetMinuteBarColor(kItem,preKItem); //分时图颜色单独计算
else barColor=this.GetBarColor(kItem,value);
var bUp=barColor.IsUp;
this.Canvas.strokeStyle=barColor.Color;
//var x=this.ChartFrame.GetXFromIndex(j);
this.Canvas.beginPath();
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(yBottom,ToFixedPoint(x));
this.Canvas.stroke();
preKItem=kItem;
}
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
var range={ Min:null, Max:null };
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(range.Max) || range.Max<value) range.Max=value;
if (!IFrameSplitOperator.IsNumber(range.Min) || range.Min>value) range.Min=value
}
if (range.Max>0 && range.Min>0) range.Min=0;
else if (range.Max<0 && range.Min<0) range.Max=0;
return range;
}
this.GetBarColor=function(kItem, value)
{
if (this.BarColorType===1) //更具正负决定柱子颜色
{
if (value>=0) return { Color:this.UpColor, IsUp:true }; //颜色, 是否是上涨
else return { Color:this.DownColor, IsUp:false };
}
if (kItem.Close>=kItem.Open) return { Color:this.UpColor, IsUp:true }; //颜色, 是否是上涨
else return { Color:this.DownColor, IsUp:false };
}
//true=实心 false=空心
this.IsSolidBar=function(bUp)
{
var bSolidBar=true; //实心柱子
if (this.BarType===0 || this.BarType===1 || this.BarType===2)
{
if (this.BarType===0) //空心
bSolidBar=false;
else if (this.BarType===2) //涨实跌空
bSolidBar=bUp;
}
else
{
if (this.KLineDrawType==6) //完全空心柱
bSolidBar=false;
else if (bUp && (this.KLineDrawType==1 || this.KLineDrawType==2 || this.KLineDrawType==3)) //空心柱子
bSolidBar=false;
}
return bSolidBar;
}
this.GetMinuteBarColor=function(kItem, preItem)
{
var prePrice=kItem.YClose;
if (preItem) prePrice=preItem.Close;
if (kItem.Close>=prePrice) return { Color:this.UpColor, IsUp:true }; //颜色, 是否是上涨
else return { Color:this.DownColor, IsUp:false };
}
this.GetItemData=function(indexData)
{
if (!indexData) return null;
if (!IFrameSplitOperator.IsNumber(indexData.Index)) return null;
if (!this.HistoryData || !IFrameSplitOperator.IsNonEmptyArray(this.HistoryData.Data)) return null;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var index=indexData.Index;
if (index<0 || index>=this.Data.Data.length || index>=this.HistoryData.Data.length) return null;
var item=this.Data.Data[index];
var kItem=this.HistoryData.Data[index];
return [ { Value:item, Color:this.GetBarColor(kItem).Color, Name: this.Name } ];
}
}
// VERTLINE(HIGH>=HHV(HIGH,20),1)表示在创20天新高画垂直虚线。
// 支持横屏
function ChartVericaltLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartVericaltLine'; //类名
this.LineWidth=2;
this.LineCap;
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
var isHScreen=this.ChartFrame.IsHScreen==true;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.GetBorder();
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var top=border.RightEx;
var bottom=border.LeftEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var top=border.TopEx;
var bottom=border.BottomEx;
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
this.Canvas.save();
this.Canvas.strokeStyle=this.Color;
if (this.LineType) this.Canvas.setLineDash(this.LineType);
if (this.LineCap) this.Canvas.lineCap = this.LineCap;
this.Canvas.beginPath();
var lineWidth=this.Canvas.lineWidth;
if (this.LineWidth>0)
{
lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
}
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
var center=xOffset+dataWidth/2;
center=ToFixedPoint2(lineWidth, center);
if (isHScreen)
{
this.Canvas.moveTo(top,center);
this.Canvas.lineTo(bottom,center);
}
else
{
this.Canvas.moveTo(center, top);
this.Canvas.lineTo(center,bottom);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
this.GetMaxMin=function()
{
return { Min:null, Max:null };
}
}
//HORLINE 支持横屏
function ChartHorizontalLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartHorizontalLine'; //类名
this.LineWidth=2;
this.LineCap;
this.ExtendType=0; //1=表示向左延长,2=表示向右延长,3=表示左右延长
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
var isHScreen=this.ChartFrame.IsHScreen==true;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var border=this.GetBorder();
var xPointCount=this.ChartFrame.XPointCount;
if (isHScreen)
{
var left=border.TopEx;
var right=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var left=border.LeftEx
var right=border.RightEx;
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
this.Canvas.save();
this.Canvas.strokeStyle=this.Color;
if (this.LineType) this.Canvas.setLineDash(this.LineType);
if (this.LineCap) this.Canvas.lineCap = this.LineCap;
this.Canvas.beginPath();
var lineWidth=this.Canvas.lineWidth;
if (this.LineWidth>0)
{
lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
}
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item)) continue;
var y=this.ChartFrame.GetYFromData(item);
y=ToFixedPoint2(lineWidth, y);
var center=xOffset+dataWidth/2;
center=ToFixedPoint2(lineWidth, center);
if (this.ExtendType==3) //左右延长
{
if (isHScreen)
{
this.Canvas.moveTo(y, left);
this.Canvas.lineTo(y, right);
}
else
{
this.Canvas.moveTo(left, y);
this.Canvas.lineTo(right, y);
}
}
else if (this.ExtendType==1) //左延长
{
if (isHScreen)
{
this.Canvas.moveTo(y, left);
this.Canvas.lineTo(y, center);
}
else
{
this.Canvas.moveTo(left, y);
this.Canvas.lineTo(center, y);
}
}
else //右延长
{
if (isHScreen)
{
this.Canvas.moveTo(y, center);
this.Canvas.lineTo(y, right);
}
else
{
this.Canvas.moveTo(center, y);
this.Canvas.lineTo(right, y);
}
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
}
//线段 多数据(一个X点有多条Y数据) 支持横屏
function ChartLineMultiData()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartLineMultiData'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.PointColor; //='rgb(255,193,80)';
this.PointRadius; //=2;
this.LineWidth;
this.Draw=function()
{
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
this.Canvas.save();
if (IFrameSplitOperator.IsPlusNumber(this.LineWidth)) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var bFirstPoint=true;
var drawCount=0;
var aryPoint=[];
var aryValue;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var lineItem=this.Data.Data[i];
if (!lineItem) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) break;
if (Array.isArray(lineItem)) aryValue=lineItem;
else aryValue=[lineItem];
for(var index=0; index<aryValue.length; ++index)
{
var item=aryValue[index];
if (!item) continue;
var value =item.Value;
var y=this.ChartFrame.GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
if (item.Type===1) aryPoint.push({X:x, Y:y});
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
if (item.Type===1) aryPoint.push({X:x, Y:y});
}
++drawCount;
}
}
if (drawCount>0) this.Canvas.stroke();
this.DrawPoint(aryPoint);
this.Canvas.restore();
}
this.DrawPoint=function(aryPoint)
{
if (!this.PointColor) return;
if (!IFrameSplitOperator.IsPlusNumber(this.PointRadius)) return;
var radius=this.PointRadius*GetDevicePixelRatio();
for(var i=0;i<aryPoint.length;++i)
{
var item=aryPoint[i];
this.Canvas.beginPath();
this.Canvas.arc(item.X,item.Y,radius,0,360,false);
this.Canvas.fillStyle=this.PointColor; //填充颜色
this.Canvas.fill(); //画实心圆
this.Canvas.closePath();
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item=this.Data.Data[i];
if (!item) continue;
var aryValue;
if (Array.isArray(item)) aryValue=item;
else aryValue=[item];
for(var j=0; j<aryValue.length; ++j)
{
var value=aryValue[j].Value;
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
}
return range;
}
}
//柱子 支持横屏
function ChartStickLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartStickLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.BarType=0; //柱子类型 0=实心 1=空心 -1=画虚线空心柱
this.LineDotted=[3,3]; //虚线设置
this.Width=0; //柱子宽度 0=1 3,50=k线宽度 101=K线宽度+间距宽度
this.SetEmptyBar=function() //设置空心柱子
{
if (this.BarType!=1 && this.BarType!=-1) return false;
this.Canvas.lineWidth=GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
var emptyBGColor=g_JSChartResource.EmptyBarBGColor;
if (emptyBGColor) this.Canvas.fillStyle=emptyBGColor;
if (this.BarType==-1) //虚线
{
this.Canvas.setLineDash(this.LineDotted); //虚线
}
return true;
}
this.IsEmptyBar=function()
{
return (this.BarType==1 || this.BarType==-1);
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
var zoomIndex=this.ChartFrame.ZoomIndex;
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var isMinute=this.IsMinuteFrame();
this.Canvas.save();
var bFillBar=false;
var bFillKLine=false;
var emptyBGColor=g_JSChartResource.EmptyBarBGColor;
if (isMinute)
{
if (this.Width>1) this.Canvas.lineWidth=2*GetDevicePixelRatio();
else this.Canvas.lineWidth=GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
}
else if(this.Width==0) //宽度时0,使用宽度1
{
this.SetEmptyBar();
this.Canvas.lineWidth=GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
}
else if (this.Width==3 || this.Width==50) //3和50 K线宽度
{
if (dataWidth>=4)
{
bFillKLine=true;
this.SetEmptyBar();
if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color;
this.Canvas.strokeStyle=this.Color;
}
else //太细了 画竖线
{
this.Canvas.lineWidth=GetDevicePixelRatio();
this.Canvas.strokeStyle=this.Color;
}
}
else if (this.Width==101)
{
var lineWidth=dataWidth+distanceWidth+1*GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
this.Canvas.strokeStyle=this.Color;
}
else if (this.Width<=3)
{
var minWidth=2*GetDevicePixelRatio();
var barWidth=dataWidth*(this.Width/3);
if (barWidth<minWidth) barWidth=minWidth;
this.SetEmptyBar();
if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color;
bFillBar=true;
}
else
{
var barWidth=this.Width*GetDevicePixelRatio()+dataWidth;
this.SetEmptyBar();
if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color;
bFillBar=true;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
var price=value.Value;
var price2=value.Value2;
if (price2==null) price2=0;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
}
var y=this.ChartFrame.GetYFromData(price);
var y2=this.ChartFrame.GetYFromData(price2);
if (x>chartright) break;
if (bFillBar)
{
if (isHScreen)
{
var left=x-barWidth/2;
var width=barWidth;
if (this.IsEmptyBar()) //空心
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(Math.min(y,y2)),ToFixedPoint(left),ToFixedRect(Math.abs(y-y2)),ToFixedRect(width));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(left),ToFixedRect(Math.abs(y-y2)),ToFixedRect(width));
}
}
else
{
var left=x-barWidth/2;
var width=barWidth;
if (left+width>chartright) width=chartright-left; //不要超过右边框子
if (this.IsEmptyBar()) //空心
{
if (emptyBGColor)
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));
}
}
}
else if (bFillKLine)
{
if (this.IsEmptyBar()) //空心
{
if (isHScreen)
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(Math.min(y,y2)),ToFixedPoint(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth));
this.Canvas.stroke();
}
else
{
if (emptyBGColor)
this.Canvas.fillRect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2)));
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(xOffset),ToFixedPoint(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2)));
this.Canvas.stroke();
}
}
else
{
if (isHScreen)
this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth));
else
this.Canvas.fillRect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2)));
}
}
else
{
if (isHScreen)
{
this.Canvas.beginPath();
this.Canvas.moveTo(y,ToFixedPoint(x));
this.Canvas.lineTo(y2,ToFixedPoint(x));
this.Canvas.stroke();
}
else
{
var xFix=parseInt(x.toString())+0.5;
this.Canvas.beginPath();
this.Canvas.moveTo(xFix,y);
this.Canvas.lineTo(xFix,y2);
this.Canvas.stroke();
}
}
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data == null) continue;
var value2=data.Value2;
if (value2==null) value2=0;
if (data==null || isNaN(data.Value) ||isNaN(value2)) continue;
var valueMax=Math.max(data.Value,value2);
var valueMin=Math.min(data.Value,value2);
if (range.Max==null) range.Max=valueMax;
if (range.Min==null) range.Min=valueMin;
if (range.Max<valueMax) range.Max=valueMax;
if (range.Min>valueMin) range.Min=valueMin;
}
return range;
}
}
function ChartText()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartText'; //类名
this.TextFont="14px 微软雅黑";
this.Draw=function()
{
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
for(var i in this.Data.Data)
{
var value=this.Data.Data[i];
if (value==null) continue;
var price=value.Value;
var position=value.Position;
if (position=='Left')
{
var x=this.ChartFrame.GetXFromIndex(0);
var y=this.ChartFrame.GetYFromData(price);
if (x>chartright) continue;
this.Canvas.textAlign='left';
this.Canvas.textBaseline='middle';
this.Canvas.fillStyle=value.Color;
this.Canvas.font=this.TextFont;
this.Canvas.fillText(value.Message,x,y);
}
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i in this.Data.Data)
{
var data=this.Data.Data[i];
if (data==null || isNaN(data.Value)) continue;
var value=data.Value;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
return range;
}
}
/*
文字输出 支持横屏
数组(Data)不为null的数据中输出 this.Text文本
*/
function ChartSingleText()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartSingleText'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.TextFont="14px 微软雅黑"; //线段宽度
this.Text;
this.TextAlign='left';
this.TextBG; //{ Color:"rgb(0,0,92)", Border:"rgb(205,0,92)", Margin:[0,1,1,1], } // { Color:背景色, Border:边框颜色, Margin=[上,下,左, 右] }
this.Direction=0; //0=middle 1=bottom 2=top
this.FixedFontSize=-1; //固定字体大小
this.YOffset=0; //连线
this.Position; //指定输出位置
this.ShowOffset={ X:0, Y:0 }; //显示偏移
this.IconFont; //Iconfont
this.IconSize=
{
Max: g_JSChartResource.DRAWICON.Icon.MaxSize, Min:g_JSChartResource.DRAWICON.Icon.MinSize, //图标的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWICON.Icon.Zoom.Type , Value:g_JSChartResource.DRAWICON.Icon.Zoom.Value }, //放大倍数
YOffset:g_JSChartResource.DRAWICON.Icon.YOffset //Direction==2的向下偏移
};
this.TextSize=
{
Max: g_JSChartResource.DRAWICON.Text.MaxSize, Min:g_JSChartResource.DRAWICON.Text.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWICON.Text.Zoom.Type , Value:g_JSChartResource.DRAWICON.Text.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWICON.Text.FontName,
YOffset:g_JSChartResource.DRAWICON.Text.YOffset
}
this.Font=
{
DRAWTEXT_FIX:g_JSChartResource.DRAWTEXT_FIX.Font,
DRAWNUMBER_FIX: g_JSChartResource.DRAWNUMBER_FIX.Font
}
this.ExportData=this.ExportBoolData;
this.ReloadResource=function(resource)
{
if (this.Name=="DRAWTEXT")
{
this.TextSize=
{
Max: g_JSChartResource.DRAWTEXT.MaxSize, Min:g_JSChartResource.DRAWTEXT.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWTEXT.Zoom.Type , Value:g_JSChartResource.DRAWTEXT.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWTEXT.FontName,
YOffset:g_JSChartResource.DRAWTEXT.YOffset
}
}
else if (this.Name=="DRAWNUMBER")
{
this.TextSize=
{
Max: g_JSChartResource.DRAWNUMBER.MaxSize, Min:g_JSChartResource.DRAWNUMBER.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWNUMBER.Zoom.Type , Value:g_JSChartResource.DRAWNUMBER.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWNUMBER.FontName,
YOffset:g_JSChartResource.DRAWNUMBER.YOffset
}
}
else if (this.Name=="DRAWTEXT_FIX")
{
this.Font.DRAWTEXT_FIX=g_JSChartResource.DRAWTEXT_FIX.Font;
}
else if (this.Name=="DRAWNUMBER_FIX")
{
this.Font.DRAWNUMBER_FIX=g_JSChartResource.DRAWNUMBER_FIX.Font;
}
}
this.SuperGetMaxMin=this.GetMaxMin;
this.GetMaxMin=function()
{
if ( this.Name=="DRAWTEXT_FIX" || this.Name=='DRAWNUMBER_FIX') //固定位置的 没有大小值
{
return { Min:null,Max:null };
}
else if (this.Name=="DRAWTEXTREL" || this.Name=="DRAWTEXTABS")
{
return { Min:null,Max:null };
}
else
{
return this.SuperGetMaxMin();
}
}
this.DrawRectText=function()
{
if (!this.DrawData) return;
var isHScreen=(this.ChartFrame.IsHScreen===true)
var border=this.ChartFrame.GetBorder();
if (this.Name=="DRAWTEXTREL")
{
if (isHScreen)
{
var height=border.RightTitle-border.LeftEx;
var width=border.BottomEx-border.TopEx;
var x=this.DrawData.Point.X/1000*width+border.TopEx;
var y=border.RightTitle-this.DrawData.Point.Y/1000*width;
}
else
{
var width=border.RightEx-border.LeftEx;
var height=border.BottomEx-border.TopTitle;
var x=this.DrawData.Point.X/1000*width+border.LeftEx;
var y=this.DrawData.Point.Y/1000*height+border.TopTitle;
}
}
else if (this.Name=="DRAWTEXTABS")
{
if (isHScreen)
{
var x=this.DrawData.Point.X+border.TopEx;
var y=border.RightTitle-this.DrawData.Point.Y;
}
else
{
var x=this.DrawData.Point.X+border.LeftEx;
var y=this.DrawData.Point.Y+border.TopTitle;
}
}
else
{
return;
}
if (this.Direction==1) this.Canvas.textBaseline='bottom';
else if (this.Direction==2) this.Canvas.textBaseline='top';
else this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.font=this.TextFont;
this.Canvas.fillStyle=this.Color;
this.DrawText(this.DrawData.Text,x,y,isHScreen);
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (this.Name=="DRAWTEXTREL" || this.Name=="DRAWTEXTABS")
{
this.DrawRectText();
return;
}
if (this.Position)
{
this.DrawPosition();
return;
}
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true)
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
this.Canvas.save();
this.ClipClient(this.ChartFrame.IsHScreen);
if (isHScreen)
{
chartright=this.ChartBorder.GetBottom();
top=this.ChartBorder.GetRightEx();
bottom=this.ChartBorder.GetLeftEx();
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
var xPointCount=this.ChartFrame.XPointCount;
var isArrayText=Array.isArray(this.Text);
var pixelTatio = GetDevicePixelRatio();
var drawTextInfo={ Text:{ }, Font:{ } };
if (this.Direction==1)
{
this.Canvas.textBaseline='bottom';
drawTextInfo.Text={ Baseline: 'bottom'};
}
else if (this.Direction==2)
{
this.Canvas.textBaseline='top';
drawTextInfo.Text={ Baseline: 'top'};
}
else
{
this.Canvas.textBaseline='middle';
drawTextInfo.Text={ Baseline: 'middle'};
}
if (this.IconFont)
{
this.Color=this.IconFont.Color;
this.Text=this.IconFont.Text;
if (this.FixedFontSize>0) var iconSize=this.FixedFontSize;
else var iconSize=this.GetDynamicIconSize(dataWidth,distanceWidth,this.IconSize.Max,this.IconSize.Min,this.IconSize.Zoom);
this.Canvas.font=iconSize+'px '+this.IconFont.Family;
}
else
{
if (this.FixedFontSize>0)
this.TextFont=`${this.FixedFontSize}px ${this.TextSize.FontName}`;
else
this.TextFont=this.GetDynamicFont(dataWidth,distanceWidth,this.TextSize.Max,this.TextSize.Min,this.TextSize.Zoom,this.TextSize.FontName);
this.Canvas.font=this.TextFont;
}
drawTextInfo.Font={ Height:this.GetFontHeight() };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y=this.ChartFrame.GetYFromData(value,false);
if (x>chartright) break;
y+=this.ShowOffset.Y;
x+=this.ShowOffset.X;
this.Canvas.textAlign=this.TextAlign;
this.Canvas.fillStyle=this.Color;
drawTextInfo.Text.Color=this.Color;
drawTextInfo.Text.Align=this.TextAlign;
drawTextInfo.X=x;
drawTextInfo.Y=y;
if (this.YOffset>0 && this.Direction>0)
{
var yPrice=y;
this.Canvas.setLineDash([5,10]);
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen)
{
if (this.Direction==1)
{
y=top-this.YOffset*pixelTatio;
yPrice+=5*pixelTatio;
}
else
{
y=bottom+this.YOffset*pixelTatio;
yPrice-=5*pixelTatio;
}
this.Canvas.moveTo(ToFixedPoint(yPrice),ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(x));
}
else
{
if (this.Direction==1)
{
y=top+this.YOffset*pixelTatio;
yPrice+=5*pixelTatio;
}
else
{
y=bottom-this.YOffset*pixelTatio;
yPrice-=5*pixelTatio;
}
this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yPrice));
this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(y));
}
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
if (isArrayText)
{
var text=this.Text[i];
if (!text) continue;
if (this.Name=='DRAWNUMBER')
{
if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
else if (this.Direction==2) y+=this.TextSize.YOffset*pixelTatio;
}
if (this.Name=="DRAWTEXT")
this.DrawTextV2(text,drawTextInfo,isHScreen);
else
this.DrawText(text,x,y,isHScreen);
}
else
{
if (this.Name=='DRAWICON')
{
if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
else if (this.Direction==2)
{
if (this.IconFont) y+=this.IconSize.YOffset*pixelTatio;
else y+=this.TextSize.YOffset*pixelTatio;
}
}
else if (this.Name=="DRAWTEXT")
{
if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
else if (this.Direction==2) y+=this.TextSize.YOffset*pixelTatio;
}
if (this.Name=="DRAWTEXT")
{
this.DrawTextV2(this.Text,drawTextInfo,isHScreen);
}
else
{
this.DrawText(this.Text,x,y,isHScreen);
}
}
}
this.Canvas.restore();
}
this.DrawPosition=function() //绘制在指定位置上
{
if (!this.Text) return;
var isHScreen=(this.ChartFrame.IsHScreen===true)
if (isHScreen)
{
var y=this.ChartBorder.GetRightEx()-this.ChartBorder.GetWidthEx()*this.Position.Y;
var x=this.ChartBorder.GetTop()+this.ChartBorder.GetHeight()*this.Position.X;
}
else
{
var x=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*this.Position.X;
var y=this.ChartBorder.GetTopEx()+this.ChartBorder.GetHeightEx()*this.Position.Y;
}
this.Canvas.fillStyle=this.Color;
if (this.Name=="DRAWTEXT_FIX") this.Canvas.font=this.Font.DRAWTEXT_FIX;
else if (this.Name=="DRAWNUMBER_FIX") this.Canvas.font=this.Font.DRAWNUMBER_FIX;
//TYPE:0为左对齐,1为右对齐.
if (this.Position.Type==0) this.Canvas.textAlign='left';
else if (this.Position.Type==1) this.Canvas.textAlign='right';
else this.Canvas.textAlign='center';
if (this.Direction==1) this.Canvas.textBaseline='bottom';
else if (this.Direction==2) this.Canvas.textBaseline='top';
else this.Canvas.textBaseline='middle';
if (Array.isArray(this.Text))
{
if (!this.Data || !this.Data.Data) return;
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0; i<this.Data.Data.length && j<xPointCount; ++i,++j)
{
var text=this.Text[i];
if (text)
{
this.DrawText(text,x,y,isHScreen);
break;
}
}
}
else
{
this.DrawText(this.Text,x,y,isHScreen);
}
}
this.DrawText=function(text,x,y,isHScreen)
{
if (isHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,x,y);
}
}
this.DrawTextV2=function(text, drawInfo, isHScreen)
{
var textWidth=this.Canvas.measureText(text).width;
if (isHScreen)
{
var x=drawInfo.Y;
var y=drawInfo.X;
if (drawInfo.Text.Align=="right") y=y-textWidth;
else if (drawInfo.Text.Align=="center") y=y-textWidth/2;
if (drawInfo.Text.Baseline=="top") x-=drawInfo.Font.Height;
else if (drawInfo.Text.Baseline=="middle") x-=drawInfo.Font.Height/2;
if (this.TextBG && (this.TextBG.Color || this.TextBG.Border))
{
var margin=this.TextBG.Margin; //0=上 1=下 2=左 3=右
var xRect=x-margin[0];
var yRect=y-margin[2];
var bgWidth=textWidth+margin[2]+margin[3];
var bgHeight=drawInfo.Font.Height+margin[0]+margin[1];
if (this.TextBG.Color)
{
this.Canvas.fillStyle=this.TextBG.Color;
this.Canvas.fillRect(xRect,yRect,bgHeight,bgWidth);
}
if (this.TextBG.Border)
{
this.Canvas.strokeStyle=this.TextBG.Border;
this.Canvas.strokeRect(ToFixedPoint(xRect),ToFixedPoint(yRect),ToFixedRect(bgHeight),ToFixedRect(bgWidth));
}
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=drawInfo.Text.Color;
this.Canvas.save();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
var x=drawInfo.X;
var y=drawInfo.Y;
if (drawInfo.Text.Align=="right") x=x-textWidth;
else if (drawInfo.Text.Align=="center") x=x-textWidth/2;
if (drawInfo.Text.Baseline=="top") y+=drawInfo.Font.Height;
else if (drawInfo.Text.Baseline=="middle") y+=drawInfo.Font.Height/2;
if (this.TextBG && (this.TextBG.Color || this.TextBG.Border))
{
var margin=this.TextBG.Margin; //0=上 1=下 2=左 3=右
var xRect=x-margin[2];
var yRect=y-drawInfo.Font.Height-margin[1];
var bgWidth=textWidth+margin[2]+margin[3];
var bgHeight=drawInfo.Font.Height+margin[0]+margin[1];
if (this.TextBG.Color)
{
this.Canvas.fillStyle=this.TextBG.Color;
this.Canvas.fillRect(xRect,yRect,bgWidth,bgHeight);
}
if (this.TextBG.Border)
{
this.Canvas.strokeStyle=this.TextBG.Border;
this.Canvas.strokeRect(ToFixedPoint(xRect),ToFixedPoint(yRect),ToFixedRect(bgWidth),ToFixedRect(bgHeight));
}
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=drawInfo.Text.Color;
this.Canvas.fillText(text,x,y);
}
}
}
function ChartTradeIcon()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartTradeIcon'; //类名
this.TextAlign='center';
this.TextBaseline='middle';
this.SVG={ Family:"iconfont", Size:12 };
this.AryIcon;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if(!this.Data || !this.Data.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryIcon)) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
this.Canvas.font=`${this.SVG.Size}px ${this.SVG.Family}`;
this.Canvas.textAlign=this.TextAlign;
this.Canvas.textBaseline='middle';
var yOffset=0;
if (this.TradeType=="BUY" || this.TradeType=="BUYSHORT")
{
this.Canvas.textBaseline="top";
yOffset+=(bHScreen?-2:2);
}
else if (this.TradeType=="SELL" || this.TradeType=="SELLSHORT")
{
this.Canvas.textBaseline="bottom";
yOffset=(bHScreen?2:-2);
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
var border=this.ChartFrame.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
if (bHScreen)
{
chartright=this.ChartBorder.GetBottom();
//top=this.ChartBorder.GetRightEx();
//bottom=this.ChartBorder.GetLeftEx();
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (value<=0) continue;
var iconItem=this.AryIcon[i];
if (!IFrameSplitOperator.IsNumber(iconItem.Value) || !iconItem.Icon) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var y=this.GetYFromData(iconItem.Value, false);
this.Canvas.fillStyle=iconItem.Color;
if (dataWidth>2) x=ToFixedPoint(x);
this.DrawTradeIcon(iconItem.Icon,x,y+yOffset, bHScreen);
}
}
this.DrawTradeIcon=function(text,x,y,isHScreen)
{
if (isHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,x,y);
}
}
this.GetMaxMin=function()
{
var range={Max:null, Min:null };
if(!this.Data || !this.Data.Data) return range;
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryIcon)) return range;
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (value<=0) continue;
var iconItem=this.AryIcon[i];
if (!IFrameSplitOperator.IsNumber(iconItem.Value) || !iconItem.Icon) continue;
if (range.Max==null) range.Max=iconItem.Value;
else if (range.Max<iconItem.Value) range.Max=iconItem.Value;
if (range.Min==null) range.Min=iconItem.Value;
else if (range.Min>iconItem.Value) range.Min=iconItem.Value;
}
return range;
}
}
function ChartDrawText()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawText'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.TextFont="14px 微软雅黑"; //线段宽度
this.TextBaseline="middle";
this.TextAlign='left';
this.Text
this.TextBG; //{ Color:"rgb(0,0,92)", Border:"rgb(205,0,92)", Margin:[0,1,1,1], } // { Color:背景色, Border:边框颜色, Margin=[上,下,左, 右] }
this.FixedFontSize=-1; //固定字体大小
this.YOffset=0; //连线
this.FixedPosition=-1; //固定位置输出 1顶部, 2底部
this.VerticalLine; //垂直线
this.ShowOffset={ X:0, Y:0 }; //显示偏移
this.ExportData=this.ExportBoolData;
this.TextSize=
{
Max: g_JSChartResource.DRAWICON.Text.MaxSize, Min:g_JSChartResource.DRAWICON.Text.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWICON.Text.Zoom.Type , Value:g_JSChartResource.DRAWICON.Text.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWICON.Text.FontName,
YOffset:g_JSChartResource.DRAWICON.Text.YOffset
}
this.ReloadResource=function(resource)
{
this.TextSize=
{
Max: g_JSChartResource.DRAWTEXT.MaxSize, Min:g_JSChartResource.DRAWTEXT.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWTEXT.Zoom.Type , Value:g_JSChartResource.DRAWTEXT.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWTEXT.FontName,
YOffset:g_JSChartResource.DRAWTEXT.YOffset
}
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true)
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
this.Canvas.save();
this.ClipClient(isHScreen);
if (isHScreen)
{
chartright=this.ChartBorder.GetBottom();
top=this.ChartBorder.GetRightEx();
bottom=this.ChartBorder.GetLeftEx();
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
var xPointCount=this.ChartFrame.XPointCount;
var isArrayText=Array.isArray(this.Text);
var drawTextInfo={ Text:{ Color:this.Color, Align:this.TextAlign, Baseline:this.TextBaseline }, Font:{ } };
if (this.FixedFontSize>0) //固定字体大小模式
this.TextFont=`${this.FixedFontSize}px ${this.TextSize.FontName}`;
else //动态字体大小
this.TextFont=this.GetDynamicFont(dataWidth,distanceWidth,this.TextSize.Max,this.TextSize.Min,this.TextSize.Zoom,this.TextSize.FontName);
this.Canvas.font=this.TextFont;
drawTextInfo.Font={ Height:this.GetFontHeight() };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
var y;
if (this.FixedPosition===1)
{
y=top;
}
else if (this.FixedPosition===2)
{
y=bottom;
}
else
{
y=this.ChartFrame.GetYFromData(value,false);
}
if (x>chartright) break;
y+=this.ShowOffset.Y;
x+=this.ShowOffset.X;
drawTextInfo.X=x;
drawTextInfo.Y=y;
if (isArrayText)
{
var text=this.Text[i];
if (!text) continue;
this.DrawText(text,drawTextInfo,isHScreen);
}
else
{
this.DrawText(this.Text,drawTextInfo,isHScreen);
}
this.DrawVerticalLine(i, drawTextInfo, isHScreen);
}
this.Canvas.restore();
}
this.DrawText=function(text, drawInfo, isHScreen)
{
var textWidth=this.Canvas.measureText(text).width;
if (isHScreen)
{
var x=drawInfo.Y;
var y=drawInfo.X;
if (drawInfo.Text.Align=="right") y=y-textWidth;
else if (drawInfo.Text.Align=="center") y=y-textWidth/2;
if (drawInfo.Text.Baseline=="top") x-=drawInfo.Font.Height;
else if (drawInfo.Text.Baseline=="middle") x-=drawInfo.Font.Height/2;
if (this.TextBG && (this.TextBG.Color || this.TextBG.Border))
{
var margin=this.TextBG.Margin; //0=上 1=下 2=左 3=右
var xRect=x-margin[0];
var yRect=y-margin[2];
var bgWidth=textWidth+margin[2]+margin[3];
var bgHeight=drawInfo.Font.Height+margin[0]+margin[1];
if (this.TextBG.Color)
{
this.Canvas.fillStyle=this.TextBG.Color;
this.Canvas.fillRect(xRect,yRect,bgHeight,bgWidth);
}
if (this.TextBG.Border)
{
this.Canvas.strokeStyle=this.TextBG.Border;
this.Canvas.strokeRect(ToFixedPoint(xRect),ToFixedPoint(yRect),ToFixedRect(bgHeight),ToFixedRect(bgWidth));
}
drawInfo.Rect={Bottom:xRect, Top:xRect+bgHeight };
}
else
{
var xRect=x;
var bgHeight=drawInfo.Font.Height;
drawInfo.Rect={Bottom:xRect, Top:xRect+bgHeight };
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=drawInfo.Text.Color;
this.Canvas.save();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
var x=drawInfo.X;
var y=drawInfo.Y;
if (drawInfo.Text.Align=="right") x=x-textWidth;
else if (drawInfo.Text.Align=="center") x=x-textWidth/2;
if (drawInfo.Text.Baseline=="top") y+=drawInfo.Font.Height;
else if (drawInfo.Text.Baseline=="middle") y+=drawInfo.Font.Height/2;
if (this.TextBG && (this.TextBG.Color || this.TextBG.Border))
{
var margin=this.TextBG.Margin; //0=上 1=下 2=左 3=右
var xRect=x-margin[2];
var yRect=y-drawInfo.Font.Height-margin[1];
var bgWidth=textWidth+margin[2]+margin[3];
var bgHeight=drawInfo.Font.Height+margin[0]+margin[1];
if (this.TextBG.Color)
{
this.Canvas.fillStyle=this.TextBG.Color;
this.Canvas.fillRect(xRect,yRect,bgWidth,bgHeight);
}
if (this.TextBG.Border)
{
this.Canvas.strokeStyle=this.TextBG.Border;
this.Canvas.strokeRect(ToFixedPoint(xRect),ToFixedPoint(yRect),ToFixedRect(bgWidth),ToFixedRect(bgHeight));
}
drawInfo.Rect={Top:yRect, Bottom:yRect+bgHeight };
}
else
{
var yRect=y-drawInfo.Font.Height;
var bgHeight=drawInfo.Font.Height;
drawInfo.Rect={Top:yRect, Bottom:yRect+bgHeight };
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=drawInfo.Text.Color;
this.Canvas.fillText(text,x,y);
}
}
//画连线
this.DrawVerticalLine=function(index, drawTextInfo, isHScreen)
{
if (!this.VerticalLine) return;
var item=this.VerticalLine.Data[index];
if (!item) return;
if (!IFrameSplitOperator.IsNumber(item.High)) return;
if (!IFrameSplitOperator.IsNumber(item.Low)) return;
var yHigh=this.ChartFrame.GetYFromData(item.High);
var yLow=this.ChartFrame.GetYFromData(item.Low);
var yLine, yLine2;
if (isHScreen)
{
if (drawTextInfo.Rect.Bottom>yHigh)
{
yLine=drawTextInfo.Rect.Bottom-1;
yLine2=yHigh+1;
}
else if (drawTextInfo.Rect.Top<yLow)
{
yLine=drawTextInfo.Rect.Top-1;
yLine2=yLow-1;
}
else
{
return;
}
}
else
{
if (drawTextInfo.Rect.Bottom<yHigh)
{
yLine=drawTextInfo.Rect.Bottom+1;
yLine2=yHigh-1;
}
else if (drawTextInfo.Rect.Top>yLow)
{
yLine=drawTextInfo.Rect.Top-1;
yLine2=yLow+1;
}
else
{
return;
}
}
this.Canvas.save();
var pixelTatio = GetDevicePixelRatio();
var xLine=drawTextInfo.X;
if (this.VerticalLine.LineType==1)
{
if (this.VerticalLine.LineDotted)
this.Canvas.setLineDash(this.VerticalLine.LineDotted);
else
this.Canvas.setLineDash([5,10]);
}
if (IFrameSplitOperator.IsPlusNumber(this.VerticalLine.LineWidth))
{
this.Canvas.lineWidth=this.VerticalLine.LineWidth*pixelTatio;
}
this.Canvas.strokeStyle=this.VerticalLine.Color;
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(ToFixedPoint(yLine),ToFixedPoint(xLine));
this.Canvas.lineTo(ToFixedPoint(yLine2),ToFixedPoint(xLine));
}
else
{
this.Canvas.moveTo(ToFixedPoint(xLine),ToFixedPoint(yLine));
this.Canvas.lineTo(ToFixedPoint(xLine),ToFixedPoint(yLine2));
}
this.Canvas.stroke();
this.Canvas.restore();
}
}
function ChartDrawNumber()
{
this.newMethod=ChartDrawText; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawNumber'; //类名
this.ReloadResource=function(resource)
{
this.TextSize=
{
Max: g_JSChartResource.DRAWNUMBER.MaxSize, Min:g_JSChartResource.DRAWNUMBER.MinSize, //字体的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWNUMBER.Zoom.Type , Value:g_JSChartResource.DRAWNUMBER.Zoom.Value }, //放大倍数
FontName:g_JSChartResource.DRAWNUMBER.FontName,
YOffset:g_JSChartResource.DRAWNUMBER.YOffset
}
}
}
//直线 水平直线 只有1个数据
function ChartStraightLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartStraightLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.Draw=function()
{
if (!this.Data || !this.Data.Data) return;
if (this.Data.Data.length!=1) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
var yValue=this.Data.Data[0];
var y=this.ChartFrame.GetYFromData(yValue);
var xLeft=this.ChartFrame.GetXFromIndex(0);
var xRight=this.ChartFrame.GetXFromIndex(xPointCount-1);
var yFix=parseInt(y.toString())+0.5;
this.Canvas.beginPath();
this.Canvas.moveTo(xLeft,yFix);
this.Canvas.lineTo(xRight,yFix);
this.Canvas.strokeStyle=this.Color;
this.Canvas.stroke();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if (!this.Data || !this.Data.Data) return range;
if (this.Data.Data.length!=1) return range;
range.Min=this.Data.Data[0];
range.Max=this.Data.Data[0];
return range;
}
}
/*
水平面积 只有1个数据
Data 数据结构
Value, Value2 区间最大最小值
Color=面积的颜色
Title=标题 TitleColor=标题颜色
支持横屏
*/
function ChartStraightArea()
{
this.newMethod = IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartStraightArea'; //类名
this.Color = "rgb(255,193,37)"; //线段颜色
this.Font ='11px 微软雅黑';
this.Draw = function ()
{
if (this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
if (this.ChartFrame.IsHScreen===true)
{
this.HScreenDraw();
return;
}
var dataWidth = this.ChartFrame.DataWidth;
var distanceWidth = this.ChartFrame.DistanceWidth;
var chartright = this.ChartBorder.GetRight();
var bottom = this.ChartBorder.GetBottom();
var left = this.ChartBorder.GetLeft();
var xPointCount = this.ChartFrame.XPointCount;
var xRight = this.ChartFrame.GetXFromIndex(xPointCount - 1);
for(let i in this.Data.Data)
{
let item=this.Data.Data[i];
if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue;
if (item.Color==null) continue;
let valueMax=Math.max(item.Value,item.Value2);
let valueMin=Math.min(item.Value,item.Value2);
var yTop=this.ChartFrame.GetYFromData(valueMax);
var yBottom=this.ChartFrame.GetYFromData(valueMin);
this.Canvas.fillStyle = item.Color;
this.Canvas.fillRect(ToFixedRect(left), ToFixedRect(yTop), ToFixedRect(xRight - left), ToFixedRect(yBottom - yTop));
if(item.Title && item.TitleColor)
{
this.Canvas.textAlign = 'right';
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle = item.TitleColor;
this.Canvas.font = this.Font;
let y = yTop + (yBottom - yTop)/2;
this.Canvas.fillText(item.Title, xRight, y);
}
}
}
this.HScreenDraw=function()
{
var bottom = this.ChartBorder.GetBottom();
var top=this.ChartBorder.GetTop();
var height=this.ChartBorder.GetHeight();
for(let i in this.Data.Data)
{
let item=this.Data.Data[i];
if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue;
if (item.Color==null) continue;
let valueMax=Math.max(item.Value,item.Value2);
let valueMin=Math.min(item.Value,item.Value2);
var yTop=this.ChartFrame.GetYFromData(valueMax);
var yBottom=this.ChartFrame.GetYFromData(valueMin);
this.Canvas.fillStyle = item.Color;
this.Canvas.fillRect(ToFixedRect(yBottom), ToFixedRect(top), ToFixedRect(yTop-yBottom),ToFixedRect(height));
if(item.Title && item.TitleColor)
{
var xText=yTop + (yBottom - yTop)/2;
var yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.textAlign = 'right';
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle = item.TitleColor;
this.Canvas.font = this.Font;
this.Canvas.fillText(item.Title, 0, -2);
this.Canvas.restore();
}
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if (!this.Data || !this.Data.Data) return range;
for (let i in this.Data.Data)
{
let item = this.Data.Data[i];
if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue;
let valueMax=Math.max(item.Value,item.Value2);
let valueMin=Math.min(item.Value,item.Value2);
if (range.Max==null) range.Max=valueMax;
if (range.Min==null) range.Min=valueMin;
if (range.Max<valueMax) range.Max=valueMax;
if (range.Min>valueMin) range.Min=valueMin;
}
return range;
}
}
//分钟线 支持横屏
function ChartMinutePriceLine()
{
this.newMethod=ChartLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartMinutePriceLine'; //类名
this.YClose;
this.IsDrawArea=true; //是否画价格面积图
this.AreaColor='rgba(0,191,255,0.1)';
this.IsShowLead=false;
this.LeadData;
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.BeforeOpenData; //盘前数据 Data:[] 数据, TotalCount:一共的数据个数
this.BeforeLineColor=g_JSChartResource.Minute.Before.LineColor;
this.BeforeAvPriceColor=g_JSChartResource.Minute.Before.AvPriceColor;
this.BeforePoint=CloneData(g_JSChartResource.Minute.Before.Point);
this.AfterCloseData; //盘后数据
this.AfterLineColor=g_JSChartResource.Minute.After.LineColor;
this.AfterAvPriceColor=g_JSChartResource.Minute.After.AvPriceColor;
this.AfterPoint=CloneData(g_JSChartResource.Minute.After.Point);
this.MultiDayBeforeOpenData; //多日分时图 盘前数据 数组 1天一个
this.MultiDayAfterCloseData; //多日分时图 盘后数据 数组 1天一个
this.ColorLineData; //自定义价格线分段颜色
this.Source; //原始分钟数据
this.PtInChart=this.PtInLine;
this.DrawSelectedStatus=this.DrawLinePoint;
this.PtInChart=this.PtInLine;
this.DrawSelectedStatus=this.DrawLinePoint;
this.DayOffset;
this.LastPoint={}; //最后一个点的信息 {X, Y, Data:, Value:, DateTime:YYYYMMDDHHMMSS }
this.FFMChart; //定制图形
this.DrawType=0; //0=走势图 14=定制图形
this.UpdateLastPoint=function(dateTime, x,y, item)
{
if (IFrameSplitOperator.IsNumber(this.LastPoint.DateTime) && this.LastPoint.DateTime>dateTime) return;
this.LastPoint.DateTime=dateTime;
this.LastPoint.X=x;
this.LastPoint.Y=y;
this.LastPoint.Data=item;
this.LastPoint.Value=item.Value;
}
this.Draw=function()
{
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
this.LastPoint={};
if (!this.IsShow) return;
if (this.DrawType==14)
{
if (this.FFMChart && this.FFMChart.Draw)
this.FFMChart.Draw(this);
return;
}
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
var bottom=this.ChartBorder.GetBottom();
var left=this.ChartBorder.GetLeft();
var data=this.Data;
this.DrawBeforeOpen(); //盘前
this.DrawMultiDayBeforeOpen();
if (this.IsShowLead) this.DrawLead(); //领先指标
if (!data) return;
var bFirstPoint=true;
var ptFirst={}; //第1个点
var drawCount=0;
var pointCount=0;
this.Canvas.save();
if (IFrameSplitOperator.IsPlusNumber(this.LineWidth>0)) this.Canvas.lineWidth=this.LineWidth;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
value=data.Data[i];
++pointCount;
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={X:x,Y:y};
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
if (this.Source)
{
var item=this.Source.Data[i];
var dateTime=item.Date*1000000+item.Time*100;
this.UpdateLastPoint(dateTime, x,y, { Value:value, Index:i, Date:item.Date, Time:item.Time, Type:0, Explain:"盘中"});
}
++drawCount;
if (pointCount>=minuteCount) //上一天的数据和这天地数据线段要断开
{
bFirstPoint=true;
this.Canvas.stroke();
if (this.IsDrawArea) //画面积
{
if (isHScreen)
{
this.Canvas.lineTo(left,x);
this.Canvas.lineTo(left,ptFirst.X);
this.SetFillStyle(this.AreaColor,this.ChartBorder.GetRightEx(),bottom,this.ChartBorder.GetLeftEx(),bottom);
}
else
{
this.Canvas.lineTo(x,bottom);
this.Canvas.lineTo(ptFirst.X,bottom);
this.SetFillStyle(this.AreaColor, left,this.ChartBorder.GetTopEx(), left,bottom);
}
this.Canvas.fill();
}
pointCount=0;
drawCount=0;
}
}
if (drawCount>0)
{
if (drawCount==1) //如果线段只有1个点 线段无法画出来 直接画点
{
this.Canvas.beginPath();
if (isHScreen)
this.Canvas.arc(ptFirst.Y, ptFirst.X, 1,0,360, false);
else
this.Canvas.arc(ptFirst.X, ptFirst.Y, 1,0,360, false);
this.Canvas.closePath();
this.Canvas.fillStyle=this.Color;
this.Canvas.fill();
}
else
{
this.Canvas.stroke();
if (this.IsDrawArea) //画面积
{
if (isHScreen)
{
this.Canvas.lineTo(left,x);
this.Canvas.lineTo(left,ptFirst.X);
this.SetFillStyle(this.AreaColor,this.ChartBorder.GetRightEx(),bottom,this.ChartBorder.GetLeftEx(),bottom);
}
else
{
this.Canvas.lineTo(x,bottom);
this.Canvas.lineTo(ptFirst.X,bottom);
this.SetFillStyle(this.AreaColor,left,this.ChartBorder.GetTopEx(), left,bottom);
}
this.Canvas.fill();
}
}
}
this.Canvas.restore();
this.DrawColorLine();
this.DrawAfterClose(); //收盘集合竞价
this.DrawMultiDayAfterClose();
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_MINUTE_LAST_POINT);
if (event)
{
var pixelRatio=GetDevicePixelRatio();
var data=
{
InterLastPoint:{X:this.LastPoint.X, Y:this.LastPoint.Y}, //内部点 给画布用
LastPoint:{X:this.LastPoint.X/pixelRatio, Y:this.LastPoint.Y/pixelRatio}, //外部点 给DOM用
Price:this.LastPoint.Price, Data:this.LastPoint.Data,
PixelRatio:pixelRatio,
};
event.Callback(event,data,this);
}
}
}
//画领先指标
this.DrawLead=function()
{
if (!this.LeadData) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
//if (isHScreen) return;
//var dataWidth=this.ChartFrame.DataWidth;
//var distanceWidth=this.ChartFrame.DistanceWidth;
//var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
var bottom=this.ChartBorder.GetBottomEx();
var top=this.ChartBorder.GetTopEx();
if (isHScreen===true) top=this.ChartBorder.GetRightEx();
if (xPointCount>minuteCount) return;
var aryLead=[]; //{X: Value:}
var max=null, min=null;
var yCenter=this.ChartFrame.GetYFromData(this.YClose);
var leadHeight=(yCenter-top)/3;
var data=this.LeadData;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (value==0) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (max==null || max<value) max=value;
if (min==null || min>value) min=value;
aryLead.push({X:x, Value:value})
}
if (aryLead.length<=0) return;
var maxValue=Math.max(Math.abs(max),Math.abs(min));
for(var i in aryLead)
{
var item=aryLead[i];
if (item.Value>0) this.Canvas.strokeStyle=this.UpColor;
else this.Canvas.strokeStyle=this.DownColor;
var y=yCenter-(item.Value*leadHeight/maxValue);
var x=ToFixedPoint(item.X);
this.Canvas.beginPath();
if (isHScreen===true)
{
this.Canvas.moveTo(yCenter,x);
this.Canvas.lineTo(y,x);
}
else
{
this.Canvas.moveTo(x,yCenter);
this.Canvas.lineTo(x,y);
}
this.Canvas.stroke();
}
}
this.DrawBeforeOpen=function()
{
if (this.ChartBorder.LeftExtendWidth<10) return;
if (!this.BeforeOpenData) return;
this.DrawCallAuction(-1, this.BeforeOpenData, true);
}
this.DrawAfterClose=function()
{
if (this.ChartBorder.RightExtendWidth<10) return;
if (!this.AfterCloseData) return;
this.DrawCallAuction(-1, this.AfterCloseData, false);
}
this.DrawMultiDayBeforeOpen=function()
{
if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Left<=0) return;
if (!this.MultiDayBeforeOpenData) return;
var offset=0, showDayCount=this.MultiDayBeforeOpenData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
for(var i=offset,j=0; i<this.MultiDayBeforeOpenData.length && j<showDayCount; ++i,++j)
{
var dayItem=this.MultiDayBeforeOpenData[i];
this.DrawCallAuction(j, dayItem, true);
}
}
this.DrawMultiDayAfterClose=function()
{
if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Right<=0) return;
if (!this.MultiDayAfterCloseData) return;
var offset=0,showDayCount=this.MultiDayAfterCloseData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
for(var i=offset,j=0; i<this.MultiDayAfterCloseData.length && j<showDayCount; ++i,++j)
{
var dayItem=this.MultiDayAfterCloseData[i];
this.DrawCallAuction(j, dayItem, false);
}
}
this.DrawCallAuction=function(indexDay, callAutionData, isBeforeOpen)
{
if (!callAutionData) return;
callAutionData.Index=indexDay;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var bFirstPoint=true;
var drawCount=0;
var callAutionInfo={ TotalCount:callAutionData.TotalCount };
if (callAutionData.Ver==3.0) //均线
{
for(var i=0; i<callAutionData.Data.length; ++i)
{
var item=callAutionData.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.AvPrice)) continue;
if (isBeforeOpen)
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(item.AvPrice);
}
else
{
var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetRightExtendYFromData(item.AvPrice);
}
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.BeforeAvPriceColor;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0)
{
this.Canvas.stroke();
}
}
var bFirstPoint=true;
var drawCount=0;
var aryPoint=[];
for(var i=0; i<callAutionData.Data.length; ++i)
{
var item=callAutionData.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Price))
{
if (i==0 && isBeforeOpen && IFrameSplitOperator.IsNumber(this.YClose))
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(this.YClose);
this.Canvas.strokeStyle=this.BeforeLineColor;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
continue;
}
if (isBeforeOpen)
{
var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetLeftExtendYFromData(item.Price);
}
else
{
var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
var y=this.ChartFrame.GetRightExtendYFromData(item.Price);
}
if (bFirstPoint)
{
this.Canvas.strokeStyle=(isBeforeOpen? this.BeforeLineColor:this.AfterLineColor);
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
aryPoint.push({X:x, Y:y });
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
aryPoint.push({X:x, Y:y });
}
var dateTime=item.Date*1000000+item.Time;
this.UpdateLastPoint(dateTime, x,y, { Value:item.Price, Index:i, Date:item.Date, Time:item.Time, Type:isBeforeOpen?1:2, Explain:isBeforeOpen?"盘前":"盘后"});
++drawCount;
}
if (drawCount>0)
{
this.Canvas.stroke();
}
if (callAutionData.Ver==2.0 && this.BeforePoint.Radius>0)
{
this.Canvas.fillStyle=(isBeforeOpen? this.BeforePoint.Color : this.AfterPoint.Color);
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.beginPath();
if (isHScreen) this.Canvas.arc(item.Y, item.X, this.BeforePoint.Radius, 0, 2 * Math.PI);
else this.Canvas.arc(item.X, item.Y, this.BeforePoint.Radius, 0, 2 * Math.PI);
this.Canvas.fill();
}
}
}
this.FindColorLineItem=function(minuteItem)
{
if (!minuteItem || !this.ColorLineData) return null;
for(var i in this.ColorLineData)
{
var item=this.ColorLineData[i];
if (item.Date==minuteItem.Date && (minuteItem.Time>=item.Start && minuteItem.Time<=item.End))
{
return item;
}
}
return null;
}
//TODO:这个函数比较耗时间 后面再优化吧
this.DrawColorLine=function()
{
if (!this.ColorLineData|| !this.Source || !this.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var border=this.ChartBorder.GetBorder();
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
var data=this.Data;
var bFirstPoint=true;
var ptLast={}; //最后一个点
var ptFirst={};
var drawCount=0;
var preColor=null;
this.Canvas.save();
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
value=data.Data[i];
var item=this.Source.Data[i];
if (!value || !item) continue;
var colorItem=this.FindColorLineItem(item);
if (!colorItem)
{
if (drawCount>0)
{
this.Canvas.stroke();
bFirstPoint=true;
}
continue;
}
if (preColor && preColor!=colorItem.Color)
{
this.Canvas.stroke();
bFirstPoint=true;
/*
this.Canvas.strokeStyle=colorItem.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(ptLast.Y,ptLast.X);
else this.Canvas.moveTo(ptLast.X,ptLast.Y);
bFirstPoint=false;
preColor=colorItem.Color;
*/
}
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.strokeStyle=colorItem.Color;
if (IFrameSplitOperator.IsNumber(colorItem.LineWidth))
this.Canvas.lineWidth=colorItem.LineWidth;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={X:x,Y:y};
preColor=colorItem.Color;
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
ptLast.X=x;
ptLast.Y=y;
ptLast.Price=value;
++drawCount;
}
if (drawCount>0)
{
this.Canvas.stroke();
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
if (this.DrawType==14)
{
if (this.FFMChart && this.FFMChart.GetMaxMin)
return this.FFMChart.GetMaxMin(this);
}
var xPointCount=this.ChartFrame.XPointCount;
var range={};
if (this.YClose==null) return range;
if (!this.IsShow) return range;
range.Min=this.YClose;
range.Max=this.YClose;
if (this.ChartBorder.LeftExtendWidth>10 && this.BeforeOpenData)
{
for(var i in this.BeforeOpenData.Data)
{
var item=this.BeforeOpenData.Data[i];
if (!item) continue;
if (IFrameSplitOperator.IsNumber(item.Price))
{
if (range.Max==null) range.Max=item.Price;
if (range.Min==null) range.Min=item.Price;
if (range.Max<item.Price) range.Max=item.Price;
if (range.Min>item.Price) range.Min=item.Price;
}
//集合竞价均线统计
if (this.BeforeOpenData.Ver==3.0 && IFrameSplitOperator.IsNumber(item.AvPrice))
{
if (range.Max==null) range.Max=item.AvPrice;
if (range.Min==null) range.Min=item.AvPrice;
if (range.Max<item.AvPrice) range.Max=item.AvPrice;
if (range.Min>item.AvPrice) range.Min=item.AvPrice;
}
}
}
//价格数据
var data=this.Data;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
value=data.Data[i];
if (value==null) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
if (range.Max==this.YClose && range.Min==this.YClose)
{
range.Max=this.YClose+this.YClose*0.1;
range.Min=this.YClose-this.YClose*0.1;
return range;
}
var distance=Math.max(Math.abs(this.YClose-range.Max),Math.abs(this.YClose-range.Min));
range.Max=this.YClose+distance;
range.Min=this.YClose-distance;
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
if (isHScreen) return false;
if (!this.IsShow) return false;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var position=this.ChartBorder.PtInClient(x,y,this.Canvas,isHScreen);
if (position!=1) return false;
var data=this.Data;
var index=this.ChartFrame.GetXData(x);
var end=Math.ceil(index);
var start=Math.floor(index);
if (end>=data.Data.length || start>=data.Data.length) return false;
var lineWidth=5;
if (end==start)
{
var value=data.Data[start];
}
else
{
var startValue=data.Data[start];
var endValue=data.Data[end];
var ptStart={X:this.ChartFrame.GetXFromIndex(start), Y:this.ChartFrame.GetYFromData(startValue)};
var ptEnd={X:this.ChartFrame.GetXFromIndex(end), Y:this.ChartFrame.GetYFromData(endValue)};
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
{
tooltip.Data={ Index:index, Start:{ Index:start, Item:data.Data[start] }, End:{ Index:end, Value:data.Data[end]} };
tooltip.ChartPaint=this;
tooltip.Type=5; //走势图线
return true;
}
}
return false;
}
}
//分钟线叠加 支持横屏
function ChartOverlayMinutePriceLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.Color="rgb(65,105,225)";
this.MainData; //主图数据
this.SourceData; //原始数据
this.ClassName="ChartOverlayMinutePriceLine";
this.Title;
this.Symbol; //叠加的股票代码
this.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
this.OverlayType=0; //叠加方式 0=百分比叠加 1=绝对叠加
this.IsCalcuateMaxMin=true; //是否参与计算Y轴的最大最小值
this.SetOption=function(option)
{
if (option)
{
if (IFrameSplitOperator.IsNumber(option.OverlayType)) this.OverlayType=option.OverlayType;
if (IFrameSplitOperator.IsBool(option.IsCalcuateMaxMin)) this.IsCalcuateMaxMin=option.IsCalcuateMaxMin;
}
}
this.PtInChart=function(x,y)
{
var option={ MinuteOverlayPrice:true, OverlayType:this.OverlayType };
return this.PtInLine(x, y, option);
}
this.DrawSelectedStatus=function()
{
var option={ MinuteOverlayPrice:true, OverlayType:this.OverlayType };
this.DrawLinePoint(option);
}
this.Draw=function()
{
if (!this.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
this.Canvas.save();
this.ClipClient(isHScreen);
var bFirstPoint=true;
var drawCount=0;
var xOffset=0, showValue=0;
var yClose=null, mainYClose=null;
var pointCount=0;
for(var i=this.Data.DataOffset+xOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item=this.Data.Data[i];
if (item && IFrameSplitOperator.IsNumber(item.Close))
{
if (bFirstPoint) //百分比使用每天的昨收计算
{
yClose=item.YClose;
var minItem=this.MainData.Data[i];
mainYClose=minItem.YClose;
}
var value=item.Close;
showValue=value; //绝对叠加
if (this.OverlayType==0)
showValue=value/yClose*mainYClose; //百分比
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(showValue, false);
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
}
++pointCount;
if (pointCount>=minuteCount) //上一天的数据和这天地数据线段要断开
{
bFirstPoint=true;
pointCount=0;
if (drawCount>0) this.Canvas.stroke();
drawCount=0;
}
}
if (drawCount>0) this.Canvas.stroke();
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={ Min:null, Max:null };
if (!this.IsCalcuateMaxMin) return range;
var minuteCount=this.ChartFrame.MinuteCount;
var yClose=null, mainYClose=null;
var bFirstPoint=true;
var pointCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item=this.Data.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Close))
{
++pointCount;
continue;
}
if (bFirstPoint)
{
yClose=item.YClose;
var minItem=this.MainData.Data[i];
mainYClose=minItem.YClose;
bFirstPoint=false;
}
var value=item.Close;
if (this.OverlayType==0) value=value/yClose*mainYClose;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
++pointCount;
if (pointCount>=minuteCount)
{
bFirstPoint=true;
pointCount=0;
}
}
//JSConsole.Chart.Log(`[ChartOverlayMinutePriceLine::GetMaxMin] max=${range.Max} min=${range.Min}`);
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
if (isHScreen) return false;
if (!this.IsShow) return false;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
if (!IFrameSplitOperator.IsNumber(this.YClose) || !IFrameSplitOperator.IsNumber(this.MainYClose)) return false;
var position=this.ChartBorder.PtInClient(x,y,this.Canvas,isHScreen);
if (position!=1) return false;
var data=this.Data;
var index=this.ChartFrame.GetXData(x);
var end=Math.ceil(index);
var start=Math.floor(index);
if (end>=data.Data.length || start>=data.Data.length) return false;
var lineWidth=5;
if (end==start)
{
var value=data.Data[start];
}
else
{
var startValue=data.Data[start].Close
startValue=startValue/this.YClose*this.MainYClose;
var endValue=data.Data[end].Close
endValue=endValue/this.YClose*this.MainYClose;
var ptStart={X:this.ChartFrame.GetXFromIndex(start), Y:this.ChartFrame.GetYFromData(startValue)};
var ptEnd={X:this.ChartFrame.GetXFromIndex(end), Y:this.ChartFrame.GetYFromData(endValue)};
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
{
tooltip.Data={ Index:index, Start:{ Index:start, Item:data.Data[start] }, End:{ Index:end, Value:data.Data[end]} };
tooltip.ChartPaint=this;
tooltip.Type=6; //走势图线
//tooltip.Stock={Symbol:this.Symbol, Name:this.Title };
return true;
}
}
return false;
}
}
//分钟持仓线
function ChartMinutePositionLine()
{
this.newMethod=ChartLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartMinutePositionLine'; //类名
this.Draw=function()
{
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.IsShow) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
var bottom=this.ChartBorder.GetBottomEx();
var left=this.ChartBorder.GetLeftEx();
var data=this.Data;
if (!data) return;
var bFirstPoint=true;
var ptFirst={}; //第1个点
var ptLast={}; //最后一个点
var drawCount=0;
var pointCount=0;
this.Canvas.save();
if (IFrameSplitOperator.IsPlusNumber(this.LineWidth>0)) this.Canvas.lineWidth=this.LineWidth;
if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
value=data.Data[i];
++pointCount;
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(y,x);
else this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={X:x,Y:y};
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
ptLast.X=x;
ptLast.Y=y;
ptLast.Price=value;
++drawCount;
if (pointCount>=minuteCount) //上一天的数据和这天地数据线段要断开
{
bFirstPoint=true;
this.Canvas.stroke();
pointCount=0;
drawCount=0;
}
}
if (drawCount>0)
{
if (drawCount==1) //如果线段只有1个点 线段无法画出来 直接画点
{
this.Canvas.beginPath();
if (isHScreen)
this.Canvas.arc(ptFirst.Y, ptFirst.X, 1,0,360, false);
else
this.Canvas.arc(ptFirst.X, ptFirst.Y, 1,0,360, false);
this.Canvas.closePath();
this.Canvas.fillStyle=this.Color;
this.Canvas.fill();
}
else
{
this.Canvas.stroke();
}
}
this.Canvas.restore();
}
}
//分钟信息地雷 支持横屏
function ChartMinuteInfo()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMinuteInfo";
this.Data=new Map() //Map key=date-time, value=[{Date, Time, Title, Type, ID:}]
this.SourceData;
this.ChartMinutePrice;
this.YClose;
this.HQChartBorder;
this.TextColor=g_JSChartResource.MinuteInfo.TextColor;
this.Font=g_JSChartResource.MinuteInfo.Font;
this.PointColor=g_JSChartResource.MinuteInfo.PointColor;
this.PointRadius=g_JSChartResource.MinuteInfo.PointRadius;
this.LineColor=g_JSChartResource.MinuteInfo.LineColor;
this.TextBGColor=g_JSChartResource.MinuteInfo.TextBGColor;
this.PixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.TextHeight=20;
this.TextRectCache=[];
this.InfoDrawCache=[];
this.FrameBottom;
this.FrameTop;
this.FrameLeft;
this.FrameRight;
this.YOffset=5;
this.IsHScreen=false;
this.IsDrawFull=false; //是否全屏画
this.TooltipRect=[]; //Rect
this.SetOption=function(option)
{
if (option.TextColor) this.TextColor=option.TextColor;
if (option.TextBGColor) this.TextBGColor=option.TextBGColor;
if (option.Font) this.Font=option.Font;
if (option.PointColor) this.PointColor=option.PointColor;
if (option.LineColor) this.LineColor=option.LineColor;
if (option.TextHeight>0) this.TextHeight=option.TextHeight;
if (option.IsDrawFull==true) this.IsDrawFull=true;
}
this.Draw=function()
{
this.TooltipRect=[];
if (!this.ChartMinutePrice) return;
if (!this.Data || this.Data.size<=0) return;
this.TextRectCache=[];
this.InfoDrawCache=[];
this.PixelTatio=GetDevicePixelRatio();
this.YOffset=5*this.PixelTatio;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var minuteCount=this.ChartFrame.MinuteCount;
this.FrameBottom=this.ChartBorder.GetBottom();
if (this.IsDrawFull && this.HQChartBorder) this.FrameBottom=this.HQChartBorder.GetBottom();
this.FrameTop=this.ChartBorder.GetTop();
this.FrameLeft=this.ChartBorder.GetLeft();
this.FrameRight=this.ChartBorder.GetRight();
if (this.IsHScreen)
{
this.FrameRight=this.ChartBorder.GetBottom();
this.FrameLeft=this.ChartBorder.GetTop();
this.FrameBottom=this.ChartBorder.GetLeft();
this.FrameTop=this.ChartBorder.GetRight();
}
this.YClose=this.ChartMinutePrice.YClose;
var data=this.ChartMinutePrice.Source;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var item=data.Data[i];
if (!item) continue;
var dateTime=item.DateTime;
if (!this.Data.has(dateTime)) continue;
if (this.IsHScreen)
this.CalcuateInfoHScreenPosition(this.Data.get(dateTime), j, item);
else
this.CalcuateInfoPosition(this.Data.get(dateTime), j, item);
}
for(var i in this.InfoDrawCache)
{
var item=this.InfoDrawCache[i];
this.DrawInfoLines(item);
}
for(var i in this.InfoDrawCache)
{
var item=this.InfoDrawCache[i];
this.DrawInfoText(item);
if (!this.IsHScreen)
{
var rtBorder=item.Border;
var textRect=new Rect(rtBorder.X,rtBorder.Y,rtBorder.Width,rtBorder.Height);
var tooltipData={ Data:{ Item:item }, Rect:textRect };
this.TooltipRect.push(tooltipData);
}
}
this.TextRectCache=[];
this.InfoDrawCache=[];
}
this.CalcuateInfoPosition=function(infoItem, index, minuteItem)
{
if (!infoItem || !infoItem.Data || infoItem.Data.length<=0) return;
var showItem=infoItem.Data[0];
this.Canvas.font = this.Font;
var textWidth=this.Canvas.measureText(showItem.Title).width+4*this.PixelTatio;
var textHeight=this.TextHeight*this.PixelTatio;
var x=this.ChartFrame.GetXFromIndex(index);
var y;
if (IFrameSplitOperator.IsNumber(showItem.Price)) y=this.ChartFrame.GetYFromData(showItem.Price);
else y=this.ChartFrame.GetYFromData(minuteItem.Close);
x=ToFixedPoint(x);
var isDrawLeft=x<(this.FrameLeft+Math.abs(this.FrameLeft-this.FrameRight)/2);
var ARRAY_OFFSET=[2,4,6,8,3,5,7];
var offset=textHeight+ARRAY_OFFSET[index%ARRAY_OFFSET.length]*this.PixelTatio;
var yData=
{
Y:
[
{Value:y+(textHeight+this.YOffset), Offset: offset},
{Value:y-(2*textHeight+this.YOffset), Offset:-offset}
]
};
if (minuteItem.Close<this.YClose)
yData.Y=yData.Y.reverse();
var rtBorder={X:x, Y:null, Width:textWidth,Height:textHeight};
if (!isDrawLeft) rtBorder.X-=rtBorder.Width;
this.FixTextRect(rtBorder,yData);
var InfoDrawItem= { Border:rtBorder, Start:{X:x,Y:y}, IsLeft:isDrawLeft, Title:showItem.Title, Date:showItem.Date, Time:showItem.Time };
if (showItem.Content) InfoDrawItem.Content=showItem.Content;
if (showItem.Link) InfoDrawItem.Link=showItem.Link;
if (showItem.Color) InfoDrawItem.Color=showItem.Color;
if (showItem.BGColor) InfoDrawItem.BGColor=showItem.BGColor;
this.InfoDrawCache.push(InfoDrawItem);
this.TextRectCache.push(rtBorder);
}
this.CalcuateInfoHScreenPosition=function(infoItem, index, minuteItem)
{
if (!infoItem || !infoItem.Data || infoItem.Data.length<=0) return;
var showItem=infoItem.Data[0];
this.Canvas.font = this.Font;
var textHeight=this.Canvas.measureText(showItem.Title).width+4*this.PixelTatio;
var textWidth=this.TextHeight*this.PixelTatio;
var y=this.ChartFrame.GetXFromIndex(index);
var x;
if (IFrameSplitOperator.IsNumber(showItem.Price)) x=this.ChartFrame.GetYFromData(showItem.Price);
else x=this.ChartFrame.GetYFromData(minuteItem.Close);
y=ToFixedPoint(y);
var isDrawLeft=y<(this.FrameLeft+Math.abs(this.FrameLeft-this.FrameRight)/2);
var ARRAY_OFFSET=[2,4,6,8,3,5,7];
var offset=textWidth+ARRAY_OFFSET[index%ARRAY_OFFSET.length]*this.PixelTatio;
var xData=
{
X:
[
{Value:x+(textWidth+this.YOffset), Offset: offset},
{Value:x-(2*textWidth+this.YOffset), Offset:-offset}
]
};
if (minuteItem.Close>this.YClose)
xData.X=xData.X.reverse();
var rtBorder={X:null, Y:y, Width:textWidth,Height:textHeight};
if (!isDrawLeft) rtBorder.Y-=rtBorder.Height;
this.FixHScreenTextRect(rtBorder,xData);
var InfoDrawItem={ Border:rtBorder, Start:{X:x,Y:y}, IsLeft:isDrawLeft, Title:showItem.Title };
if (showItem.Content) InfoDrawItem.Content=showItem.Content;
if (showItem.Link) InfoDrawItem.Link=showItem.Link;
if (showItem.Color) InfoDrawItem.Color=showItem.Color;
if (showItem.BGColor) InfoDrawItem.BGColor=showItem.BGColor;
this.InfoDrawCache.push(InfoDrawItem);
this.TextRectCache.push(rtBorder);
}
this.DrawInfoLines=function(item)
{
var rtBorder=item.Border;
var isDrawLeft=item.IsLeft;
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(item.Start.X),item.Start.Y);
if (isDrawLeft)
{
this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y);
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(rtBorder.X,rtBorder.Y+rtBorder.Height);
else this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y);
}
this.Canvas.stroke();
this.Canvas.fillStyle = this.PointColor;
this.Canvas.beginPath();
this.Canvas.arc(item.Start.X,item.Start.Y, this.PointRadius, 0, 2 * Math.PI);
this.Canvas.closePath();
this.Canvas.fill();
}
this.DrawInfoText=function(item)
{
var rtBorder=item.Border;
var x=rtBorder.X, y=rtBorder.Y;
if (item.BGColor) this.Canvas.fillStyle=item.BGColor
else this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(x, y, rtBorder.Width,rtBorder.Height);
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.rect(x,y,rtBorder.Width,rtBorder.Height);
this.Canvas.stroke();
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(rtBorder.X,rtBorder.Y);
this.Canvas.rotate(90 * Math.PI / 180);
x=0;y=0;
}
this.Canvas.textAlign = 'left'
this.Canvas.textBaseline = 'middle';
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle = this.TextColor;
this.Canvas.font = this.Font;
if (this.IsHScreen) this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y-rtBorder.Width/2);
else this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y+rtBorder.Height/2);
if (this.IsHScreen) this.Canvas.restore();
}
this.FixTextRect=function(rect,yData)
{
for(var k in yData.Y)
{
var yItem=yData.Y[k];
rect.Y=yItem.Value;
var y;
for(var j=0;j<10;++j)
{
var isOverlap=false;
for(var i in this.TextRectCache)
{
var item=this.TextRectCache[i];
if (this.IsOverlap(item, rect))
{
isOverlap=true;
break;
}
}
if (isOverlap==false) return;
y=rect.Y;
y+=yItem.Offset;
if (y+rect.Height>this.FrameBottom || y<this.FrameTop) break;
rect.Y=y;
}
}
}
this.FixHScreenTextRect=function(rect,xData)
{
for(var k in xData.X)
{
var xItem=xData.X[k];
rect.X=xItem.Value;
var x;
for(var j=0;j<10;++j)
{
var isOverlap=false;
for(var i in this.TextRectCache)
{
var item=this.TextRectCache[i];
if (this.IsOverlap(item, rect))
{
isOverlap=true;
break;
}
}
if (isOverlap==false) return;
x=rect.X;
x+=xItem.Offset;
if (x+rect.Width<this.FrameBottom || x>this.FrameTop) break;
rect.X=x;
}
}
}
this.IsOverlap=function(rc1, rc2)
{
if (rc1.X + rc1.Width > rc2.X &&rc2.X + rc2.Width > rc1.X &&rc1.Y + rc1.Height > rc2.Y &&rc2.Y + rc2.Height > rc1.Y)
return true;
else
return false;
}
this.GetMaxMin=function()
{
var range={Min:null, Max:null};
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
for(var i in this.TooltipRect)
{
var item=this.TooltipRect[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
//JSConsole.Chart.Log('[ChartMinuteInfo::GetTooltipData] info ', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=3; //异动信息
return true;
}
}
return false;
}
}
//MACD森林线 支持横屏
function ChartMACD()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMACD";
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.LineWidth=1;
this.DrawSelectedStatus=this.DrawLinePoint;
this.ExportData=this.ExportArrayData;
this.PtInChart=function(x,y)
{
var dataWidth=this.ChartFrame.DataWidth;
var barWidth=this.LineWidth*GetDevicePixelRatio();
if (this.barWidth==50) barWidth=null;
else if (barWidth>dataWidth) barWidth=dataWidth;
if (barWidth<4) barWidth=4; //宽度太小了点不到
return this.PtInBar(x, y, { BarWidth:barWidth })
}
this.DrawBars=function(lineWidth, bUpBar)
{
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var isHSCreen=this.ChartFrame.IsHScreen===true;
if (isHSCreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Top;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Left;
}
if (bUpBar) this.Canvas.strokeStyle=this.UpColor;
else this.Canvas.strokeStyle=this.DownColor;
var yBottom=this.ChartFrame.GetYFromData(0);
this.Canvas.beginPath();
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
if (bUpBar)
{
if (value<0) continue;
}
else
{
if (value>=0) continue;
}
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (x>chartright) break;
var y=this.ChartFrame.GetYFromData(value);
var xFix=ToFixedPoint2(lineWidth, x); //毛边修正
if (isHSCreen)
{
this.Canvas.moveTo(yBottom,ToFixedPoint(x));
this.Canvas.lineTo(y,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(xFix,yBottom);
this.Canvas.lineTo(xFix,y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var lineWidth=this.LineWidth*GetDevicePixelRatio();
if (this.LineWidth==50) lineWidth=dataWidth;
else if (lineWidth>dataWidth) lineWidth=dataWidth;
var backupLineWidth=this.Canvas.lineWidth;
this.Canvas.lineWidth=lineWidth;
//上下分开画
this.DrawBars(lineWidth, true);
this.DrawBars(lineWidth, false);
this.Canvas.lineWidth=backupLineWidth;
}
this.GetItemData=function(indexData)
{
if (!indexData) return null;
if (!IFrameSplitOperator.IsNumber(indexData.Index)) return null;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var index=indexData.Index;
if (index<0 || index>=this.Data.Data.length) return null;
var item=this.Data.Data[index];
return [ { Value:item, Color:item>0 ? this.UpColor:this.DownColor, Name: this.Name } ];
}
}
function ChartClipColorStick()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartClipColorStick";
this.UpColor=g_JSChartResource.UpBarColor;
this.DownColor=g_JSChartResource.DownBarColor;
this.LineWidth=1;
this.Style=0; //1=同方向 0=上下两个方向
//差值线
this.DownDiffColor=g_JSChartResource.DownBarColor;
this.UpDiffColor=g_JSChartResource.UpBarColor;
//文字
this.TextLabelConfig=
{
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
TextMargin:{ Left:2, Right:2, Bottom:2, Top:2 },
TextColor:"rgb(230,230,230)",
UpColor:"rgb(137,16,19)",
DownColor:"rgb(44,104,57)",
UnchangeColor:"rgb(111,112,115)",
BorderColor:"rgb(0,0,0)",
//缓存
LabelWidth:0,
TextHeight:0,
MaxTextWidth:0,
}
this.BaseLineColor; //基准线
this.BaseValue=0;
this.Super_GetMaxMin=this.GetMaxMin; //父类的方法
this.ValueRange; //{ Max:, Min: } //固定最大最小值
this.IsShowText=false;
this.SetOption=function(option)
{
if (!option) return;
if (option.UpColor) this.UpColor=option.UpColor;
if (option.DownColor) this.DownColor=option.DownColor;
if (option.DownDiffColor) this.DownDiffColor=option.DownDiffColor;
if (option.UpDiffColor) this.UpDiffColor=option.UpDiffColor;
if (option.BaseLineColor) this.BaseLineColor=option.BaseLineColor;
if (IFrameSplitOperator.IsNumber(option.BaseValue)) this.BaseValue=option.BaseValue;
if (IFrameSplitOperator.IsNumber(option.Style)) this.Style=option.Style;
if (option.ValueRange) this.ValueRange=option.ValueRange;
}
this.Draw=function()
{
this.IsShowText=false;
this.TextLabelConfig.LabelWidth=0;
this.TextLabelConfig.TextHeight=0;
this.TextLabelConfig.MaxTextWidth=0;
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var bHScreen=this.ChartFrame.IsHScreen===true;
var lineWidth=this.LineWidth*GetDevicePixelRatio();
if (this.LineWidth==50) lineWidth=dataWidth;
else if (lineWidth>dataWidth) lineWidth=dataWidth;
if (!bHScreen)
{
var itemWidth=dataWidth+distanceWidth;
var bMinute=this.IsMinuteFrame();
if (bMinute)
{
var border=this.ChartBorder.GetBorder();
itemWidth=(border.Right-border.Left)/(xPointCount-1);
}
this.Canvas.font=this.TextLabelConfig.Font;
this.TextLabelConfig.MaxTextWidth=this.Canvas.measureText("-888").width;
this.TextLabelConfig.LabelWidth=this.TextLabelConfig.MaxTextWidth+this.TextLabelConfig.TextMargin.Left+this.TextLabelConfig.TextMargin.Right;
this.IsShowText=itemWidth>this.TextLabelConfig.LabelWidth;
this.TextLabelConfig.TextHeight=this.Canvas.measureText("擎").width;
}
this.Canvas.save();
if (IFrameSplitOperator.IsNumber(this.BaseValue) && this.BaseValue!=0)
{
this.DrawBaseLine();
if (this.BaseValue>0) this.DrawBars(lineWidth, true, true);
else this.DrawBars(lineWidth, false, true);
}
else
{
//上下分开画
this.DrawBars(lineWidth, true, true);
this.DrawBars(lineWidth, false);
}
this.Canvas.restore();
}
this.DrawBars=function(lineWidth, bUpBar, bDrawLabel)
{
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var bHScreen=this.ChartFrame.IsHScreen===true;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Top;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Left;
}
var yBottom=this.ChartFrame.GetYFromData(this.BaseValue);
var aryBar=[], aryDiffBar=[], aryText=[];
var preValue=null;
var start=this.Data.DataOffset;
if (start-1>0) preValue=this.Data.Data[start-1]; //上一个数值
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (x>chartright) break;
var textItem={ X:x, Value:value };
if (IFrameSplitOperator.IsNumber(preValue)) textItem.DiffValue=value-preValue;
aryText.push(textItem);
preValue=value;
if (bUpBar)
{
if (value<0) continue;
}
else
{
if (value>=0) continue;
}
var bDiffBar=false;
var diffValue=null;
if (this.BaseValue>0)
{
if (value<this.BaseValue)
{
bDiffBar=true;
if (this.Style==1)
diffValue=this.BaseValue+(this.BaseValue-value);
else
diffValue=this.BaseValue-(this.BaseValue-value);
}
}
else if (this.BaseValue<0)
{
if (value>this.BaseValue)
{
bDiffBar=true;
if (this.Style==1)
diffValue=this.BaseValue-(value-this.BaseValue);
else
diffValue=this.BaseValue+(value-this.BaseValue)
}
}
if (!bDiffBar)
{
var y=this.ChartFrame.GetYFromData(value);
aryBar.push({X:x, Y:y });
}
else
{
var y=this.ChartFrame.GetYFromData(diffValue);
aryDiffBar.push({X:x, Y:y });
}
}
this.Canvas.lineWidth=lineWidth;
if (bUpBar) this.Canvas.strokeStyle=this.UpColor;
else this.Canvas.strokeStyle=this.DownColor;
this.DrawStick(aryBar,lineWidth,yBottom);
if (this.BaseValue>0)
{
this.Canvas.strokeStyle=this.UpDiffColor;
this.DrawStick(aryDiffBar,lineWidth,yBottom);
}
else if (this.BaseValue<0)
{
this.Canvas.strokeStyle=this.DownDiffColor;
this.DrawStick(aryDiffBar,lineWidth,yBottom);
}
if (this.IsShowText && bDrawLabel) this.DrawStickText(aryText);
}
this.DrawStick=function(aryData, lineWidth, yBottom)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryData)) return;
var bHScreen=this.ChartFrame.IsHScreen===true;
var drawCount=0;
this.Canvas.beginPath();
for(var i=0; i<aryData.length; ++i)
{
var item=aryData[i];
var y=item.Y;
var xFix=ToFixedPoint2(lineWidth, item.X); //毛边修正
if (bHScreen)
{
this.Canvas.moveTo(yBottom,ToFixedPoint(x));
this.Canvas.lineTo(y,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(xFix,yBottom);
this.Canvas.lineTo(xFix,y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
}
this.DrawBaseLine=function()
{
if (!IFrameSplitOperator.IsNumber(this.BaseValue) || this.BaseValue==0) return;
if (!this.BaseLineColor) return;
var bHScreen=this.ChartFrame.IsHScreen===true;
var border=this.ChartFrame.GetBorder();
var y=this.ChartFrame.GetYFromData(this.BaseValue);
this.Canvas.strokeStyle=this.BaseLineColor;
this.Canvas.lineWidth=1*GetDevicePixelRatio();
if (bHScreen)
{
}
else
{
var yFix=ToFixedPoint(y);
this.Canvas.beginPath();
this.Canvas.moveTo(border.Left,yFix);
this.Canvas.lineTo(border.Right,yFix);
this.Canvas.stroke();
}
}
this.DrawStickText=function(aryData)
{
var config=this.TextLabelConfig;
this.Canvas.font=config.Font;
var border=this.ChartBorder.GetBorder();
var itemHeight=config.TextHeight*2+config.TextMargin.Bottom+config.TextMargin.Top;
for(var i=0; i<aryData.length; ++i)
{
var item=aryData[i];
var value=item.Value;
var xCenter=item.X;
var xLeft=xCenter-config.LabelWidth/2;
var rtDraw={ Left:xLeft, Width:config.LabelWidth, Top:border.BottomEx+1, Height:itemHeight };
rtDraw.Right=rtDraw.Left+rtDraw.Width;
rtDraw.Bottom=rtDraw.Top+rtDraw.Height;
if (IFrameSplitOperator.IsNumber(value))
{
var bgColor=config.UnchangeColor;
if (value>0) bgColor=config.UpColor;
else if (value<0) bgColor=config.DownColor;
this.DrawTextLabel(value, bgColor, config.BorderColor, config.TextColor, rtDraw, config.TextHeight, config.MaxTextWidth, config.TextMargin);
}
var value=item.DiffValue;
var rtDraw={ Left:xLeft, Width:config.LabelWidth, Bottom:border.TopEx-1, Height:itemHeight };
rtDraw.Right=rtDraw.Left+rtDraw.Width;
rtDraw.Top=rtDraw.Bottom-rtDraw.Height;
if (IFrameSplitOperator.IsNumber(value))
{
var bgColor=config.UnchangeColor;
if (value>0) bgColor=config.UpColor;
else if (value<0) bgColor=config.DownColor;
this.DrawTextLabel(value, bgColor, config.BorderColor, config.TextColor, rtDraw, config.TextHeight, config.MaxTextWidth, config.TextMargin);
}
}
}
//数值标签
this.DrawTextLabel=function(value, clrGB, clrBorder, clrText, rtDraw, textHeight, textWidth, textMargin)
{
if (clrGB)
{
this.Canvas.fillStyle=clrGB;
this.Canvas.fillRect(rtDraw.Left ,rtDraw.Top, (rtDraw.Width), (rtDraw.Height));
}
if (clrBorder)
{
this.Canvas.lineWidth=2;
this.Canvas.strokeStyle=clrBorder;
this.Canvas.strokeRect(rtDraw.Left, rtDraw.Top, rtDraw.Width, rtDraw.Height);
}
else
{
this.Canvas.lineWidth=1;
this.Canvas.strokeStyle="rgb(0,0,0)";
this.Canvas.strokeRect(rtDraw.Left, rtDraw.Top, rtDraw.Width, rtDraw.Height);
}
var aryText=[null, null]; //大于3位数的 2行输出
var sign=""; //负数
if (value<0)
{
value=Math.abs(value);
sign='-';
}
if (value>999)
{
var thousand=parseInt(value/1000);
var hundred=parseInt(value%1000);
aryText[0]=`${sign}${thousand}`;
aryText[1]=`${hundred}`;
if (hundred<10) aryText[1]=`00${hundred}`;
else if (hundred<100) aryText[1]=`0${hundred}`;
}
else
{
aryText[1]=`${sign}${value.toFixed(0)}`;
}
this.Canvas.textAlign="right";
this.Canvas.textBaseline="top";
var xRight=rtDraw.Right-(rtDraw.Right-rtDraw.Left-textWidth)/2;
this.Canvas.fillStyle=clrText;
var yText=textMargin.Top+rtDraw.Top;
for(var i=0;i<aryText.length;++i)
{
var text=aryText[i];
if (text)
{
this.Canvas.fillText(text,xRight,yText);
}
yText+=textHeight;
}
}
this.GetMaxMin=function()
{
if (!IFrameSplitOperator.IsNumber(this.BaseValue) || this.BaseValue==0)
return this.Super_GetMaxMin();
if (this.ValueRange) //固定最大最小
{
var range={ Min:this.ValueRange.Min, Max:this.ValueRange.Max };
return range;
}
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
if (this.ChartFrame.GlobalOption && this.ChartFrame.GlobalOption.IsValueFullRange)
{
start=0;
xPointCount=this.Data.Data.length;
}
var range={ Min:null, Max:null }, maxDiffValue=null; //基准值的差值
if(!this.Data || !this.Data.Data) return range;
if (this.BaseValue>0) range.Min=this.BaseValue;
else range.Max=this.BaseValue;
for(var i=start,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || isNaN(value)) continue;
if (this.BaseValue>0)
{
if (value<0) continue;
if (value<this.BaseValue)
{
var diffValue=this.BaseValue-value;
if (maxDiffValue==null || maxDiffValue<diffValue) maxDiffValue=diffValue;
continue;
}
}
else
{
if (value>0) continue;
if (value>this.BaseValue)
{
var diffValue=value-this.BaseValue;
if (maxDiffValue==null || maxDiffValue<diffValue) maxDiffValue=diffValue;
continue;
}
}
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) range.Min=value;
}
if (this.BaseValue>0)
{
if (this.Style==1)
{
if (IFrameSplitOperator.IsNumber(maxDiffValue))
{
var value=this.BaseValue+maxDiffValue;
if (IFrameSplitOperator.IsNumber(range.Max) || range.Max<value) range.Max=value;
}
}
else
{
if (IFrameSplitOperator.IsNumber(maxDiffValue) && IFrameSplitOperator.IsNumber(range.Min))
range.Min-=maxDiffValue;
}
}
else
{
if (this.Style==1)
{
if (IFrameSplitOperator.IsNumber(maxDiffValue))
{
var value=this.BaseValue-maxDiffValue;
if (IFrameSplitOperator.IsNumber(range.Min) || range.Min>value) range.Min=value;
}
}
else
{
if (IFrameSplitOperator.IsNumber(maxDiffValue) && IFrameSplitOperator.IsNumber(range.Max))
range.Max+=maxDiffValue;
}
}
return range;
}
}
//柱子
function ChartBar()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartBar";
this.UpBarColor=g_JSChartResource.UpBarColor;
this.DownBarColor=g_JSChartResource.DownBarColor;
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var bFirstPoint=true;
var drawCount=0;
var yBottom=this.ChartFrame.GetYFromData(0);
if (dataWidth>=4)
{
yBottom=ToFixedRect(yBottom); //调整为整数
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value==0) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (value>0) this.Canvas.fillStyle=this.UpBarColor;
else this.Canvas.fillStyle=this.DownBarColor;
//高度调整为整数
var height=ToFixedRect(Math.abs(yBottom-y));
if(yBottom-y>0) y=yBottom-height;
else y=yBottom+height;
this.Canvas.fillRect(ToFixedRect(left),y,ToFixedRect(dataWidth),height);
}
}
else //太细了 直接画柱子
{
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value==0) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (value>0) this.Canvas.strokeStyle=this.UpBarColor;
else this.Canvas.strokeStyle=this.DownBarColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x),y);
this.Canvas.lineTo(ToFixedPoint(x),yBottom);
this.Canvas.stroke();
}
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=0;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (range.Max==null) range.Max=value;
if (range.Max<value) range.Max=value;
}
return range;
}
}
// 面积图 支持横屏
function ChartBand()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true;
this.ClassName="ChartBand";
this.FirstColor = g_JSChartResource.Index.LineColor[0];
this.SecondColor = g_JSChartResource.Index.LineColor[1];
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var isMinute=this.IsMinuteFrame();
var isHScreen=this.ChartFrame.IsHScreen;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var x = 0;
var y = 0;
var y2 = 0;
var firstlinePoints = [];
var secondlinePoints = [];
for(var i=this.Data.DataOffset,j=0; i<this.Data.Data.length && j<xPointCount;++i, ++j, xOffset+=(dataWidth+distanceWidth))
{
firstlinePoints = [];
secondlinePoints = [];
for(;i<this.Data.Data.length && j<xPointCount;++i, ++j, xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) break;
if (isMinute)
{
x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
x=left+(right-left)/2;
}
y=this.ChartFrame.GetYFromData(value.Value);
y2 = this.ChartFrame.GetYFromData(value.Value2);
if (isHScreen)
{
firstlinePoints.push({x:y,y:x});
secondlinePoints.push({x:y2,y:x});
}
else
{
firstlinePoints.push({x:x,y:y});
secondlinePoints.push({x:x,y:y2});
}
}
if (firstlinePoints.length>1 && secondlinePoints.length>1)
{
this.DrawBand(firstlinePoints, secondlinePoints);
}
}
}
this.ClipTop=function(aryFrist)
{
var isHScreen=this.ChartFrame.IsHScreen;
this.Canvas.beginPath();
for(var i=0;i<aryFrist.length;++i)
{
if (i == 0)
this.Canvas.moveTo(aryFrist[i].x, aryFrist[i].y);
else
this.Canvas.lineTo(aryFrist[i].x, aryFrist[i].y);
}
var ptStart=aryFrist[0];
var ptEnd=aryFrist[aryFrist.length-1];
if (isHScreen)
{
var xLeft=this.ChartBorder.GetRightEx();
this.Canvas.lineTo(xLeft, ptEnd.y);
this.Canvas.lineTo(xLeft, ptStart.y);
}
else
{
var yTop=this.ChartBorder.GetTopEx();
this.Canvas.lineTo(ptEnd.x, yTop);
this.Canvas.lineTo(ptStart.x, yTop);
}
this.Canvas.closePath();
this.Canvas.clip();
}
this.ClipBottom=function(aryFrist)
{
var isHScreen=this.ChartFrame.IsHScreen;
this.Canvas.beginPath();
for(var i=0;i<aryFrist.length;++i)
{
if (i == 0)
this.Canvas.moveTo(aryFrist[i].x, aryFrist[i].y);
else
this.Canvas.lineTo(aryFrist[i].x, aryFrist[i].y);
}
var ptStart=aryFrist[0];
var ptEnd=aryFrist[aryFrist.length-1];
if (isHScreen)
{
var xLeft=this.ChartBorder.GetLeftEx();
this.Canvas.lineTo(xLeft, ptEnd.y);
this.Canvas.lineTo(xLeft, ptStart.y);
}
else
{
var yBottom=this.ChartBorder.GetBottomEx();
this.Canvas.lineTo(ptEnd.x, yBottom);
this.Canvas.lineTo(ptStart.x, yBottom);
}
this.Canvas.closePath();
//this.Canvas.fillStyle = "rgb(255,0,0)";
//this.Canvas.fill();
this.Canvas.clip();
}
this.DrawArea=function(aryFrist, arySecond, clrArea)
{
this.Canvas.beginPath();
for(var i=0;i<aryFrist.length;++i)
{
if (i == 0)
this.Canvas.moveTo(aryFrist[i].x, aryFrist[i].y);
else
this.Canvas.lineTo(aryFrist[i].x, aryFrist[i].y);
}
for (var i = arySecond.length-1; i >= 0; --i)
{
this.Canvas.lineTo(arySecond[i].x, arySecond[i].y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = clrArea;
this.Canvas.fill();
}
this.DrawBand=function(aryFrist, arySecond)
{
if (this.FirstColor)
{
this.Canvas.save();
this.ClipTop(aryFrist);
this.DrawArea(aryFrist, arySecond, this.FirstColor);
this.Canvas.restore();
}
if (this.SecondColor)
{
this.Canvas.save();
this.ClipBottom(aryFrist);
this.DrawArea(aryFrist, arySecond, this.SecondColor);
this.Canvas.restore();
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) continue;
var maxData = value.Value>value.Value2?value.Value:value.Value2;
var minData = value.Value<value.Value2?value.Value:value.Value2;
if (range.Max==null)
range.Max = maxData;
else if (range.Max < maxData)
range.Max = maxData;
if (range.Min==null)
range.Min = minData;
else if (range.Min > minData)
range.Min = minData;
}
return range;
}
}
// 线段围成的面积图 支持横屏
function ChartLineArea()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true; //面积图在K线前面画,否则回挡住K线的
this.ClassName="ChartLineArea";
this.Color='rgb(56,67,99)';
this.IsHScreen=false;
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var x = 0, y = 0, y2 = 0;
var aryPoint=[];
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
aryPoint[i]=null;
if (value==null || value.Value==null || value.Value2 == null) continue;
x=this.ChartFrame.GetXFromIndex(j);
y=this.ChartFrame.GetYFromData(value.Value);
y2 = this.ChartFrame.GetYFromData(value.Value2);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }};
else
aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }};
}
this.Canvas.fillStyle = this.Color;
var firstPoint=true;
var pointCount=0;
var aryLine2=[];
for(var i in aryPoint)
{
var item=aryPoint[i];
if (!item)
{
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fill();
}
firstPoint=true;
pointCount=0;
aryLine2=[];
continue;
}
if (firstPoint)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.Line.X, item.Line.Y);
firstPoint=false;
}
else
{
this.Canvas.lineTo(item.Line.X, item.Line.Y);
}
aryLine2.push(item);
++pointCount;
}
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fill();
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!value || value.Value==null || value.Value2 == null) continue;
var maxData = value.Value>value.Value2?value.Value:value.Value2;
var minData = value.Value<value.Value2?value.Value:value.Value2;
if (range.Max==null) range.Max = maxData;
else if (range.Max < maxData) range.Max = maxData;
if (range.Min==null) range.Min = minData;
else if (range.Min > minData) range.Min = minData;
}
return range;
}
}
// 线段围成的面积图 支持横屏
function ChartFillRGN()
{
this.newMethod=ChartLineArea; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true; //面积图在K线前面画,否则回挡住K线的
this.IsHScreen=false;
this.ClassName="ChartFillRGN";
this.DrawRGB=function(aryPoint)
{
var firstPoint=true;
var pointCount=0;
var aryLine2=[];
var color=null;
for(var i in aryPoint)
{
var item=aryPoint[i];
if (!item || (color && item.Color!=color) )
{
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
firstPoint=true;
pointCount=0;
aryLine2=[];
color=null;
}
if (!item) continue;
if (firstPoint)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.Line.X, item.Line.Y);
firstPoint=false;
color=item.Color;
}
else
{
this.Canvas.lineTo(item.Line.X, item.Line.Y);
}
aryLine2.push(item);
++pointCount;
}
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
}
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var x = 0, y = 0, y2 = 0;
var aryPoint=[]; //点坐标
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
aryPoint[i]=null;
if (value==null || value.Value==null || value.Value2 == null || !value.Color) continue;
x=this.ChartFrame.GetXFromIndex(j);
y=this.ChartFrame.GetYFromData(value.Value);
y2 = this.ChartFrame.GetYFromData(value.Value2);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
else
aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
}
this.DrawRGB(aryPoint);
}
}
//支持横屏
//用法:FLOATRGN(PRICE,WIDTH,COND1,COLOR1,COND2,COLOR2...),以PRICE为基础填充宽度为WIDTH像素的区域,WIDTH为负则向下填充,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不填充,从COND1之后的参数均可以省略,最多可以有10组条件
//例如:FLOATRGN(CLOSE,VOL/HHV(VOL,10)*15,CLOSE>OPEN,RGB(255,0,0),1,RGB(0,255,0)) 表示沿收盘价填充宽度为成交量的区域,区域最大宽度为15像素,阳线时用红色,阴线时用绿色。
function ChartFLOATRGN()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = false; //面积图在K线前面画,否则回挡住K线的
this.ClassName="ChartFLOATRGN";
this.Color='rgb(56,67,99)';
this.IsHScreen=false;
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var x = 0, y = 0, y2 = 0;
var aryPoint=[]; //点坐标
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
aryPoint[i]=null;
if (!item || !IFrameSplitOperator.IsNumber(item.Value)|| !IFrameSplitOperator.IsNumber(item.Value2) || !item.Color) continue;
x=this.ChartFrame.GetXFromIndex(j);
y=this.ChartFrame.GetYFromData(item.Value);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y+item.Value2*GetDevicePixelRatio(), Y:x }, Color:item.Color };
else
aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y-item.Value2*GetDevicePixelRatio() }, Color:item.Color };
}
//计算左右位置的点
var preItem=null;
for(var i in aryPoint)
{
var item=aryPoint[i];
if (preItem && item)
{
if (this.IsHScreen)
{
var xWidth=(item.Line.Y-preItem.Line.Y);
x=preItem.Line.Y+xWidth/2;
y=preItem.Line.X+(item.Line.X-preItem.Line.X)/2;
y2=preItem.Line2.X+(item.Line2.X-preItem.Line2.X)/2;
preItem.RightLine={X:y, Y:x};
preItem.RightLine2={X:y2, Y:x};
item.LeftLine={X:y, Y:x};
item.LeftLine2={X:y2, Y:x};
}
else
{
var xWidth=(item.Line.X-preItem.Line.X);
x=preItem.Line.X+xWidth/2;
y=preItem.Line.Y+(item.Line.Y-preItem.Line.Y)/2;
y2=preItem.Line2.Y+(item.Line2.Y-preItem.Line2.Y)/2;
preItem.RightLine={X:x, Y:y};
preItem.RightLine2={X:x, Y:y2};
item.LeftLine={X:x, Y:y};
item.LeftLine2={X:x, Y:y2};
}
}
preItem=item; //上一个点
}
this.DrawRGB(aryPoint);
}
this.DrawRGB=function(aryPoint)
{
var firstPoint=true;
var pointCount=0;
var aryLine2=[];
var color=null;
if (this.IsHScreen)
{
var left=this.ChartBorder.GetLeftEx();
var right=this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
}
this.Canvas.save();
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
this.Canvas.clip();
for(var i in aryPoint)
{
var item=aryPoint[i];
if (!item || (color && item.Color!=color) )
{
if (pointCount>0)
{
var lastItem=aryLine2[aryLine2.length-1];
var firstItem=aryLine2[0];
if (lastItem.RightLine)
{
this.Canvas.lineTo(lastItem.RightLine.X, lastItem.RightLine.Y);
this.Canvas.lineTo(lastItem.RightLine2.X, lastItem.RightLine2.Y);
}
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
if (firstItem.LeftLine2)
{
this.Canvas.lineTo(firstItem.LeftLine2.X, firstItem.LeftLine2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
firstPoint=true;
pointCount=0;
aryLine2=[];
color=null;
}
if (!item) continue;
if (firstPoint)
{
this.Canvas.beginPath();
if (item.LeftLine)
{
this.Canvas.moveTo(item.LeftLine.X, item.LeftLine.Y);
this.Canvas.lineTo(item.Line.X, item.Line.Y);
}
else
{
this.Canvas.moveTo(item.Line.X, item.Line.Y);
}
firstPoint=false;
color=item.Color;
}
else
{
this.Canvas.lineTo(item.Line.X, item.Line.Y);
}
aryLine2.push(item);
++pointCount;
}
if (pointCount>0)
{
var lastItem=aryLine2[aryLine2.length-1];
var firstItem=aryLine2[0];
if (lastItem.RightLine)
{
this.Canvas.lineTo(lastItem.RightLine.X, lastItem.RightLine.Y);
this.Canvas.lineTo(lastItem.RightLine2.X, lastItem.RightLine2.Y);
}
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
}
if (firstItem.LeftLine2)
{
this.Canvas.lineTo(firstItem.LeftLine2.X, firstItem.LeftLine2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item=this.Data.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Value)) continue;
var value=item.Value;
if (range.Max==null) range.Max = value;
else if (range.Max < value) range.Max = value;
if (range.Min==null) range.Min = value;
else if (range.Min > value) range.Min = value;
}
return range;
}
}
//线段围城的顶部或底部面积图 TODO:支持横屏
function ChartFillBGRGN()
{
this.newMethod=ChartFillRGN; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true; //面积图在K线前面画,否则回挡住K线的
this.IsHScreen=false;
this.ClassName="ChartFillBGRGN";
this.DrawVerticalRGN=function()
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var y=top, y2=bottom;
var aryPoint=[]; //点坐标
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
aryPoint[i]=null;
if (!value || !value.Color) continue;
x=this.ChartFrame.GetXFromIndex(j);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
else
aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
}
this.DrawRGB(aryPoint);
}
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
if (this.Name=="FILLVERTICALRGN")
{
this.DrawVerticalRGN();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var x = 0, y = 0, y2 = top;
if (this.Name=="FILLBOTTOMRGN") y2=bottom;
var aryPoint=[]; //点坐标
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
aryPoint[i]=null;
if (value==null || value.Value==null || !value.Color) continue;
x=this.ChartFrame.GetXFromIndex(j);
y=this.ChartFrame.GetYFromData(value.Value);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
else
aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
}
this.DrawRGB(aryPoint);
}
this.DrawRGB=function(aryPoint)
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var halfWidth=(distanceWidth+dataWidth)/2;
var firstPoint=true;
var pointCount=0;
var aryLine2=[];
var color=null;
for(var i in aryPoint)
{
var item=aryPoint[i];
if (!item || (color && item.Color!=color) )
{
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
firstPoint=true;
pointCount=0;
aryLine2=[];
color=null;
}
if (!item) continue;
if (firstPoint)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.Line.X-halfWidth, item.Line.Y);
this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
firstPoint=false;
color=item.Color;
}
else
{
this.Canvas.lineTo(item.Line.X-halfWidth, item.Line.Y);
this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
}
aryLine2.push(item);
++pointCount;
}
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
}
this.Canvas.closePath();
this.Canvas.fillStyle = color;
this.Canvas.fill();
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (!value || value.Value==null ) continue;
var value=value.Value;
if (range.Max==null) range.Max = value;
else if (range.Max < value) range.Max = value;
if (range.Min==null) range.Min = value;
else if (range.Min > value) range.Min = value;
}
return range;
}
}
// 通道面积图 支持横屏
function ChartChannel()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true;
this.ClassName="ChartChannel";
this.IsHScreen=false; //是否是横屏
this.PointCount=0;
this.DataWidth=0;
this.DistanceWidth=0;
this.ChartRight=0; //可以绘制的最右边
this.LineColor='RGB(255,0,0)';
this.LineDotted=[3,3];
this.AreaColor='RGB(255,222,173)';
this.LineWidth=1;
this.CalculateData=function() //把数据通过nul值分割开, 并计算坐标
{
var data=[];
var lineData=[];
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<this.PointCount;++i,++j)
{
var item=this.Data.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Value) || !IFrameSplitOperator.IsNumber(item.Value2))
{
if (lineData.length>0)
{
data.push(lineData);
lineData=[]; //创建新的一组数据
}
continue;
}
var x=this.ChartFrame.GetXFromIndex(j);
if (x>this.ChartRight) break;
var y=this.ChartFrame.GetYFromData(item.Value);
var y2=this.ChartFrame.GetYFromData(item.Value2);
lineData.push({X:x, Y:y,Y2:y2});
}
if (lineData.length>0) data.push(lineData);
return data;
}
this.DrawArea=function(lineData)
{
if (lineData.length<=0) return;
this.Canvas.beginPath();
var drawCount=0;
var firstItem=lineData[0];
if (this.IsHScreen) this.Canvas.moveTo(firstItem.Y,firstItem.X);
else this.Canvas.moveTo(firstItem.X,firstItem.Y);
for(var i=1;i<lineData.length;++i)
{
var item=lineData[i];
if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
++drawCount;
}
for(var i=lineData.length-1;i>=0;--i)
{
var item=lineData[i];
if (this.IsHScreen) this.Canvas.lineTo(item.Y2,item.X);
else this.Canvas.lineTo(item.X,item.Y2);
++drawCount;
}
this.Canvas.closePath();
this.Canvas.fillStyle = this.AreaColor;
this.Canvas.fill();
}
this.DrawLine=function(lineData)
{
this.Canvas.strokeStyle=this.LineColor;
for(var k=0;k<2;++k)
{
var bFirstPoint=true;
var drawCount=0;
for(var i=0;i<lineData.length;++i)
{
var item=lineData[i];
if (bFirstPoint)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(k===0?item.Y:item.Y2,item.X);
else this.Canvas.moveTo(item.X, k===0?item.Y:item.Y2 );
bFirstPoint=false;
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(k===0?item.Y:item.Y2,item.X);
else this.Canvas.lineTo(item.X,k===0?item.Y:item.Y2);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
}
}
this.Draw=function()
{
if (this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
this.PointCount=this.ChartFrame.XPointCount;
this.DataWidth=this.ChartFrame.DataWidth;
this.DistanceWidth=this.ChartFrame.DistanceWidth;
if (this.IsHScreen) this.ChartRight=this.ChartBorder.GetBottom();
else this.ChartRight=this.ChartBorder.GetRight();
var drawData=this.CalculateData();
if (!drawData || drawData.length<=0) return;
this.Canvas.save();
this.Canvas.lineWidth=this.LineWidth*GetDevicePixelRatio();
this.Canvas.setLineDash(this.LineDotted); //虚线
for(var i=0;i<drawData.length;++i)
{
var lineData=drawData[i];
this.DrawArea(lineData);
this.DrawLine(lineData);
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={Min:null, Max:null};
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) continue;
var maxData = value.Value>value.Value2?value.Value:value.Value2;
var minData = value.Value<value.Value2?value.Value:value.Value2;
if (range.Max==null)
range.Max = maxData;
else if (range.Max < maxData)
range.Max = maxData;
if (range.Min==null)
range.Min = minData;
else if (range.Min > minData)
range.Min = minData;
}
return range;
}
}
//填充背景 支持横屏
function ChartBackground()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartBackground";
this.Color=null;
this.ColorAngle=0; //0 竖向 1 横向
this.IsDrawFirst = true; //面积图在K线前面画,否则回挡住K线的
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Color) return;
if (this.Color.length<=0) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.Color.length==2)
{
if (this.IsHScreen)
{
if (this.ColorAngle==0)
{
var ptStart={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
}
else
{
var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() };
}
}
else
{
if (this.ColorAngle==0)
{
var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() };
}
else
{
var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() };
}
}
let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y);
gradient.addColorStop(0, this.Color[0]);
gradient.addColorStop(1, this.Color[1]);
this.Canvas.fillStyle=gradient;
}
else if (this.Color.length==1)
{
this.Canvas.fillStyle=this.Color[0];
}
else
{
return;
}
if (this.Name=="DRAWGBK2" || this.Name=="KLINE_BG")
{
this.DrawRegion();
return;
}
if (this.IsHScreen)
{
var left=this.ChartBorder.GetLeftEx();
var top=this.ChartBorder.GetTop();
var width=this.ChartBorder.GetWidthEx();
var height=this.ChartBorder.GetHeight();
}
else
{
var left=this.ChartBorder.GetLeft();
var top=this.ChartBorder.GetTopEx();
var width=this.ChartBorder.GetWidth();
var height=this.ChartBorder.GetHeightEx();
}
this.Canvas.fillRect(left, top,width, height);
}
this.DrawRegion=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
if (this.IsHScreen)
{
top=this.ChartBorder.GetRightEx();
bottom=this.ChartBorder.GetLeftEx();
}
var aryPoint=[]; //点坐标
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
aryPoint[i]=null;
if (!IFrameSplitOperator.IsNumber(value) || value<=0) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value.Value);
if (this.IsHScreen)
aryPoint[i]={ Line:{ X:bottom, Y:x }, Line2:{ X:top, Y:x } };
else
aryPoint[i]={ Line:{ X:x, Y:top }, Line2:{ X:x, Y:bottom } };
}
this.DrawBG(aryPoint);
}
this.DrawBG=function(aryPoint)
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var halfWidth=(distanceWidth+dataWidth)/2;
var firstPoint=true;
var pointCount=0;
var aryLine2=[];
var color=null;
for(var i in aryPoint)
{
var item=aryPoint[i];
if (!item || (color && item.Color!=color) )
{
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
if (this.IsHScreen)
{
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y+halfWidth);
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y-halfWidth);
}
else
{
this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
}
}
this.Canvas.closePath();
this.Canvas.fill();
}
firstPoint=true;
pointCount=0;
aryLine2=[];
color=null;
}
if (!item) continue;
if (firstPoint)
{
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(item.Line.X, item.Line.Y-halfWidth);
this.Canvas.lineTo(item.Line.X, item.Line.Y+halfWidth);
}
else
{
this.Canvas.moveTo(item.Line.X-halfWidth, item.Line.Y);
this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
}
firstPoint=false;
color=item.Color;
}
else
{
if (this.IsHScreen)
{
this.Canvas.lineTo(item.Line.X, item.Line.Y-halfWidth);
this.Canvas.lineTo(item.Line.X, item.Line.Y+halfWidth);
}
else
{
this.Canvas.lineTo(item.Line.X-halfWidth, item.Line.Y);
this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
}
}
aryLine2.push(item);
++pointCount;
}
if (pointCount>0)
{
for(var j=aryLine2.length-1; j>=0; --j)
{
var item2=aryLine2[j];
if (this.IsHScreen)
{
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y+halfWidth);
this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y-halfWidth);
}
else
{
this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
}
}
this.Canvas.closePath();
this.Canvas.fill();
}
}
this.GetMaxMin=function()
{
return { Min:null, Max:null };
}
}
//填充部分背景 支持横屏
function ChartBackgroundDiv()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartBackgroundDiv";
this.AryColor;
this.ColorType=0;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryColor)) return;
if (!this.Data || !this.Data.Data) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var border,xOffset, chartright, yTop, yBottom;
if (bHScreen)
{
border=this.ChartBorder.GetHScreenBorder();
xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.BottomEx;
yTop=border.LeftEx;
yBottom=border.RightEx;
}
else
{
border=this.ChartBorder.GetBorder();
xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
chartright=border.RightEx;
yTop=border.TopEx;
yBottom=border.BottomEx;
}
var rtBG=null //{ Left:null, Top:null, Right:null, Bottom:null };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
if (!item)
{
if (rtBG) this.DrawDiv(rtBG,bHScreen);
rtBG=null;
}
else
{
var y=yTop;
var y2=yBottom;
if (IFrameSplitOperator.IsNonEmptyArray(item.AryValue))
{
var value=this.ChartFrame.GetYFromData(item.AryValue[0]);
var value2=this.ChartFrame.GetYFromData(item.AryValue[1]);
y=Math.min(value, value2);
y2=Math.max(value, value2);
}
if (bHScreen)
{
if (!rtBG)
{
rtBG={ Left:y, Right:y2, Top:left, Bottom:right };
}
else
{
rtBG.Bottom=right;
if (rtBG.Left>y) rtBG.Left=y;
if (rtBG.Right<y2) rtBG.Right=y2;
}
}
else
{
if (!rtBG)
{
rtBG={ Left:left, Right:right, Top:y, Bottom:y2 };
}
else
{
rtBG.Right=right;
if (rtBG.Top>y) rtBG.Top=y;
if (rtBG.Bottom<y2) rtBG.Bottom=y2;
}
}
}
}
}
this.DrawDiv=function(rtBG, bHScreen)
{
if (this.ColorType==2) //2=用COLOR1画框线
{
this.Canvas.strokeStyle = this.AryColor[0];
this.Canvas.strokeRect(ToFixedPoint(rtBG.Left),ToFixedPoint(rtBG.Top),ToFixedRect(rtBG.Right-rtBG.Left),ToFixedRect(rtBG.Bottom-rtBG.Top));
}
else if (this.ColorType==3) //3=用COLOR1画框线,用COLOR2填充
{
this.Canvas.fillStyle=this.AryColor[1];
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top),ToFixedRect(rtBG.Right-rtBG.Left),ToFixedRect(rtBG.Bottom-rtBG.Top));
this.Canvas.strokeStyle = this.AryColor[0];
this.Canvas.strokeRect(ToFixedPoint(rtBG.Left),ToFixedPoint(rtBG.Top),ToFixedRect(rtBG.Right-rtBG.Left),ToFixedRect(rtBG.Bottom-rtBG.Top));
}
else if (this.ColorType==0 || this.ColorType==1) //0=上下渐进 1=左右渐进
{
var gradient=null;
if (bHScreen)
{
if (this.ColorType==0)
gradient = this.Canvas.createLinearGradient(rtBG.Left,rtBG.Top, rtBG.Right,rtBG.Top);
else
gradient = this.Canvas.createLinearGradient(rtBG.Left,rtBG.Top, rtBG.Left,rtBG.Bottom);
}
else
{
if (this.ColorType==0)
gradient = this.Canvas.createLinearGradient(rtBG.Left,rtBG.Top, rtBG.Left,rtBG.Bottom);
else
gradient = this.Canvas.createLinearGradient(rtBG.Left,rtBG.Top, rtBG.Right,rtBG.Top);
}
gradient.addColorStop(0.5, this.AryColor[0]);
gradient.addColorStop(1, this.AryColor[1]);
this.Canvas.fillStyle=gradient;
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top),ToFixedRect(rtBG.Right-rtBG.Left),ToFixedRect(rtBG.Bottom-rtBG.Top));
}
else
{
return;
}
}
}
//画矩形
function ChartRectangle()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartRectangle";
this.Color=[];
this.Rect;
this.BorderColor=g_JSChartResource.FrameBorderPen;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Color || !this.Rect) return;
if (this.Color.length<=0) return;
this.Canvas.strokeStyle=this.BorderColor;
var bFill=false;
if (this.Color.length==2)
{
/* TODO 渐变下次做吧
if (this.ColorAngle==0)
{
var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() };
}
else
{
var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() };
}
let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y);
gradient.addColorStop(0, this.Color[0]);
gradient.addColorStop(1, this.Color[1]);
this.Canvas.fillStyle=gradient;
*/
this.Canvas.fillStyle=this.Color[0];
bFill=true;
}
else if (this.Color.length==1)
{
if (this.Color[0])
{
this.Canvas.fillStyle=this.Color[0];
bFill=true;
}
}
else
{
return;
}
var chartWidth=this.ChartBorder.GetWidth();
var chartHeight=this.ChartBorder.GetHeightEx();
var left=this.Rect.Left/1000*chartWidth;
var top=this.Rect.Top/1000*chartHeight;
var right=this.Rect.Right/1000*chartWidth;
var bottom=this.Rect.Bottom/1000*chartHeight;
left=this.ChartBorder.GetLeft()+left
top=this.ChartBorder.GetTopEx()+top;
right=this.ChartBorder.GetLeft()+right;
bottom=this.ChartBorder.GetTopEx()+bottom;
var width=Math.abs(left-right);
var height=Math.abs(top-bottom);
if (bFill) this.Canvas.fillRect(left, top,width, height);
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left), ToFixedPoint(top),ToFixedRect(width), ToFixedRect(height));
this.Canvas.stroke();
}
}
// 文字+线段输出
function ChartTextLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartTextLine";
this.Text; //Text=内容 Color
this.Line; //Type=线段类型 0=不画 1=直线 2=虚线, Color
this.Price;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Text || !this.Line || !IFrameSplitOperator.IsNumber(this.Price)) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var bottom=this.ChartBorder.GetBottomEx();
var top=this.ChartBorder.GetTopEx();
var y=this.ChartFrame.GetYFromData(this.Price);
var textWidth=0;
if (this.Text.Title)
{
var x=left+2*GetDevicePixelRatio();
var yText=y;
this.Canvas.textAlign = 'left';
this.Canvas.textBaseline = 'middle';
var offsetY=8*GetDevicePixelRatio();
if (y-offsetY<top)
{
this.Canvas.textBaseline='top';
yText=top;
}
else if (y+offsetY>bottom)
{
this.Canvas.textBaseline='bottom';
yText=bottom;
}
this.Canvas.fillStyle = this.Text.Color;
this.Canvas.font = this.Text.Font;
this.Canvas.fillText(this.Text.Title, x, yText);
textWidth=this.Canvas.measureText(this.Text.Title).width+4*GetDevicePixelRatio();
}
if (this.Line.Type>0)
{
if (this.Line.Type==2) //虚线
{
this.Canvas.save();
this.Canvas.setLineDash([3,5]); //虚线
}
var x=left+textWidth;
this.Canvas.strokeStyle=this.Line.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(x,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
if (this.Line.Type==2)
{
this.Canvas.restore();
}
}
}
this.GetMaxMin=function()
{
var range={Min:null, Max:null};
if (IFrameSplitOperator.IsNumber(this.Price))
{
range.Min=this.Price;
range.Max=this.Price;
}
return range;
}
}
// 柱子集合 支持横屏
function ChartMultiBar()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiBar";
this.Bars=[]; // [ {Point:[ {Index, Value, Value2 }, ], Color:, Width: , Type: 0 实心 1 空心 }, ]
this.IsHScreen=false;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (!this.Data || this.Data.length<=0) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var dataWidth=this.ChartFrame.DataWidth;
var pixelRatio=GetDevicePixelRatio();
var drawBars=[];
for(var i in this.Bars)
{
var item=this.Bars[i];
var drawPoints={ Point:[], Color:item.Color, Width:dataWidth, Type:0 };
if (item.Type>0) drawPoints.Type=item.Type;
if (item.Width>0)
{
drawPoints.Width=item.Width*pixelRatio;
if (drawPoints.Width>dataWidth) drawPoints.Width=dataWidth;
}
else
{
if(drawPoints.Width<4) drawPoints.Width=1*pixelRatio;
}
for(var j in item.Point)
{
var point=item.Point[j];
if (!IFrameSplitOperator.IsNumber(point.Index)) continue;
var index=point.Index-offset;
if (index>=0 && index<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(point.Value);
var y2=this.ChartFrame.GetYFromData(point.Value2);
drawPoints.Point.push({X:x, Y:y, Y2:y2});
}
}
if (drawPoints.Point.length>0) drawBars.push(drawPoints)
}
for(var i in drawBars)
{
var item=drawBars[i];
if (item.Width>=4)
{
if (item.Type==1) this.DrawHollowBar(item);
else this.DrawFillBar(item);
}
else
{
this.DrawLineBar(item);
}
}
}
this.DrawLineBar=function(bar)
{
this.Canvas.strokeStyle=bar.Color;
var backupLineWidth=this.Canvas.lineWidth;
this.Canvas.lineWidth=bar.Width;
for(var i in bar.Point)
{
var item=bar.Point[i];
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(item.Y),ToFixedPoint(item.X));
this.Canvas.lineTo(ToFixedPoint(item.Y2),ToFixedPoint(item.X));
}
else
{
this.Canvas.moveTo(ToFixedPoint(item.X),ToFixedPoint(item.Y));
this.Canvas.lineTo(ToFixedPoint(item.X),ToFixedPoint(item.Y2));
}
this.Canvas.stroke();
}
this.Canvas.lineWidth=backupLineWidth;
}
this.DrawFillBar=function(bar)
{
this.Canvas.fillStyle=bar.Color;
for(var i in bar.Point)
{
var item=bar.Point[i];
var x=item.X-(bar.Width/2);
var y=Math.min(item.Y,item.Y2);
var barWidth=bar.Width;
var barHeight=Math.abs(item.Y-item.Y2);
if (this.IsHScreen)
this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(x),ToFixedRect(barHeight),ToFixedRect(barWidth));
else
this.Canvas.fillRect(ToFixedRect(x),ToFixedRect(y),ToFixedRect(barWidth),ToFixedRect(barHeight));
}
}
this.DrawHollowBar=function(bar) //空心柱子
{
this.Canvas.strokeStyle=bar.Color;
var backupLineWidth=1;
for(var i in bar.Point)
{
var item=bar.Point[i];
var x=item.X-(bar.Width/2);
var y=Math.min(item.Y,item.Y2);
var barWidth=bar.Width;
var barHeight=Math.abs(item.Y-item.Y2);
this.Canvas.beginPath();
if (this.IsHScreen)
this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(x),ToFixedRect(barHeight),ToFixedRect(barWidth));
else
this.Canvas.rect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(barWidth),ToFixedRect(barHeight));
this.Canvas.stroke();
}
this.Canvas.lineWidth=backupLineWidth;
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Bars)
{
var item=this.Bars[i];
for(var j in item.Point)
{
var point=item.Point[j];
if (point.Index>=start && point.Index<end)
{
var minValue=Math.min(point.Value,point.Value2);
var maxValue=Math.max(point.Value,point.Value2);
if (range.Max==null) range.Max=maxValue;
else if (range.Max<maxValue) range.Max=maxValue;
if (range.Min==null) range.Min=minValue;
else if (range.Min>minValue) range.Min=minValue;
}
}
}
return range;
}
}
// 线段集合 支持横屏
function ChartMultiLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiLine";
this.Lines=[]; // [ {Point:[ {Index, Value }, ], Color: }, ]
this.LineDash;
this.LineWidth=1;
this.IsHScreen=false;
//箭头配置
this.ArrawAngle=35; //三角斜边一直线夹角
this.ArrawLength=10; //三角斜边长度
this.ArrawLineWidth=5; //箭头粗细
this.Arrow={ Start:false, End:false }; //Start=是否绘制开始箭头 <- End=是否绘制结束箭头 ->
this.IsFullRangeMaxMin=false;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (!this.Data || this.Data.length<=0) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Lines)) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var drawLines=[];
var arrowLines=[];
for(var i=0; i<this.Lines.length; ++i)
{
var line=this.Lines[i];
var drawPoints={ Point:[], Color:line.Color, AryCircle:null };
var drawArrowPoints={ Start:[], End:[] };
if (line.BGColor) drawPoints.BGColor=line.BGColor;
if (IFrameSplitOperator.IsNonEmptyArray(line.Circle)) drawPoints.AryCircle=line.Circle;
var isExtendLine=false;
if (IFrameSplitOperator.IsBool(line.IsExtendLine)) isExtendLine=line.IsExtendLine;
if (isExtendLine) //左右延申
{
var prePoint=null;
var bFirstPoint=true;
for(var j=0; j<line.Point.length; ++j)
{
var point=line.Point[j];
if (!IFrameSplitOperator.IsNumber(point.Index)) continue;
var index=point.Index-offset;
if (index>0 && index<xPointCount)
{
if (bFirstPoint)
{
if (prePoint)
{
var preIndex=prePoint.Index-offset;
var x=this.ChartFrame.GetXFromIndex(preIndex, false);
var y=this.ChartFrame.GetYFromData(prePoint.Value, false);
var pointItem={X:x, Y:y, End:false};
drawPoints.Point.push(pointItem);
}
bFirstPoint=false;
}
var x=this.ChartFrame.GetXFromIndex(index, false);
var y=this.ChartFrame.GetYFromData(point.Value, false);
var pointItem={X:x, Y:y, End:false};
drawPoints.Point.push(pointItem);
}
else
{
if (drawPoints.Point.length>0)
{
var x=this.ChartFrame.GetXFromIndex(index, false);
var y=this.ChartFrame.GetYFromData(point.Value, false);
var pointItem={X:x, Y:y, End:true};
drawPoints.Point.push(pointItem);
bFirstPoint=true;
prePoint=null;
}
}
prePoint=point;
}
if (drawPoints.Point.length>=2)
{
drawLines.push(drawPoints);
arrowLines.push(drawArrowPoints);
}
}
else
{
for(var j=0; j<line.Point.length; ++j)
{
var point=line.Point[j];
if (!IFrameSplitOperator.IsNumber(point.Index)) continue;
var index=point.Index-offset;
if (index>=0 && index<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(point.Value, false);
var pointItem={X:x, Y:y, End:false};
drawPoints.Point.push(pointItem);
if (j==0 || j==1) drawArrowPoints.Start.push(pointItem); //起始点
if (j==line.Point.length-1 || j==line.Point.length-2) drawArrowPoints.End.push(pointItem); //结束点
}
else
{
if (drawPoints.Point.length>0) drawPoints.Point[drawPoints.Point.length-1].End=true; //点断开
}
}
if (drawPoints.Point.length>=2)
{
drawLines.push(drawPoints);
arrowLines.push(drawArrowPoints);
}
}
}
var pixelRatio=GetDevicePixelRatio();
this.Canvas.save();
this.ClipClient(this.IsHScreen);
//绘制线段
for(var i=0; i<drawLines.length; ++i)
{
if (this.LineDash) this.Canvas.setLineDash(this.LineDash);
if (IFrameSplitOperator.IsPlusNumber(this.LineWidth)) this.Canvas.lineWidth=this.LineWidth*pixelRatio;
else this.Canvas.lineWidth=1*pixelRatio;
var item=drawLines[i];
this.DrawLine(item, arrowLines[i]);
//绘制圆点
if (item.AryCircle) this.DrawCircle(item)
}
this.Canvas.restore();
}
this.DrawCircle=function(line)
{
var pixelRatio=GetDevicePixelRatio();
for(var i=0; i<line.Point.length; ++i)
{
var item=line.Point[i];
for(var j=0;j<line.AryCircle.length;++j)
{
var circleItem=line.AryCircle[j];
var type=0;
if (IFrameSplitOperator.IsNumber(circleItem.Type)) type=circleItem.Type;
this.Canvas.beginPath();
this.Canvas.arc(item.X, item.Y, circleItem.Radius, 0, 2 * Math.PI);
if (type==1)
{
if (IFrameSplitOperator.IsPlusNumber(circleItem.LineWidth)) this.Canvas.lineWidth=circleItem.LineWidth*pixelRatio;
this.Canvas.strokeStyle=circleItem.Color;
this.Canvas.stroke();
}
else
{
this.Canvas.fillStyle=circleItem.Color;
this.Canvas.fill()
}
}
}
}
this.DrawLine=function(line, arrow)
{
if (line.BGColor) //背景色
{
this.Canvas.fillStyle=line.BGColor;
for(var i=0; i<line.Point.length; ++i)
{
var item=line.Point[i];
if (i==0)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(item.Y,item.X);
else this.Canvas.moveTo(item.X,item.Y);
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
}
}
this.Canvas.closePath();
this.Canvas.fill();
}
this.Canvas.strokeStyle=line.Color;
var drawCount=0;
for(var i=0; i<line.Point.length; ++i)
{
var item=line.Point[i];
if (drawCount==0)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(item.Y,item.X);
else this.Canvas.moveTo(item.X,item.Y);
++drawCount;
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
++drawCount;
}
if (item.End==true) //点断了 要重新画
{
if (drawCount>0) this.Canvas.stroke();
drawCount=0;
}
}
if (drawCount>0) this.Canvas.stroke();
//绘制箭头
if (arrow.End.length==2 && this.Arrow.End==true)
this.DrawArrow(arrow.End[0],arrow.End[1]);
if (arrow.Start.length==2 && this.Arrow.Start==true)
this.DrawArrow(arrow.Start[1],arrow.Start[0]);
}
this.DrawArrow=function(ptStart,ptEnd)
{
//计算箭头
var theta=this.ArrawAngle; //三角斜边一直线夹角
var headlen=this.ArrawLength; //三角斜边长度
var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
this.Canvas.beginPath();
var arrowX = ptEnd.X + topX;
var arrowY = ptEnd.Y + topY;
this.Canvas.moveTo(arrowX,arrowY);
this.Canvas.lineTo(ptEnd.X, ptEnd.Y);
arrowX = ptEnd.X + botX;
arrowY = ptEnd.Y + botY;
this.Canvas.lineTo(arrowX,arrowY);
this.Canvas.setLineDash([]);
this.Canvas.lineWidth=this.ArrawLineWidth*GetDevicePixelRatio();
this.Canvas.stroke();
}
this.GetMaxMin=function()
{
if (this.IsFullRangeMaxMin) return this.GetFullRangeMaxMin();
var range={ Min:null, Max:null };
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Lines)
{
var line=this.Lines[i];
for(var j in line.Point)
{
var point=line.Point[j];
if (point.Index>=start && point.Index<end)
{
if (range.Max==null) range.Max=point.Value;
else if (range.Max<point.Value) range.Max=point.Value;
if (range.Min==null) range.Min=point.Value;
else if (range.Min>point.Value) range.Min=point.Value;
}
}
}
return range;
}
//全部数据的最大最小值
this.GetFullRangeMaxMin=function()
{
var range={ Min:null, Max:null };
if (!IFrameSplitOperator.IsNonEmptyArray(this.Lines)) return range;
for(var i=0; i<this.Lines.length; ++i)
{
var line=this.Lines[i];
if (!IFrameSplitOperator.IsNonEmptyArray(line.Point)) continue;
for(var j=0; j<line.Point.length; ++j)
{
var point=line.Point[j];
if (range.Max==null) range.Max=point.Value;
else if (range.Max<point.Value) range.Max=point.Value;
if (range.Min==null) range.Min=point.Value;
else if (range.Min>point.Value) range.Min=point.Value;
}
}
return range;
}
}
// 线段集合 支持横屏
function ChartMultiPoint()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiPoint";
this.PointGroup=[]; // [ {Point:[ {Index, Value }, ], Color: }, ]
this.IsHScreen=false;
this.LineWidth=1;
this.PointRadius=5;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Data || this.Data.length<=0) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.PointGroup)) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var pixel=GetDevicePixelRatio();
this.Canvas.save();
this.ClipClient(this.IsHScreen);
for(var i=0; i<this.PointGroup.length; ++i)
{
var item=this.PointGroup[i];
var color=item.Color;
var bgColor=item.BGColor;
var lineWidth=this.LineWidth;
var radius=this.PointRadius;
if (IFrameSplitOperator.IsNumber(item.LineWidth)) lineWidth=item.LineWidth;
if (IFrameSplitOperator.IsNumber(item.PointRadius)) radius=item.PointRadius;
var path=new Path2D();
var count=0;
for(var j=0; j<item.Point.length; ++j)
{
var point=item.Point[j];
if (!IFrameSplitOperator.IsNumber(point.Index)) continue;
var index=point.Index-offset;
if (index>=0 && index<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(point.Value, false);
var pointPath = new Path2D();
if (this.IsHScreen)
pointPath.arc(y,x,radius*pixel,0,360,false);
else
pointPath.arc(x,y,radius*pixel,0,360,false);
path.addPath(pointPath);
++count;
}
}
if (count>0 && (bgColor || color))
{
this.Canvas.lineWidth=lineWidth*pixel;
this.Canvas.fillStyle=bgColor; //背景填充颜色
this.Canvas.strokeStyle=color;
if (bgColor) this.Canvas.fill(path);
if (color) this.Canvas.stroke(path);
}
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i=0; i<this.PointGroup.length; ++i)
{
var item=this.PointGroup[i];
if (!IFrameSplitOperator.IsNonEmptyArray(item.Point)) continue;
for(var j=0; j<item.Point.length; ++j)
{
var point=item.Point[j];
if (point.Index>=start && point.Index<end)
{
if (range.Max==null) range.Max=point.Value;
else if (range.Max<point.Value) range.Max=point.Value;
if (range.Min==null) range.Min=point.Value;
else if (range.Min>point.Value) range.Min=point.Value;
}
}
}
return range;
}
}
// 多文本集合 支持横屏
function ChartMultiText()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiText";
this.Texts=[]; //[ {Index:, Value:, Text:, Color:, Font: , Baseline:, Line:{ Color:, Dash:[虚线点], KData:"H/L", Offset:[5,10], Width:线粗细 }} ]
this.Font=g_JSChartResource.DefaultTextFont;
this.Color=g_JSChartResource.DefaultTextColor;
this.IsHScreen=false; //是否横屏
this.BuildKey=function(item)
{
if (IFrameSplitOperator.IsNumber(item.Time))
{
var key=`${item.Date}-${item.Time}`;
}
else
{
var key=`${item.Date}`;
}
return key;
}
this.GetShowTextData=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var mapText=new Map(); //key='date-time' value={ Data:[] }
for(var i=0; i<this.Texts.length; ++i)
{
var item=this.Texts[i];
if (!item.Text) continue;
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
var index=item.Index-offset;
if (index>=0 && index<xPointCount)
{
var key=this.BuildKey(item);
if (mapText.has(key))
{
var textItem=mapText.get(key);
textItem.Data.push(item);
}
else
{
var textItem={ Data:[item] };
mapText.set(key, textItem);
}
}
}
return mapText;
}
this.DrawAllText=function(mapText)
{
var bHScreen=(this.ChartFrame.IsHScreen===true);
var isMinute=this.IsMinuteFrame();
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var chartleft=border.TopEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var left=this.ChartBorder.GetTop();
var right=this.ChartBorder.GetBottom();
var top=border.RightEx;
var bottom=border.LeftEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var chartleft=border.LeftEx;
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=border.TopEx;
var bottom=border.BottomEx;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var kItem=this.Data.Data[i];
if (!kItem) continue;
var key=this.BuildKey(kItem);
if (!mapText.has(key)) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var textItem=mapText.get(key);
for(var k=0;k<textItem.Data.length;++k)
{
var item=textItem.Data[k];
var y=top;
if (item.Value=="TOP") y=top;
else if (item.Value=="BOTTOM") y=bottom;
else y=this.ChartFrame.GetYFromData(item.Value, false);
if (item.Color) this.Canvas.fillStyle = item.Color;
else this.Canvas.fillStyle = this.Color;
if (item.Font) this.Canvas.font = item.Font;
else this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(item.Text).width;
this.Canvas.textAlign='center';
if (x+textWidth/2>=chartright)
{
this.Canvas.textAlign='right';
x=chartright;
}
else if (x-textWidth/2<chartleft)
{
this.Canvas.textAlign = 'left';
x=chartleft;
}
if (item.Baseline==1) this.Canvas.textBaseline='top';
else if (item.Baseline==2) this.Canvas.textBaseline='bottom';
else this.Canvas.textBaseline = 'middle';
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Text,0,0);
this.Canvas.restore();
}
else
{
if (IFrameSplitOperator.IsNumber(item.YMove)) y+=item.YMove;
this.Canvas.fillText(item.Text, x, y);
}
if (item.Line)
{
var kItem=this.Data.Data[item.Index];
var price=item.Line.KData=="H"? kItem.High:kItem.Low;
var yPrice=this.ChartFrame.GetYFromData(price, false);
var yText=y;
if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
{
if (yText>yPrice) //文字在下方
{
yText-=item.Line.Offset[1];
yPrice+=item.Line.Offset[0]
}
else if (yText<yPrice)
{
yText+=item.Line.Offset[1];
yPrice-=item.Line.Offset[0]
}
}
this.Canvas.save();
if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash); //虚线
if (item.Line.Width>0) this.Canvas.lineWidth=item.Line.Width; //线宽
this.Canvas.strokeStyle = item.Line.Color;
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(yText, ToFixedPoint(x));
this.Canvas.lineTo(yPrice,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yText);
this.Canvas.lineTo(ToFixedPoint(x),yPrice);
}
this.Canvas.stroke();
this.Canvas.restore();
}
}
}
}
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (!this.Data || this.Data.length<=0) return;
if (!this.Texts) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var mapText=this.GetShowTextData();
if (mapText.size<=0) return;
this.Canvas.save();
this.ClipClient(this.IsHScreen);
this.DrawAllText(mapText);
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
if (!this.Texts) return range;
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Texts)
{
var item=this.Texts[i];
if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
if (item.Index>=start && item.Index<end)
{
if (range.Max==null) range.Max=item.Value;
else if (range.Max<item.Value) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
else if (range.Min>item.Value) range.Min=item.Value;
}
}
return range;
}
}
//图标集合(2.0) 支持横屏
function ChartMultiSVGIconV2()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiSVGIconV2";
this.AryIcon; //[ {Index:, Value:, Symbol:, Color:, Baseline:, Line:{ Color:, Dash:[虚线点], KData:"H/L", Offset:[5,10], Width:线粗细 } } ]
this.IconSize=
{
Max: g_JSChartResource.DRAWICON.Icon.MaxSize, Min:g_JSChartResource.DRAWICON.Icon.MinSize , //图标的最大最小值
Zoom:{ Type:g_JSChartResource.DRAWICON.Icon.Zoom.Type , Value:g_JSChartResource.DRAWICON.Icon.Zoom.Value } //放大倍数
};
this.Family;
this.Color=g_JSChartResource.DefaultTextColor;
this.IsHScreen=false;
this.IconRect=[]; //0=序号,1=区域
this.MapCache=null; //key=date/date-time value={ Data:[] }
this.BuildKey=function(item)
{
if (IFrameSplitOperator.IsNumber(item.Time)) return `${item.Date}-${item.Time}`;
else return item.Date;
}
this.BuildCacheData=function()
{
var mapData=new Map();
this.MapCache=mapData;
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryIcon)) return;
for(var i=0;i<this.AryIcon.length;++i)
{
var item=this.AryIcon[i];
var key=this.BuildKey(item);
if (mapData.has(key))
{
var mapItem=mapData.get(key);
mapItem.Data.push(item);
}
else
{
mapData.set(key,{ Data:[item] });
}
}
}
this.ClipClient=function(isHScreen) //裁剪客户端
{
if (isHScreen==true)
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
}
this.Canvas.beginPath();
this.Canvas.rect(left,top,(right-left),(bottom-top));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
}
this.Draw=function()
{
this.IconRect=[];
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return; //k线数据
if (!this.Family) return;
if (!this.MapCache || this.MapCache.size<=0) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var isMinute=this.IsMinuteFrame();
var border=this.GetBorder();
if (this.IsHScreen)
{
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var chartLeft=border.TopEx;
}
else
{
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var chartLeft=border.LeftEx;
}
this.Canvas.save();
this.ClipClient(this.ChartFrame.IsHScreen);
var fontSize=this.GetDynamicIconSize(dataWidth,distanceWidth,this.IconSize.Max,this.IconSize.Min,this.IconSize.Zoom);
this.Canvas.font=fontSize+'px '+this.Family;
var drawInfo={ Left:chartLeft, Right:chartright, FontSize:fontSize, DataWidth:dataWidth, DistanceWidth:distanceWidth };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var kItem=this.Data.Data[i];
var key=this.BuildKey(kItem);
if (!this.MapCache.has(key)) continue;
var mapItem=this.MapCache.get(key);
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
this.DrawItem(mapItem, kItem, x, drawInfo);
}
this.Canvas.restore();
}
this.GetKValue=function(kItem, valueName)
{
switch(valueName)
{
case "HIGH":
case "H":
return kItem.High;
case "L":
case "LOW":
return kItem.Low;
case "C":
case "CLOSE":
return kItem.Close;
case "O":
case "OPEN":
return KItem.Open;
default:
return null;
}
}
this.DrawItem=function(groupItem, kItem, x, drawInfo)
{
if (!IFrameSplitOperator.IsNonEmptyArray(groupItem.Data)) return;
var fontSize=drawInfo.FontSize;
var left=drawInfo.Left, right=drawInfo.Right;
var dataWidth=drawInfo.DataWidth;
//var distanceWidth=drawInfo.DistanceWidth;
for(var i=0;i<groupItem.Data.length;++i)
{
var item=groupItem.Data[i];
var value=item.Value;
if (IFrameSplitOperator.IsString(item.Value)) value=this.GetKValue(kItem,item.Value);
if (!IFrameSplitOperator.IsNumber(value)) continue;
var y=this.ChartFrame.GetYFromData(item.Value,false);
if (item.Color) this.Canvas.fillStyle = item.Color;
else this.Canvas.fillStyle = this.Color;
var textWidth=this.Canvas.measureText(item.Symbol).width;
this.Canvas.textAlign='center';
var rtIcon=new Rect(x-fontSize/2,y-fontSize/2,fontSize,fontSize);
if (item.Baseline==1)
{
this.Canvas.textBaseline='top';
rtIcon.Y=y;
}
else if (item.Baseline==2)
{
this.Canvas.textBaseline='bottom';
rtIcon.Y=y-fontSize;
}
else
{
this.Canvas.textBaseline = 'middle';
rtIcon.Y=y-fontSize/2;
}
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Symbol,0,0);
this.Canvas.restore();
}
else
{
if (IFrameSplitOperator.IsNumber(item.YMove)) y+=item.YMove;
this.Canvas.fillText(item.Symbol, x, y);
if (item.Text) this.IconRect.push({ Rect:rtIcon , Item:item, KItem:kItem });
else if (IFrameSplitOperator.IsNonEmptyArray(item.AryText)) this.IconRect.push({ Rect:rtIcon , Item:item, KItem:kItem });
}
if (item.Line)
{
var price=item.Line.KData=="H"? kItem.High:kItem.Low;
var yPrice=this.ChartFrame.GetYFromData(price, false);
var yText=y;
if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
{
if (yText>yPrice) //文字在下方
{
yText-=item.Line.Offset[1];
yPrice+=item.Line.Offset[0]
}
else if (yText<yPrice)
{
yText+=item.Line.Offset[1];
yPrice-=item.Line.Offset[0]
}
}
this.Canvas.save();
if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash); //虚线
if (item.Line.Width>0) this.Canvas.lineWidth=item.Line.Width; //线宽
this.Canvas.strokeStyle = item.Line.Color;
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(yText, ToFixedPoint(x));
this.Canvas.lineTo(yPrice,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),yText);
this.Canvas.lineTo(ToFixedPoint(x),yPrice);
}
this.Canvas.stroke();
this.Canvas.restore();
}
}
}
this.GetTooltipData=function(x,y,tooltip)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.IconRect)) return false;
for(var i=0; i<this.IconRect.length; ++i)
{
var item=this.IconRect[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
JSConsole.Chart.Log('[ChartMultiSVGIconV2::GetTooltipData] icon ', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=4; //指标
return true;
}
}
return false;
}
this.GetMaxMin=function()
{
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var range={ Min:null, Max:null };
if(!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return range;
if (!this.MapCache || this.MapCache.size<=0) return;
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.Data.DataOffset,j=0, k=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var kItem=this.Data.Data[i];
var key=this.BuildKey(kItem);
if (!this.MapCache.has(key)) continue;
var mapItem=this.MapCache.get(key);
if (!IFrameSplitOperator.IsNonEmptyArray(mapItem.Data)) continue;
for(k=0;k<mapItem.Data.length;++k)
{
var item=mapItem.Data[k];
var value=item.Value;
if (IFrameSplitOperator.IsString(item.Value)) value=this.GetKValue(kItem,item.Value);
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (range.Max==null) range.Max=value;
else if (range.Max<value) range.Max=value;
if (range.Min==null) range.Min=value;
else if (range.Min>value) range.Min=value;
}
}
return range;
}
}
// 多dom节点
function ChartMultiHtmlDom()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartMultiHtmlDom";
this.Texts=[]; //[ {Index:, Value:, Text: ] Text=dom内容
this.IsHScreen=false; //是否横屏
this.DrawCallback; //function(op, obj) op:1=开始 2=结束 3=绘制单个数据 4=销毁
this.DrawItem=[];
this.EnableDraw=true; //是否允许绘制
this.HQChart;
this.IsDestroy=false; //是否已销毁
this.Draw=function()
{
if (!this.EnableDraw) return;
if (this.IsDestroy) return;
this.DrawItem=[];
if (this.DrawCallback) this.DrawCallback(1, {Self:this} );
this.DrawDom();
if (this.DrawCallback) this.DrawCallback(2, { Self:this, DrawItem:this.DrawItem } );
}
this.OnDestroy=function()
{
this.IsDestroy=true;
if (this.DrawCallback) this.DrawCallback(4, { Self:this } );
}
this.DrawDom=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Data || this.Data.length<=0) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var pixelTatio = GetDevicePixelRatio();
if (this.HQChart)
{
var elementLeft=this.HQChart.UIElement.getBoundingClientRect().left;
var elementTop=this.HQChart.UIElement.getBoundingClientRect().top;
}
else
{
var elementLeft=null,elementTop=null;
}
for(var i in this.Texts)
{
var item=this.Texts[i];
if (!item.Text) continue;
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
var isMinuteFrame=this.IsMinuteFrame();
var index=item.Index-offset;
var kItem=this.Data.Data[item.Index]; //K线数据
var obj={ KData:kItem, Item:item, IsShow:false, Self:this };
if (index>=0 && index<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
if (item.Value=="Top")
{
var y=top;
}
else if (item.Value=="Bottom")
{
var y=bottom;
}
else
{
var y=this.ChartFrame.GetYFromData(item.Value);
}
obj.X=x/pixelTatio;
obj.Y=y/pixelTatio;
obj.UIElement={Left:elementLeft, Top:elementTop};
obj.IsShow=true;
}
this.DrawItem.push(obj);
if (this.DrawCallback) this.DrawCallback(3, obj);
if (item.Line)
{
if (isMinuteFrame)
{
var price=this.Data.Data[item.Index];
}
else
{
var kItem=this.Data.Data[item.Index];
var price=item.Line.KData=="H"? kItem.High:kItem.Low;
}
var yPrice=this.ChartFrame.GetYFromData(price);
var yText=y;
if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
{
if (yText>yPrice) //文字在下方
{
yText-=item.Line.Offset[1];
yPrice+=item.Line.Offset[0]
}
else if (yText<yPrice)
{
yText+=item.Line.Offset[1];
yPrice-=item.Line.Offset[0]
}
}
this.Canvas.save();
if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash); //虚线
var pixelRatio=GetDevicePixelRatio();
var lineWidth=1*pixelRatio;
if (item.Line.Width>0) lineWidth=item.Line.Width*pixelRatio;
this.Canvas.lineWidth=lineWidth; //线宽
this.Canvas.strokeStyle = item.Line.Color;
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(yText, ToFixedPoint(x));
this.Canvas.lineTo(yPrice,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint2(lineWidth,x),yText);
this.Canvas.lineTo(ToFixedPoint2(lineWidth,x),yPrice);
}
this.Canvas.stroke();
this.Canvas.restore();
}
}
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Texts)
{
var item=this.Texts[i];
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
if (item.Index>=start && item.Index<end)
{
if (range.Max==null) range.Max=item.Value;
else if (range.Max<item.Value) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
else if (range.Min>item.Value) range.Min=item.Value;
}
}
return range;
}
}
//绘制SVG图标
function ChartDrawSVG()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartDrawSVG";
this.Family;
this.TextFont;
this.Texts=[]; //[ { Index:, Value:, Symbol:, Text:, Size: } ] SVG:图标 Text:文字 Size:图标大小
this.IsHScreen=false; //是否横屏
this.IsDestroy=false; //是否已销毁
this.EnableTooltip=true;
this.TooltipRect=[];
this.ExcludeArea=null; //排除区域 { Left, Top, Width, Height, Type:0 }
this.AutoPosition=null; //{ Direction:0, MaxYOffset:40 } //自动调整Y轴偏移,防止文字重叠
this.AryDrawRect=[]; //已经绘制的区域
this.AutoYOffset=0;
//this.Data; 存K线数据
this.Draw=function()
{
this.TooltipRect=[];
this.AryDrawRect=[];
this.AutoYOffset=0;
if (!this.IsShow || this.ChartFrame.IsMinSize || !this.IsVisible) return;
if (this.IsShowIndexTitleOnly()) return;
if (this.IsHideScriptIndex()) return;
this.DrawSVG();
}
this.DrawDetail=function(rtSVG, data, svgItem)
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.Content)) return;
var lefMargin=2;
var rightMargin=2;
var itemSpace=2;
var rtBorder={ Left:rtSVG.Right, Right:rtSVG.Right, Bottom:rtSVG.Bottom };
var rightBorder=0; //右边的边界 0=div的宽度 1=图形框架边框
if (IFrameSplitOperator.IsNumber(data.ItemSpace)) itemSpace=data.ItemSpace;
if (IFrameSplitOperator.IsNumber(data.YOffset)) rtBorder.Bottom+=data.YOffset;
if (IFrameSplitOperator.IsNumber(data.XOffset)) rtBorder.Left+=data.XOffset;
if (IFrameSplitOperator.IsNumber(data.LeftMargin)) lefMargin=data.LeftMargin;
if (IFrameSplitOperator.IsNumber(data.RightMargin)) rightMargin=data.RightMargin;
if (IFrameSplitOperator.IsNumber(data.RightBorder)) rightBorder=data.RightBorder;
if (data.Font) this.Canvas.font=data.Font;
else this.Canvas.font=this.TextFont;
this.Canvas.textBaseline='bottom';
this.Canvas.textAlign='left';
var textHeight=this.Canvas.measureText("擎").width+2;
rtBorder.Height=textHeight+5;
var yText=rtBorder.Bottom-(rtBorder.Height-textHeight)/2;
var xText=rtBorder.Left+lefMargin;
var aryText=[];
for(var i=0;i<data.Content.length;++i)
{
if (aryText.length>0) xText+=itemSpace;
var item=data.Content[i];
if (!item.Text) continue;
var textWidth=this.Canvas.measureText(item.Text).width+2;
aryText.push({ X:xText, Y:yText, Width:textWidth, Data:item });
xText+=textWidth;
rtBorder.Right=xText;
}
rtBorder.Right+=rightMargin;
rtBorder.Width=rtBorder.Right-rtBorder.Left;
rtBorder.Top=rtBorder.Bottom-rtBorder.Height;
var right=this.ChartBorder.GetChartWidth()-1;
if (rightBorder==1) right=this.ChartBorder.GetRight();
if (rtBorder.Right>right) //右边显示不下,显示在左边
{
rtBorder.Right=rtSVG.Left;
if (IFrameSplitOperator.IsNumber(data.XOffset)) rtBorder.Right-=data.XOffset;
rtBorder.Left=rtBorder.Right-rtBorder.Width;
var xText=rtBorder.Left+lefMargin;
for(var i=0;i<aryText.length;++i)
{
if (i>0) xText+=itemSpace;
var item=aryText[i];
item.X=xText;
xText+=item.Width;
}
}
if (data.BGColor)
{
this.Canvas.fillStyle=data.BGColor;
this.Canvas.fillRect(rtBorder.Left,rtBorder.Top,rtBorder.Width,rtBorder.Height);
}
if (data.BorderColor)
{
this.Canvas.strokeStyle=data.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtBorder.Left),ToFixedPoint(rtBorder.Top),ToFixedRect(rtBorder.Width),ToFixedRect(rtBorder.Height));
}
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
this.Canvas.fillStyle = item.Data.Color;
this.Canvas.fillText(item.Data.Text, item.X, item.Y);
}
this.AryDrawRect.push( {Left:rtBorder.Left, Top:rtBorder.Top, Right:rtBorder.Right, Bottom:rtBorder.Bottom, Type:"Detail", Data:svgItem } );
}
this.GetDetailPosition=function(rtSVG, data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.Content)) return null;
var lefMargin=2;
var rightMargin=2;
var itemSpace=2;
var rtBorder={ Left:rtSVG.Right, Right:rtSVG.Right, Bottom:rtSVG.Bottom };
var rightBorder=0; //右边的边界 0=div的宽度 1=图形框架边框
if (IFrameSplitOperator.IsNumber(data.ItemSpace)) itemSpace=data.ItemSpace;
if (IFrameSplitOperator.IsNumber(data.YOffset)) rtBorder.Bottom+=data.YOffset;
if (IFrameSplitOperator.IsNumber(data.XOffset)) rtBorder.Left+=data.XOffset;
if (IFrameSplitOperator.IsNumber(data.LeftMargin)) lefMargin=data.LeftMargin;
if (IFrameSplitOperator.IsNumber(data.RightMargin)) rightMargin=data.RightMargin;
if (IFrameSplitOperator.IsNumber(data.RightBorder)) rightBorder=data.RightBorder;
if (data.Font) this.Canvas.font=data.Font;
else this.Canvas.font=this.TextFont;
var textHeight=this.Canvas.measureText("擎").width+2;
rtBorder.Height=textHeight+5;
var yText=rtBorder.Bottom-(rtBorder.Height-textHeight)/2;
var xText=rtBorder.Left+lefMargin;
var bFrist=true;
for(var i=0;i<data.Content.length;++i)
{
if (!bFrist) xText+=itemSpace;
var item=data.Content[i];
if (!item.Text) continue;
var textWidth=this.Canvas.measureText(item.Text).width+2;
xText+=textWidth;
rtBorder.Right=xText;
bFrist=false;
}
rtBorder.Right+=rightMargin;
rtBorder.Width=rtBorder.Right-rtBorder.Left;
rtBorder.Top=rtBorder.Bottom-rtBorder.Height;
var right=this.ChartBorder.GetChartWidth()-1;
if (rightBorder==1) right=this.ChartBorder.GetRight();
if (rtBorder.Right>right) //右边显示不下,显示在左边
{
rtBorder.Right=rtSVG.Left;
if (IFrameSplitOperator.IsNumber(data.XOffset)) rtBorder.Right-=data.XOffset;
rtBorder.Left=rtBorder.Right-rtBorder.Width;
}
return rtBorder;
}
this.CalculateShowPosition=function(item, pt)
{
var x=pt.X, y=pt.Y;
var svgItem=item.SVG;
if (IFrameSplitOperator.IsNumber(svgItem.YOffset)) y+=svgItem.YOffset;
var fontSVG=`${svgItem.Size}px ${this.Family}`;
this.Canvas.font=fontSVG;
var halfSize=svgItem.Size/2;
var rtSVG={ Left:x-halfSize, Right:x+halfSize, Top:y-svgItem.Size, Bottom:y, Height:svgItem.Size, Width:svgItem.Size };
if (svgItem.VAlign===0) //top
{
rtSVG.Top=y;
rtSVG.Bottom=rtSVG.Top+svgItem.Size;
}
else if (svgItem.VAlign===1) //middle
{
rtSVG.Top=y-svgItem.Size/2;
rtSVG.Bottom=rtSVG.Top+svgItem.Size;
}
if (rtSVG.Top<0)
{
rtSVG.Top=0;
rtSVG.Bottom=svgItem.Size;
y=rtSVG.Bottom;
}
var rtContent=null;
if (item.Detail)
rtContent=this.GetDetailPosition(rtSVG,item.Detail);
var yOffset=0, yMoveStep=-5;
if (IFrameSplitOperator.IsNumber(this.AutoPosition.MoveYStep)) yMoveStep=-(Math.abs(this.AutoPosition.MoveYStep))
for(var i=0;i<20;++i)
{
if (rtSVG && !rtContent)
{
if (!this.IsRectOverlap(rtSVG))
break;
}
else if (rtSVG && rtContent)
{
if (!this.IsRectOverlap(rtSVG) && !this.IsRectOverlap(rtContent))
break;
}
yOffset+=yMoveStep;
if (Math.abs(yOffset)>=this.AutoPosition.MaxYOffset) break;
rtSVG.Top+=yMoveStep;
rtSVG.Bottom+=yMoveStep;
if (rtContent)
{
rtContent.Top+=yMoveStep;
rtContent.Bottom+=yMoveStep;
}
}
pt.X=x;
pt.Y=y+yOffset;
}
this.IsRectOverlap=function(rect)
{
for(var i=0; i<this.AryDrawRect.length; ++i)
{
var item=this.AryDrawRect[i];
if ( ((rect.Left>=item.Left && rect.Left<=item.Right) || (rect.Right>=item.Left && rect.Right<=item.Right)) &&
((rect.Top>=item.Top && rect.Top<=item.Bottom) || (rect.Bottom>=item.Top && rect.Bottom<=item.Bottom)) )
{
return true;
}
}
return false;
}
this.DrawSVG=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Texts)) return;
if (!this.Family) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var xPointCount=this.ChartFrame.XPointCount;
var offset=this.Data.DataOffset;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var pixelRatio = GetDevicePixelRatio();
var x=0,y=0;
for(var i=0; i<this.Texts.length; ++i)
{
var item=this.Texts[i];
if (!item.SVG || !item.SVG.Symbol) continue;
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
var isMinuteFrame=this.IsMinuteFrame();
var index=item.Index-offset;
var kItem=this.Data.Data[item.Index];
if (index<0 || index>=xPointCount) continue;
x=this.ChartFrame.GetXFromIndex(index);
if (item.Value=="Top") y=top;
else if (item.Value=="Bottom") y=bottom;
else y=this.ChartFrame.GetYFromData(item.Value, false);
if (IFrameSplitOperator.IsNumber(item.YOffset)) y+=item.YOffset; //Y轴偏移
var svgItem=item.SVG;
if (IFrameSplitOperator.IsNumber(svgItem.YOffset)) y+=svgItem.YOffset;
if (this.AutoPosition)
{
var pt={ X:x, Y:y };
this.CalculateShowPosition(item, pt); //重新计算位置
x=pt.X;
y=pt.Y;
}
var fontSVG=`${svgItem.Size}px ${this.Family}`;
this.Canvas.font=fontSVG;
var halfSize=svgItem.Size/2;
var textBaseline='bottom';
var rtSVG={ Left:x-halfSize, Right:x+halfSize, Top:y-svgItem.Size, Bottom:y, Height:svgItem.Size, Width:svgItem.Size };
if (svgItem.VAlign===0)
{
textBaseline="top";
rtSVG.Top=y;
rtSVG.Bottom=rtSVG.Top+svgItem.Size;
}
else if (svgItem.VAlign===1)
{
textBaseline='middle';
rtSVG.Top=y-svgItem.Size/2;
rtSVG.Bottom=rtSVG.Top+svgItem.Size;
}
if (rtSVG.Top<0)
{
rtSVG.Top=0;
rtSVG.Bottom=svgItem.Size;
y=rtSVG.Bottom;
}
this.Canvas.textBaseline=textBaseline;
this.Canvas.textAlign='center';
this.Canvas.fillStyle = svgItem.Color;
this.Canvas.fillText(svgItem.Symbol, x, y);
this.AryDrawRect.push( {Left:rtSVG.Left, Top:rtSVG.Top, Right:rtSVG.Right, Bottom:rtSVG.Bottom, Type:"SVG", Data:item } );
if (this.EnableTooltip) this.TooltipRect.push({ Rect:rtSVG,Index:i });
//文字
if (item.Text && item.Text.Content && this.TextFont)
{
var textItem=item.Text;
this.Canvas.font=this.TextFont;
this.Canvas.fillStyle=textItem.Color;
var yText=y;
if (IFrameSplitOperator.IsNumber(textItem.YOffset)) yText+=textItem.YOffset;
this.Canvas.fillText(textItem.Content, x, yText);
}
if (item.Detail)
{
this.DrawDetail(rtSVG,item.Detail, item);
}
//连线
if (item.Line)
{
var lineItem=item.Line;
var price=null, yPrice=null;
var kItem=this.Data.Data[item.Index];
if (lineItem.Value=="Bottom")
{
yPrice=bottom;
}
else if (lineItem.Value=="Top")
{
yPrice=top;
}
else
{
switch(lineItem.Value)
{
case "C":
price=kItem.Close;
break;
case "H":
price=kItem.High;
break;
case "L":
price=kItem.Low;
break;
}
if (!IFrameSplitOperator.IsNumber(price)) continue;
yPrice=this.ChartFrame.GetYFromData(price);
}
if (yPrice>=rtSVG.Top && yPrice<=rtSVG.Bottom) continue;
var yText;
if (yPrice<rtSVG.Top)
{
yText=rtSVG.Top;
if (IFrameSplitOperator.IsNumber(lineItem.SVGBlank))
{
//yPrice+=lineItem.Blank;
yText-=lineItem.SVGBlank;
}
}
else
{
yText=rtSVG.Bottom;
if (IFrameSplitOperator.IsNumber(lineItem.SVGBlank))
{
//yPrice-=lineItem.Blank;
yText+=lineItem.SVGBlank;
}
}
if (lineItem.Dash) this.Canvas.setLineDash(lineItem.Dash); //虚线
var lineWidth=1*pixelRatio;
if (lineItem.Width>0) lineWidth=lineItem.Width*pixelRatio;
this.Canvas.lineWidth=lineWidth; //线宽
this.Canvas.strokeStyle = lineItem.Color;
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(yText, ToFixedPoint(x));
this.Canvas.lineTo(yPrice,ToFixedPoint(x));
}
else
{
this.Canvas.moveTo(ToFixedPoint2(lineWidth,x),yText);
this.Canvas.lineTo(ToFixedPoint2(lineWidth,x),yPrice);
}
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
}
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Texts)) return range;
for(var i=0; i<this.Texts.length; ++i)
{
var item=this.Texts[i];
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
if (item.Index>=start && item.Index<end)
{
if(!IFrameSplitOperator.IsNumber(item.Value)) continue;
if (range.Max==null) range.Max=item.Value;
else if (range.Max<item.Value) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
else if (range.Min>item.Value) range.Min=item.Value;
}
}
return range;
}
this.GetTooltipData=function(x,y,tooltip)
{
if (!this.IsShow) return false;
for(var i=0;i<this.TooltipRect.length;++i)
{
var item=this.TooltipRect[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
var data=this.Texts[item.Index];
JSConsole.Chart.Log('[ChartDrawSVG::GetTooltipData] svg icon.', item);
tooltip.Data={ Rect:item.Rect, Item:data, Index:item.Index };
tooltip.ChartPaint=this;
tooltip.Type=7; //drawsvg
if (data.Tooltip && data.Tooltip.Ver==2.0) tooltip.Type=8; //drawsvg 新本版
return true;
}
}
return false;
}
}
// OX图 支持横屏
function ChartOX()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartOX";
this.Font;
this.Family=g_JSChartResource.ChartOX.Family;
this.Color=[g_JSChartResource.ChartOX.Up.Color, g_JSChartResource.ChartOX.Down.Color];
this.Text=[g_JSChartResource.ChartOX.Up.Text, g_JSChartResource.ChartOX.Down.Text];
this.IsHScreen=false; //是否横屏
this.SquareSize=10;
this.OXData=null; //{ Data:[ { Type: 0/1, Data:[ price, price ] } ], Max:, Min: }
this.SquareLineColor=g_JSChartResource.ChartOX.SquareLineColor;
this.TooltipData=[]; //{ Rect:, Data }
//计算每个单元格的大小
this.CalcualteSquare=function()
{
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var top=border.LeftEx;
var bottom=border.RightEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
}
this.SquareSize=(bottom-top)/(this.OXData.Max-this.OXData.Min)*this.OXData.BlockSize;
var fontSize=parseInt(this.SquareSize);
this.Font=`${fontSize}px ${this.Family}`;
}
this.DrawSquares=function()
{
this.Canvas.beginPath();
this.Canvas.strokeStyle=this.SquareLineColor;
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var left=border.Top;
var right=border.Bottom;
}
else
{
var border=this.ChartBorder.GetBorder();
var left=border.Left;
var right=border.Right;
var top=border.TopEx;
var bottom=border.BottomEx;
}
for(var price=this.OXData.StartPrice; price<this.OXData.Max; price+=this.OXData.BlockSize)
{
var y=this.ChartFrame.GetYFromData(price);
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),border.Top);
this.Canvas.lineTo(ToFixedPoint(y), border.Bottom);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
}
for(var price=this.OXData.StartPrice; price>this.OXData.Min; price-=this.OXData.BlockSize)
{
var y=this.ChartFrame.GetYFromData(price);
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),border.Top);
this.Canvas.lineTo(ToFixedPoint(y), border.Bottom);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
}
var xStart=left+g_JSChartResource.FrameLeftMargin;
for(var i=xStart;i<right; i+=this.SquareSize)
{
if (this.IsHScreen)
{
this.Canvas.moveTo(border.LeftEx,ToFixedPoint(i));
this.Canvas.lineTo(border.RightEx,ToFixedPoint(i));
}
else
{
this.Canvas.moveTo(ToFixedPoint(i),top);
this.Canvas.lineTo(ToFixedPoint(i),bottom);
}
}
this.Canvas.stroke();
}
this.Draw=function()
{
this.TooltipData=[];
if (this.ChartFrame.IsMinSize) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.OXData || !this.OXData.Data) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
this.CalcualteSquare();
this.DrawSquares();
if (this.IsHScreen)
{
var left=this.ChartBorder.GetTop();
var right=this.ChartBorder.GetBottom();
var xOffset=left+g_JSChartResource.FrameLeftMargin;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='center';
this.Canvas.font=this.Font;
for(var i=0;i<this.OXData.Data.length;++i, xOffset+=this.SquareSize)
{
if (xOffset>right) break;
var item=this.OXData.Data[i];
this.Canvas.fillStyle=this.Color[item.Type];
var text=this.Text[item.Type];
if (!IFrameSplitOperator.IsNonEmptyArray(item.Data)) continue;
for(var j=0; j<item.Data.length; ++j)
{
var value=item.Data[j];
var y=this.ChartFrame.GetYFromData(value+this.OXData.BlockSize/2);
this.Canvas.fillText(text,y,xOffset+this.SquareSize/2);
}
}
}
else
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var xOffset=left+g_JSChartResource.FrameLeftMargin;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='center';
this.Canvas.font=this.Font;
for(var i=0;i<this.OXData.Data.length;++i, xOffset+=this.SquareSize)
{
if (xOffset>right) break;
var item=this.OXData.Data[i];
this.Canvas.fillStyle=this.Color[item.Type];
var text=this.Text[item.Type];
var rt={ X:xOffset, Width:this.SquareSize };
var maxValue=null, minValue=null;
if (!IFrameSplitOperator.IsNonEmptyArray(item.Data)) continue;
for(var j=0; j<item.Data.length; ++j)
{
var value=item.Data[j];
var y=this.ChartFrame.GetYFromData(value+this.OXData.BlockSize/2);
this.Canvas.fillText(text,xOffset+this.SquareSize/2,y);
if (maxValue==null) maxValue=value;
else if (maxValue<value) maxValue=value;
if (minValue==null) minValue=value;
else if (minValue>value) minValue=value;
}
rt.Y=this.ChartFrame.GetYFromData(maxValue+this.OXData.BlockSize);
rt.Height=this.ChartFrame.GetYFromData(minValue)-rt.Y;
var tooltipItem={ Data:item, Rect:rt };
this.TooltipData.push(tooltipItem);
}
}
}
this.GetTooltipData=function(x,y,tooltip)
{
for(var i in this.TooltipData)
{
var item=this.TooltipData[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
JSConsole.Chart.Log('[ChartOX::GetTooltipData] item ', item);
tooltip.Data=item;
tooltip.ChartPaint=this;
tooltip.Type=5; //OX指标
return true;
}
}
return false;
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
if (this.OXData)
{
if (IFrameSplitOperator.IsNumber(this.OXData.Max)) range.Max=this.OXData.Max;
if (IFrameSplitOperator.IsNumber(this.OXData.Min)) range.Min=this.OXData.Min;
}
return range;
}
}
//成交量柱子图-可视范围
function ChartVolProfileVisibleRange()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartVolProfileVisibleRange";
this.IsDrawFirst=true;
this.IsShowText=true; //是否显示成交量数据
this.VolType=0; //0=up|down bar 1=total bar
this.BarPosition=1; //柱子方向 0=左边 1=右边
this.BarWidthRate=0.3;
this.VolFont;
this.HQChart;
this.IsDestroy=false;
this.Data=null;
this.MaxVol;
this.MaxVolPrice;
this.VolLineColor=g_JSChartResource.ChartVolProfileVisibleRange.VolLineColor;
this.VolLineFont=g_JSChartResource.ChartVolProfileVisibleRange.VolLineFont;
this.VolLineTextColor=g_JSChartResource.ChartVolProfileVisibleRange.VolLineTextColor;
//value Area
this.VAHLineColor=g_JSChartResource.ChartVolProfileVisibleRange.VAHLineColor;
this.VAHTextColor=g_JSChartResource.ChartVolProfileVisibleRange.VAHTextColor;
this.VALLineColor=g_JSChartResource.ChartVolProfileVisibleRange.VALLineColor;
this.VALTextColor=g_JSChartResource.ChartVolProfileVisibleRange.VALTextColor;
this.VAFont=g_JSChartResource.ChartVolProfileVisibleRange.VAFont;
this.TextConfig=
{
Color:g_JSChartResource.ChartVolProfileVisibleRange.Text.Color,
Family:g_JSChartResource.ChartVolProfileVisibleRange.Text.Family,
FontMaxSize:g_JSChartResource.ChartVolProfileVisibleRange.Text.FontMaxSize,
FontMinSize:g_JSChartResource.ChartVolProfileVisibleRange.Text.FontMinSize,
Color:g_JSChartResource.ChartVolProfileVisibleRange.Text.Color,
}
this.BarColor=
[
g_JSChartResource.ChartVolProfileVisibleRange.UpVolColor,
g_JSChartResource.ChartVolProfileVisibleRange.DownVolColor,
g_JSChartResource.ChartVolProfileVisibleRange.AreaUpColor,
g_JSChartResource.ChartVolProfileVisibleRange.AreaDonwColor
]
this.MaxVolLine;
this.OnDestroy=function()
{
this.IsDestroy=true;
}
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsBool(option.IsShowText)) this.IsShowText=option.IsShowText;
if (IFrameSplitOperator.IsNumber(option.VolType)) this.IsShowText=option.VolType;
if (IFrameSplitOperator.IsNumber(option.BarPosition)) this.BarPosition=option.BarPosition;
if (IFrameSplitOperator.IsNumber(option.BarWidthRate)) this.IsShowText=option.BarWidthRate;
}
this.PtInChart=function(x,y)
{
if (this.MaxVolLine)
{
if (x>=this.MaxVolLine.Start.X && x<=this.MaxVolLine.End.X && y>=this.MaxVolLine.Start.Y-5 && y<this.MaxVolLine.Start.Y+5)
return { Identify:this.Identify, Chart:this };
}
return null;
}
this.SetSelectedStatus=function(status)
{
if (status==0) this.IsDrawFirst=true;
else this.IsDrawFirst=false;
}
this.DrawSelectedStatus=function()
{
var radius=this.SelectedRadius;
var pixelRatio=GetDevicePixelRatio();
this.Canvas.save();
if (this.MaxVolLine)
{
this.Canvas.lineWidth=this.SelectedLineWidth*pixelRatio;
this.Canvas.strokeStyle=this.SelectedLineColor;
if (this.SelectedBGColor) this.Canvas.fillStyle=this.SelectedBGColor;
var space=(this.MaxVolLine.End.X-this.MaxVolLine.Start.X)/6;
var aryPoint=[];
for(var x=this.MaxVolLine.Start.X+space; x<this.MaxVolLine.End.X; x+=space)
{
aryPoint.push({X:x, Y:this.MaxVolLine.Start.Y});
}
for(var i=0;i<aryPoint.length;++i)
{
var item=aryPoint[i];
this.Canvas.beginPath();
this.Canvas.arc(item.X,item.Y,radius,0,360,false);
this.Canvas.closePath();
if (this.SelectedBGColor) this.Canvas.fill();
this.Canvas.stroke();
}
}
this.Canvas.restore();
}
this.Draw=function()
{
this.VolFont=null;
this.MaxVolLine=null;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
if (this.ChartFrame.IsMinSize) return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
this.Canvas.save();
this.DrawVolBar();
this.Canvas.restore();
}
this.DrawPriceLine=function()
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var pixelTatio = GetDevicePixelRatio();
var aryPrice=[];
var maxVolPrice=this.MaxVolPrice;
if (IFrameSplitOperator.IsNumber(this.Data.MaxVolPrice)) maxVolPrice=this.Data.MaxVolPrice;
if (maxVolPrice>=this.ChartFrame.HorizontalMin && maxVolPrice<=this.ChartFrame.HorizontalMax)
aryPrice.push({Price:maxVolPrice, Font:this.VolLineFont, LineColor:this.VolLineColor, LineWidth:2, TextColor:this.VolLineTextColor, Type:1});
if (IFrameSplitOperator.IsNumber(this.Data.VAHPrice) && this.Data.VAHPrice>=this.ChartFrame.HorizontalMin && this.Data.VAHPrice<=this.ChartFrame.HorizontalMax)
aryPrice.push({Price:this.Data.VAHPrice, Font:this.VAFont, LineColor:this.VAHLineColor, LineWidth:2, TextColor:this.VAHTextColor, Type:2});
if (IFrameSplitOperator.IsNumber(this.Data.VALPrice) && this.Data.VALPrice>=this.ChartFrame.HorizontalMin && this.Data.VALPrice<=this.ChartFrame.HorizontalMax)
aryPrice.push({Price:this.Data.VALPrice, Font:this.VAFont, LineColor:this.VALLineColor, LineWidth:2, TextColor:this.VALTextColor, Type:3});
for(var i=0;i<aryPrice.length;++i)
{
var item=aryPrice[i];
var yLine=ToFixedPoint2(item.LineWidth,this.ChartFrame.GetYFromData(item.Price,false));
this.Canvas.lineWidth=item.LineWidth;
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,yLine);
this.Canvas.lineTo(right,yLine);
this.Canvas.stroke();
if (item.Type==1) this.MaxVolLine= { Start:{X:left,Y:yLine}, End:{X:right,Y:yLine} };
if (this.ChartBorder.Right>10) //刻度文字
{
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var text=item.Price.toFixed(defaultfloatPrecision);
this.Canvas.font=item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var fontHeight=this.GetFontHeight();
var textWidth=this.Canvas.measureText(text).width+2*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
this.Canvas.fillRect(right,yLine-fontHeight/2,textWidth,fontHeight);
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(text,right+1*pixelTatio, yLine);
}
}
}
this.DrawVolBar=function()
{
var cellHeight=this.GetPriceYOffset(this.Data.PriceOffset);
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartFrame.GetYFromData(this.Data.MaxPrice)-cellHeight/2;
var bottom=this.ChartFrame.GetYFromData(this.Data.MinPrice)+cellHeight/2;
var width=right-left;
var height=bottom-top;
var maxBarWidth=width*this.BarWidthRate;
if (this.IsShowText)
{
this.VolFont=this.GetDynamicVolTextFont(cellHeight, maxBarWidth);
if (this.VolFont) this.Canvas.font=this.VolFont;
}
for(var i=0,j=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (item.Price<this.ChartFrame.HorizontalMin || item.Price>this.ChartFrame.HorizontalMax) continue;
this.DrawVolBarItem(item, left, right, maxBarWidth, cellHeight);
}
this.DrawPriceLine();
}
this.DrawVolBarItem=function(item, left, right, maxBarWidth, cellHeight)
{
var barLeft=left;
var barRight=right;
var barTop=this.ChartFrame.GetYFromData(item.Price)-cellHeight/2;
var barHeight=cellHeight-1;
if (barHeight<1) barHeight=1;
if (this.VolType==1)
{
if (!item.TotalVol) return;
if (!IFrameSplitOperator.IsNumber(item.TotalVol.Value)) return;
var barWidth=item.TotalVol.Value*maxBarWidth/this.MaxVol;
var color;
if (IFrameSplitOperator.IsNumber(item.TotalVol.ColorID)) color=this.BarColor[item.TotalVol.ColorID];
else if (item.TotalVol.Color) color=item.TotalVol.Color;
this.Canvas.fillStyle=color;
if (this.BarPosition==1)
{
this.Canvas.fillRect(barRight,ToFixedRect(barTop),-barWidth,ToFixedRect(barHeight));
}
else
{
this.Canvas.fillRect(barLeft,ToFixedRect(barTop),barWidth,ToFixedRect(barHeight));
}
if (this.IsShowText && this.VolFont)
{
var text=IFrameSplitOperator.FormatVolString(item.TotalVol.Value, this.HQChart.LanguageID);
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle=this.TextConfig.Color;
if (this.BarPosition==1)
{
this.Canvas.textAlign = 'right';
this.Canvas.fillText(text,right-5,barTop+cellHeight/2);
}
else
{
this.Canvas.textAlign = 'left';
this.Canvas.fillText(text,left+5,barTop+cellHeight/2);
}
}
}
else
{
var text="";
for(var i=0;i<item.Vol.length;++i)
{
var volItem=item.Vol[i];
if (!IFrameSplitOperator.IsNumber(volItem.Value)) continue;
var color;
if (IFrameSplitOperator.IsNumber(volItem.ColorID)) color=this.BarColor[volItem.ColorID];
else if (volItem.Color) color=volItem.Color;
if (!color) continue;
var barWidth=volItem.Value*maxBarWidth/this.MaxVol;
this.Canvas.fillStyle=color;
if (this.BarPosition==1)
{
this.Canvas.fillRect(barRight,ToFixedRect(barTop),-barWidth,ToFixedRect(barHeight));
barRight-=barWidth;
}
else
{
this.Canvas.fillRect(barLeft,ToFixedRect(barTop),barWidth,ToFixedRect(barHeight));
barLeft+=barWidth;
}
var volText=IFrameSplitOperator.FormatVolString(volItem.Value, this.HQChart.LanguageID);
if (text.length>0) text+="x";
text+=volText;
}
if (this.IsShowText && this.VolFont)
{
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle=this.TextConfig.Color;
if (this.BarPosition==1)
{
this.Canvas.textAlign = 'right';
this.Canvas.fillText(text,right-5,barTop+cellHeight/2);
}
else
{
this.Canvas.textAlign = 'left';
this.Canvas.fillText(text,left+5,barTop+cellHeight/2);
}
}
}
}
this.GetPriceYOffset=function(value)
{
var frame=this.ChartFrame;
var y=frame.ChartBorder.GetHeightEx()*(value)/(frame.HorizontalMax-frame.HorizontalMin);
return y;
}
this.GetDynamicVolTextFont=function(cellHeight, width, fontOption)
{
var fontSize=parseInt(cellHeight)-2;
if (cellHeight<5) fontSize=parseInt(cellHeight); //高度太小了就不要上下间距了
if (fontSize>this.TextConfig.FontMaxSize) fontSize=this.TextConfig.FontMaxSize;
else if (fontSize<=0) fontSize=1;
if (fontSize<this.TextConfig.FontMinSize) return null;
var font=this.FormatFontString(fontSize, this.TextConfig.Family, fontOption);
return font;
}
this.FormatFontString=function(fontSize, family, option)
{
var font;
if (!option)
{
font=`${fontSize}px ${family}`;
}
else
{
if (option.Weight) font=`${option.Weight} ${fontSize}px ${family}`;
}
return font;
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
return range;
}
}
//堆积柱状图
function ChartStackedBar()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartStackedBar";
this.Data; //{ Data:[ [bar1, bar2], [bar1,bar2 ] ] };
this.BarName=[];
this.BarColor=['rgb(255,165,0)',"rgb(95,158,160)"];
this.LineWidth=1;
this.BarType=0; //0=线段 1=K线宽度一致
this.IsHScreen;
this.Draw=function()
{
if (!this.IsShow || this.ChartFrame.IsMinSize) return;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.IsHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
var top=border.RightEx;
var bottom=border.LeftEx;
}
else
{
var border=this.ChartFrame.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var top=border.TopEx;
var bottom=border.BottomEx;
var lockRect=this.GetLockRect();
if (lockRect) chartright=lockRect.Left;
}
var isMinute=this.IsMinuteFrame();
this.Canvas.save();
if (this.BarType==1)
{
}
else
{
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var lineWidth=this.Canvas.lineWidth;
}
var yZero=this.ChartFrame.GetYFromData(0);
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var bars=this.Data.Data[i];
if (!IFrameSplitOperator.IsNonEmptyArray(bars)) continue;
if (isMinute)
{
var x=this.ChartFrame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (x>chartright) break;
if (this.BarType==1)
{
if (dataWidth>=4) //柱子太细就直接画竖线
this.DrawKBarItem(bars, x, left, right, top, bottom, yZero, dataWidth);
else
this.DrawBarItem(bars, x, top, bottom, yZero, lineWidth);
}
else
{
this.DrawBarItem(bars, x, top, bottom, yZero, lineWidth);
}
}
this.Canvas.restore();
}
this.DrawKBarItem=function(aryBar, x, left, right, top, bottom, yZero, barWidth)
{
var plusValue=0, yPlus=yZero; //正数
var negativeValue=0, yNegative= yZero; //负数
for(var i=0;i<aryBar.length;++i)
{
var item=aryBar[i];
if (!IFrameSplitOperator.IsNumber(item)) continue;
if(item==0) continue;
this.Canvas.fillStyle=this.BarColor[i];
if (item>0)
{
plusValue+=item;
var y=this.ChartFrame.GetYFromData(plusValue);
var rtBar={Left: left, Top:y, Width:barWidth, Height:(yPlus-y)};
yPlus=y;
}
else
{
negativeValue+=item;
var y=this.ChartFrame.GetYFromData(negativeValue);
var rtBar={Left:left, Top:y, Width:barWidth, Height:(yNegative-y)};
yNegative=y;
}
if (this.IsHScreen)
this.Canvas.fillRect(rtBar.Top,rtBar.Left, rtBar.Height, rtBar.Width);
else
this.Canvas.fillRect(rtBar.Left, rtBar.Top, rtBar.Width, rtBar.Height);
}
}
this.DrawBarItem=function(aryBar,x, top, bottom, yZero, lineWidth)
{
var x=ToFixedPoint2(lineWidth, x);
var plusValue=0, yPlus=yZero; //正数
var negativeValue=0, yNegative=yZero; //负数
for(var i=0;i<aryBar.length;++i)
{
var item=aryBar[i];
if (!IFrameSplitOperator.IsNumber(item)) continue;
if(item==0) continue;
var line={};
if (item>0)
{
plusValue+=item;
var y=this.ChartFrame.GetYFromData(plusValue);
var line={X:x, Y:yPlus, X2:x, Y2:y};
yPlus=y;
}
else
{
negativeValue+=item;
var y=this.ChartFrame.GetYFromData(negativeValue);
var line={X:x, Y:yNegative, X2:x, Y2:y};
yNegative=y;
}
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(line.Y,line.X);
this.Canvas.lineTo(line.Y2,line.X2);
}
else
{
this.Canvas.moveTo(line.X,line.Y);
this.Canvas.lineTo(line.X2,line.Y2);
}
this.Canvas.strokeStyle=this.BarColor[i];
this.Canvas.stroke();
}
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Min=null;
range.Max=null;
if(!this.Data || !this.Data.Data) return range;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var bars=this.Data.Data[i];
if (!bars || !IFrameSplitOperator.IsNonEmptyArray(bars)) continue;
var plusValue=0; //正数
var negativeValue=0; //负数
for(var k=0;k<bars.length;++k)
{
var barValue=bars[k];
if (!IFrameSplitOperator.IsNumber(barValue)) continue;
if (barValue==0) continue;
if (barValue>0) plusValue+=barValue;
else if (barValue<0) negativeValue+=barValue;
}
if (range.Max==null)
{
range.Max=plusValue;
range.Min=negativeValue;
}
if (range.Max<plusValue) range.Max=plusValue;
if (range.Min>negativeValue) range.Min=negativeValue;
}
return range;
}
this.PtInChart=function(x,y)
{
var option={ StackedBar:true };
if (this.BarType==0) option.BarWidth=4;
return this.PtInBar(x,y, option );
}
this.DrawSelectedStatus=function()
{
this.DrawLinePoint({ StackedBar:true });
}
}
//锁 支持横屏
function ChartLock()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartLock";
this.WidthDiv = 0.2; // 框子宽度占比
this.LockCount = 20; // 锁最新的几个数据
this.BGColor = g_JSChartResource.LockBGColor;
this.TextColor = g_JSChartResource.LockTextColor;
this.Font = g_JSChartResource.DefaultTextFont;
this.Title = '🔒开通权限';
this.LockRect=null; //上锁区域
this.LockID; //锁ID
this.Callback; //回调
this.IndexName; //指标名字
this.MinWidth=null; //最小宽度
this.Draw=function(isDraw)
{
this.LockRect=null;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (this.ChartFrame.IsHScreen===true)
{
this.HScreenDraw(isDraw);
return;
}
var xOffset = this.ChartBorder.GetRight();
var lOffsetWidth = 0;
if (this.ChartFrame.Data != null)
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetRight();
var xPointCount=this.ChartFrame.XPointCount;
for(var i=this.ChartFrame.Data.DataOffset,j=0;i<this.ChartFrame.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.ChartFrame.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
}
lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount;
}
if (lOffsetWidth == 0)
{
lOffsetWidth = (xOffset - this.ChartBorder.GetLeft()) * this.WidthDiv;
}
var lLeft = xOffset - lOffsetWidth;
if (lLeft < this.ChartBorder.GetLeft())
lLeft = this.ChartBorder.GetLeft();
var lHeight = this.ChartBorder.GetBottom() - this.ChartBorder.GetTop();
var lWidth = this.ChartBorder.GetRight() - lLeft;
if (this.MinWidth>10 && lWidth<this.MinWidth)
{
lWidth=this.MinWidth;
lLeft=this.ChartBorder.GetRight()-lWidth;
if (lLeft < this.ChartBorder.GetLeft()) lLeft = this.ChartBorder.GetLeft();
}
if (isDraw)
{
this.Canvas.fillStyle = this.BGColor;
this.Canvas.fillRect(lLeft, this.ChartBorder.GetTop(), lWidth, lHeight);
var xCenter = lLeft + lWidth / 2;
var yCenter = this.ChartBorder.GetTop() + lHeight / 2;
this.Canvas.textAlign = 'center';
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle = this.TextColor;
this.Canvas.font = this.Font;
this.Canvas.fillText(this.Title, xCenter, yCenter);
}
this.LockRect={Left:lLeft,Top:this.ChartBorder.GetTop(),Width:lWidth,Heigh:lHeight}; //保存上锁区域
}
this.HScreenDraw=function(isDraw)
{
var xOffset = this.ChartBorder.GetBottom();
var lOffsetWidth = 0;
if (this.ChartFrame.Data != null)
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
//求最后1个数据的位置
for(var i=this.ChartFrame.Data.DataOffset,j=0;i<this.ChartFrame.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.ChartFrame.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
}
lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount;
}
if (lOffsetWidth == 0)
{
lOffsetWidth = (xOffset - this.ChartBorder.GetTop()) * this.WidthDiv;
}
var lLeft = xOffset - lOffsetWidth;
if (lLeft < this.ChartBorder.GetTop()) lLeft = this.ChartBorder.GetTop();
var lHeight = this.ChartBorder.GetRight()-this.ChartBorder.GetLeft();
var lWidth = this.ChartBorder.GetBottom() - lLeft;
this.Canvas.fillStyle = this.BGColor;
this.Canvas.fillRect(this.ChartBorder.GetLeft(), lLeft,lHeight,lWidth);
var xCenter = this.ChartBorder.GetLeft() + lHeight / 2;
var yCenter = lLeft + lWidth / 2;
this.Canvas.save();
this.Canvas.translate(xCenter, yCenter);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.textAlign = 'center';
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle = this.TextColor;
this.Canvas.font = this.Font;
this.Canvas.fillText(this.Title, 0, 0);
this.Canvas.restore();
this.LockRect={Left:this.ChartBorder.GetLeft(),Top:lLeft,Width:lHeight,Heigh:lWidth}; //保存上锁区域
}
//x,y是否在上锁区域
this.GetTooltipData=function(x,y,tooltip)
{
if (this.LockRect==null) return false;
this.Canvas.beginPath();
this.Canvas.rect(this.LockRect.Left,this.LockRect.Top,this.LockRect.Width,this.LockRect.Heigh);
if (this.Canvas.isPointInPath(x,y))
{
tooltip.Data={ ID:this.LockID, Callback:this.Callback, IndexName:this.IndexName };
tooltip.ChartPaint=this;
return true;
}
return false;
}
}
//买卖盘
function ChartBuySell()
{
this.newMethod=ChartSingleText; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartBuySell";
this.TextFont=g_JSChartResource.KLineTrain.Font; //"bold 14px arial"; //买卖信息字体
this.LastDataIcon=g_JSChartResource.KLineTrain.LastDataIcon; //{Color:'rgb(0,0,205)',Text:'↓'};
this.BuyIcon=g_JSChartResource.KLineTrain.BuyIcon; //{Color:'rgb(0,0,205)',Text:'B'};
this.SellIcon=g_JSChartResource.KLineTrain.SellIcon; //{Color:'rgb(0,0,205)',Text:'S'};
this.BuySellData=new Map(); //Key=数据索引index Value:Data:[ { Op: 买/卖 0=buy 1=sell, Date:, Time, Price: Vol:}, ]
this.IconFont=g_JSChartResource.KLineTrain.IconFont;
this.LastDataDrawType=0; //0=画在最后一个数据上 1=画在指定索引上
this.LastDataIndex=-1;
this.AddTradeItem=function(tradeItem)
{
if (this.BuySellData.has(tradeItem.Key))
{
var Trade=this.BuySellData.get(tradeItem.Key);
Trade.Data.push(tradeItem);
}
else
{
this.BuySellData.set(tradeItem.Key, { Data:[tradeItem] });
}
}
this.ClearTradeData=function()
{
this.BuySellData=new Map();
}
this.Draw=function()
{
if (!this.Data || !this.Data.Data) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var chartright=this.ChartBorder.GetRight();
if (isHScreen===true) chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
if (this.IconFont)
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var iconSize=dataWidth+distanceWidth;
var minIconSize=18*pixelTatio;
if (iconSize<minIconSize) iconSize=minIconSize;
this.Canvas.font=iconSize+'px '+this.IconFont.Family;
}
else
{
this.Canvas.font=this.TextFont;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) break;
var bDrawLastData=false;
if (this.LastDataDrawType==1)
{
if (i==this.LastDataIndex) bDrawLastData=true;
}
else
{
if (i==this.Data.Data.length-1) bDrawLastData=true;
}
if (bDrawLastData)
{
//最后一个位置 画一个箭头
var x=this.ChartFrame.GetXFromIndex(j);
var yHigh=this.ChartFrame.GetYFromData(value.High);
this.Canvas.textAlign='center';
this.Canvas.textBaseline='bottom';
if (this.IconFont)
{
this.Canvas.fillStyle=this.IconFont.Last.Color
this.DrawText(this.IconFont.Last.Text,x,yHigh,isHScreen);
}
else
{
this.Canvas.fillStyle=this.LastDataIcon.Color;
this.Canvas.font=this.TextFont;
this.DrawText(this.LastDataIcon.Text,x,yHigh,isHScreen);
}
}
var key=i;
if (!this.BuySellData.has(key)) continue;
var trade=this.BuySellData.get(key);
var yHigh=this.ChartFrame.GetYFromData(value.High);
var yLow=this.ChartFrame.GetYFromData(value.Low);
var drawInfo=[false, false]; //0=buy 1=sell
for(var k in trade.Data)
{
if (drawInfo[0]==true && drawInfo[1]==true) break; //买卖图标只画一次
var bsItem=trade.Data[k];
if (bsItem.Op==0 && drawInfo[0]==false) //买 标识在最低价上
{
this.Canvas.textAlign='center';
this.Canvas.textBaseline='top';
if (this.IconFont)
{
this.Canvas.fillStyle=this.IconFont.Buy.Color
this.DrawText(this.IconFont.Buy.Text,x,yLow,isHScreen);
}
else
{
this.Canvas.fillStyle=this.BuyIcon.Color;
this.DrawText(this.BuyIcon.Text,x,yLow,isHScreen);
}
drawInfo[0]=true;
}
else if (bsItem.Op==1 && drawInfo[1]==false) //卖 标识在最高价上
{
this.Canvas.textAlign='center';
this.Canvas.textBaseline='bottom';
if (this.IconFont)
{
this.Canvas.fillStyle=this.IconFont.Sell.Color
this.DrawText(this.IconFont.Sell.Text,x,yHigh,isHScreen);
}
else
{
this.Canvas.fillStyle=this.SellIcon.Color;
this.DrawText(this.SellIcon.Text,x,yHigh,isHScreen);
}
drawInfo[1]=true;
}
}
}
}
}
//深度图
function ChartOrderbookDepth()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="ChartOrderbookDepth";
this.Data=null;
this.AskColor={ Line:g_JSChartResource.DepthChart.AskColor.Line, Area:g_JSChartResource.DepthChart.AskColor.Area } //卖
this.BidColor={ Line:g_JSChartResource.DepthChart.BidColor.Line, Area:g_JSChartResource.DepthChart.BidColor.Area } //买
this.LineWidth=g_JSChartResource.DepthChart.LineWidth;
this.Draw=function()
{
if (!this.Data) return;
var lineWidthBackup=this.Canvas.lineWidth;
this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
this.DrawArea(this.Data.Bids, this.BidColor.Line, this.BidColor.Area, true);
this.DrawArea(this.Data.Asks, this.AskColor.Line, this.AskColor.Area, false);
this.Canvas.lineWidth=lineWidthBackup;
}
this.DrawArea=function(aryData, colorLine, colorArea, isLeft)
{
var xRange=this.ChartFrame.VerticalRange;
var aryPoint=[];
for(var i in aryData)
{
var item=aryData[i];
if (isLeft)
{
if (item.Price<xRange.Min) break;
}
else
{
if (item.Price>xRange.Max) break;
}
var x=this.ChartFrame.GetXFromIndex(item.Price);
var y=this.ChartFrame.GetYFromData(item.Vol);
aryPoint.push({X:x,Y:y});
}
if (aryPoint.length<=1) return;
var left=this.ChartBorder.GetLeft();
var bottom=this.ChartBorder.GetBottom();
var right=this.ChartBorder.GetRight();
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, bottom);
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.lineTo(item.X,item.Y);
}
this.Canvas.lineTo(isLeft?left:right,aryPoint[aryPoint.length-1].Y);
this.Canvas.lineTo(isLeft?left:right,bottom);
this.Canvas.lineTo(aryPoint[0].X,bottom);
this.Canvas.closePath();
this.Canvas.fillStyle = colorArea;
this.Canvas.fill();
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, bottom);
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.lineTo(item.X,item.Y);
}
this.Canvas.lineTo(isLeft?left:right,aryPoint[aryPoint.length-1].Y);
this.Canvas.strokeStyle=colorLine;
this.Canvas.stroke();
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null, XMin:null, XMax:null };
var xRange=this.ChartFrame.VerticalRange;
for(var i in this.Data.Asks)
{
var item=this.Data.Asks[i];
if (item.Price>xRange.Max) break;
if (range.XMin==null || range.XMin>item.Price) range.XMin=item.Price;
if (range.XMax==null || range.XMax<item.Price) range.XMax=item.Price;
if (range.Min==null || range.Min>item.Vol) range.Min=item.Vol;
if (range.Max==null || range.Max<item.Vol) range.Max=item.Vol;
}
for(var i in this.Data.Bids)
{
var item=this.Data.Bids[i];
if (item.Price<xRange.Min) break;
if (range.XMin==null || range.XMin>item.Price) range.XMin=item.Price;
if (range.XMax==null || range.XMax<item.Price) range.XMax=item.Price;
if (range.Min==null || range.Min>item.Vol) range.Min=item.Vol;
if (range.Max==null || range.Max<item.Vol) range.Max=item.Vol;
}
return range;
}
}
/*
扩展图形
*/
function ExtendChartPaintFactory()
{
this.DataMap=new Map(
[
["FrameSplitPaint", { Create:function() { return new FrameSplitPaint(); } }],
["RectSelectPaint", { Create:function() { return new RectSelectPaint(); } }],
["RectDragPaint", { Create:function() { return new RectDragPaint(); } }],
["DragMovePaint", { Create:function() { return new DragMovePaint(); } }],
["SessionBreaksPaint", { Create:function() { return new SessionBreaksPaint(); }}],
["FrameButtomToolbarPaint", {Create:function() { return new FrameButtomToolbarPaint(); }}]
]
);
this.SetCallbackDraw=new Set();
this.Create=function(name)
{
if (!this.DataMap.has(name)) return null;
var item=this.DataMap.get(name);
return item.Create();
}
this.Add=function(name, option)
{
this.DataMap.set(name, { Create:option.Create } );
}
this.AddCallbackDrawClassName=function(className)
{
if (!className) return;
this.SetCallbackDraw.add(className);
}
this.IsCallbackDraw=function(className)
{
return this.SetCallbackDraw.has(className);
}
}
var g_ExtendChartPaintFactory=new ExtendChartPaintFactory();
function IExtendChartPainting()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.Data; //数据区
this.IsDynamic=false;
this.IsAnimation=false; //是否是动画
this.ClassName='IExtendChartPainting';
this.SizeChange=true; //大小是否改变
this.IsEraseBG=false; //是否每次画的时候需要擦除K线图背景
this.DrawAfterTitle=false; //是否在动态标题画完以后再画,防止动态标题覆盖
this.DrawAfterPicture=false; //是否在画图工具以后绘制
this.IsCallbackDraw=false; //在回调函数里绘制, 不在Draw()中绘制
this.ID=Guid();
//上下左右间距
this.Left=5;
this.Right=5;
this.Top=5;
this.Bottom=5;
this.Draw=function()
{
}
//设置参数接口
this.SetOption=function(option)
{
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
}
//K线Tooltip, 显示在左边或右边
function KLineTooltipPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDynamic=true;
this.IsEraseBG=true;
this.DrawAfterTitle=true;
this.ClassName='KLineTooltipPaint';
this.BorderColor=g_JSChartResource.TooltipPaint.BorderColor; //边框颜色
this.BGColor=g_JSChartResource.TooltipPaint.BGColor; //背景色
this.TitleColor=g_JSChartResource.TooltipPaint.TitleColor; //标题颜色
this.DateTimeColor=g_JSChartResource.TooltipPaint.DateTimeColor; //日期时间颜色
this.VolColor=g_JSChartResource.TooltipPaint.VolColor; //标题成交量
this.AmountColor=g_JSChartResource.TooltipPaint.AmountColor; //成交金额
this.LatestPoint; //手势位置
this.ShowPosition=0; //显示位置 0=左 1=右
this.Left=1*GetDevicePixelRatio();
this.Top=5*GetDevicePixelRatio();
this.Width=50;
this.Height=100;
this.LineHeight=15*GetDevicePixelRatio(); //行高
this.LineSpace=2; //行间距
this.Mergin={ Left:2, Top:3, Bottom:5, Right:5 };
this.ExtendLineWidth=2;
this.Font=[g_JSChartResource.TooltipPaint.TitleFont];
this.HQChart;
this.KLineTitlePaint;
this.IsHScreen=false; //是否横屏
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.TooltipPaint.BorderColor; //边框颜色
this.BGColor=g_JSChartResource.TooltipPaint.BGColor; //背景色
this.TitleColor=g_JSChartResource.TooltipPaint.TitleColor; //标题颜色
this.DateTimeColor=g_JSChartResource.TooltipPaint.DateTimeColor; //日期时间颜色
this.VolColor=g_JSChartResource.TooltipPaint.VolColor; //标题成交量
this.AmountColor=g_JSChartResource.TooltipPaint.AmountColor; //成交金额
}
this.GetLeft=function()
{
if (this.IsHScreen)
{
return this.ChartBorder.GetRightEx()-this.Height-this.Top;
}
else
{
if (this.ShowPosition==0)
return this.ChartBorder.GetLeft()+this.Left;
else
return this.ChartBorder.GetRight()-this.Width-this.Left;
}
}
this.GetTop=function()
{
if (this.IsHScreen)
{
if (this.ShowPosition==0)
return this.ChartBorder.GetTop()+this.Left;
else
return this.ChartBorder.GetBottom()-this.Width-this.Left;
}
else
{
return this.ChartBorder.GetTopEx()+this.Top;
}
}
this.IsEnableDraw=function()
{
if (!this.HQChart || !this.HQChart.TitlePaint || !this.HQChart.TitlePaint[0]) return false;
if (this.HQChart.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.HQChart.TouchStatus.CorssCursorShow==false) return false;
}
else if (this.HQChart.EnableClickModel)
{
if (this.HQChart.ClickModel.IsShowCorssCursor===false) return false;
}
else if (this.HQChart.VerticalDrag)
{
if (this.HQChart.VerticalDrag.IsDrag) return false; //拖X轴的时候 不要显示tooltip
}
else if (!this.HQChart.IsOnTouch)
{
return false;
}
if (this.HQChart.CurrentChartDrawPicture) return false; //画图工具操作的时候 不显示
return true;
}
this.Draw=function()
{
if (!this.IsEnableDraw()) return;
this.IsHScreen=this.ChartFrame.IsHScreen===true;
this.KLineTitlePaint=this.HQChart.TitlePaint[0];
var klineData=this.KLineTitlePaint.GetCurrentKLineData();
if (!klineData) return;
var titleData=this.GetFormatTitle({Data:klineData});
if (!titleData || !IFrameSplitOperator.IsNonEmptyArray(titleData.AryText)) return;
this.CalculateTooltipSize(titleData);
this.CalculateShowPosition();
this.DrawBG();
this.DrawTooltipData(titleData);
this.DrawBorder();
}
this.CalculateTooltipSize=function(titleData)
{
this.Canvas.font=this.Font[0];
this.LineHeight=this.Canvas.measureText("擎").width;
var pixelRatio=GetDevicePixelRatio();
var height=0;
var maxTitleWidth=0, maxTextWidth=0, maxLineWidth=0;
for(var i=0; i<titleData.AryText.length; ++i)
{
var item=titleData.AryText[i];
if (height>0) height+=this.LineSpace;
var lineWidth=0;
if (item.Title)
{
var textWidth=this.Canvas.measureText(item.Title).width+2;
if (maxTitleWidth<textWidth) maxTitleWidth=textWidth;
lineWidth+=textWidth;
}
if (item.Text)
{
var textWidth=this.Canvas.measureText(item.Text).width+2;
if (maxTextWidth<textWidth) maxTextWidth=textWidth;
lineWidth+=textWidth;
}
if (maxLineWidth<lineWidth) maxLineWidth=lineWidth;
height+=this.LineHeight;
}
this.Height=height+(this.Mergin.Top+this.Mergin.Bottom)*pixelRatio;
this.Width=(maxLineWidth)+(this.Mergin.Left+this.Mergin.Right+this.ExtendLineWidth)*pixelRatio;
return { Height:this.Height, Width:this.Width, MaxTitleWidth:maxTitleWidth, MaxTextWidth:maxTextWidth };
}
//判断显示位置
this.CalculateShowPosition=function()
{
this.ShowPosition=0;
if (!this.LatestPoint) return;
if(this.IsHScreen)
{
var top=this.ChartBorder.GetTop();
var height=this.ChartBorder.GetHeight();
var yCenter=top+height/2;
if (this.LatestPoint.Y<yCenter) this.ShowPosition=1;
}
else
{
var left=this.ChartBorder.GetLeft();
var width=this.ChartBorder.GetWidth();
var xCenter=left+width/2;
if (this.LatestPoint.X<xCenter) this.ShowPosition=1;
}
}
this.GetFormatTitle=function(data)
{
if (!data || !data.Data) return;
var item=data.Data;
var upperSymbol;
if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var aryText=[];
var result={ AryText:aryText };
var text, title, color;
text=IFrameSplitOperator.FormatDateString(item.Date);
aryText.push({ Text:text, Color:this.DateTimeColor });
var period=this.HQChart.Period;
if (ChartData.IsMinutePeriod(period,true) && IFrameSplitOperator.IsNumber(item.Time))
{
text=IFrameSplitOperator.FormatTimeString(item.Time);
aryText.push({ Text:text, Color:this.DateTimeColor });
}
else if (ChartData.IsSecondPeriod(period) && IFrameSplitOperator.IsNumber(item.Time))
{
text=IFrameSplitOperator.FormatTimeString(item.Time,'HH:MM:SS');
aryText.push({ Text:text, Color:this.DateTimeColor });
}
else if (ChartData.IsMilliSecondPeriod(period) && IFrameSplitOperator.IsNumber(item.Time))
{
text=IFrameSplitOperator.FormatTimeString(item.Time,'HH:MM:SS.fff');
aryText.push({ Text:text, Color:this.DateTimeColor });
}
if (IFrameSplitOperator.IsNumber(item.Open)) //开盘
{
title=g_JSChartLocalization.GetText('Tooltip-Open',this.LanguageID);
color=this.KLineTitlePaint.GetColor(item.Open,item.YClose);
text=item.Open.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.High)) //高
{
title=g_JSChartLocalization.GetText('Tooltip-High',this.LanguageID);
color=this.KLineTitlePaint.GetColor(item.High,item.YClose);
text=item.High.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.Low)) //低
{
title=g_JSChartLocalization.GetText('Tooltip-Low',this.LanguageID);
color=this.KLineTitlePaint.GetColor(item.Low,item.YClose);
text=item.Low.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.Close)) //收
{
title=g_JSChartLocalization.GetText('Tooltip-Close',this.LanguageID);
color=this.KLineTitlePaint.GetColor(item.Close,item.YClose);
text=item.Close.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
//涨幅
title=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID);
if (IFrameSplitOperator.IsNumber(item.YFClose) && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol))
{
var value=(item.Close-item.YFClose)/item.YFClose*100;
color = this.KLineTitlePaint.GetColor(value, 0);
text = value.toFixed(2)+'%';
}
else if (IFrameSplitOperator.IsNumber(item.YClose))
{
var value=(item.Close-item.YClose)/item.YClose*100;
color = this.KLineTitlePaint.GetColor(value, 0);
text = value.toFixed(2)+'%';
}
else
{
text='--.--';
color=this.KLineTitlePaint.GetColor(0, 0);
}
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
if (IFrameSplitOperator.IsNumber(item.Vol))
{
title=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID);
var vol=item.Vol;
if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.VolColor });
}
if (IFrameSplitOperator.IsNumber(item.Amount))
{
title=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID);
var text=IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.AmountColor });
}
//换手率
if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && item.FlowCapital>0)
{
title=g_JSChartLocalization.GetText('Tooltip-Exchange',this.LanguageID);
var value=item.Vol/item.FlowCapital*100;
var text=value.toFixed(2)+'%';
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
//持仓量
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
{
title=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
var text=IFrameSplitOperator.FromatIntegerString(item.Position,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
return result;
}
this.DrawTooltipData=function(titleData)
{
if (!titleData || !IFrameSplitOperator.IsNonEmptyArray(titleData.AryText)) return;
var pixelRatio=GetDevicePixelRatio();
var left=this.GetLeft()+2*pixelRatio;
var top=this.GetTop()+3*pixelRatio;
if (this.IsHScreen)
{
this.Canvas.save();
var x=this.GetLeft()+this.Height, y=this.GetTop();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
//x, y 作为原点
left=2*pixelRatio;
top=3*pixelRatio;
}
this.Canvas.textBaseline="top";
var right=left+this.Width-this.Mergin.Right*pixelRatio;
left+=this.Mergin.Left*pixelRatio;
top+=this.Mergin.Top*pixelRatio;
for(var i=0; i<titleData.AryText.length; ++i)
{
var item=titleData.AryText[i];
if (item.Title)
{
this.Canvas.textAlign="left";
this.Canvas.fillStyle=item.TitleColor;
this.Canvas.fillText(item.Title,left,top);
}
if (item.Text)
{
this.Canvas.textAlign="right";
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(item.Text,right,top);
}
top+=this.LineHeight+this.LineSpace;
}
if (this.IsHScreen) this.Canvas.restore();
}
/*
this.DrawTooltipData=function(item)
{
//JSConsole.Chart.Log('[KLineTooltipPaint::DrawKLineData] ', item);
var upperSymbol;
if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var left=this.GetLeft()+2*GetDevicePixelRatio();
var top=this.GetTop()+3*GetDevicePixelRatio();
if (this.IsHScreen)
{
this.Canvas.save();
var x=this.GetLeft()+this.Height, y=this.GetTop();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
//x, y 作为原点
left=2*GetDevicePixelRatio();
top=3*GetDevicePixelRatio();
}
this.Canvas.textBaseline="top";
this.Canvas.textAlign="left";
this.Canvas.font=this.Font[0];
var labelWidth=this.Canvas.measureText('擎: ').width;
var text=IFrameSplitOperator.FormatDateString(item.Date);
this.Canvas.fillStyle=this.DateTimeColor;
this.Canvas.fillText(text, left,top);
var period=this.HQChart.Period;
if (ChartData.IsMinutePeriod(period,true) && IFrameSplitOperator.IsNumber(item.Time))
{
top+=this.LineHeight;
text=IFrameSplitOperator.FormatTimeString(item.Time);
this.Canvas.fillText(text, left,top);
}
else if (ChartData.IsSecondPeriod(period) && IFrameSplitOperator.IsNumber(item.Time))
{
top+=this.LineHeight;
text=IFrameSplitOperator.FormatTimeString(item.Time,'HH:MM:SS');
this.Canvas.fillText(text, left,top);
}
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Open',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(item.Open,item.YClose);
text=item.Open.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-High',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(item.High,item.YClose);
var text=item.High.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Low',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(item.Low,item.YClose);
var text=item.Low.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Close',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(item.Close,item.YClose);
var text=item.Close.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID);
this.Canvas.fillText(text, left,top);
if (item.YFClose>0 && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol))
{
var value=(item.Close-item.YFClose)/item.YFClose*100;
var color = this.KLineTitlePaint.GetColor(value, 0);
var text = value.toFixed(2)+'%';
}
else if (item.YClose>0)
{
var value=(item.Close-item.YClose)/item.YClose*100;
var color = this.KLineTitlePaint.GetColor(value, 0);
var text = value.toFixed(2)+'%';
}
else
{
var text='--.--';
var color=this.KLineTitlePaint.GetColor(0, 0);
}
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID);
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(text, left,top);
var vol=item.Vol;
if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
this.Canvas.fillStyle=this.VolColor;
this.Canvas.fillText(text,left+labelWidth,top);
if (IFrameSplitOperator.IsNumber(item.Amount))
{
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID);
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID);
this.Canvas.fillStyle=this.AmountColor;
this.Canvas.fillText(text,left+labelWidth,top);
}
//换手率
if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && item.FlowCapital>0)
{
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Exchange',this.LanguageID);
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(text, left,top);
var value=item.Vol/item.FlowCapital*100;
var text=value.toFixed(2)+'%';
this.Canvas.fillText(text,left+labelWidth,top);
}
//持仓量
var upperSymbol=this.HQChart.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
{
this.Canvas.fillStyle=this.TitleColor;
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FromatIntegerString(item.Position,2,this.LanguageID);
this.Canvas.fillText(text,left+labelWidth,top);
}
if (this.IsHScreen) this.Canvas.restore();
}
*/
this.DrawBorder=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var left=this.GetLeft();
var top=this.GetTop();
this.Canvas.strokeStyle=this.BorderColor;
if (isHScreen) this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),this.Height,this.Width);
else this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),ToFixedRect(this.Width),ToFixedRect(this.Height));
}
this.DrawBG=function()
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var left=this.GetLeft();
var top=this.GetTop();
this.Canvas.fillStyle=this.BGColor;
if (isHScreen) this.Canvas.fillRect(left,top,this.Height,this.Width);
else this.Canvas.fillRect(left,top,this.Width,this.Height);
}
//设置参数接口
this.SetOption=function(option)
{
if (option.LineHeight>0) this.LineHeight=option.LineHeight*GetDevicePixelRatio();
if (option.BGColor) this.BGColor=option.BGColor;
if (option.LanguageID>0) this.LanguageID=option.LanguageID;
}
}
function MinuteTooltipPaint()
{
this.newMethod=KLineTooltipPaint; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='MinuteTooltipPaint';
this.Left=1*GetDevicePixelRatio();
this.Top=1*GetDevicePixelRatio();
this.YClose;
this.IsShowAveragePrice=true; //是否显示均价
this.TitlePaint;
this.GetTop=function()
{
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
if (this.ShowPosition==0)
return border.TopEx+this.Left;
else
return border.BottomEx-this.Width-this.Left;
}
else
{
var border=this.ChartBorder.GetBorder();
return border.Top+this.Top;
}
}
this.GetLeft=function()
{
if (this.IsHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
return border.Right-this.Height-this.Top;
}
else
{
var border=this.ChartBorder.GetBorder();
if (this.ShowPosition==0)
return border.LeftEx+this.Left;
else
return border.RightEx-this.Width-this.Left;
}
}
this.Draw=function()
{
if (!this.IsEnableDraw()) return;
this.IsHScreen=this.ChartFrame.IsHScreen===true;
this.TitlePaint=this.HQChart.TitlePaint[0];
if (!this.TitlePaint) return;
var drawData; //{ Type:0=连续交易 1=集合竞价, Data:数据 }
var pointInfo=this.TitlePaint.PointInfo;
if (pointInfo && (pointInfo.ClientPos==2 || pointInfo.ClientPos==3 || (pointInfo.ClientPos>=200&& pointInfo.ClientPos<=299) || (pointInfo.ClientPos>=300&& pointInfo.ClientPos<=399)))
{
var auctionData=this.TitlePaint.GetCurrentAuctionData();
if (!auctionData) return;
drawData={ Type:1, Data:auctionData };
}
else
{
var minuteData=this.TitlePaint.GetCurrentKLineData();
if (!minuteData) return;
drawData={ Type:0, Data:minuteData };
}
var titleData=this.GetFormatTitle(drawData);
if (!titleData || !IFrameSplitOperator.IsNonEmptyArray(titleData.AryText)) return;
this.CalculateTooltipSize(titleData);
this.CalculateShowPosition();
this.DrawBG();
this.DrawTooltipData(titleData);
this.DrawBorder();
}
this.GetFormatTitle=function(data)
{
if (!data || !data.Data) return;
var item;
var close, vol, amount;
if (data.Type==0) //盘中
{
item=data.Data;
close=item.Close;
vol=item.Vol;
amount=item.Amount;
}
else if (data.Type==1) //盘前 盘后
{
item=data.Data.Data;
if (!item) return;
close=item.Price;
}
var upperSymbol;
if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
this.YClose=this.TitlePaint.YClose;
this.YClose=item.YClose;
if (isFutures && IFrameSplitOperator.IsNumber(item.YClearing)) this.YClose=item.YClearing;
var aryText=[];
var result={ AryText:aryText };
var text, title, color;
if (IFrameSplitOperator.IsNumber(item.Date))
{
text=IFrameSplitOperator.FormatDateString(item.Date);
aryText.push({ Text:text, Color:this.DateTimeColor });
}
if (IFrameSplitOperator.IsNumber(item.Time))
{
text=IFrameSplitOperator.FormatTimeString(item.Time);
aryText.push({ Text:text, Color:this.DateTimeColor });
}
if (IFrameSplitOperator.IsNumber(close)) //最新
{
title=g_JSChartLocalization.GetText('Tooltip-Price',this.LanguageID);
color=this.TitlePaint.GetColor(close,this.YClose);
text=close.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
var isShowAvPrice=true;
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) isShowAvPrice=false; //外汇没有均价
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol) && !MARKET_SUFFIX_NAME.IsETShowAvPrice(upperSymbol)) isShowAvPrice=false;
else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) isShowAvPrice=false;
//均价
if (isShowAvPrice && IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice)
{
title=g_JSChartLocalization.GetText('Tooltip-AvPrice',this.LanguageID);
var color=this.TitlePaint.GetColor(item.AvPrice,this.YClose);
text=item.AvPrice.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
//涨幅
if (IFrameSplitOperator.IsNumber(close) && IFrameSplitOperator.IsNumber(this.YClose))
{
title=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID);
if (this.YClose===0)
{
text = '--.--';
color = this.TitleColor;
}
else
{
var value=(close-this.YClose)/this.YClose*100;
color = this.TitlePaint.GetColor(value, 0);
text = value.toFixed(2)+'%';
}
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
//成交量
if (IFrameSplitOperator.IsNumber(vol))
{
title=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID);
var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.VolColor });
}
//成交金额
if (IFrameSplitOperator.IsNumber(amount))
{
title=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID);
var text=IFrameSplitOperator.FormatValueString(amount,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.AmountColor });
}
if (IFrameSplitOperator.IsNumber(item.Position))
{
title=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
var text=IFrameSplitOperator.FormatValueString(item.Position,2,this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
return result;
}
/*
this.DrawTooltipData=function(item)
{
//JSConsole.Chart.Log('[KLineTooltipPaint::DrawKLineData] ', item);
if (!this.HQChart.Symbol) return;
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var left=this.GetLeft()+2*GetDevicePixelRatio();
var top=this.GetTop()+3*GetDevicePixelRatio();
this.YClose=this.KLineTitlePaint.YClose;
var upperSymbol=this.HQChart.Symbol.toUpperCase();
if (this.IsHScreen)
{
this.Canvas.save();
var x=this.GetLeft()+this.Height, y=this.GetTop();
this.Canvas.translate(x, y);
this.Canvas.rotate(90 * Math.PI / 180);
//x, y 作为原点
left=2*GetDevicePixelRatio();
top=3*GetDevicePixelRatio();
}
this.Canvas.textBaseline="top";
this.Canvas.textAlign="left";
this.Canvas.font=this.Font[0];
var labelWidth=this.Canvas.measureText('擎: ').width;
var aryDateTime=item.DateTime.split(' ');
if (aryDateTime && aryDateTime.length==2)
{
var text=IFrameSplitOperator.FormatDateString(aryDateTime[0]);
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(text, left,top);
top+=this.LineHeight;
text=IFrameSplitOperator.FormatTimeString(aryDateTime[1]);
this.Canvas.fillText(text, left,top);
}
var close=item.Close;
var increase=item.Increase;
var vol=item.Vol;
var amount=item.Amount;
if (item.Before) //读取盘前数据
{
close=item.Before.Close;
increase=item.Before.Increase;
vol=item.Before.Vol;
amount=item.Before.Amount;
}
//最新价格
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Price',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(close,this.YClose);
var text=close.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
var isShowAvPrice=true;
if (item.Before) isShowAvPrice=false; //集合竞价均价
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) isShowAvPrice=false; //外汇没有均价
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol) && !MARKET_SUFFIX_NAME.IsETShowAvPrice(upperSymbol)) isShowAvPrice=false;
else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) isShowAvPrice=false;
//均价
if (isShowAvPrice && IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice)
{
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-AvPrice',this.LanguageID);
this.Canvas.fillText(text, left,top);
var color=this.KLineTitlePaint.GetColor(item.AvPrice,this.YClose);
var text=item.AvPrice.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
}
//涨幅
top+=this.LineHeight;
this.Canvas.fillStyle=this.TitleColor;
text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID);
this.Canvas.fillText(text, left,top);
var value=(close-this.YClose)/this.YClose*100;
var color = this.KLineTitlePaint.GetColor(value, 0);
var text = value.toFixed(2)+'%';
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,left+labelWidth,top);
//成交量
if (IFrameSplitOperator.IsNumber(vol))
{
this.Canvas.fillStyle=this.TitleColor;
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID);
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
this.Canvas.fillText(text,left+labelWidth,top);
}
//成交金额
if (IFrameSplitOperator.IsNumber(amount))
{
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID);
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FormatValueString(amount,2,this.LanguageID);
this.Canvas.fillText(text,left+labelWidth,top);
}
if (IFrameSplitOperator.IsNumber(item.Position))
{
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FormatValueString(item.Position,2,this.LanguageID);
this.Canvas.fillText(text,left+labelWidth,top);
}
if (this.IsHScreen) this.Canvas.restore();
}
*/
}
//PC端 分时图tooltip左侧固定
function MinuteLeftTooltipPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDynamic=true;
this.IsEraseBG=true;
this.DrawAfterTitle=true;
this.ClassName='MinuteLeftTooltipPaint';
this.BorderColor=g_JSChartResource.PCTooltipPaint.BorderColor; //边框颜色
this.BGColor=g_JSChartResource.PCTooltipPaint.BGColor; //背景色
this.TitleColor=g_JSChartResource.PCTooltipPaint.TitleColor; //标题颜色
this.DateTimeColor=g_JSChartResource.PCTooltipPaint.DateTimeColor; //日期时间颜色
this.VolColor=g_JSChartResource.PCTooltipPaint.VolColor; //标题成交量
this.AmountColor=g_JSChartResource.PCTooltipPaint.AmountColor; //成交金额
this.PositionColor=g_JSChartResource.PCTooltipPaint.PositionColor; //持仓
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.TitlePaint;
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.YClose;
this.Mergin={ Left:2, Top:3, Bottom:2, Right:2 };
this.LineHeight=15 //行高
this.FixedWidth; //固定宽度
this.Font=g_JSChartResource.PCTooltipPaint.TitleFont;
this.HQChart;
//设置参数接口
this.SetOption=function(option)
{
if (option.BGColor) this.BGColor=option.BGColor;
if (option.LanguageID>0) this.LanguageID=option.LanguageID;
if (IFrameSplitOperator.IsNumber(option.FixedWidth)) this.FixedWidth=option.FixedWidth;
}
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.PCTooltipPaint.BorderColor; //边框颜色
this.BGColor=g_JSChartResource.PCTooltipPaint.BGColor; //背景色
this.TitleColor=g_JSChartResource.PCTooltipPaint.TitleColor; //标题颜色
this.DateTimeColor=g_JSChartResource.PCTooltipPaint.DateTimeColor; //日期时间颜色
this.VolColor=g_JSChartResource.PCTooltipPaint.VolColor; //标题成交量
this.AmountColor=g_JSChartResource.PCTooltipPaint.AmountColor; //成交金额
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.Font=g_JSChartResource.PCTooltipPaint.TitleFont;
}
this.IsEnableDraw=function()
{
if (!this.HQChart || !this.HQChart.TitlePaint || !this.HQChart.TitlePaint[0]) return false;
var pt=this.HQChart.LastPoint;
if (!pt) return false;
if (this.HQChart.ChartCorssCursor && !this.HQChart.ChartCorssCursor.IsShowCorss) return false;
return this.HQChart.IsMouseOnClient(pt.X, pt.Y);
}
this.Draw=function()
{
if (!this.IsEnableDraw()) return;
this.TitlePaint=this.HQChart.TitlePaint[0];
if (!this.TitlePaint) return;
var pointInfo=this.TitlePaint.PointInfo;
var drawData; //{ Type:0=连续交易 1=集合竞价, Data:数据 }
if (pointInfo && (pointInfo.ClientPos==2 || pointInfo.ClientPos==3 || (pointInfo.ClientPos>=200&& pointInfo.ClientPos<=299) || (pointInfo.ClientPos>=300&& pointInfo.ClientPos<=399)))
{
var auctionData=this.TitlePaint.GetCurrentAuctionData();
if (!auctionData) return;
drawData={ Type:1, Data:auctionData };
}
else
{
var minuteData=this.TitlePaint.GetCurrentKLineData();
if (!minuteData) return;
drawData={ Type:0, Data:minuteData };
}
this.YClose=this.TitlePaint.YClose;
var aryText=this.GetForamtTitle(drawData);
if (!IFrameSplitOperator.IsNonEmptyArray(aryText)) return;
this.Canvas.font=this.Font;
this.Canvas.textBaseline = 'top';
this.LineHeight=GetFontHeight(this.Canvas, null, "擎");
var border=this.ChartBorder.GetBorder();
var height=this.LineHeight*aryText.length*2;
var rtBorder={Left:1, Top:1, Right:border.Left };
rtBorder.Bottom=rtBorder.Top+height;
rtBorder.Width=rtBorder.Right-rtBorder.Left;
rtBorder.Height=rtBorder.Bottom-rtBorder.Top;
rtBorder.Height+=(this.Mergin.Top+this.Mergin.Bottom);
rtBorder.Bottom=rtBorder.Top+rtBorder.Height;
if (IFrameSplitOperator.IsNumber(this.FixedWidth)) rtBorder.Width=this.FixedWidth;
this.Canvas.fillStyle = this.BGColor;
this.Canvas.fillRect(rtBorder.Left,rtBorder.Top,rtBorder.Width,rtBorder.Height);
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtBorder.Left),ToFixedPoint(rtBorder.Top),ToFixedRect(rtBorder.Width),ToFixedRect(rtBorder.Height));
var right=(rtBorder.Left+rtBorder.Width)-this.Mergin.Right;
var left=this.Mergin.Left+rtBorder.Left;
var top=this.Mergin.Top+rtBorder.Top;
var rtItem={ Left:left, Top:top, Right:right };
rtItem.Width=rtItem.Right-rtItem.Left;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
this.DrawText(item, rtItem);
}
}
this.DrawText=function(item, rtItem)
{
this.Canvas.fillStyle = item.TitleColor;
this.Canvas.textAlign = 'left';
this.Canvas.fillText(item.Title, rtItem.Left, rtItem.Top);
rtItem.Top+=this.LineHeight;
rtItem.Bottom=rtItem.Top+this.LineHeight;
this.Canvas.textAlign = 'right';
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Text, rtItem.Right, rtItem.Top);
rtItem.Top+=this.LineHeight;
rtItem.Bottom=rtItem.Top+this.LineHeight;
}
//{ Title:, Text:, Color: }
this.GetForamtTitle=function(drawData)
{
if (!drawData || !drawData.Data) return null;
var aryText=[];
var isFutures=false;
var upperSymbol;
if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(upperSymbol);//价格小数位数
if (upperSymbol) isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
if (drawData.Type==0) //连续交易
{
var item=drawData.Data;
if (!item) return;
this.YClose=item.YClose;
if (isFutures && IFrameSplitOperator.IsNumber(item.YClearing)) this.YClose=item.YClearing;
var titleItem=this.FormatDate(item.Date);
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtTime(item.Time,"HH:MM",'PCTooltip-Time');
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtPrice(item.Close,defaultfloatPrecision,'PCTooltip-Price');
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtPrice(item.AvPrice,defaultfloatPrecision,'PCTooltip-AvPrice');
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtIncrease(item.Close,"PCTooltip-Increase");
if (titleItem) aryText.push(titleItem);
var titleItem=this.FormatVol(item.Vol,'PCTooltip-Vol');
if (titleItem) aryText.push(titleItem);
if (IFrameSplitOperator.IsNumber(item.Amount))
{
var titleItem=
{
Title:g_JSChartLocalization.GetText('PCTooltip-Amount',this.LanguageID),
TitleColor:this.TitleColor,
Text:IFrameSplitOperator.FromatIntegerString(item.Amount,2,this.LanguageID),
TextColor:this.AmountColor
};
aryText.push(titleItem);
}
if (isFutures && IFrameSplitOperator.IsNumber(item.Position)) //持仓
{
var titleItem=this.FormatPosition(item.Position,'PCTooltip-Position');
if (titleItem) aryText.push(titleItem);
}
}
else if (drawData.Type==1) //集合竞价
{
var item=drawData.Data.Data;
if (!item) return;
this.YClose=item.YClose;
if (isFutures && IFrameSplitOperator.IsNumber(item.YClearing)) this.YClose=item.YClearing;
var titleItem=this.FormatDate(item.Date);
if (titleItem) aryText.push(titleItem);
var timeForamt="HH:MM:SS";
if (item.Ver===1) timeForamt="HH:MM"
var titleItem=this.ForamtTime(item.Time,timeForamt,'PCTooltip-Time');
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtPrice(item.Price,defaultfloatPrecision,'PCTooltip-AC-Price');
if (titleItem) aryText.push(titleItem);
var titleItem=this.ForamtIncrease(item.Price,"PCTooltip-AC-Increase");
if (titleItem) aryText.push(titleItem);
if (IFrameSplitOperator.IsNonEmptyArray(item.Vol))
{
var titleItem=this.FormatVol(item.Vol[0],'PCTooltip-AC-Vol');
if (titleItem) aryText.push(titleItem);
var titleItem=this.FormatVol(item.Vol[1],'PCTooltip-AC-NotMatchVol');
if (titleItem) aryText.push(titleItem);
}
}
return aryText;
}
this.GetColor=function(price,yclse)
{
if(price>yclse) return this.UpColor;
else if (price<yclse) return this.DownColor;
else return this.UnchagneColor;
}
this.FormatDate=function(date)
{
if (!IFrameSplitOperator.IsNumber(date)) return null;
var titleItem=
{
Title:g_JSChartLocalization.GetText('PCTooltip-Date',this.LanguageID),
TitleColor:this.TitleColor,
Text:IFrameSplitOperator.FormatDateString(date, "MM-DD", this.LanguageID),
TextColor:this.DateTimeColor
};
return titleItem;
}
this.ForamtTime=function(time, format, TitleID)
{
if (!IFrameSplitOperator.IsNumber(time)) return null;
var titleItem=
{
Title:g_JSChartLocalization.GetText(TitleID,this.LanguageID),
TitleColor:this.TitleColor,
Text:IFrameSplitOperator.FormatTimeString(time, format, this.LanguageID),
TextColor:this.DateTimeColor
};
return titleItem;
}
this.ForamtPrice=function(price, defaultfloatPrecision, TitleID)
{
if (!IFrameSplitOperator.IsNumber(price)) return null;
var titleItem=
{
Title:g_JSChartLocalization.GetText(TitleID, this.LanguageID),
TitleColor:this.TitleColor,
Text:price.toFixed(defaultfloatPrecision),
TextColor:this.GetColor(price, this.YClose)
};
return titleItem;
}
this.ForamtIncrease=function(price, TitleID)
{
if (!IFrameSplitOperator.IsNumber(price) || price==0) return null;
var value=(price-this.YClose)/this.YClose*100;
var titleItem=
{
Title:g_JSChartLocalization.GetText(TitleID,this.LanguageID),
TitleColor:this.TitleColor,
Text:value.toFixed(2)+'%',
TextColor:this.GetColor(value, 0)
};
if (this.YClose===0)
{
titleItem.Text="--.--";
titleItem.TextColor=this.TitleColor
}
return titleItem;
}
this.FormatVol=function(vol, TitleID)
{
if (!IFrameSplitOperator.IsNumber(vol)) return null;
var titleItem=
{
Title:g_JSChartLocalization.GetText(TitleID,this.LanguageID),
TitleColor:this.TitleColor,
Text:IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID),
TextColor:this.VolColor
};
return titleItem;
}
this.FormatPosition=function(value, TitleID)
{
if (!IFrameSplitOperator.IsNumber(value)) return null;
var titleItem=
{
Title:g_JSChartLocalization.GetText(TitleID,this.LanguageID),
TitleColor:this.TitleColor,
Text:value.toFixed(0),
TextColor:this.PositionColor
};
return titleItem;
}
}
//股票信息
function StockInfoExtendChartPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.Left=80;
this.Right=1;
this.Top=1;
this.Bottom=1;
this.BorderColor=g_JSChartResource.FrameBorderPen;
this.Symbol;
this.Name;
this.TitleFont=["14px 微软雅黑"];
this.Draw=function()
{
var left=this.ChartBorder.GetRight()+this.Left;
var right=this.ChartBorder.GetChartWidth()-this.Right;
var y=this.Top+18;
var middle=left+(right-left)/2;
if (this.Symbol && this.Name)
{
this.Canvas.font=this.TitleFont[0];
this.Canvas.textAlign="right";
this.Canvas.textBaseline="bottom";
this.Canvas.fillText(this.Symbol,middle-2,y);
this.Canvas.textAlign="left";
this.Canvas.fillText(this.Name,middle+2,y);
}
;
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.moveTo(left,y);
this.Canvas.lineTo(right,y);
this.Canvas.stroke();
y+=30;
this.DrawBorder();
}
this.DrawBorder=function()
{
var left=this.ChartBorder.GetRight()+this.Left;
var right=this.ChartBorder.GetChartWidth()-this.Right;
var top=this.Top;
var bottom=this.ChartBorder.GetChartHeight()-this.Bottom;
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(left,top,(right-left),(bottom-top));
}
}
//筹码分布
function StockChip()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.Name='筹码分布';
this.ClassName='StockChip';
this.HQChart;
this.PenBorder=g_JSChartResource.FrameBorderPen; //边框
this.ColorProfit='rgb(255,0,0)'; //盈利的线段
this.ColorNoProfit='rgb(90,141,248)'; //非盈利
this.ColorAveragePrice='rgb(0,139,0)'; //平均价线
this.ColorBG='rgb(190,190,190)'; //筹码背景线段颜色
this.PixelRatio=GetDevicePixelRatio();
this.ShowType=0; //0=所有筹码 1=周期前 2=周期内
this.IsDynamic=true;
this.ClientRect={};
this.Font=g_JSChartResource.TitleFont;
this.InfoColor=g_JSChartResource.StockChip.InfoColor;
this.DayInfoColor=g_JSChartResource.StockChip.DayInfoColor;
this.LineHeight=16;
this.Left=50*this.PixelRatio; //左边间距
this.IsShowX=false; //是否显示X刻度 成交量
this.ShowXCount=3;
this.Width=150*this.PixelRatio; //筹码图宽度
this.CalculateType=0; //0=平均分布 1=三角分布
this.PriceZoom=100; //价格放大倍数
this.NotSupportMessage="不支持筹码图";
this.Buttons=[];
this.DefaultButton=CloneData(g_JSChartResource.StockChip.DefaultButton); //默认筹码分布图
this.LongButton=CloneData(g_JSChartResource.StockChip.LongButton); //远期筹码分布图
this.RecentButton=CloneData(g_JSChartResource.StockChip.RecentButton); //近期筹码分布图
this.ButtonTooltip=CloneData(g_JSChartResource.Buttons.Tooltip);
this.DAY_COLOR=
[
['rgb(255,0,0)','rgb(255,128,128)','rgb(255,0,128)','rgb(255,100,0)','rgb(192,128,0)','rgb(255,192,0)'],
['rgb(120,80,225)','rgb(160,160,225)','rgb(80,80,255)','rgb(120,120,255)','rgb(32,64,192)','rgb(0,64,128)'],
];
this.SetOption=function(option)
{
if (!option) return;
if (option.ShowType>0) this.ShowType=option.ShowType;
if (option.IsShowX) this.IsShowX=option.IsShowX;
if (option.ShowXCount>0) this.ShowXCount=option.ShowXCount;
if (option.Width>100) this.Width=option.Width*GetDevicePixelRatio();
if (option.CalculateType>0) this.CalculateType=option.CalculateType;
if (IFrameSplitOperator.IsNumber(option.PriceZoom)) this.PriceZoom=option.PriceZoom;
}
this.ReloadResource=function(resource)
{
this.PenBorder=g_JSChartResource.FrameBorderPen;
this.Font=g_JSChartResource.TitleFont;
this.InfoColor=g_JSChartResource.StockChip.InfoColor;
this.DayInfoColor=g_JSChartResource.StockChip.DayInfoColor;
this.DefaultButton=CloneData(g_JSChartResource.StockChip.DefaultButton); //默认筹码分布图
this.LongButton=CloneData(g_JSChartResource.StockChip.LongButton); //远期筹码分布图
this.RecentButton=CloneData(g_JSChartResource.StockChip.RecentButton); //近期筹码分布图
this.ButtonTooltip=CloneData(g_JSChartResource.Buttons.Tooltip);
}
this.Draw=function()
{
this.PixelRatio=GetDevicePixelRatio();
var left=ToFixedPoint(this.ChartBorder.GetRight()+this.Left);
var top=ToFixedPoint(this.ChartBorder.GetTop());
var right=ToFixedPoint(left+this.Width-1*this.PixelRatio);
var bottom=ToFixedPoint(this.ChartBorder.GetBottom());
var width=right-left;
var height=bottom-top;
this.ClientRect={Left:left,Top:top,Width:width,Height:height};
if (ChartData.IsTickPeriod(this.HQChart.Period)) //分笔图没有筹码
{
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.InfoColor;
var x=left+width/2;
var y=top+height/2;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(this.NotSupportMessage,x,y);
this.DrawBorder();
return;
}
if (this.CalculateChip())
{
this.DrawFrame();
this.DrawAllChip();
if (this.ShowType==1|| this.ShowType==2) this.DrawDayChip();
this.CalculateCast(); //计算成本
this.DrawChipInfo();
}
else
{
JSConsole.Chart.Log('[StockChip::Draw] no data');
}
this.DrawBorder();
this.SizeChange=false;
}
this.DrawChipInfo=function()
{
var bottom=this.ClientRect.Top+this.ClientRect.Height-1;
var left=this.ClientRect.Left+2;
var right=this.ClientRect.Left+this.ClientRect.Width;
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.InfoColor;
this.Canvas.textBaseline='bottom';
this.Canvas.textAlign='left';
var lineHeight=this.LineHeight*GetDevicePixelRatio();
var text='70%成本价 --.--';
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Cast))
text='70%成本价'+ this.Data.Cast[1].MinPrice.toFixed(2)+'-'+this.Data.Cast[1].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[1].Rate.toFixed(2)+'%';
this.Canvas.fillText(text,left,bottom);
bottom-=lineHeight;
text='90%成本价 --.--';
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Cast))
text='90%成本价'+ this.Data.Cast[0].MinPrice.toFixed(2)+'-'+this.Data.Cast[0].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[0].Rate.toFixed(2)+'%';;
this.Canvas.fillText(text,left,bottom);
bottom-=lineHeight;
text='平均成本:'+this.Data.ChipInfo.AveragePrice.toFixed(2)+'元';
this.Canvas.fillText(text,left,bottom);
bottom-=lineHeight;
text=+this.Data.YPrice.toFixed(2)+'处获利盘:'+this.Data.ChipInfo.YProfitRate.toFixed(2)+'%';
this.Canvas.fillText(text,left,bottom);
bottom-=lineHeight;
text='获利比例:';
this.Canvas.fillText(text,left,bottom);
var textWidth=this.Canvas.measureText(text).width+2;
var barLeft=left+textWidth;
var barWidth=(right-5-barLeft);
this.Canvas.strokeStyle=this.ColorNoProfit;
this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth,lineHeight);
this.Canvas.strokeStyle=this.ColorProfit;
this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth*(this.Data.ChipInfo.ProfitRate/100),lineHeight);
text=this.Data.ChipInfo.ProfitRate.toFixed(2)+'%';
this.Canvas.textAlign='center';
this.Canvas.fillText(text,barLeft+barWidth/2,bottom);
bottom-=lineHeight;
this.Canvas.textAlign='left';
text='成本分布,日期:'+IFrameSplitOperator.FormatDateString(this.Data.SelectData.Date);
if (this.Data.SelectData.Time) text+=' '+IFrameSplitOperator.FormatTimeString(this.Data.SelectData.Time);
this.Canvas.fillText(text,left,bottom);
bottom-=lineHeight;
if (this.ShowType!=1 && this.ShowType!=2) return;
var right=this.ClientRect.Left+this.ClientRect.Width-1;
this.Canvas.textAlign='right';
var textWidth=50;
this.Data.DayChip.sort(function(a,b){return b.Day-a.Day;})
for(var i in this.Data.DayChip)
{
var item=this.Data.DayChip[i];
var rate=0;
if (this.Data.ChipInfo && this.Data.ChipInfo.Vol>0) rate=item.Vol/this.Data.ChipInfo.Vol*100;
text=item.Day+'周期'+(this.ShowType==1?'前':'内')+'成本'+(IFrameSplitOperator.IsNumber(rate)? (rate.toFixed(2)+'%'):"--.--%");
if (i==0) textWidth=this.Canvas.measureText(text).width+8;
this.Canvas.fillStyle=item.Color;
this.Canvas.fillRect(right-textWidth,bottom-lineHeight,textWidth,lineHeight);
this.Canvas.fillStyle=this.DayInfoColor;
this.Canvas.fillText(text,right,bottom);
bottom-=lineHeight;
}
}
this.DrawDayChip=function()
{
var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame;
for(var i in this.Data.DayChip)
{
var aryPoint=[];
var chipData=this.Data.DayChip[i].Chip;
if (!chipData) continue;
var totalVol=0;
for(var j=0;j<chipData.length;++j)
{
var vol=chipData[j];
if(!vol) continue;
totalVol+=vol;
var price=(j+this.Data.MinPrice)/100;
var y=KLineFrame.GetYFromData(price);
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
aryPoint.push({X:x,Y:y});
}
this.Data.DayChip[i].Vol=totalVol;
this.DrawArea(aryPoint,this.Data.DayChip[i].Color);
}
}
this.DrawToolbar=function(moveonPoint, mouseStatus)
{
this.Buttons=[];
var left=this.ClientRect.Left;
var right=this.ClientRect.Left+this.ClientRect.Width;
var yButton=this.ClientRect.Top+this.ChartBorder.TitleHeight/2;
var aryButton=
[
{ID:JSCHART_BUTTON_ID.CHIP_RECENT, Style: this.RecentButton, ShowType:2 },
{ID:JSCHART_BUTTON_ID.CHIP_LONG, Style: this.LongButton , ShowType:1},
{ID:JSCHART_BUTTON_ID.CHIP_DEFULT, Style: this.DefaultButton, ShowType:0 }
];
//右往左绘制
for(var i=0;i<aryButton.length;++i)
{
var item=aryButton[i];
var size=item.Style.Size;
var xBotton=right-size-item.Style.MerginLeft;
var font=`${size}px ${item.Style.Family}`;
var rtButton={ Left:xBotton, Top:yButton-size/2, Right:xBotton+size+item.Style.MerginLeft, Bottom:yButton+size/2, Width:size+item.Style.MerginLeft, Height:size };
var color=item.Style.Color;
var btnItem={ ID:item.ID, Rect:rtButton };
if (this.ShowType==item.ShowType)
{
color=item.Style.SelectedColor;
if (mouseStatus && moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:btnItem, Frame:this, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
else
{
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
color=item.Style.MoveOnColor;
if (mouseStatus) mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:btnItem, Frame:this, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
}
this.Canvas.fillStyle=color;
this.Canvas.font=font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Style.Text, xBotton, yButton);
this.Buttons.push(btnItem);
right=xBotton;
}
}
this.DrawToolbarTooltip=function(mouseOnToolbar)
{
if (!mouseOnToolbar) return;
var left=this.ClientRect.Left;
var right=this.ClientRect.Left+this.ClientRect.Width;
var key='Toolbar-'+mouseOnToolbar.Item.ID;
text=g_JSChartLocalization.GetText(key,0);
if (!text) return;
var rtButton=mouseOnToolbar.Rect;
var xCenter=rtButton.Left+rtButton.Width/2;
this.Canvas.font=this.ButtonTooltip.Font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
var textWidth=this.Canvas.measureText(text).width+8;
var textHeight=this.GetFontHeight();
var bgHeight=textHeight+8;
var x=xCenter-textWidth/2;
var y=rtButton.Top-bgHeight;
if (y<0) y=rtButton.Bottom+1;
if (x+textWidth>right) x=right-textWidth-2;
this.Canvas.fillStyle=this.ButtonTooltip.ColorBG;
this.Canvas.fillRect(x,y,textWidth,bgHeight); //画一个背景色, 不然是一个黑的背景
this.Canvas.fillStyle=this.ButtonTooltip.Color;
this.Canvas.fillText(text, x+4,y+bgHeight/2);
}
this.PtInButtons=function(x,y) //坐标是否在按钮上
{
for(var i=0;i<this.Buttons.length;++i)
{
var item=this.Buttons[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { ID:item.ID, Rect:rect };
}
}
return null;
}
this.DrawAllChip=function()
{
var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame;
var selectPrice=this.Data.SelectData.Close;
var aryProfitPoint=[];
var aryNoProfitPoint=[];
var totalVol=0,totalAmount=0,totalProfitVol=0, totalYProfitVol=0; //总的成交量, 总的成交金额, 总的盈利的成交量
var yPrice=this.Data.YPrice;
var maxPrice=KLineFrame.HorizontalMax;
var minPrice=KLineFrame.HorizontalMin;
var MaxVol=1;
for(var i=0;i<this.Data.AllChip.length;++i)
{
var vol=this.Data.AllChip[i];
if(!vol) continue;
var price=(i+this.Data.MinPrice)/this.PriceZoom;
totalVol+=vol;
totalAmount+=price*vol;
if (price<yPrice) totalYProfitVol+=vol; //获利的成交量
if (price<selectPrice) totalProfitVol+=vol; //鼠标当前位置 获利的成交量
if (price<=maxPrice && price>=minPrice)
{
if (MaxVol<vol) MaxVol=vol;
}
}
this.Data.MaxVol=MaxVol; //把成交量最大值替换成 当前屏成交量最大值
for(var i=0;i<this.Data.AllChip.length;++i)
{
var vol=this.Data.AllChip[i];
if(!vol) continue;
var price=(i+this.Data.MinPrice)/this.PriceZoom;
if (price>maxPrice || price<minPrice) continue;
var y=KLineFrame.GetYFromData(price);
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
if (price<selectPrice) aryProfitPoint.push({X:x,Y:y});
else aryNoProfitPoint.push({X:x,Y:y});
}
this.Data.ChipInfo=
{
Vol:totalVol, AveragePrice:totalAmount/totalVol, ProfitVol:totalProfitVol,
ProfitRate:totalVol>0?totalProfitVol/totalVol*100:0,
YProfitRate:totalVol>0?totalYProfitVol/totalVol*100:0
};
if (this.ShowType==0)
{
this.DrawLines(aryProfitPoint,this.ColorProfit);
this.DrawLines(aryNoProfitPoint,this.ColorNoProfit);
var averagePrice=this.Data.ChipInfo.AveragePrice;
if (averagePrice>0 && averagePrice<=maxPrice && averagePrice>=minPrice)
{
averagePrice=averagePrice.toFixed(2);
this.DrawAveragePriceLine(aryProfitPoint,aryNoProfitPoint,KLineFrame.GetYFromData(averagePrice),this.ColorAveragePrice);
}
}
else //在火焰山模式下, 筹码用一个颜色
{
this.DrawLines(aryProfitPoint,this.ColorBG);
this.DrawLines(aryNoProfitPoint,this.ColorBG);
}
}
this.CalculateCast=function() //计算 90% 70%的成本价
{
if (!this.Data.ChipInfo || !this.Data.ChipInfo.Vol) return;
var aryCast=
[
{Start:0.05,End:0.95, MaxPrice:0, MinPrice:0, Rate:0},
{Start:0.15,End:0.85, MaxPrice:0, MinPrice:0, Rate:0}
];
var averagePrice=this.Data.ChipInfo.AveragePrice;
var totalProfitVol=this.Data.ChipInfo.ProfitVol;
var tempVol=0;
for(var i=0, castCount=0;i<this.Data.AllChip.length;++i)
{
if (castCount==4) break;
var vol=this.Data.AllChip[i];
if (vol<=0) continue;
var price=(i+this.Data.MinPrice)/this.PriceZoom;
tempVol+=vol;
var rate=tempVol/totalProfitVol;
for(var j in aryCast)
{
var itemCast=aryCast[j];
if (itemCast.MinPrice<=0 && rate>itemCast.Start)
{
itemCast.MinPrice=price;
++castCount;
}
if (itemCast.MaxPrice<=0 && rate>itemCast.End)
{
itemCast.MaxPrice=price;
++castCount;
}
}
}
for(var i in aryCast)
{
var item=aryCast[i];
var addPrice=item.MaxPrice+item.MinPrice;
if (addPrice) item.Rate=Math.abs(item.MaxPrice-item.MinPrice)/addPrice*100;
}
this.Data.Cast=aryCast;
}
this.DrawArea=function(aryPoint,color)
{
if (aryPoint.length<=0) return;
this.Canvas.fillStyle=color;
this.Canvas.beginPath();
this.Canvas.moveTo(this.ClientRect.Left,aryPoint[0].Y);
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.lineTo(item.X,item.Y);
}
this.Canvas.lineTo(this.ClientRect.Left,aryPoint[aryPoint.length-1].Y);
this.Canvas.fill();
}
this.DrawLines=function(aryPoint,color)
{
if (aryPoint.length<=0) return;
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.moveTo(this.ClientRect.Left,item.Y);
this.Canvas.lineTo(item.X,item.Y);
}
this.Canvas.stroke();
}
this.DrawAveragePriceLine=function(aryProfitPoint,aryNoProfitPoint,y,color)
{
for(var i in aryProfitPoint)
{
var item=aryProfitPoint[i];
if (item.Y==y)
{
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
this.Canvas.moveTo(this.ClientRect.Left,item.Y);
this.Canvas.lineTo(item.X,item.Y);
this.Canvas.stroke();
return;
}
}
for(var i in aryNoProfitPoint)
{
var item=aryNoProfitPoint[i];
if (item.Y==y)
{
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
this.Canvas.moveTo(this.ClientRect.Left,item.Y);
this.Canvas.lineTo(item.X,item.Y);
this.Canvas.stroke();
return;
}
}
}
this.DrawBorder=function()
{
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.strokeRect(this.ClientRect.Left,this.ClientRect.Top,this.ClientRect.Width,this.ClientRect.Height);
}
this.EvenlyDistribute=function(aryChip, data) //平均分布 data={Low, High, Vol, MaxVol, MaxPrice, MinPrice }
{
var low=data.Low, high=data.High, maxPrice=data.MaxPrice, minPrice=data.MinPrice, maxVol=1;
if ( (high-low)== 0) return;
var averageVol=data.Vol/(high-low);
for(var j=low;j<=high && j<=maxPrice;++j)
{
var index=j-minPrice;
aryChip[index]+=averageVol;
if (maxVol<aryChip[index]) maxVol=aryChip[index];
}
data.MaxVol=maxVol;
}
this.TriangleDistribute=function(aryChip, data) //三角分布
{
var low=data.Low, high=data.High, maxPrice=data.MaxPrice, minPrice=data.MinPrice, maxVol=1;
var ANGLE = 45, PI=3.1415926535;
var middlePrice = (high - low) / 2.0 + low;
var totalValue=0;
var aryVol=[];
for(var i=low+1, j=1 ;i<=middlePrice;++i,++j)
{
var y = Math.tan(ANGLE* PI / 180)*j;
totalValue+=y;
aryVol.push({Index:i-minPrice, Value:y});
}
for(var i=high-1, j=1 ;i>middlePrice;--i,++j)
{
var y = Math.tan(ANGLE* PI / 180)*j;
totalValue+=y
aryVol.push({Index:i-minPrice, Value:y});
}
if (totalValue>0)
{
for(var i=0;i<aryVol.length;++i)
{
var item=aryVol[i];
aryChip[item.Index]+=item.Value*data.Vol/totalValue;
if (maxVol<aryChip[item.Index]) maxVol=aryChip[item.Index];
}
data.MaxVol=maxVol;
}
}
this.CalculateDistribute=function(aryChip, data)
{
if (this.CalculateType==1) this.TriangleDistribute(aryChip, data);
else this.EvenlyDistribute(aryChip, data);
}
this.CalculateChip=function() //计算筹码
{
if (!this.HQChart) return false;
if (!this.HQChart.FlowCapitalReady) return false;
var symbol=this.HQChart.Symbol;
if (!symbol) return false;
if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) return false; //指数暂时不支持移动筹码
var bindData=this.HQChart.ChartPaint[0].Data;
//if (bindData.Period>=4) return false; //分钟K线不支持, 没时间做,以后再做吧
var count=bindData.DataOffset+parseInt(this.HQChart.CursorIndex);
if (count>=bindData.Data.length) count=bindData.Data.length-1;
var selData=bindData.Data[count];
var yPrice=selData.Close;
var mouseY=this.HQChart.LastPoint.Y;
if (mouseY) yPrice=this.HQChart.Frame.SubFrame[0].Frame.GetYData(mouseY);
//JSConsole.Chart.Log("[StockChip::CalculateChip]",count,this.HQChart.CursorIndex,selData);
const rate=1;
var aryVol=[];
var seed=1,vol,maxPrice,minPrice;
for(let i=count;i>=0;--i)
{
var item=bindData.Data[i];
var changeRate=1; //换手率
if (item.FlowCapital>0) changeRate=item.Vol/item.FlowCapital;
if (i==count) vol=item.Vol*changeRate;
else vol=item.Vol*seed;
var dataItem={Vol:vol,High:item.High,Low:item.Low};
aryVol.push(dataItem);
seed*=(1-changeRate*rate);
if (!maxPrice || maxPrice<item.High) maxPrice=item.High;
if (!minPrice || minPrice>item.Low) minPrice=item.Low;
}
//JSConsole.Chart.Log("[StockChip::CalculateChip]",maxPrice,minPrice);
if (!maxPrice || !minPrice) return true;
var priceZoom=this.PriceZoom;
maxPrice=parseInt(maxPrice*priceZoom);
minPrice=parseInt(minPrice*priceZoom);
var dataCount=maxPrice-minPrice;
var aryChip=new Array()
for(let i=0;i<=dataCount;++i)
{
aryChip.push(0);
}
var dayChip=[];
var distributeData;
if (this.ShowType==2)
{
var dayChip=
[
{Day:100, Color:this.DAY_COLOR[1][5]}, {Day:60, Color:this.DAY_COLOR[1][4]}, {Day:30, Color:this.DAY_COLOR[1][3]},
{Day:20, Color:this.DAY_COLOR[1][2]}, {Day:10, Color:this.DAY_COLOR[1][1]}, {Day:5, Color:this.DAY_COLOR[1][0]}
];
for(let i in aryVol)
{
var item=aryVol[i];
var high=parseInt(item.High*priceZoom);
var low=parseInt(item.Low*priceZoom);
var averageVol=item.Vol;
if (high-low>0) averageVol=item.Vol/(high-low);
if (averageVol<=0.000000001) continue;
for(var k=0;k<dayChip.length;++k)
{
if (i==dayChip[k].Day)
{
dayChip[k].Chip=aryChip.slice(0);
break;
}
}
distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
this.CalculateDistribute(aryChip, distributeData );
}
}
else if (this.ShowType==1)
{
var dayChip=
[
{Day:5, Color:this.DAY_COLOR[0][0]},{Day:10, Color:this.DAY_COLOR[0][1]},{Day:20, Color:this.DAY_COLOR[0][2]},
{Day:30, Color:this.DAY_COLOR[0][3]},{Day:60, Color:this.DAY_COLOR[0][4]},{Day:100, Color:this.DAY_COLOR[0][5]}
];
for(let i=aryVol.length-1;i>=0;--i)
{
var item=aryVol[i];
var high=parseInt(item.High*priceZoom);
var low=parseInt(item.Low*priceZoom);
var averageVol=item.Vol;
if (high-low>0) averageVol=item.Vol/(high-low);
if (averageVol<=0.000000001) continue;
for(var k=0;k<dayChip.length;++k)
{
if (i==dayChip[k].Day)
{
dayChip[k].Chip=aryChip.slice(0);
break;
}
}
distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
this.CalculateDistribute(aryChip, distributeData);
}
}
else
{
for(let i in aryVol)
{
var item=aryVol[i];
var high=parseInt(item.High*priceZoom);
var low=parseInt(item.Low*priceZoom);
var averageVol=item.Vol;
if (high-low>0) averageVol=item.Vol/(high-low);
if (averageVol<=0.000000001) continue;
distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
this.CalculateDistribute(aryChip, distributeData);
}
}
if (!distributeData) return false;
this.Data={AllChip:aryChip, MaxVol:distributeData.MaxVol, MaxPrice:maxPrice, MinPrice:minPrice,SelectData:selData, DayChip:dayChip, YPrice:yPrice};
return true;
}
this.DrawFrame=function() //X轴成交量坐标
{
if (this.IsShowX==false) return;
if (this.Data.MaxVol<=0) return;
var isDrawXFrame=this.HQChart.Frame.SubFrame.length===1 ? false:true; //是否画X轴,如果只有1个窗口就不画
var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame;
var chartBorder=KLineFrame.ChartBorder;
var bottom=ToFixedPoint(chartBorder.GetBottomEx()+1);
if (!isDrawXFrame) bottom=this.ClientRect.Top+this.ClientRect.Height;
var left=this.ClientRect.Left;
var right=left+this.ClientRect.Width;
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
if (isDrawXFrame)
{
this.Canvas.moveTo(left,bottom);
this.Canvas.lineTo(right,bottom);
}
var showCount=this.ShowXCount;
var maxValue=this.Data.MaxVol;
var perValue=Math.floor(maxValue/showCount);
this.Canvas.font=this.Font;
this.Canvas.textBaseline='top';
this.Canvas.fillStyle=this.InfoColor;
var xOffset=10*GetDevicePixelRatio();
for(var i=1;i<=showCount;++i)
{
var vol=perValue*i;
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
x=ToFixedPoint(x);
if (i==showCount) //最后一个刻度不要画线了
{
this.Canvas.textAlign='right';
var text=IFrameSplitOperator.FormatValueString(maxValue, 1);
this.Canvas.fillText(text,x,bottom+2);
}
else
{
this.Canvas.moveTo(x,this.ClientRect.Top);
this.Canvas.lineTo(x,bottom);
this.Canvas.textAlign='center';
var text=IFrameSplitOperator.FormatValueString(vol, 1);
var textWidth=this.Canvas.measureText(text).width;
this.Canvas.fillText(text,Math.floor(x-textWidth*0.25),bottom+2);
}
}
this.Canvas.stroke();
}
}
//窗口分割
function FrameSplitPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='FrameSplitPaint';
this.LineColor='rgb(255,0,0)';
this.TextColor="rgb(255,0,0)";
this.LineWidth=2;
this.Font='bold '+18*GetDevicePixelRatio() +"px 微软雅黑";
this.TextTopOffset=10*GetDevicePixelRatio();
//设置参数接口
this.SetOption=function(option)
{
if (option)
{
if (option.LineColor) this.LineColor=option.LineColor;
if (option.TextColor) this.TextColor=option.TextColor;
if (option.Font) this.Font=option.Font;
if (IFrameSplitOperator.IsNumber(option.LineWidth)) this.LineWidth=option.LineWidth;
if (IFrameSplitOperator.IsNumber(option.TextTopOffset)) this.TextTopOffset=option.TextTopOffset;
}
}
this.Draw=function()
{
if (!this.HQChart) return;
if (this.HQChart.Period!=0 && this.HQChart.Period!=1) return;
if (!this.HQChart.ChartPaint[0]) return;
var data=this.HQChart.ChartPaint[0].Data;
if (!data) return;
this.Data=data;
if (!this.ChartFrame || !this.ChartFrame.SubFrame) return;
var subFrame=this.ChartFrame.SubFrame[0].Frame;
if (!subFrame) return;
var isHScreen=(subFrame.IsHScreen===true);
var dataWidth=subFrame.DataWidth;
var distanceWidth=subFrame.DistanceWidth;
var xPointCount=subFrame.XPointCount;
var lineWidth=this.LineWidth * GetDevicePixelRatio();
if (isHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var drawHeight=border.ChartHeight-border.TopTitle-5*GetDevicePixelRatio();
}
this.Canvas.save();
this.Canvas.lineWidth=lineWidth;
this.Canvas.font=this.Font;
this.Canvas.textAlign='center';
this.Canvas.textBaseline='top';
var preQuarter={ Left:border.LeftEx, Top:ToFixedPoint2(lineWidth,border.TopTitle), Height:drawHeight, LineWidth:lineWidth };
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
var dateInfo=this.GetQuarter(item.Date);
if (!dateInfo) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
if (!preQuarter.DateInfo)
{
preQuarter.DateInfo=dateInfo;
preQuarter.Right=x;
}
else
{
var preDateInfo=preQuarter.DateInfo;
if (preDateInfo.Year!=dateInfo.Year || preDateInfo.Quarter!=dateInfo.Quarter)
{
preQuarter.Right=x;
this.DrawQuarter(preQuarter);
preQuarter.Left=x;
preQuarter.Right=null;
preQuarter.DateInfo=dateInfo;
}
else
{
preQuarter.Right=x;
}
}
}
this.DrawQuarter(preQuarter);
this.Canvas.restore();
}
this.DrawQuarter=function(quarterInfo)
{
if (!IFrameSplitOperator.IsNumber(quarterInfo.Left) || !IFrameSplitOperator.IsNumber(quarterInfo.Right)) return;
var left=ToFixedPoint2(quarterInfo.LineWidth,quarterInfo.Left);
var right=ToFixedPoint2(quarterInfo.LineWidth,quarterInfo.Right);
var drawWidth=right-left;
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.strokeRect(left, quarterInfo.Top, drawWidth, quarterInfo.Height);
var date=quarterInfo.DateInfo;
var shortYear=date.Year%100;
if (shortYear<10) var strYear='0'+shortYear;
else var strYear=shortYear.toString();
var text=`${strYear}年${date.Quarter}季度`;
var textWidth = this.Canvas.measureText(text).width;
if (textWidth<(drawWidth+5))
{
var x=left+drawWidth/2;
var y=quarterInfo.Top+this.TextTopOffset;
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,x,y);
}
}
this.GetQuarter=function(date)
{
if (!IFrameSplitOperator.IsNumber(date)) return null;
var year=parseInt(date/10000);
var month=parseInt((date%10000)/100);
switch(month)
{
case 1:
case 2:
case 3:
var quarter=1;
break;
case 4:
case 5:
case 6:
var quarter=2;
break;
case 7:
case 8:
case 9:
var quarter=3;
break;
case 10:
case 11:
case 12:
var quarter=4;
break;
default:
return null;
}
return { Year:year, Month:month, Quarter:quarter };
}
}
//区间选择选中范围背景
function RectSelectPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='RectSelectPaint';
this.LineColor=g_JSChartResource.RectSelect.LineColor; //竖线
this.LineWidth=g_JSChartResource.RectSelect.LineWidth;
this.LineDotted=g_JSChartResource.RectSelect.LineDotted;
this.AreaColor=g_JSChartResource.RectSelect.AreaColor; //面积
this.SubAreaColor=g_JSChartResource.RectSelect.SubAreaColor;
//标记图标
this.MarkConfig=
{
Family:g_JSChartResource.RectSelect.Mark.Family,
Text:g_JSChartResource.RectSelect.Mark.Text,
Color:g_JSChartResource.RectSelect.Mark.Color,
Size:g_JSChartResource.RectSelect.Mark.Size,
IsShow:false,
Position: { Index:g_JSChartResource.RectSelect.Mark.Position.Index, Top:g_JSChartResource.RectSelect.Mark.Position.Top }
}
this.FirstPoint;
this.SecondPoint;
this.CenterPoint;
this.PreventClose=false; //如果外面有div,可以设置成true, 有外面控制
this.SpaceReselected=false; //空格重选
this.SubClient={ FirstPoint:null, SecondPoint:null, Start:null, End:null };
this.StartDate; //{ Date:, Index: }
this.EndDate; //{ Date:, Index: }
this.CenterDate; //{ Date:, Index: }
this.HQChart;
this.DragRect; //拖拽边框区域数组 []
this.ShowRangeText=
{
Enable:false,
Position:0, //0顶部 1=中间 2=底部
Font:g_JSChartResource.RectSelect.RangeTextFont,
Color:g_JSChartResource.RectSelect.RangeTextColor,
BGColor:g_JSChartResource.RectSelect.RangeTextBGColor,
SubPosition:0,
SubFont:g_JSChartResource.RectSelect.RangeTextSubFont,
SubColor:g_JSChartResource.RectSelect.RangeTextSubColor,
SubBGColor:g_JSChartResource.RectSelect.RangeTextSubBGColor,
};
this.BorderCache;
this.IsOnlyOnePoint=false; //空格选中区间,单点模式
this.IsFullFrame=false; //区间选择包含子窗口
//设置参数接口
this.SetOption=function(option)
{
if (option)
{
if (option.LineColor) this.LineColor=option.LineColor;
if (option.AreaColor) this.AreaColor=option.AreaColor;
if (IFrameSplitOperator.IsBool(option.SpaceReselected)) this.SpaceReselected=option.SpaceReselected;
if (option.ShowRangeText)
{
var item=option.ShowRangeText;
if (IFrameSplitOperator.IsBool(item.Enable)) this.ShowRangeText.Enable=item.Enable;
if (IFrameSplitOperator.IsNumber(item.Position)) this.ShowRangeText.Position=item.Position;
if (IFrameSplitOperator.IsNumber(item.SubPosition)) this.ShowRangeText.SubPosition=item.SubPosition;
}
if (option.Mark)
{
var item=option.Mark;
if (IFrameSplitOperator.IsBool(item.IsShow)) this.MarkConfig.IsShow=item.IsShow;
if (item.Position)
{
if (IFrameSplitOperator.IsNumber(item.Position.Index)) this.MarkConfig.Position.Index=item.Position.Index;
if (item.Position.Top) this.MarkConfig.Position.Top=item.Position.Top;
}
}
}
}
this.ReloadResource=function(resource)
{
this.LineColor=g_JSChartResource.RectSelect.LineColor; //竖线
this.LineWidth=g_JSChartResource.RectSelect.LineWidth;
this.LineDotted=g_JSChartResource.RectSelect.LineDotted;
this.AreaColor=g_JSChartResource.RectSelect.AreaColor; //面积
this.ShowRangeText.Font=g_JSChartResource.RectSelect.RangeTextFont;
this.ShowRangeText.Color=g_JSChartResource.RectSelect.RangeTextColor;
this.ShowRangeText.BGColor=g_JSChartResource.RectSelect.RangeTextBGColor;
}
this.IsMinuteChart=function()
{
var className=this.HQChart.ClassName;
var isMinuteChart=(className=="MinuteChartContainer" || className=="MinuteChartHScreenContainer") ? true:false;
return isMinuteChart;
}
this.GetKData=function()
{
if (!this.HQChart) return null;
var isMinuteChart=this.IsMinuteChart();
var data=null;
if (isMinuteChart)
{
if (!this.HQChart.SourceData) return null;
data=this.HQChart.SourceData;
}
else
{
if (!this.HQChart.ChartPaint[0]) return null;
data=this.HQChart.ChartPaint[0].Data;
if (!data) return null;
}
return data;
}
this.GetPointCount=function()
{
var count=0;
if (this.FirstPoint) ++count;
if (this.SecondPoint) ++count;
return count;
}
this.DateToNumber=function(value, isMinuteChart)
{
if (isMinuteChart)
{
if (IFrameSplitOperator.IsNumber(value.Date)) return value.Date*10000+value.Time;
else return value.Time;
}
else
{
var period=this.HQChart.Period;
if (ChartData.IsDayPeriod(period, true)) return value.Date; //YYYYMMDD
else if (ChartData.IsMinutePeriod(period, true)) return value.Date*10000+value.Time; //YYYYMMDDHHMM
else if (ChartData.IsSecondPeriod(period) || ChartData.IsTickPeriod(period)) return value.Date*1000000+value.Time; //YYYYMMDDHHMMSS
else if (ChartData.IsMilliSecondPeriod(period) ) return value.Date*1000000000+value.Time; //YYYYMMDDHHMMSSFFF
}
return null;
}
this.GetSelectRectDataByOnePoint=function()
{
if (!this.FirstPoint) return null;
var data=this.GetKData();
if (!data) return null;
var isMinuteChart=this.IsMinuteChart();
var firstDate=this.DateToNumber(this.FirstPoint,isMinuteChart);
var selectData={ Start:null, End:null, Data:data };
for(var i=0;i<data.Data.length;++i)
{
var item=data.Data[i];
if (!item) continue;
var value=this.DateToNumber(item,isMinuteChart);
if (firstDate==value)
{
selectData.Start=i;
selectData.End=i;
return selectData;
}
}
return null;
}
this.GetSelectRectData=function()
{
if (this.IsOnlyOnePoint) return this.GetSelectRectDataByOnePoint();
if (!this.FirstPoint || !this.SecondPoint) return null;
var data=this.GetKData();
if (!data) return null;
var isMinuteChart=this.IsMinuteChart();
var firstDate=this.DateToNumber(this.FirstPoint,isMinuteChart);
var secondDate=this.DateToNumber(this.SecondPoint,isMinuteChart);
var selectData={ Start:null, End:null, Data:data };
for(var i=0;i<data.Data.length;++i)
{
var item=data.Data[i];
if (!item) continue;
var value=this.DateToNumber(item,isMinuteChart);
if (firstDate==value) selectData.Start=i;
if (secondDate==value) selectData.End=i;
if (IFrameSplitOperator.IsNumber(selectData.Start) && IFrameSplitOperator.IsNumber(selectData.End))
{
if (selectData.Start>selectData.End)
{
var temp=selectData.Start;
selectData.Start=selectData.End;
selectData.End=temp;
}
return selectData;
}
}
return null;
}
this.SortPoint=function()
{
var isMinuteChart=this.IsMinuteChart();
this.CenterData=null;
if (this.FirstPoint && !this.SecondPoint)
{
this.StartDate={ Date:this.DateToNumber(this.FirstPoint,isMinuteChart), Index:0 };
}
else if (this.FirstPoint && this.SecondPoint)
{
var firstValue=this.DateToNumber(this.FirstPoint,isMinuteChart);
var secondValue=this.DateToNumber(this.SecondPoint,isMinuteChart);
if (firstValue<secondValue)
{
this.StartDate={ Date:firstValue, Index:0 };
this.EndDate={ Date:secondValue, Index:1 };
}
else
{
this.StartDate={ Date:secondValue, Index:1 };
this.EndDate={ Date:firstValue, Index:0 };
}
if (this.CenterPoint)
{
var centerValue=this.DateToNumber(this.CenterPoint, isMinuteChart);
this.CenterDate={ Date:centerValue, Index:2 };
}
//子区域
if (this.SubClient.FirstPoint && this.SubClient.SecondPoint)
{
var firstValue=this.DateToNumber(this.SubClient.FirstPoint,isMinuteChart);
var secondValue=this.DateToNumber(this.SubClient.SecondPoint,isMinuteChart);
if (firstValue<secondValue)
{
this.SubClient.Start={ Date:firstValue, Index:3 };
this.SubClient.End={ Date:secondValue, Index:4 };
}
else
{
this.SubClient.Start={ Date:secondValue, Index:4 };
this.SubClient.End={ Date:firstValue, Index:3 };
}
//不能超出区间范围
if (this.SubClient.End.Date<=this.StartDate.Date || this.SubClient.Start.Date>=this.EndDate.Date)
{
this.SubClient.Start=null;
this.SubClient.End=null;
}
else
{
if (this.SubClient.Start.Date<this.StartDate.Date) this.SubClient.Start.Date=this.StartDate.Date;
if (this.SubClient.End.Date>this.EndDate.Date) this.SubClient.End.Date=this.EndDate.Date;
}
}
}
}
this.GetCenterPoint=function()
{
if (!this.FirstPoint || !this.SecondPoint) return null;
if (!IFrameSplitOperator.IsNumber(this.FirstPoint.DataIndex)) return null;
if (!IFrameSplitOperator.IsNumber(this.SecondPoint.DataIndex)) return null;
var count=this.FirstPoint.DataIndex-this.SecondPoint.DataIndex;
if (Math.abs(count)<3) return null;
var centerIndex=parseInt(this.FirstPoint.DataIndex+(this.SecondPoint.DataIndex-this.FirstPoint.DataIndex)/2);
if (centerIndex<0) return null;
var data=this.GetKData();
if (!data || !data.Data) return null;
var kItem=data.Data[centerIndex];
if (!kItem) return null;
return { Date:kItem.Date, Time:kItem.Time, DataIndex:centerIndex };
}
this.MovePoint=function(offset)
{
if (!this.FirstPoint || !this.SecondPoint) return false;
var data=this.GetKData();
if (!data || !data.Data) return false;
var dataIndex=this.FirstPoint.DataIndex+offset;
var kItem=data.Data[dataIndex];
if (!kItem) return false;
var firstPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
var dataIndex=this.SecondPoint.DataIndex+offset;
var kItem=data.Data[dataIndex];
if (!kItem) return false;
var secondPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
var dataIndex=this.CenterPoint.DataIndex+offset;
var kItem=data.Data[dataIndex];
if (!kItem) return false;
var centerPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
this.FirstPoint=firstPoint;
this.SecondPoint=secondPoint;
this.CenterPoint=centerPoint;
return true;
}
this.MoveSubRect=function(step, isLeft)
{
if (!this.FirstPoint || !this.SecondPoint) return false;
if (!this.SubClient || !this.SubClient.FirstPoint || !this.SubClient.SecondPoint) return false;
var data=this.GetKData();
if (!data || !data.Data) return false;
//区间范围
var startIndex=Math.min(this.FirstPoint.DataIndex,this.SecondPoint.DataIndex);
var endIndex=Math.max(this.FirstPoint.DataIndex,this.SecondPoint.DataIndex);
var subStartPoint=this.SubClient.FirstPoint;
var subEndPoint=this.SubClient.SecondPoint;
if (this.SubClient.FirstPoint.DataIndex>this.SubClient.SecondPoint.DataIndex)
{
var subStartPoint=this.SubClient.SecondPoint;
var subEndPoint=this.SubClient.FirstPoint;
}
var subStartIndex=subStartPoint.DataIndex;
var subEndIndex=subEndPoint.DataIndex;
if (isLeft)
{
if (subStartIndex<=startIndex) return false;
subStartIndex-=step;
subEndIndex-=step;
}
else
{
if (subEndPoint.DataIndex>=endIndex) return false;
subStartIndex+=step;
subEndIndex+=step;
}
var bChanged=false;
if (subStartIndex!=subStartPoint.DataIndex)
{
subStartPoint.DataIndex=subStartIndex;
var kItem=data.Data[subStartIndex];
subStartPoint.Date=kItem.Date;
subStartPoint.Time=kItem.Time;
bChanged=true;
}
if (subEndIndex!=subStartPoint.DataIndex)
{
subEndPoint.DataIndex=subEndIndex;
var kItem=data.Data[subEndIndex];
subEndPoint.Date=kItem.Date;
subEndPoint.Time=kItem.Time;
bChanged=true;
}
return bChanged
}
this.SetPoint=function(kItem, option)
{
var dataIndex=null;
if (option)
{
if (IFrameSplitOperator.IsNumber(option.DataIndex)) dataIndex=option.DataIndex;
}
if (option && IFrameSplitOperator.IsNumber(option.Index))
{
switch(option.Index)
{
case 0:
this.FirstPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
this.CenterPoint=this.GetCenterPoint();
return true;
case 1:
this.SecondPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
this.CenterPoint=this.GetCenterPoint();
return true;
case 2: //中心偏移
var offset=dataIndex-this.CenterPoint.DataIndex;
//this.CenterPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
if (Math.abs(offset)>0)
return this.MovePoint(offset);
return false;
case 3:
this.SubClient.FirstPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
return true;
case 4:
this.SubClient.SecondPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
return true;
default:
return false;
}
}
else
{
if (this.IsOnlyOnePoint)
{
this.FirstPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
return true;
}
if (!this.FirstPoint)
{
this.FirstPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
return true;
}
if (!this.SecondPoint)
{
this.SecondPoint={ Date:kItem.Date, Time:kItem.Time, DataIndex:dataIndex };
this.CenterPoint=this.GetCenterPoint();
return true;
}
return false;
}
}
this.ClearPoint=function()
{
if (this.PreventClose) return false;
var bRedraw=false;
if (this.FirstPoint)
{
this.FirstPoint=null;
bRedraw=true;
}
if (this.SecondPoint)
{
this.SecondPoint=null;
bRedraw=true;
}
this.SubClient.FirstPoint=null;
this.SubClient.SecondPoint=null;
return bRedraw;
}
this.Draw=function()
{
this.BorderCache=null;
this.StartDate=null;
this.EndDate=null;
this.CenterDate=null;
this.DragRect=[];
this.SubClient.Start=null;
this.SubClient.End=null;
if (!this.FirstPoint && !this.SecondPoint) return;
this.SortPoint();
var data=this.GetKData();
if (!data) return;
this.Data=data;
if (!this.ChartFrame || !this.ChartFrame.SubFrame) return;
var subFrame=this.ChartFrame.SubFrame[0].Frame;
if (!subFrame) return;
var isHScreen=(subFrame.IsHScreen===true);
var dataWidth=subFrame.DataWidth;
var distanceWidth=subFrame.DistanceWidth;
var xPointCount=subFrame.XPointCount;
if (isHScreen)
{
var border=subFrame.GetBorder();
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.BottomEx;
this.BorderCache=border;
}
else
{
var border=subFrame.GetBorder();
if (this.IsFullFrame) border=this.ChartFrame.ChartBorder.GetBorder(); //全部指标窗口选中
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
var drawHeight=border.ChartHeight-border.TopTitle-5*GetDevicePixelRatio();
var top=border.TopEx;
var bottom=border.BottomEx;
this.BorderCache=border;
}
this.Canvas.save();
var isDayPeriod=ChartData.IsDayPeriod(this.HQChart.Period,true);
var isMinuteChart=this.IsMinuteChart();
var startPoint=null, endPoint=null, subStartPoint=null, subEndPoint=null;
var startDate=null, startEnd=null;
var aryLines=[];
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data.Data[i];
if (!item) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (isMinuteChart)
var x=subFrame.GetXFromIndex(j);
else
var x=left+(right-left)/2;
var value=this.DateToNumber(item, isMinuteChart);
if (this.StartDate && value==this.StartDate.Date)
{
startPoint={ XIndex:i, X:x, Top:top, Bottom: bottom, PointIndex:this.StartDate.Index, Type:0, Item:item };
aryLines.push(startPoint);
}
if (this.EndDate && value==this.EndDate.Date)
{
endPoint={ XIndex:i, X:x , Top:top, Bottom: bottom, PointIndex:this.EndDate.Index, Type:1, Item:item };
aryLines.push(endPoint);
}
if (this.CenterDate && value==this.CenterDate.Date)
{
var centerPoint={ XIndex:i, X:x , Top:top, Bottom: bottom, PointIndex:this.CenterDate.Index, Type:2, Item:item };
aryLines.push(centerPoint);
}
if (this.SubClient && this.SubClient.Start && this.SubClient.End)
{
if (value==this.SubClient.Start.Date)
{
this.SubClient.Start.Point={ Date:value, X:x, Top:top, Bottom: bottom, KItem:item };
}
if (value==this.SubClient.End.Date)
{
this.SubClient.End.Point={ Date:value, X:x, Top:top, Bottom: bottom, kItem:item };
}
}
if (!startDate)
{
startDate={ Date:value, X:x, Top:top, Bottom: bottom };
startEnd={ Date:value, X:x, Top:top, Bottom: bottom };
}
else
{
startEnd.Date=value;
startEnd.X=x;
}
if (startPoint && endPoint) break;
}
this.DrawLines(aryLines);
this.DrawArea(startPoint, endPoint, startDate, startEnd, this.AreaColor);
this.DrawMark(startPoint, endPoint);
if (this.SubClient && this.SubClient.Start && this.SubClient.End)
{
this.DrawArea(this.SubClient.Start.Point, this.SubClient.End.Point, startDate, startEnd, this.SubAreaColor, 4);
if (this.SubClient.Start.Point)
{
var item=this.SubClient.Start.Point;
var point={ X:item.X, Top:item.Top, Bottom: item.Bottom, PointIndex:item.DataIndex, Type:3, Item:item.KItem };
aryLines.push(point);
}
}
this.DrawRangeText(aryLines);
this.Canvas.restore();
}
this.DrawRangeText=function(aryLines)
{
if (!this.ShowRangeText) return;
if (this.ShowRangeText.Enable==false) return;
//文字
var border=this.BorderCache;
var isMinuteChart=this.IsMinuteChart();
var period=this.HQChart.Period;
var x,y,text;
for(var i=0;i<aryLines.length;++i)
{
var item=aryLines[i];
if (item.Type===0 || item.Type==1 || item.Type==3) //第1个点,第2个点
{
if (isMinuteChart)
{
var strDate=IFrameSplitOperator.FormatDateString(item.Item.Date,"YYYY-MM-DD");
var strTime=IFrameSplitOperator.FormatTimeString(item.Item.Time,"HH:MM");
text=`${strDate} ${strTime}`;
}
else
{
var strDate=IFrameSplitOperator.FormatDateString(item.Item.Date,"YYYY-MM-DD");
var strTime=null;
if (ChartData.IsMinutePeriod(period, true)) strTime=IFrameSplitOperator.FormatTimeString(item.Item.Time,"HH:MM");
else if (ChartData.IsSecondPeriod(period) || ChartData.IsTickPeriod(period)) strTime=IFrameSplitOperator.FormatTimeString(item.Item.Time,"HH:MM:SS");
if (strTime) text=`${strDate} ${strTime}`;
else text=strDate;
}
if (item.Type==3)
{
var postion=this.ShowRangeText.SubPosition;
var bgColor=this.ShowRangeText.SubBGColor;
var textColor=this.ShowRangeText.SubColor;
this.Canvas.font=this.ShowRangeText.SubFont;
var textHeight=this.GetFontHeight();
}
else
{
var postion=this.ShowRangeText.Position;
var bgColor=this.ShowRangeText.BGColor;
var textColor=this.ShowRangeText.Color;
this.Canvas.font=this.ShowRangeText.Font;
var textHeight=this.GetFontHeight();
}
var textWidth=this.Canvas.measureText(text).width+4;
var rtBG={ Height:textHeight, Width:textWidth };
if (item.Type==0 || item.Type==3) //第1个点
{
if (textWidth>item.X)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
x=item.X+2;
rtBG.X=item.X;
}
else
{
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
x=item.X-2;
rtBG.X=item.X-textWidth;
}
}
else if (item.Type==1) //第2个点
{
if (textWidth>(border.Right-item.X))
{
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
x=item.X-2;
rtBG.X=item.X-textWidth;
}
else
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
x=item.X+2;
rtBG.X=item.X;
}
}
if (postion==1)
{
y=item.Top+(item.Bottom-item.Top)/2;
if (item.Type==3) y+=textHeight;
rtBG.Y=y-textHeight/2;
}
else if (postion==2)
{
y=item.Bottom;
rtBG.Y=y-textHeight/2;
}
else
{
y=item.Top;
rtBG.Y=y-textHeight/2;
}
if (bgColor)
{
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(ToFixedPoint(rtBG.X),ToFixedPoint(rtBG.Y),ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
}
if (textColor)
{
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(text,x,y,textWidth);
}
}
}
}
this.DrawLines=function(aryLines)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryLines)) return;
var lineWidth=this.LineWidth * GetDevicePixelRatio();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.lineWidth=lineWidth;
for(var i=0;i<aryLines.length;++i)
{
var item=aryLines[i];
var left=ToFixedPoint2(lineWidth,item.X);
if (item.Type==0 || item.Type==1)
{
if (this.LineDotted) this.Canvas.setLineDash(this.LineDotted); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,item.Top);
this.Canvas.lineTo(left,item.Bottom);
this.Canvas.stroke();
if (this.LineDotted) this.Canvas.setLineDash([]);
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,item.Top);
this.Canvas.lineTo(left,item.Bottom);
this.Canvas.stroke();
}
var rtLine=new Rect(left-3,item.Top,10,item.Bottom-item.Top);
this.DragRect[i]={ Rect:rtLine, PointIndex:item.PointIndex, Type:item.Type};
}
}
this.PtInPaint=function(x,y)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.DragRect)) return null;
for(var i=0;i<this.DragRect.length;++i)
{
var item=this.DragRect[i];
var rtLine=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rtLine.X,rtLine.Y,rtLine.Width,rtLine.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { Index:i, PointIndex:item.PointIndex, Type:item.Type, Self:this, Type:item.Type };
}
}
/*
if (this.PreventClose && this.DragClientRect)
{
this.Canvas.beginPath();
this.Canvas.rect(this.DragClientRect.Left,this.DragClientRect.Top,this.DragClientRect.Width, this.DragClientRect.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { Index:-1, Type:3, Self:this };
}
}
*/
return null;
}
this.DrawArea=function(startPoint, endPoint, startDate, startEnd, color, type)
{
if (!startDate || !startEnd || !this.StartDate || !this.EndDate) return;
var aryArea;
if (startPoint && endPoint)
aryArea=[startPoint, endPoint];
else if (!startPoint && endPoint)
aryArea=[startDate, endPoint];
else if (startPoint && !endPoint)
aryArea=[startPoint, startEnd];
else if (startDate.Date>this.StartDate.Date && startEnd.Date<this.EndDate.Date)
aryArea=[startDate,startEnd];
if (aryArea && aryArea.length==2)
{
var start=aryArea[0],end=aryArea[1];
var left=ToFixedPoint(start.X);
var right=ToFixedPoint(end.X);
var drawWidth=right-left;
var drawHeight=start.Bottom-start.Top;
this.Canvas.fillStyle=color;
this.Canvas.fillRect(left, start.Top, drawWidth, drawHeight);
var rtArea={ X:left, Y:start.Top, Right:right, Bottom:start.Top+drawHeight, Width:drawWidth, Height:drawHeight };
if (IFrameSplitOperator.IsNumber(type)) this.DragRect.push( {Rect:rtArea, Type:type} );
}
}
this.DrawMark=function(startPoint,endPoint)
{
if (!startPoint ||!endPoint) return;
if (!this.ChartFrame || !this.ChartFrame.SubFrame) return;
var subFrame=this.ChartFrame.SubFrame[0].Frame;
if (!subFrame) return;
if (!this.MarkConfig) return;
var config=this.MarkConfig;
if (!config.IsShow) return;
var font=`${config.Size}px ${config.Family}`;
this.Canvas.font=font;
var top=null;
switch(config.Position.Top)
{
case "TopEx":
top=subFrame.ChartBorder.GetTopEx();
break;
case "Top":
top=subFrame.ChartBorder.GetTop();
break;
case "TopTitle":
top=subFrame.ChartBorder.GetTopTitle();
break;
default:
return;
}
var xText=startPoint.X;
var yText=top;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="bottom";
this.Canvas.fillStyle=config.Color;
this.Canvas.fillText(config.Text,xText,yText);
}
}
//鼠标拖动选中区域
function RectDragPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='RectDragPaint';
this.LineColor=g_JSChartResource.RectDrag.LineColor; //竖线
this.LineWidth=g_JSChartResource.RectDrag.LineWidth;
this.BGColor=g_JSChartResource.RectDrag.BGColor;
this.ShowMode=0; //0=只画边框 1=遮挡未选中区域 2=整体全选
this.Enable=false;
this.FirstPoint;
this.SecondPoint;
this.IsClearCanvas=true; //画布是否是清空状态
//设置参数接口
this.SetOption=function(option)
{
if (option)
{
if (option.LineColor) this.LineColor=option.LineColor;
if (option.BGColor) this.BGColor=option.BGColor;
if (IFrameSplitOperator.IsNumber(option.ShowMode)) this.ShowMode=option.ShowMode;
}
}
this.ReloadResource=function(resource)
{
this.LineColor=g_JSChartResource.RectDrag.LineColor; //竖线
this.LineWidth=g_JSChartResource.RectDrag.LineWidth;
this.BGColor=g_JSChartResource.RectDrag.BGColor; //面积
}
this.ClearPoint=function()
{
this.FirstPoint=null;
this.SecondPoint=null;
if (!this.IsClearCanvas) this.Draw();
}
this.SetFirstPoint=function(x, y)
{
this.FirstPoint={ X:x, Y:y };
}
this.SetSecondPoint=function(x, y)
{
this.SecondPoint={ X:x, Y:y };
}
this.DrawSelectedBorderMode=function(rtSelect)
{
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.strokeRect(ToFixedPoint(rtSelect.Left),ToFixedPoint(rtSelect.Top),ToFixedRect(rtSelect.Width),ToFixedRect(rtSelect.Height));
}
this.DrawUnselectedMaskMode=function(rtSelect, rtClient)
{
if (this.BGColor)
{
this.Canvas.save();
var clipPath=new Path2D();
clipPath.rect(rtClient.Left, rtClient.Top, rtClient.Width, rtSelect.Top-rtClient.Top);
var leftPath=new Path2D();
leftPath.rect(rtClient.Left,rtSelect.Top, rtSelect.Left-rtClient.Left, rtSelect.Height);
clipPath.addPath(leftPath);
var rightPath=new Path2D();
rightPath.rect(rtSelect.Right,rtSelect.Top, rtClient.Right-rtSelect.Right, rtSelect.Height);
clipPath.addPath(rightPath);
var bottmPath=new Path2D();
bottmPath.rect(rtClient.Left,rtSelect.Bottom, rtClient.Width, rtClient.Bottom-rtSelect.Bottom);
clipPath.addPath(bottmPath);
this.Canvas.clip(clipPath);
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtClient.Left,rtClient.Top,rtClient.Width,rtClient.Height);
this.Canvas.restore();
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.strokeRect(ToFixedPoint(rtSelect.Left),ToFixedPoint(rtSelect.Top),ToFixedRect(rtSelect.Width),ToFixedRect(rtSelect.Height));
}
this.DrawFullselectedMode=function(rtSelect, rtClient)
{
if (this.BGColor)
{
this.Canvas.save();
var clipPath=new Path2D();
clipPath.rect(rtClient.Left, rtClient.Top, rtSelect.Left-rtClient.Left, rtClient.Height);
var rightPath=new Path2D();
rightPath.rect(rtSelect.Right,rtClient.Top, rtClient.Right-rtSelect.Right, rtClient.Height);
clipPath.addPath(rightPath);
this.Canvas.clip(clipPath);
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtClient.Left,rtClient.Top,rtClient.Width,rtClient.Height);
this.Canvas.restore();
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.strokeRect(ToFixedPoint(rtSelect.Left),ToFixedPoint(rtClient.Top),ToFixedRect(rtSelect.Width),ToFixedRect(rtClient.Height));
}
this.Draw=function()
{
if (!this.Enable) return;
if (!this.HQChart) return;
var finder=this.HQChart.GetExtraCanvas(JSChart.RectDragCanvasKey);
if (!finder) return;
this.Canvas=finder.Canvas;
this.HQChart.ClearCanvas(this.Canvas);
this.IsClearCanvas=true;
if (!this.FirstPoint && !this.SecondPoint) return;
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var rtClient={Left:left, Top:top, Right:right, Bottom:bottom };
rtClient.Width=rtClient.Right-rtClient.Left;
rtClient.Height=rtClient.Bottom-rtClient.Top;
var rtSelect=
{
Left:Math.min(this.FirstPoint.X,this.SecondPoint.X),
Right:Math.max(this.FirstPoint.X,this.SecondPoint.X),
Top:Math.min(this.FirstPoint.Y,this.SecondPoint.Y),
Bottom:Math.max(this.FirstPoint.Y,this.SecondPoint.Y)
}
if (rtSelect.Top<top) rtSelect.Top=top;
else if (rtSelect.Top>bottom) rtSelect.Top=bottom;
if (rtSelect.Bottom<top) rtSelect.Bottom=top;
else if (rtSelect.Bottom>bottom) rtSelect.Bottom=bottom;
if (rtSelect.Left<left) rtSelect.Left=left;
else if (rtSelect.Left>right) rtSelect.Left=right;
if (rtSelect.Right<left) rtSelect.Right=left;
else if (rtSelect.Right>right) rtSelect.Right=right;
rtSelect.Width=rtSelect.Right-rtSelect.Left;
rtSelect.Height=rtSelect.Bottom-rtSelect.Top;
switch(this.ShowMode)
{
case 1:
this.DrawUnselectedMaskMode(rtSelect,rtClient);
break;
case 2:
this.DrawFullselectedMode(rtSelect,rtClient);
break;
default:
this.DrawSelectedBorderMode(rtSelect);
break;
}
this.IsClearCanvas=false;
}
}
//深度图 支持横屏
/*
数据格式:
[
{
Data:[ {X,Y}, ],
Type: 1=Up 2=Down 0=Default,
LineColor:
AreaColor:
TextColor:
Range:{X:{Max,Min:}, Y:{Max:,Min:} }
Height:高度 百分比,
Order:"ASC", //DESC=降序 ASC=升序
IsShowCorssCursor:true/false; //是否显示十字光标的提示信息
},
]
*/
function DepthMapPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DepthMapPaint';
this.LineColor=g_JSChartResource.DepthMapPaint.LineColor;
this.AreaColor=CloneData(g_JSChartResource.DepthMapPaint.AreaColor);
this.TextColor=g_JSChartResource.DepthMapPaint.TextColor;
this.TextBGColor=g_JSChartResource.DepthMapPaint.TextBGColor;
//this.Width=200*GetDevicePixelRatio();
this.FrameID=0;
this.ID=Guid(); //唯一的ID
this.IsDynamic=false;
this.IsCallbackDraw=true; //在回调函数里绘制, 不在Draw()中绘制
this.YRange; //Y值范围
this.WidthRate=0.8; //最大使用宽度 0-1
this.IsShow=true;
/*
this.Data=[
{
Data: [ {X:100,Y:20}, {X:110,Y:30}, {X:120,Y:40},{X:130,Y:50} ],
Type:1,
Range:{ X:{Max:130, Min:100}, Y:{ Max:50, Min:0} },
Height:0.5,
LineColor:'rgba(255,106,106,0.6)',
AreaColor:['rgba(255,106,106,0.5)','rgba(255,106,106,0.4)','rgba(255,106,106,0.3)','rgba(255,106,106,0.2)'],
IsASC:false, //true=升序 false=降序
},
{
Data: [ {X:100,Y:20}, {X:110,Y:30}, {X:120,Y:40},{X:130,Y:50} ],
Type:2,
Range:{ X:{Max:130, Min:100}, Y:{ Max:50, Min:0} },
Height:0.5,
IsASC:true, //true=升序 false=降序
},
{
Data:[ {X:11.60, Y:50}, {X:11.65, Y:80}, {X:11.68, Y:85},{X:11.70, Y:55}],
Type:0,
DrawType:0 , //0=面积 1=横线
Range:{ Y:{ Max:100, Min:0} },
LineColor:'rgba(255,165,0,0.6)',
AreaColor:['rgba(255,165,0,0.5)','rgba(255,165,0,0.4)','rgba(255,165,0,0.3)','rgba(255,165,0,0.2)']
}
];
*/
this.SetOption=function(option) //设置
{
if (option.FrameID>0) this.FrameID=option.FrameID;
if (IFrameSplitOperator.IsObjectExist(option.ID)) this.ID=option.ID;
if (option.IsShowCorssCursor) this.IsShowCorssCursor=option.IsShowCorssCursor;
if (IFrameSplitOperator.IsNumber(option.WidthRate)) this.WidthRate=option.WidthRate;
}
this.Draw=function()
{
if (!this.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return;
if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var frame=this.ChartFrame.SubFrame[this.FrameID].Frame;
var chartBorder=frame.ChartBorder;
var height=chartBorder.GetHeightEx();
var left=chartBorder.GetRight();
var top=chartBorder.GetTopEx();
var bottom=chartBorder.GetBottomEx();
var width=this.ChartBorder.Right*this.WidthRate;
if (isHScreen)
{
left=chartBorder.GetBottom();
top=chartBorder.GetRight();
bottom=chartBorder.GetLeft();
var width=this.Width;
if (width>this.ChartBorder.Bottom) width=this.ChartBorder.Bottom;
}
var rtClient={ Left:left, Top:top, Right:left+width, Bottom:bottom, Height:height, Width:width };
this.YRange={ Max:null, Min:0 };
for(var i=0; i<this.Data.length; ++i)
{
var item=this.Data[i];
this.CalculateYRange(item, this.YRange);
}
for(var i=0;i<this.Data.length;++i)
{
var item=this.Data[i];
if (item.Height>0 && item.Height<=1) rtClient.Height=height*item.Height;
else rtClient.Height=height;
if (item.Type==1)
{
rtClient.Top=top;
rtClient.Bottom=top+rtClient.Height;
this.DrawUpArea(item,rtClient);
}
else if (item.Type==2)
{
rtClient.Bottom=bottom;
rtClient.Top=rtClient.Bottom-rtClient.Height;
this.DrawDownArea(item,rtClient);
}
else
{
rtClient.Top=top;
rtClient.Bottom=bottom;
this.DrawDefaultArea(item,rtClient);
}
}
}
this.CalculateYRange=function(drawData, yRange)
{
for(var i in drawData.Data)
{
var item=drawData.Data[i];
if (yRange.Max==null || yRange.Max<item.Y) yRange.Max=item.Y;
if (yRange.Min==null || yRange.Min>item.Y) yRange.Min=item.Y;
}
}
this.GetXFromData=function(value, rtClient, minMax) //获取X轴坐标
{
var width = rtClient.Width * (value - minMax.Min) / (minMax.Max - minMax.Min);
return rtClient.Left + width;
}
this.GetYFromData=function(value, rtClient, minMax, isASC)
{
if (isASC)
{
var height = rtClient.Height * (value - minMax.Min) / (minMax.Max - minMax.Min);
return rtClient.Bottom - height;
}
else
{
var height = rtClient.Height * (value - minMax.Min) / (minMax.Max - minMax.Min);
return rtClient.Top + height;
}
}
this.DrawDefaultArea=function(drawData, rtClient)
{
var frame=this.ChartFrame.SubFrame[this.FrameID].Frame;
var yRange=(drawData.Range && drawData.Range.Y) ? drawData.Range.Y : this.YRange;
var aryPoint=[];
for(var i=0; i<drawData.Data.length; ++i)
{
var item=drawData.Data[i];
var x=this.GetXFromData(item.Y,rtClient,yRange);
if (item.X>frame.HorizontalMax || item.X<frame.HorizontalMin) continue;
var y=frame.GetYFromData(item.X);
aryPoint.push({X:x,Y:y});
}
var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
if (aryPoint.length>0)
{
if (drawData.DrawType==1) this.DrawHLine(aryPoint,lineColor,rtClient);
else this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
}
}
this.DrawUpArea=function(drawData,rtClient)
{
var aryPoint=[];
for(var i in drawData.Data)
{
var item=drawData.Data[i];
var x=this.GetXFromData(item.Y,rtClient,drawData.Range.Y);
var y=this.GetYFromData(item.X,rtClient,drawData.Range.X,drawData.IsASC);
aryPoint.push({X:x,Y:y});
}
var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
if (aryPoint.length>0) this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
}
this.DrawDownArea=function(drawData,rtClient)
{
var aryPoint=[];
for(var i in drawData.Data)
{
var item=drawData.Data[i];
var x=this.GetXFromData(item.Y,rtClient,drawData.Range.Y);
var y=this.GetYFromData(item.X,rtClient,drawData.Range.X,drawData.IsASC);
aryPoint.push({X:x,Y:y});
}
var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
if (aryPoint.length>0) this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
}
this.DrawHLine=function(aryPoint, lineColor, rtClient)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
this.Canvas.strokeStyle=lineColor;
this.Canvas.beginPath();
var drawCount=0;
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
if (isHScreen)
{
}
else
{
this.Canvas.moveTo(rtClient.Left,item.Y);
this.Canvas.lineTo(item.X,item.Y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
}
this.DrawLine=function(aryPoint,lineColor, areaColor,rtClient)
{
var isHScreen=(this.ChartFrame.IsHScreen===true);
var bFirstPoint=true;
var drawCount=0;
this.Canvas.strokeStyle=lineColor;
for(var i in aryPoint)
{
var item=aryPoint[i];
if (bFirstPoint)
{
this.Canvas.beginPath();
if (isHScreen) this.Canvas.moveTo(item.Y,item.X);
else this.Canvas.moveTo(item.X,item.Y);
bFirstPoint=false;
}
else
{
if (isHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
}
++drawCount;
}
if (drawCount>0) this.Canvas.stroke();
//面积
var firstPoint=aryPoint[0];
var lastPoint=aryPoint[aryPoint.length-1];
if (isHScreen)
{
this.Canvas.lineTo(lastPoint.Y,rtClient.Left);
this.Canvas.lineTo(firstPoint.Y,rtClient.Left);
}
else
{
this.Canvas.lineTo(rtClient.Left,lastPoint.Y);
this.Canvas.lineTo(rtClient.Left,firstPoint.Y);
}
this.Canvas.closePath();
if (Array.isArray(areaColor))
{
if (isHScreen)
{
let gradient = this.Canvas.createLinearGradient(this.ChartBorder.GetRightEx(),this.ChartBorder.GetTop(), this.ChartBorder.GetLeft(),this.ChartBorder.GetTop());
gradient.addColorStop(0, areaColor[0]);
gradient.addColorStop(1, areaColor[1]);
this.Canvas.fillStyle=gradient;
}
else
{
let gradient = this.Canvas.createLinearGradient(rtClient.Right,rtClient.Top, rtClient.Left,rtClient.Top);
var offset=1/areaColor.length;
for(var i=0; i<areaColor.length; ++i)
{
gradient.addColorStop(i*offset, areaColor[i]);
}
this.Canvas.fillStyle=gradient;
}
}
else
{
this.Canvas.fillStyle=areaColor;
}
this.Canvas.fill();
}
this.GetYValueByXValue=function(x,floatPrecision)
{
var aryXValue=[];
var value=0;
var zoom=ZOOM_VALUE[floatPrecision];
for(var i=0; i<this.Data.length; ++i)
{
var item=this.Data[i];
if (item.Type!=0 || !item.Data || item.Data.length<0 || item.IsShowCorssCursor==false) continue;
var bFind=false;
for(var j=0; j<item.Data.length; ++j)
{
var dataItem=item.Data[j];
value=parseInt(dataItem.X*zoom);
if (value==x)
{
bFind=true;
var findItem=
{
X:dataItem.X, Y:dataItem.Y,
TextColor:item.TextColor? item.TextColor: this.TextColor,
TextBGColor:item.TextBGColor? item.TextBGColor: this.TextBGColor
};
if (dataItem.YText) findItem.YText=dataItem.YText;
aryXValue.push(findItem);
break;
}
}
if (!bFind)
{
var first=item.Data[0];
var last=item.Data[item.Data.length-1];
if (x>first.X*zoom && x<last.X*zoom)
{
aryXValue.push(
{
X:null, Y:null,
TextColor:item.TextColor? item.TextColor: this.TextColor,
TextBGColor:item.TextBGColor? item.TextBGColor: this.TextBGColor
} );
}
}
}
return aryXValue;
}
}
// Y轴右侧背景颜色
function KLineYAxisBGPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='KLineYAxisBGPaint';
this.SplitData=[]; //[ { Value: , Color:, TextColor: }, ]
this.Font=g_JSChartResource.KLineYAxisBGPaint.Font;
this.FrameID=0;
this.ID=Guid(); //唯一的ID
this.IsDynamic=false;
this.IsCallbackDraw=true; //在回调函数里绘制, 不在Draw()中绘制
this.IsShow=true;
this.BGWidth=50;
this.LineColor=g_JSChartResource.KLineYAxisBGPaint.LineColor;
this.DiffValutTextColor=g_JSChartResource.KLineYAxisBGPaint.DiffValutTextColor;
this.DiffValueBGColor=g_JSChartResource.KLineYAxisBGPaint.DiffValueBGColor; //点差背景
//临时内部变量
this.KLineFrame;
this.KLineData;
this.Range={Max:null, Min:null };
this.SetOption=function(option) //设置
{
if (option)
{
if (IFrameSplitOperator.IsNonEmptyArray(option.SplitData)) this.SplitData=option.SplitData;
}
}
this.Draw=function()
{
if (!this.IsShow) return;
if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;
var kline=this.HQChart.ChartPaint[0];
if (!kline) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
if (isHScreen) return;
this.KLineFrame=this.ChartFrame.SubFrame[this.FrameID].Frame;
var chartBorder=this.KLineFrame.ChartBorder;
var dataWidth=this.KLineFrame.DataWidth;
var distanceWidth=this.KLineFrame.DistanceWidth;
var xPointCount=this.KLineFrame.XPointCount;
var border=chartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
this.KLineData=kline.Data;
//计算最大最小值
var max=null, min=null;
for(var i=this.KLineData.DataOffset,j=0;i<this.KLineData.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.KLineData.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
if (max==null || max<data.High) max=data.High;
if (min==null || min>data.Low) min=data.Low;
}
if (!IFrameSplitOperator.IsNumber(max) || !IFrameSplitOperator.IsNumber(min)) return;
this.Range.Max=max;
this.Range.Min=min;
this.DrawBackground();
}
this.DrawBackground=function()
{
var start=this.Range.Min;
var border=this.KLineFrame.ChartBorder.GetBorder();
var bottom=this.KLineFrame.GetYFromData(start,false);
var left=border.Right;
var right=left+this.BGWidth;
this.Canvas.font=this.Font;
this.Canvas.textBaseline = 'top';
this.Canvas.textAlign = 'left';
for(var i=0;i<this.SplitData.length;++i)
{
var item=this.SplitData[i];
if (item.Value+start>this.KLineFrame.HorizontalMax)
break;
var top=this.KLineFrame.GetYFromData(start+item.Value, false);
this.Canvas.fillStyle=item.Color;
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(top),ToFixedRect(right-left),ToFixedRect(bottom-top));
if (item.Text && item.TextColor)
{
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(item.Text,right+1,top);
}
bottom=top;
//AuotRightWidth
}
//点位差
var value=this.Range.Max-this.Range.Min;
var floatPrecision=GetfloatPrecision(this.HQChart.Symbol);
var text=value.toFixed(floatPrecision);
var x=this.KLineFrame.GetYFromData(this.Range.Max,false);
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(left), ToFixedPoint(x));
this.Canvas.lineTo(ToFixedPoint(right), ToFixedPoint(x));
this.Canvas.stroke();
var textWidth=this.Canvas.measureText(text).width+4;
var textHeight=this.Canvas.measureText("擎").width+2;
var rtBG={ Left: right+1, Top:x-textHeight, Width:textWidth, Height:textHeight };
if (this.DiffValueBGColor)
{
this.Canvas.fillStyle=this.DiffValueBGColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
this.Canvas.textBaseline = 'bottom';
this.Canvas.fillStyle=this.DiffValutTextColor;
this.Canvas.fillText(text,rtBG.Left+1,x);
}
}
//背景图 支持横屏
function BackgroundPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='BackgroundPaint';
this.IsDynamic=false;
this.IsCallbackDraw=true; //在回调函数里绘制, 不在Draw()中绘制
this.FrameID=0;
this.Data; //背景数据 { Start:, End:, Color:[] }
this.ID=Guid(); //唯一的ID
/*
this.Data=
[
{ Start:{ Date:20181201 }, End:{ Date:20181230 }, Color:'rgb(44,55,44)' } ,
{ Start:{ Date:20190308 }, End:{ Date:20190404 }, Color:['rgb(44,55,255)','rgb(200,55,255)'] }
]
*/
this.ChartSubFrame;
this.ChartBorder;
this.KData;
this.Period;
this.XPointCount=0;
this.SetOption=function(option) //设置
{
if (option.FrameID>0) this.FrameID=option.FrameID;
if (IFrameSplitOperator.IsObjectExist(option.ID)) this.ID=option.ID;
}
this.Draw=function()
{
if (!this.Data || !this.HQChart) return;
if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;
var klineChart=this.HQChart.ChartPaint[0];
if (!klineChart || !klineChart.Data) return;
this.ChartSubFrame=this.ChartFrame.SubFrame[this.FrameID].Frame;
this.ChartBorder=this.ChartSubFrame.ChartBorder;
this.KData=klineChart.Data;
this.Period=this.HQChart.Period;
if (!this.KData || this.KData.Data.length<=0) return;
var isHScreen=(this.ChartSubFrame.IsHScreen===true);
this.XPointCount=this.ChartSubFrame.XPointCount;
var xPointCount=this.ChartSubFrame.XPointCount;
var firstKItem=this.KData.Data[this.KData.DataOffset];
var endIndex=this.KData.DataOffset+xPointCount-1;
if (endIndex>=this.KData.Data.length) endIndex=this.KData.Data.length-1;
var endKItem=this.KData.Data[endIndex];
var showData=this.GetShowData(firstKItem,endKItem);
if (!showData || showData.length<=0) return;
var kLineMap=this.BuildKLineMap();
var bottom=this.ChartBorder.GetBottomEx();
var top=this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx();
if (isHScreen)
{
top=this.ChartBorder.GetRightEx();
bottom=this.ChartBorder.GetLeftEx();
height=this.ChartBorder.GetWidthEx();
}
for(var i in showData)
{
var item=showData[i];
var rt=this.GetBGCoordinate(item,kLineMap);
if (!rt) continue;
if (Array.isArray(item.Color))
{
var gradient;
if (isHScreen) gradient = this.Canvas.createLinearGradient(bottom,rt.Left, top, rt.Left);
else gradient = this.Canvas.createLinearGradient(rt.Left,top, rt.Left,bottom);
var offset=1/item.Color.length;
for(var i in item.Color)
{
gradient.addColorStop(i*offset, item.Color[i]);
}
this.Canvas.fillStyle=gradient;
}
else
{
this.Canvas.fillStyle=item.Color;
}
if (isHScreen) this.Canvas.fillRect(ToFixedRect(bottom),ToFixedRect(rt.Left),ToFixedRect(height),ToFixedRect(rt.Width));
else this.Canvas.fillRect(ToFixedRect(rt.Left),ToFixedRect(top),ToFixedRect(rt.Width),ToFixedRect(height));
}
}
this.GetShowData=function(first, end)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return null;
var aryData=[];
for(var i=0;i<this.Data.length;++i)
{
var item=this.Data[i];
var showItem={ };
if (item.Start.Date>=first.Date && item.Start.Date<=end.Date) showItem.Start=item.Start;
if (item.End.Date>=first.Date && item.End.Date<=end.Date) showItem.End=item.End;
if (item.Start.Date<first.Date && item.End.Date>end.Date)
{
showItem.Start=first;
showItem.End=end;
}
if (showItem.Start || showItem.End)
{
showItem.Color=item.Color;
aryData.push(showItem);
}
}
//JSConsole.Chart.Log('[BackgroundPaint::GetShowData] aryData ', aryData);
return aryData;
}
this.BuildKLineMap=function()
{
var isHScreen=(this.ChartSubFrame.IsHScreen===true);
var dataWidth=this.ChartSubFrame.DataWidth;
var distanceWidth=this.ChartSubFrame.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=this.ChartBorder.GetRight();
if (isHScreen) chartright=this.ChartBorder.GetBottom();
var mapKLine={ Data:new Map() ,Start:null, End:null } ; //Key: date / date time, Value:索引
for(var i=this.KData.DataOffset,j=0; i<this.KData.Data.length && j<this.XPointCount; ++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var kItem=this.KData.Data[i];
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
if (j==0) mapKLine.XLeft=left;
mapKLine.XRight=right;
var value={ Index:i, ShowIndex:j , X:x, Right:right, Left:left, Date:kItem.Date };
if (ChartData.IsMinutePeriod(this.Period,true))
{
var key=`Date:${kItem.Date} Time:${kItem.Time}`;
value.Time=kItem.Time;
}
else
{
var key=`Date:${kItem.Date}`;
}
mapKLine.Data.set(key,value);
//保存下起始和结束位置
if (j==0) mapKLine.Start=value;
mapKLine.End=value;
}
return mapKLine;
}
this.GetBGCoordinate=function(item,kLineMap)
{
var xLeft=null, xRight=null;
var isMinutePeriod=ChartData.IsMinutePeriod(this.Period,true);
var bSingleDate=false;
//JSConsole.Chart.Log('[BackgroundPaint::GetBGCoordinate] item ', item);
if (isMinutePeriod)
{
if (item.Start && item.End && item.Start.Date==item.End.Date && item.Start.Time==item.End.Time) bSingleDate=true;
}
else
{
if (item.Start && item.End && item.Start.Date==item.End.Date) bSingleDate=true;
}
if (bSingleDate)
{
if (isMinutePeriod)
var key=`Date:${item.Start.Date} Time:${item.Start.Time}`;
else
var key=`Date:${item.Start.Date}`;
if (!kLineMap.Data.has(key)) return null;
var findItem=kLineMap.Data.get(key);
xLeft=findItem.Left;
xRight=findItem.Right;
return { Left:xLeft, Right:xRight, Width:xRight-xLeft };
}
if (item.Start)
{
if (isMinutePeriod)
var key=`Date:${item.Start.Date} Time:${item.Start.Time}`;
else
var key=`Date:${item.Start.Date}`;
if (kLineMap.Data.has(key))
{
var findItem=kLineMap.Data.get(key);
xLeft=findItem.Left;
}
else
{
if (isMinutePeriod)
{
if (item.Start.Date<kLineMap.Start.Date || (item.Start.Date==kLineMap.Start.Date && item.Start.Time<=kLineMap.Start.Time) )
{
xLeft=kLineMap.Start.Left;
}
else
{
for(var kItem of kLineMap.Data)
{
var value=kItem[1];
if (value.Date>item.Start.Date || (value.Date==item.Start.Date && value.Time>item.Start.Time))
{
xLeft=value.Left;
break;
}
}
}
}
else
{
if (item.Start.Date<=kLineMap.Start.Date)
{
xLeft=kLineMap.Start.Left;
}
else
{
for(var kItem of kLineMap.Data)
{
var value=kItem[1];
if (value.Date>item.Start.Date)
{
xLeft=value.Left;
break;
}
}
}
}
}
}
else
{
xLeft=kLineMap.XLeft;
}
if (item.End)
{
if (isMinutePeriod)
var key=`Date:${item.End.Date} Time:${item.End.Time}`;
else
var key=`Date:${item.End.Date}`;
if (kLineMap.Data.has(key))
{
var findItem=kLineMap.Data.get(key);
xRight=findItem.Right;
}
else
{
if (isMinutePeriod)
{
if (item.End.Date<kLineMap.Start.Date || (item.End.Date==kLineMap.Start.Date && item.End.Time<kLineMap.Start.Time)) return null;
if (item.End.Date<kLineMap.End.Date || (item.End.Date==kLineMap.End.Date && item.End.Time>=kLineMap.End.Time) )
{
xRight=kLineMap.End.Right;
}
else
{
var previousX=null;
for(var kItem of kLineMap.Data)
{
var value=kItem[1];
if (value.Date>item.End.Date || (value.Date==item.End.Date && value.Time>item.End.Time) )
{
xRight=previousX;
break;
}
previousX=value.Right;
}
}
}
else
{
if (item.End.Date<kLineMap.Start.Date) return null;
if (item.End.Date<=kLineMap.End.Date)
{
xRight=kLineMap.End.Right;
}
else
{
var previousX=null;
for(var kItem of kLineMap.Data)
{
var value=kItem[1];
if (value.Date>item.End.Date)
{
xRight=previousX;
break;
}
previousX=value.Right;
}
}
}
}
}
else
{
xRight=kLineMap.XRight;
}
if (xLeft==null || xRight==null) return null;
return { Left:xLeft, Right:xRight, Width:xRight-xLeft };
}
}
function MinuteBackgroundPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='MinuteBackgroundPaint';
this.IsDynamic=true;
this.IsCallbackDraw=false; //在回调函数里绘制, 不在Draw()中绘制
this.HQChart;
this.Data; //背景数据 { [Date:, Text:, TextColor:, Font: }
//this.Data=[ {Date:20210421, Text:"测试测试测试!!!!!"}];
this.Font=g_JSChartResource.DefaultTextFont;
this.TextColor=g_JSChartResource.DefaultTextColor;
this.MerginTop=20;
this.ID=Guid(); //唯一的ID
this.FrameID=0;
this.SetOption=function(option) //设置
{
if (!option) return;
if (option.Font) this.Font=option.Font;
if (IFrameSplitOperator.IsObjectExist(option.ID)) this.ID=option.ID;
if (option.FrameID>0) this.FrameID=option.FrameID;
if (option.MerginTop>0) this.MerginTop=option.MerginTop;
}
this.Draw=function()
{
if (!this.Data || !this.HQChart) return;
if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;
var subFrameItem=this.ChartFrame.SubFrame[this.FrameID];
if (!subFrameItem || !subFrameItem.Frame) return;
var subFrame=subFrameItem.Frame;
var minuteData=this.HQChart.SourceData;
if (!minuteData) return;
var xPointCount=subFrame.XPointCount;
var preDate=0;
var range=null;
var mapDate=new Map();
for(var i=minuteData.DataOffset,j=0;i<minuteData.Data.length && j<xPointCount;++i,++j)
{
var item = minuteData.Data[i];
if (!item) continue;
if (item.Date!=preDate)
{
preDate=item.Date;
if (!range)
{
range={ Left:this.ChartFrame.GetXFromIndex(j) , Date: item.Date};
}
else
{
range.Right=this.ChartFrame.GetXFromIndex(j-1);
mapDate.set(range.Date, range);
range={ Left:this.ChartFrame.GetXFromIndex(j) , Date: item.Date};
}
}
}
if (range && !range.Right)
{
range.Right=this.ChartFrame.GetXFromIndex(xPointCount-1);
mapDate.set(range.Date, range);
}
this.Canvas.textAlign='center';
this.Canvas.textBaseline='top';
//this.Canvas.fillStyle=this.TextColor;
//this.Canvas.font=this.Font;
var yText=subFrame.ChartBorder.GetTopEx()+this.MerginTop;
for(var i=0;i<this.Data.length;++i)
{
var item=this.Data[i];
if (!mapDate.has(item.Date)) continue;
var range=mapDate.get(item.Date);
var xCenter=range.Left+(range.Right-range.Left)/2;
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=this.Font;
if (item.TextColor) this.Canvas.fillStyle=item.TextColor;
else this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(item.Text,xCenter,yText);
}
}
}
//拖拽效果图
var JSCHART_DRAGCHART_TYPE_ID=
{
MAIN_KLINE:1,
OVERLAY_KLINE:2,
MAIN_INDEX:3,
OVERLAY_INDEX:4,
OVERLAY_MINUTE:5, //叠加走势图
MAIN_MINUTE:6, //走势图
MAIN_AVERAGE_MINUTE:7, //均线
MAIN_MINUTE_VOL:8 //成交量
};
function DragMovePaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DragMovePaint';
this.DrawAfterTitle=true;
this.IsDynamic=true;
this.Info;
this.IsShow=false;
this.Point; //显示的点
this.TextColor=g_JSChartResource.DragMovePaint.TextColor;
this.Font=g_JSChartResource.DragMovePaint.Font;
this.ReloadResource=function(resource)
{
this.TextColor=g_JSChartResource.DragMovePaint.TextColor;
this.Font=g_JSChartResource.DragMovePaint.Font;
}
this.Clear=function()
{
this.Info=null;
this.IsShow=false;
this.Point=null;
}
this.Draw=function()
{
if (!this.Info || !this.IsShow || !this.Point) return;
var text;
var windowsIndex=this.Info.FrameID+1;
if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.MAIN_KLINE)
{
text=`K线:${this.Info.Name}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_KLINE)
{
text=`叠加K线:${this.Info.Name}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.MAIN_INDEX)
{
text=`指标:${this.Info.IndexName}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_INDEX)
{
text=`叠加指标:${this.Info.IndexName}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_MINUTE)
{
text=`走势图, 叠加价格线:${this.Info.Name}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.MAIN_MINUTE)
{
text=`走势图, 价格线:${this.Info.Name}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.MAIN_AVERAGE_MINUTE)
{
text=`走势图, 均线:${this.Info.Name}, 窗口:${windowsIndex}`;
}
else if (this.Info.Type==JSCHART_DRAGCHART_TYPE_ID.MAIN_MINUTE_VOL)
{
text=`走势图, 成交量:${this.Info.Name}, 窗口:${windowsIndex}`;
}
if (text)
{
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign = 'left';
this.Canvas.textBaseline = 'bottom';
this.Canvas.fillText(text,this.Point.X,this.Point.Y);
}
}
}
function SessionBreaksPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='SessionBreaksPaint';
this.IsDynamic=false;
this.IsCallbackDraw=true; //在回调函数里绘制, 不在Draw()中绘制
this.FrameID=0;
this.KDataFeature; //数据特征 { Symbol, Period, DataCount }
this.Data;
this.ChartFrame;
this.BGColor=g_JSChartResource.SessionBreaksPaint.BGColor.slice();
this.SplitLine=
{
Color:g_JSChartResource.SessionBreaksPaint.SplitLine.Color,
Width:g_JSChartResource.SessionBreaksPaint.SplitLine.Width,
Dash:g_JSChartResource.SessionBreaksPaint.SplitLine.Dash
};
this.MapPeriod=new Map(
[
[0, { SplitType:1 }], //日
[1, { SplitType:1 }], //周
[2, { SplitType:2 }], //月
[21, { SplitType:2 }], //双周
[4, { SplitType:3 }], //1分钟
[5, { SplitType:3 }], //5分钟
[6, { SplitType:3 }], //15分钟
[7, { SplitType:3 }],
[8, { SplitType:3 }],
]); //周期和分割对应关系
this.SetOption=function(option) //设置
{
if (option.FrameID>0) this.FrameID=option.FrameID;
}
this.Draw=function()
{
if (!this.HQChart) return;
var hisData=this.HQChart.ChartOperator_Temp_GetHistroyData();;
if (!hisData) return; //数据还没有到达
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return;
if (this.IsKDataChange(hisData))
{
this.BuildCacheData(hisData);
}
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data)) return;
var mainFrame=this.HQChart.Frame.SubFrame[0].Frame;
var bHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=mainFrame.DataWidth;
var distanceWidth=mainFrame.DistanceWidth;
var xPointCount=mainFrame.XPointCount;
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var chartright=border.BottomEx;
var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var preID=null;
var aryBG=[];
var bgItem=null;
for(var i=hisData.DataOffset,j=0;i<hisData.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=this.Data[i];
if (!item) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
var xStart=left-distanceWidth/2;
var xEnd=right+distanceWidth/2;
var id=item.ID;
if (!IFrameSplitOperator.IsNumber(id)) continue;
if (preID==null)
{
bgItem={ Start:{ X:xStart }, End:{ X:xEnd }, ColorIndex:id, Count:1, IsStart:false, IsEnd:false };
preID=id;
if (i-1>=0)
{
var preItem=this.Data[i-1];
if (preItem && preItem.ID!=id) bgItem.IsStart=true;
}
}
else if (preID!=id)
{
bgItem.End.X=xStart;
bgItem.IsEnd=true;
aryBG.push(bgItem);
bgItem={ Start:{ X:xStart }, End:{ X:xEnd }, ColorIndex:id, Count:1, IsStart:true, IsEnd:false };
preID=id;
}
else
{
bgItem.End.X=xEnd;
++bgItem.Count;
}
}
if (bgItem && bgItem.Count>=2) aryBG.push(bgItem);
this.Canvas.save();
this.DrawBG(aryBG);
this.Canvas.restore();
}
this.DrawBG=function(aryBG)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryBG)) return;
var bHScreen=(this.ChartFrame.IsHScreen===true);
if (bHScreen)
{
var border=this.ChartBorder.GetHScreenBorder();
var top=border.RightEx;
var bottom=border.Left;
var height=bottom-top;
}
else
{
var border=this.ChartBorder.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
var height=bottom-top;
}
var bDrawSplitLine=false;
if (this.SplitLine.Color) bDrawSplitLine=true;
var lineCount=0;
for(var i=0;i<aryBG.length;++i)
{
var item=aryBG[i];
var xLeft=item.Start.X;
var xRight=item.End.X;
var index=item.ColorIndex%this.BGColor.length;
var bgColor=this.BGColor[index];
if (bgColor)
{
this.Canvas.fillStyle=bgColor;
if (bHScreen)
this.Canvas.fillRect(ToFixedPoint(top),ToFixedPoint(xLeft),ToFixedRect(height),ToFixedRect(xRight-xLeft));
else
this.Canvas.fillRect(ToFixedPoint(xLeft),ToFixedPoint(top),ToFixedRect(xRight-xLeft),ToFixedRect(height));
}
if (bDrawSplitLine && item.IsStart)
{
if (lineCount==0) this.Canvas.beginPath();
if (bHScreen)
{
this.Canvas.moveTo(top, ToFixedPoint(xLeft));
this.Canvas.lineTo(bottom, ToFixedPoint(xLeft));
}
else
{
this.Canvas.moveTo(ToFixedPoint(xLeft), top);
this.Canvas.lineTo(ToFixedPoint(xLeft), bottom);
}
++lineCount;
}
}
if (bDrawSplitLine && lineCount>=1)
{
if (this.SplitLine.Width>=1) this.Canvas.linewidth=this.SplitLine.Width;
if (this.SplitLine.Dash) this.Canvas.setLineDash(this.SplitLine.Dash);
if (this.SplitLine.Color) this.Canvas.strokeStyle=this.SplitLine.Color;
this.Canvas.stroke();
}
}
this.IsKDataChange=function(hisData)
{
if (!this.KDataFeature) return true;
if (this.KDataFeature.Symbol!=this.HQChart.Symbol) return true;
if (this.KDataFeature.Period!=this.HQChart.Period) return true;
if (this.KDataFeature.DataCount!=hisData.Data.length) return true;
return false;
}
this.BuildCacheData=function(hisData)
{
var period=this.HQChart.Period;
if (!this.MapPeriod.has(period))
{
this.Data=[];
this.KDataFeature={ Symbol:this.HQChart.Symbol, Period:period, DataCount:hisData.Data.length };
return;
}
var splitType=this.MapPeriod.get(period).SplitType; //1=month 2=year 3=day 4=1hour
var startDate=0;
var index=-1;
this.Data=[];
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
switch(splitType)
{
case 1: //月
if (parseInt(item.Date/100)!=parseInt(startDate/100))
{
startDate=item.Date;
++index;
}
this.Data.push({ ID:index, Date:item.Date });
break;
case 2: //年
if (parseInt(item.Date/10000)!=parseInt(startDate/10000))
{
startDate=item.Date;
++index;
}
this.Data.push({ ID:index, Date:item.Date });
break;
case 3: //日
if (item.Date!=startDate)
{
startDate=item.Date;
++index;
}
this.Data.push({ ID:index, Date:item.Date });
break;
}
}
this.KDataFeature={ Symbol:this.HQChart.Symbol, Period:period, DataCount:hisData.Data.length };
}
}
//窗口底部工具栏
function FrameButtomToolbarPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='FrameButtomToolbarPaint';
this.FrameID=-1;
this.FrameGuid=null;
this.IsDynamic=true;
this.DrawAfterTitle=true;
this.AryButton=[]; // { Title:, ID:, Data:数据, TooltipText:提示信息 }
this.SelectedID=null; // 选中按钮ID
this.AryRectButton=[];
this.BGColor=g_JSChartResource.FrameButtomToolbar.BGColor;
this.BorderColor=g_JSChartResource.FrameButtomToolbar.BorderColor;
this.ButtonConfig=CloneData(g_JSChartResource.FrameButtomToolbar.Button);
/*
{
Font:{ Family:"微软雅黑" },
TitleColor:
{
Selected:"rgb(255,255,255)", Default:"rgb(140,140,140)", MoveOn:"rgb(255,255,255)"
},
BGColor: { Selected:"rgb(234,85,4)", Default:"rgb(25,25,25)", MoveOn:"rgb(59,59,59)" },
BorderColor:"rgb(60,60,60)",
Mergin: { Left:5*GetDevicePixelRatio(), Right:5*GetDevicePixelRatio(), Top:4*GetDevicePixelRatio(), Bottom:2*GetDevicePixelRatio() }
};
*/
/*
this.AryButton=
[
{ Title:"MACD", ID:"A", TooltipText:"切换MACD指标", Data:{ IndexID:"MACD"}},
{ Title:"RSI", ID:"A1", TooltipText:"切换RSI指标", Data:{ IndexID:"RSI"} },
{ Title:"大狗棍法", ID:"B1" },
{ Title:"降龙掌", ID:"B3"}
];
this.SelectedID="A1"
*/
this.ReloadResource=function(resource)
{
this.BGColor=g_JSChartResource.FrameButtomToolbar.BGColor;
this.BorderColor=g_JSChartResource.FrameButtomToolbar.BorderColor;
this.ButtonConfig=CloneData(g_JSChartResource.FrameButtomToolbar.Button);
}
this.SetOption=function(option)
{
if (option)
{
if (IFrameSplitOperator.IsNumber(option.FrameID)) this.FrameID=option.FrameID;
if (option.FrameGuid) this.FrameGuid=option.FrameGuid;
if (IFrameSplitOperator.IsNonEmptyArray(option.AryButton)) this.AryButton=option.AryButton.slice();
if (option.SelectedID) this.SelectedID=option.SelectedID;
}
}
//设置当前选中的菜单ID
this.SetSelectedID=function(id)
{
this.SelectedID=id;
}
this.Draw=function(moveonPoint, mouseStatus)
{
this.AryRectButton=[];
var frame=this.GetFrame();
if (!frame) return;
if (frame.IsHScreen) return; //不支持横屏
if (frame.IsMinSize) return;
if (frame.ChartBorder.IsShowTitleOnly) return;
var border=frame.ChartBorder.GetBorder();
var rtBG={ Left:border.Left+1, Right:border.Right-1, Top:border.BottomEx+1, Bottom:border.Bottom-1 };
rtBG.Width=rtBG.Right-rtBG.Left;
rtBG.Height=rtBG.Bottom-rtBG.Top;
if (rtBG.Height<10) return;
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
var font=this.GetTitleFont(rtBG.Height-this.ButtonConfig.Mergin.Top-this.ButtonConfig.Mergin.Bottom);
var svgFont=this.GetSVGFont(rtBG.Height-this.ButtonConfig.Mergin.Top-this.ButtonConfig.Mergin.Bottom);
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='center';
this.Canvas.font=font;
var xBotton=rtBG.Left;
for(var i=0;i<this.AryButton.length;++i)
{
var item=this.AryButton[i];
if (!item.Title && !(item.SVGButton && item.SVGButton.Symbol)) return;
var textWidth=0;
if (item.Title)
{
textWidth=this.Canvas.measureText(item.Title).width+2;
}
var svgButtonWidth=0;
if (item.SVGButton && item.SVGButton.Symbol)
{
svgButtonWidth=this.ButtonConfig.SVG.Size;
if (textWidth>0) svgButtonWidth+=this.ButtonConfig.SVG.MerginLeft;
}
var buttonWidth=textWidth+svgButtonWidth+this.ButtonConfig.Mergin.Left+this.ButtonConfig.Mergin.Right;
var rtButton={ Left:xBotton, Top:rtBG.Top, Bottom:rtBG.Bottom, Height:rtBG.Height, Width:buttonWidth };
rtButton.Right=rtButton.Left+rtButton.Width;
//鼠标是否在按钮上
var bgColor=this.ButtonConfig.BGColor.Default;
var titleColor=this.ButtonConfig.TitleColor.Default;
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
bgColor=this.ButtonConfig.BGColor.MoveOn;
titleColor=this.ButtonConfig.TitleColor.MoveOn;
if (mouseStatus)
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:item, Frame:frame, Point:{X:moveonPoint.X, Y:moveonPoint.Y}, ID:"TitleButton" };
}
if (this.SelectedID && this.SelectedID==item.ID)
{
bgColor=this.ButtonConfig.BGColor.Selected;
titleColor=this.ButtonConfig.TitleColor.Selected;
}
if (bgColor)
{
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtButton.Left,rtButton.Top,rtButton.Width,rtButton.Height);
}
if (this.ButtonConfig.BorderColor)
{
this.Canvas.strokeStyle=this.ButtonConfig.BorderColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(rtButton.Right),rtButton.Top);
this.Canvas.lineTo(ToFixedPoint(rtButton.Right),rtButton.Bottom);
this.Canvas.stroke();
}
if (item.Title)
{
this.Canvas.fillStyle=titleColor;
var xText=rtButton.Left+(rtButton.Width-svgButtonWidth)/2; //居中
var yText=rtButton.Top+this.ButtonConfig.Mergin.Top+(rtButton.Height-this.ButtonConfig.Mergin.Top-this.ButtonConfig.Mergin.Bottom)/2;
this.Canvas.fillText(item.Title,xText,yText);
}
var rtSVG=null;
if (item.SVGButton && item.SVGButton.Symbol)
{
this.Canvas.font=svgFont;
this.Canvas.fillStyle=titleColor;
var xText=rtButton.Right-this.ButtonConfig.SVG.Size/2-this.ButtonConfig.Mergin.Right;
this.Canvas.fillText(item.SVGButton.Symbol,xText,yText);
this.Canvas.font=font;
rtSVG={Left:rtButton.Right-this.ButtonConfig.Mergin.Right-this.ButtonConfig.SVG.Size, Top:rtButton.Top, Width:this.ButtonConfig.SVG.Size, Height:this.ButtonConfig.SVG.Size};
rtSVG.Right=rtSVG.Left+rtSVG.Width;
rtSVG.Bottom=rtSVG.Top+rtSVG.Height;
}
//{ Rect:rtButton, ID:item.ID, Data:item, RectSVG:rtSVG }
if (textWidth>0 && svgButtonWidth>0)
{
var rtText={ Left:rtButton.Left, Top:rtButton.Top, Bottom:rtButton.Bottom };
rtText.Right=rtText.Left+textWidth+this.ButtonConfig.Mergin.Left+this.ButtonConfig.SVG.MerginLeft/2;
var cacheItem={ Rect:rtText, ID:item.ID, Data:item, RectCell:rtButton, ButtonType:0 };
this.AryRectButton.push(cacheItem);
var rtSVG={Left:rtText.Right, Right:rtButton.Right, Top:rtButton.Top, Bottom:rtButton.Bottom };
var cacheItem={ Rect:rtSVG, ID:item.ID, Data:item, RectCell:rtButton, ButtonType:1 };
this.AryRectButton.push(cacheItem);
}
else
{
var cacheItem={ Rect:rtButton, ID:item.ID, Data:item, RectCell:rtButton }; //RectCell 全部的大小
if (textWidth>0) cacheItem.ButtonType=0;
else if (svgButtonWidth>0) cacheItem.ButtonType=1;
this.AryRectButton.push(cacheItem);
}
xBotton+=buttonWidth+1;
}
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.beginPath();
this.Canvas.moveTo(border.Left,ToFixedPoint(border.BottomEx));
this.Canvas.lineTo(border.Right,ToFixedPoint(border.BottomEx));
this.Canvas.stroke();
}
}
this.GetFrame=function()
{
if (!this.ChartFrame) return null;
if (this.FrameID>=0)
{
var subFrame=this.ChartFrame.SubFrame[this.FrameID];
if (!subFrame || !subFrame.Frame) return null;
return subFrame.Frame;
}
return null;
}
this.GetTitleFont=function(height)
{
var config=this.ButtonConfig.Font;
var fontSize=height*GetDevicePixelRatio();
if (IFrameSplitOperator.IsPlusNumber(config.Size)) fontSize=config.Size;
var font=`${fontSize}px ${config.Family}`;
return font;
}
this.GetSVGFont=function(height)
{
var config=this.ButtonConfig.SVG;
var fontSize=height*GetDevicePixelRatio();
if (IFrameSplitOperator.IsPlusNumber(config.Size)) fontSize=config.Size;
var font=`${fontSize}px ${config.Family}`;
return font;
}
this.PtInButtons=function(x,y)
{
for(var i=0;i<this.AryRectButton.length;++i)
{
var item=this.AryRectButton[i];
var rect=item.Rect;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
{
var frame=this.GetFrame();
var result={ ID:item.Data.ID, Rect:rect, FrameID:this.FrameID, Frame:frame, Data:item.Data, ButtonType:item.ButtonType, RectCell:item.RectCell, };
return result;
}
}
return null;
}
}
//弹幕数据 { X:X偏移, Y:Y偏移, Text:内容, Color:颜色 }
function BarrageList()
{
this.PlayList=[]; //正在播放队列
this.Cache=[]; //没有播放的弹幕数据
this.MinLineHeight=40*GetDevicePixelRatio();
this.Height; //高度
this.Step=1;
//{Canves:画布, Right:右边坐标, Left:左边坐标, Font:默认字体 }
this.GetPlayList=function(obj)
{
var canves=obj.Canves;
var right=obj.Right;
var left=obj.Left;
var width=right-left;
var isMoveStep=obj.IsMoveStep;
var list=[];
var yOffset=0;
for(var i=0;i<this.PlayList.length;++i)
{
var ary=this.PlayList[i];
var lineHeight=this.MinLineHeight;
if (ary.Height>this.MinLineHeight) lineHeight=ary.Height;
var bAddNewItem=true; //是否需要加入新弹幕
var bRemoveFirst=false; //是否删除第1个数据
for(var j=0;j<ary.Data.length;++j)
{
var item=ary.Data[j];
var playItem={ X:item.X, Y:yOffset, Text:item.Text, Color:item.Color, Height:lineHeight, Font:item.Font, Info:item.Info };
list.push(playItem);
if (!isMoveStep) continue;
if(j==ary.Data.length-1 && this.Cache.length>0) //最后一个数据了 判断是否需要增加弹幕
{
bAddNewItem=false;
if (!item.TextWidth)
{
if (item.Font && item.Font.Name) canves.font=item.Font.Name;
else canves.font=obj.Font;
item.TextWidth=canves.measureText(playItem.Text+'擎擎').width;
}
if (item.X>=item.TextWidth)
bAddNewItem=true;
}
else if (j==0)
{
bRemoveFirst=false;
if (!item.TextWidth)
{
if (item.Font && item.Font.Name) canves.font=item.Font.Name;
else canves.font=obj.Font;
item.TextWidth=canves.measureText(playItem.Text+'擎擎').width;
}
if (item.X>width+item.TextWidth) bRemoveFirst=true;
}
item.X+=this.Step;
}
if(isMoveStep && bAddNewItem && this.Cache.length>0) //最后一个数据了 判断是否需要增加弹幕
{
var cacheItem=this.Cache.shift();
var newItem={ X:0, Text:cacheItem.Text, Color:cacheItem.Color , Font:cacheItem.Font, Info:cacheItem.Info };
ary.Data.push(newItem);
}
if (isMoveStep && bRemoveFirst && ary.Data.length>0)
{
var removeItem=ary.Data.shift();
this.OnItemPlayEnd(obj.HQChart,removeItem);
}
yOffset+=lineHeight;
}
return list;
}
//根据高度计算播放队列个数
this.CacluatePlayLine=function(height)
{
this.Height=height;
var lineCount=parseInt(height/this.MinLineHeight);
if (this.PlayList.length<lineCount)
{
var addCount=lineCount-this.PlayList.length;
for(var i=0;i<addCount;++i)
{
this.PlayList.push({Data:[]});
}
}
else if (this.PlayList.length>lineCount)
{
var removeCount=this.PlayList.length-lineCount;
for(var i=0;i<removeCount;++i)
{
var ary=this.PlayList.pop();
for(var j=0;j<ary.Data.length;++j)
{
var item=ary.Data[j];
var cacheItem={ Text:item.Text, Color:item.Color, Font:item.Font, Info:item.Info };
this.Cache.unshift(cacheItem);
}
}
}
JSConsole.Chart.Log(`[BarrageList::CacluatePlayLine] LineCount=${this.PlayList.length} Height=${this.Height}` )
}
//添加弹幕
this.AddBarrage=function(barrageData)
{
for(var i in barrageData)
{
var item=barrageData[i];
this.Cache.push(item);
}
}
this.OnItemPlayEnd=function(hqChart, item) //单挑弹幕播放完毕
{
//监听事件
if (!hqChart.mapEvent.has(JSCHART_EVENT_ID.BARRAGE_PLAY_END)) return;
var event=hqChart.mapEvent.get(JSCHART_EVENT_ID.BARRAGE_PLAY_END);
if (!event.Callback) return;
event.Callback(event,item,this);
}
this.Count=function() { return this.Cache.length; } //未播放的弹幕个数
}
//弹幕
function BarragePaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='BarragePaint';
this.IsAnimation=true;
this.IsEraseBG=true;
this.HQChart;
this.Font=g_JSChartResource.Barrage.Font;
this.TextColor=g_JSChartResource.Barrage.Color;
this.FontHeight=g_JSChartResource.Barrage.Height;
this.BarrageList=new BarrageList(); //字幕列表
this.IsMoveStep=false;
//设置参数接口
this.SetOption=function(option)
{
if (option)
{
if (option.Step>0) this.BarrageList.Step=option.Step;
if (option.MinLineHeight) this.Barrage.MinLineHeight=option.MinLineHeight;
}
}
this.DrawHScreen=function()
{
var height=this.ChartBorder.GetWidth();
var left=this.ChartBorder.GetTop();
var right=this.ChartBorder.GetBottom();
var top=this.ChartBorder.GetRightEx();
var wdith=this.ChartBorder.GetChartWidth();
if (height!=this.BarrageList.Height)
this.BarrageList.CacluatePlayLine(height);
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart});
this.IsMoveStep=false;
if (!play) return;
this.Canvas.save();
this.Canvas.translate(this.ChartBorder.GetChartHeight(), 0);
this.Canvas.rotate(90 * Math.PI / 180);
for(var i=0;i<play.length;++i)
{
var item=play[i];
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.TextColor;
if (item.Font) this.Canvas.font=item.Font.Name;
else this.Canvas.font=this.Font;
var fontHeight=this.FontHeight;
if (item.Font && item.Font.Height>0) fontHeight=item.Font.Height;
var yOffset=item.Y+parseInt((item.Height-fontHeight)/2);
this.Canvas.fillText(item.Text, right-item.X,top+yOffset);
}
this.Canvas.restore();
}
this.Draw=function()
{
if (this.ChartFrame.IsHScreen)
{
this.DrawHScreen();
return;
}
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeight();
if (height!=this.BarrageList.Height)
this.BarrageList.CacluatePlayLine(height);
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart});
this.IsMoveStep=false;
if (!play) return;
for(var i=0;i<play.length;++i)
{
var item=play[i];
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.TextColor;
if (item.Font) this.Canvas.font=item.Font.Name;
else this.Canvas.font=this.Font;
var fontHeight=this.FontHeight;
if (item.Font && item.Font.Height>0) fontHeight=item.Font.Height;
var yOffset=item.Y+parseInt((item.Height-fontHeight)/2);
this.Canvas.fillText(item.Text, right-item.X,top+yOffset);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//坐标分割
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////
//Y轴自定义刻度类型ID
var JSCHART_CUSTOM_YCOORDINATE_ID=
{
LATEST_VALUE_ID:0, //最新价格刻度
FIXED_VALUE_ID:1, //固定价格刻度
PAGE_LAST_PRICE_ID:2, //当前屏最后一个K线收盘价刻度
PAGE_DATA_INCREASE:3, //当前屏数据涨幅
PAGE_LAST_INDEX_VALUE_ID:4, //指标前屏最后一个数据刻度
PAGE_LAST_OVERLAY_INDEX_VALUE_ID:5, //叠加指标前屏最后一个数据刻度
};
function IFrameSplitOperator()
{
this.ChartBorder; //边框信息
this.Frame; //框架信息
this.FrameSplitData; //坐标轴分割方法
this.SplitCount=5; //刻度个数
this.StringFormat=0; //刻度字符串格式 2=原始格式
this.IsShowLeftText=true; //显示左边刻度
this.IsShowRightText=true; //显示右边刻度
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.GetEventCallback; //事件回调
this.GetKLineChartCallback; //获取K线图形
//////////////////////
// data.Min data.Max data.Interval data.Count
//
this.IntegerCoordinateSplit=function(data)
{
var splitItem=this.FrameSplitData.Find(data.Interval);
if (!splitItem) return false;
if (data.Interval==splitItem.FixInterval) return true;
var fixMax=data.Max, fixMin=data.Min;
var maxValue=data.Max/splitItem.FixInterval;
var minValue=data.Min/splitItem.FixInterval;
//调整到整数倍数,不能整除的 +1
if (IFrameSplitOperator.IsFloat(maxValue)) fixMax=parseInt((maxValue+0.5).toFixed(0))*splitItem.FixInterval;
if (IFrameSplitOperator.IsFloat(minValue)) fixMin=parseInt((minValue-0.5).toFixed(0))*splitItem.FixInterval;
if (data.Min==0) fixMin=0; //最小值是0 不用调整了.
if (fixMin<0 && data.Min>0) fixMin=0; //都是正数的, 最小值最小调整为0
var count=0;
for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval)
{
++count;
}
data.Interval=splitItem.FixInterval;
data.Max=fixMax;
data.Min=fixMin;
data.Count=count;
return true;
}
this.Filter=function(aryInfo, keepZero, filterType)
{
if (this.SplitCount <= 0 || aryInfo.length <= 0 || aryInfo.length <= this.SplitCount) return aryInfo;
//分割线比预设的多, 过掉一些
var filter = parseInt(aryInfo.length / this.SplitCount);
if (filter <= 1) filter = 2;
var data = [];
if (filterType==1)
{
for (var i = 0; i < aryInfo.length; i += filter)
{
data.push(aryInfo[i]);
}
}
else
{
for (var i = 0; i < aryInfo.length; i += filter)
{
if (i + filter >= aryInfo.length && i != aryInfo.length - 1) //最后一个数据放进去
{
data.push(aryInfo[aryInfo.length - 1]);
}
else
{
data.push(aryInfo[i]);
}
}
}
if (this.SplitCount == 2 && data.length>2) //之显示第1个和最后一个刻度
{
for(var i=1;i<data.length-1;++i)
{
var item=data[i];
item.Message[0]=null;
item.Message[1]=null;
}
}
if (keepZero) //如果不存在0轴,增加一个0轴,刻度信息部显示
{
var bExsitZero=false;
for(var i=0;i<data.length;++i)
{
var item=data[i];
if (Math.abs(item.Value) < 0.00000001)
{
bExsitZero=true;
break;
}
}
if (bExsitZero==false)
{
var zeroCoordinate = new CoordinateInfo();
zeroCoordinate.Value = 0;
zeroCoordinate.Message[0] = null
zeroCoordinate.Message[1] = null;
data.push(zeroCoordinate);
}
}
return data;
}
this.RemoveZero=function(aryInfo) //移除小数后面多余的0
{
//所有的数字小数点后面都0,才会去掉
var isAllZero = [true, true, true, true];
for (var i=0; i<aryInfo.length; ++i)
{
var item = aryInfo[i];
var message = item.Message[0];
if (!this.IsDecimalZeroEnd(message)) isAllZero[0] = false;
var message = item.Message[1];
if (!this.IsDecimalZeroEnd(message)) isAllZero[1] = false;
var message = item.Message[2];
if (!this.IsDecimalZeroEnd(message)) isAllZero[2] = false;
var message = item.Message[3];
if (!this.IsDecimalZeroEnd(message)) isAllZero[3] = false;
}
if (isAllZero[0] == false && isAllZero[1] == false && isAllZero[2]==false && isAllZero[3]==false) return;
for (var i=0; i<aryInfo.length; ++i)
{
var item = aryInfo[i];
if (isAllZero[0])
{
var message = item.Message[0];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[0] = message.replace(/[.][0]+/g, '');
}
}
if (isAllZero[1])
{
var message = item.Message[1];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[1] = message.replace(/[.][0]+/g, '');
}
}
if (isAllZero[2])
{
var message = item.Message[2];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[2] = message.replace(/[.][0]+/g, '');
}
}
if (isAllZero[3])
{
var message = item.Message[3];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[3] = message.replace(/[.][0]+/g, '');
}
}
}
}
this.IsDecimalZeroEnd = function (text) //是否是0结尾的小数
{
if (text==null) return true;
if (typeof(text)=='number') text=text.toString();
if (text=='0') return true;
var pos = text.search(/[.]/);
if (pos < 0) return false;
for (var i = pos + 1; i < text.length; ++i)
{
var char = text.charAt(i);
if (char >= '1' && char <= '9') return false;
}
return true;
}
//当前屏K线起始和结束的信息
this.GetKLinePageInfo=function()
{
if (!this.GetKLineChartCallback) return null;
var chart=this.GetKLineChartCallback();
if (!chart || !chart.Data || !(chart.Data.DataOffset>=0)) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(chart.Data.Data)) return null;
var aryKData=chart.Data.Data;
var startIndex=chart.Data.DataOffset;
var endIndex=chart.Data.DataOffset+chart.ChartFrame.XPointCount-1;
if (endIndex>=aryKData.length) endIndex=aryKData.length-1;
var result=
{
Start:{ Item:aryKData[startIndex], Index:startIndex },
End:{ Item:aryKData[endIndex], Index:endIndex },
IsLast:endIndex==aryKData.length-1
};
return result;
}
//当前屏最新指标数据
this.CustomLatestIndexDataCoordinate=function(option)
{
var pageInfo=this.GetKLinePageInfo(); //获取当前屏信息
if (!pageInfo) return;
if (!this.HQChart) return;
var event=null;
if (this.GetEventCallback)
event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_INDEX_Y_LABEL);
var endIndex=pageInfo.End.Index;
var floatPrecision=2;
if (IFrameSplitOperator.IsNumber(this.FloatPrecision)) floatPrecision=this.FloatPrecision;
for(var i=0, j=0;i<this.HQChart.ChartPaint.length;++i)
{
var chart=this.HQChart.ChartPaint[i];
if (!chart.ChartFrame) continue;
if (!chart.GetItemData) continue;
if (chart.ChartFrame.Identify==this.Frame.Identify || chart.ChartFrame==this.Frame)
{
var aryItem=chart.GetItemData( {Index:endIndex} );
if (!IFrameSplitOperator.IsNonEmptyArray(aryItem)) continue;
for(j=0; j<aryItem.length; ++j)
{
var item=aryItem[j];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
info.LineColor=item.Color;
info.LineType=-1; //默认不画线
info.IsLast=pageInfo.IsLast;//是否是最后一个数据
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
info.Value=item.Value;
var text=IFrameSplitOperator.FormatValueString(item.Value, floatPrecision,this.LanguageID);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
if (!pageInfo.IsLast)
{
var config={};
if (!pageInfo.IsLast) config.EmptyBGColor=g_JSChartResource.FrameLatestPrice.EmptyBGColor;
info.ExtendData={ Custom:config };
}
if (event)
{
var sendData={ PreventDefault:false, Label:info, Data:item, IndexName:chart.IndexName, FrameID:this.Frame.Identify };
event.Callback(event,sendData,this);
if (sendData.PreventDefault) continue;
}
this.Frame.CustomHorizontalInfo.push(info);
}
}
}
}
this.CustomLatestOverlayIndexDataCoordinate=function(option)
{
var pageInfo=this.GetKLinePageInfo(); //获取当前屏信息
if (!pageInfo) return;
if (!this.OverlayIndex) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.OverlayIndex.ChartPaint)) return;
var event=null;
if (this.GetEventCallback)
event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_OVERLAY_INDEX_Y_LABEL);
var endIndex=pageInfo.End.Index;
var floatPrecision=2;
if (IFrameSplitOperator.IsNumber(this.FloatPrecision)) floatPrecision=this.FloatPrecision;
for(var i=0, j=0;i<this.OverlayIndex.ChartPaint.length;++i)
{
var chart=this.OverlayIndex.ChartPaint[i];
if (!chart.ChartFrame) continue;
if (!chart.GetItemData) continue;
var aryItem=chart.GetItemData( {Index:endIndex} );
if (!IFrameSplitOperator.IsNonEmptyArray(aryItem)) continue;
for(j=0; j<aryItem.length; ++j)
{
var item=aryItem[j];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
info.LineColor=item.Color;
info.LineType=-1; //默认不画线
info.IsLast=pageInfo.IsLast;//是否是最后一个数据
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
info.Value=item.Value;
var text=IFrameSplitOperator.FormatValueString(item.Value, floatPrecision,this.LanguageID);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
if (!pageInfo.IsLast)
{
var config={};
if (!pageInfo.IsLast) config.EmptyBGColor=g_JSChartResource.FrameLatestPrice.EmptyBGColor;
info.ExtendData={ Custom:config };
}
if (event)
{
var sendData={ PreventDefault:false, Label:info, Data:item, IndexName:chart.IndexName, OverlayIdentify:this.OverlayIndex.Identify };
event.Callback(event,sendData,this);
if (sendData.PreventDefault) continue;
}
this.Frame.CustomHorizontalInfo.push(info);
}
}
},
//回调外部处理自定义Y轴刻度
this.InvokeCustomYCoordinateCallback=function()
{
if (!this.GetEventCallback) return null;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_CUSTOM_Y_COORDINATE);
if (!event || !event.Callback) return null;
var data={ ID:this.Frame.Identify, Frame:this.Frame, PreventDefault:false, Custom:this.Custom };
if (this.OverlayIdentify) data.OverlayIdentify=this.OverlayIdentify;
event.Callback(event,data,this);
return data;
}
this.Reset=function() //重置
{
}
this.SetOption=function(option) { }
//计算上下预留
this.ReservedHeight=function(splitData)
{
if (!this.Frame) return;
if (this.Frame.IsHScreen) return; //横屏以后再搞
var yReserved=this.Frame.HorizontalReserved;
if (!yReserved) return;
var reservedHeight=0;
if (IFrameSplitOperator.IsPlusNumber(yReserved.Top)) reservedHeight+=yReserved.Top;
if (IFrameSplitOperator.IsPlusNumber(yReserved.Bottom)) reservedHeight+=yReserved.Bottom;
if (reservedHeight<=0) return;
var border=this.Frame.GetBorder();
var top=border.TopEx;
var bottom=border.BottomEx;
var srcHeight=bottom-top;
if (srcHeight<reservedHeight) return;
var max=splitData.Max;
var min=splitData.Min;
if (IFrameSplitOperator.IsPlusNumber(yReserved.Top)) top-=yReserved.Top;
if (IFrameSplitOperator.IsPlusNumber(yReserved.Bottom)) bottom+=yReserved.Bottom;
var value=(max-min)/(bottom-top); //1个像素点对应的数值
if (IFrameSplitOperator.IsPlusNumber(yReserved.Top))
{
var topValue=value*yReserved.Top;
max+=topValue;
}
if (IFrameSplitOperator.IsPlusNumber(yReserved.Bottom))
{
var bottomValue=value*yReserved.Bottom;
min-=bottomValue;
}
splitData.Max=max;
splitData.Min=min;
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
}
}
//字符串格式化 千分位分割
IFrameSplitOperator.FormatValueThousandsString=function(value,floatPrecision)
{
if (value==null || isNaN(value))
{
if (floatPrecision>0)
{
var nullText='-.';
for(var i=0;i<floatPrecision;++i)
nullText+='-';
return nullText;
}
return '--';
}
var result='';
var num=value.toFixed(floatPrecision);
if(floatPrecision>0){
var numFloat = num.split('.')[1];
var numM = num.split('.')[0];
while (numM.length > 3)
{
result = ',' + numM.slice(-3) + result;
numM = numM.slice(0, numM.length - 3);
}
if (numM) { result = numM + result + '.' + numFloat; }
}else{
while (num.length > 3)
{
result = ',' + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) { result = num + result; }
}
return result;
}
//数据输出格式化 floatPrecision=小数位数
IFrameSplitOperator.FormatValueString=function(value, floatPrecision,languageID)
{
/*
if (value==null || isNaN(value))
{
if (floatPrecision>0)
{
var nullText='-.';
for(var i=0;i<floatPrecision;++i)
nullText+='-';
return nullText;
}
return '--';
}
if (value<0.00000000001 && value>-0.00000000001)
{
return "0";
}
var absValue = Math.abs(value);
if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID)
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue < 1000000)
return (value/1000).toFixed(floatPrecision)+"K";
else if (absValue < 1000000000)
return (value/1000000).toFixed(floatPrecision)+"M";
else if (absValue < 1000000000000)
return (value/1000000000).toFixed(floatPrecision)+"B";
else
return (value/1000000000000).toFixed(floatPrecision)+"T";
}
else if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID) //繁体
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue < 100000000)
return (value/10000).toFixed(floatPrecision)+"萬";
else if (absValue < 1000000000000)
return (value/100000000).toFixed(floatPrecision)+"億";
else
return (value/1000000000000).toFixed(floatPrecision)+"萬億";
}
else
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue<1000000)
return (value/10000).toFixed(floatPrecision)+"万";
else if (absValue < 100000000)
return (value/10000).toFixed(floatPrecision)+"万";
else if (absValue < 1000000000000)
return (value/100000000).toFixed(floatPrecision)+"亿";
else
return (value/1000000000000).toFixed(floatPrecision)+"万亿";
}
*/
return IFrameSplitOperator.FormatValueStringV2(value, floatPrecision, floatPrecision, languageID);
}
//数据输出格式化 floatPrecision=原始小数位数 floatPrecision2=转换成'万','亿'..的小数位
IFrameSplitOperator.FormatValueStringV2=function(value, floatPrecision, floatPrecision2, languageID)
{
if (value==null || isNaN(value))
{
if (floatPrecision>0)
{
var nullText='-.';
for(var i=0;i<floatPrecision;++i)
nullText+='-';
return nullText;
}
return '--';
}
if (value<0.00000000001 && value>-0.00000000001)
{
return "0";
}
var absValue = Math.abs(value);
if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID)
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue < 1000000)
return (value/1000).toFixed(floatPrecision2)+"K";
else if (absValue < 1000000000)
return (value/1000000).toFixed(floatPrecision2)+"M";
else if (absValue < 1000000000000)
return (value/1000000000).toFixed(floatPrecision2)+"B";
else
return (value/1000000000000).toFixed(floatPrecision2)+"T";
}
else if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID) //繁体
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue < 100000000)
return (value/10000).toFixed(floatPrecision2)+"萬";
else if (absValue < 1000000000000)
return (value/100000000).toFixed(floatPrecision2)+"億";
else
return (value/1000000000000).toFixed(floatPrecision2)+"萬億";
}
else
{
if (absValue < 10000)
return value.toFixed(floatPrecision);
else if (absValue<1000000)
return (value/10000).toFixed(floatPrecision2)+"万";
else if (absValue < 100000000)
return (value/10000).toFixed(floatPrecision2)+"万";
else if (absValue < 1000000000000)
return (value/100000000).toFixed(floatPrecision2)+"亿";
else
return (value/1000000000000).toFixed(floatPrecision2)+"万亿";
}
return '';
}
//成交量显示
IFrameSplitOperator.FormatVolString=function(value,languageID)
{
var absValue = Math.abs(value);
if (absValue<100000)
return value.toFixed(0);
else if (absValue<10000000)
return (value/10000).toFixed(1)+"万";
else if (absValue<100000000)
return (value/10000).toFixed(0)+"万";
else if (absValue<1000000000)
return (value/100000000).toFixed(2)+"亿";
else if (absValue < 1000000000000)
return (value/100000000).toFixed(1)+"亿";
else
return (value/1000000000000).toFixed(1)+"万亿";
}
//整形输出格式化 floatPrecision=小数位数
IFrameSplitOperator.FromatIntegerString=function(value, floatPrecision,languageID)
{
if (value<10000 && IFrameSplitOperator.IsInteger(value)) floatPrecision=0; //<10000的整形 去掉小数位数
return IFrameSplitOperator.FormatValueString(value, floatPrecision,languageID);
}
IFrameSplitOperator.NumberToString=function(value)
{
if (value<10) return '0'+value.toString();
return value.toString();
}
//毫秒格式 固定3位, 不足前面自动补0
IFrameSplitOperator.MillisecondToString=function(value)
{
if (value<10) return '00'+value.toString();
else if (value<100) return '0'+value.toString();
else return value.toString();
}
IFrameSplitOperator.FormatDateString=function(value,format, languageID)
{
var year=parseInt(value/10000);
var month=parseInt(value/100)%100;
var day=value%100;
switch(format)
{
case 'MM-DD':
return IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day);
case "MM/DD":
return `${IFrameSplitOperator.NumberToString(month)}/${IFrameSplitOperator.NumberToString(day)}`;
case "MM/DD/W":
var date=new Date(year,month-1,day);
var week=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],languageID);
return `${IFrameSplitOperator.NumberToString(month)}/${IFrameSplitOperator.NumberToString(day)}/${week}`;
case "YYYY-MM":
return `${year}-${IFrameSplitOperator.NumberToString(month)}`;
case "YYYY/MM/DD":
return year.toString() + '/' + IFrameSplitOperator.NumberToString(month) + '/' + IFrameSplitOperator.NumberToString(day);
case "YYYY/MM/DD/W":
{
var date=new Date(year,month-1,day);
var week=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],languageID);
return year.toString() + '/' + IFrameSplitOperator.NumberToString(month) + '/' + IFrameSplitOperator.NumberToString(day)+"/"+ week.toString();
}
case "DD/MM/YYYY":
return IFrameSplitOperator.NumberToString(day) + '/' + IFrameSplitOperator.NumberToString(month) + '/' + year.toString();
default: //YYYY-MM-DD
return year.toString() + '-' + IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day);
}
}
IFrameSplitOperator.FormatTimeString=function(value, format) //format hh:mm:ss
{
if (format=='HH:MM:SS')
{
var hour=parseInt(value/10000);
var minute=parseInt((value%10000)/100);
var second=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute) + ':' + IFrameSplitOperator.NumberToString(second);
}
else if (format=="hh:mm")
{
var hour=parseInt(value/10000);
var minute=parseInt((value%10000)/100);
var second=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute);
}
else if (format=='HH:MM')
{
var hour=parseInt(value/100);
var minute=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute);
}
else if (format=="HH:MM:SS.fff")
{
var millisecond=value%1000;
var dateTime=parseInt(value/1000);
var hour=parseInt(dateTime/10000);
var minute=parseInt((dateTime%10000)/100);
var second=dateTime%100;
return `${IFrameSplitOperator.NumberToString(hour)}:${IFrameSplitOperator.NumberToString(minute)}:${IFrameSplitOperator.NumberToString(second)}.${IFrameSplitOperator.MillisecondToString(millisecond)}`;
}
else
{
if (value<10000)
{
var hour=parseInt(value/100);
var minute=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute);
}
else
{
var hour=parseInt(value/10000);
var minute=parseInt((value%10000)/100);
var second=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute) + ':' + IFrameSplitOperator.NumberToString(second);
}
}
}
//报告格式化
IFrameSplitOperator.FormatReportDateString=function(value)
{
var year=parseInt(value/10000);
var month=parseInt(value/100)%100;
var monthText;
switch(month)
{
case 3:
monthText="一季度报";
break;
case 6:
monthText="半年报";
break;
case 9:
monthText="三季度报";
break;
case 12:
monthText="年报";
break;
}
return year.toString()+ monthText;
}
IFrameSplitOperator.FormatDateTimeString=function(value,isShowDate,isShowTime)
{
var aryValue=value.split(' ');
if (aryValue.length<2) return "";
var result="";
if (isShowDate)
{
var date=parseInt(aryValue[0]);
var year=parseInt(date/10000);
var month=parseInt(date%10000/100);
var day=date%100;
var text=year.toString() +'-'+ (month<10? ('0'+month.toString()) :month.toString()) +'-'+ (day<10? ('0'+day.toString()):day.toString());
result+=text;
}
if (isShowTime)
{
var time=parseInt(aryValue[1]);
if (time<10000)
{
var minute=time%100;
var hour=parseInt(time/100);
var text=IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute);
if (result.length>0) result+=" ";
result+=text;
}
else
{
var hour=parseInt(time/10000);
var minute=parseInt((time%10000)/100);
var second=time%100;
var text=IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute) + ':' + IFrameSplitOperator.NumberToString(second);
if (result.length>0) result+=" ";
result+=text;
}
}
return result;
}
//字段颜色格式化
IFrameSplitOperator.FormatValueColor = function (value, value2)
{
if (value != null && value2 == null) //只传一个值的 就判断value正负
{
if (value == 0) return 'PriceNull';
else if (value > 0) return 'PriceUp';
else return 'PriceDown';
}
//2个数值对比 返回颜色
if (value == null || value2 == null) return 'PriceNull';
if (value == value2) return 'PriceNull';
else if (value > value2) return 'PriceUp';
else return 'PriceDown';
}
IFrameSplitOperator.IsNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return typeof(value)=='number';
}
//批量判断是否是数值类型
IFrameSplitOperator.IsNumberV2=function(...aryValue)
{
if (!aryValue) return false;
if (aryValue.length==0) return false;
for(const value of aryValue)
{
if (value==null) return false;
if (isNaN(value)) return false;
if (typeof(value)!='number') return false;
}
return true;
}
//判断是否是正数
IFrameSplitOperator.IsPlusNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return value>0;
}
//是否是整形
IFrameSplitOperator.IsInteger=function(x)
{
return (typeof x === 'number') && (x % 1 === 0);
}
//判断字段是否存在
IFrameSplitOperator.IsObjectExist=function(obj)
{
if (obj===undefined) return false;
if (obj==null) return false;
return true;
}
//是否时bool
IFrameSplitOperator.IsBool=function(value)
{
if (value===true || value===false) return true;
return false;
}
IFrameSplitOperator.IsString=function(value)
{
var type=typeof(value);
if (type=='string') return true;
return false;
}
//是否是非空的数组
IFrameSplitOperator.IsNonEmptyArray=function(ary)
{
if (!ary) return false;
if (!Array.isArray(ary)) return false;
return ary.length>0;
}
IFrameSplitOperator.IsFloat=function(value)
{
if (value===undefined) return false;
if (value==null) return false;
if (isNaN(value)) return false;
return value!=parseInt(value);
}
//是否有效
IFrameSplitOperator.IsVaild=function(value)
{
if (isNaN(value)) return false;
if (value==null) return false;
if (value===undefined) return false;
return true;
}
IFrameSplitOperator.IsUndefined=function(value)
{
return value===undefined;
}
IFrameSplitOperator.IsObject=function(value)
{
return value instanceof Object;
}
IFrameSplitOperator.RemoveZero=function(strValue)
{
while(strValue.length>0)
{
var index=strValue.length-1;
var ch=strValue[index];
if (ch=="0")
{
strValue=strValue.substr(0,index);
}
else if (ch==".")
{
strValue=strValue.substr(0,index);
break;
}
else
{
break;
}
}
return strValue;
}
function FrameSplitKLinePriceY()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.CoordinateType=0; //坐标类型 0=普通坐标 1=百分比坐标 (右边坐标刻度) 2=对数对标 3=等比坐标 4=等分坐标 5=黄金分割
this.Symbol;
this.Data; //K线数据 (计算百分比坐标)
this.FrameSplitData2; //坐标轴分割方法(计算百分比刻度)
this.FloatPrecision=null; //小数位数 (设置了就使用这个位数,否则使用品种对应的小数位数)
this.Period; //周期
this.KLineChart;
this.Custom=[]; //[{Type:0}]; 定制刻度 0=显示最后的价格刻度
this.SplitType=0; //0=自动分割 1=固定分割 2=分笔图价格分割
this.DefaultSplitType=0;
this.DefaultYMaxMin; //{ Max:null, Min:null }; //指定最大,最小, Y轴范围必须比最大值大, 比最小值小
this.FixedYMaxMin; //{ Max, Min} 固定Y轴最大最小值
this.EnableZoomUpDown=false; //上下左右拖拽
this.LastMaxMin; //当前显示的最高最低范围
this.PercentageTextFormat=0; //0=显示第1行 1=显示2行 2=单行格式: 价格/百分比
this.IsEnableDragY=function()
{
return this.CoordinateType==0 || this.CoordinateType==1;
}
this.Operator=function()
{
var splitData={};
splitData.Max=this.Frame.HorizontalMax;
splitData.Min=this.Frame.HorizontalMin;
splitData.Count=this.SplitCount;
if (this.Frame.YMaxMin) //原始的数据范围
{
var item=this.Frame.YMaxMin;
if (IFrameSplitOperator.IsNumber(item.Max) && IFrameSplitOperator.IsNumber(item.Min))
{
splitData.Max=item.Max;
splitData.Min=item.Min;
}
}
if (splitData.Max==splitData.Min) //如果一样上下扩大下
{
splitData.Max+=splitData.Max*0.01;
splitData.Min-=splitData.Min*0.01
}
var isFixedMaxMin=(this.FixedYMaxMin && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Max) && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Min));
if (isFixedMaxMin)
{
splitData.Max=this.FixedYMaxMin.Max;
splitData.Min=this.FixedYMaxMin.Min;
//JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] FixedYMaxMin.Max=${this.FixedYMaxMin.Max} FixedYMaxMin.Min=${this.FixedYMaxMin.Min} `);
}
else if (this.DefaultYMaxMin) //指定最小的Y轴范围
{
var range=this.DefaultYMaxMin;
if (IFrameSplitOperator.IsNumber(range.Max))
{
if (splitData.Min>range.Max) splitData.Min=range.Max;
else if (splitData.Max<range.Max) splitData.Max=range.Max;
}
if (IFrameSplitOperator.IsNumber(range.Min))
{
if (splitData.Max<range.Min) splitData.Max=range.Min;
else if (splitData.Min>range.Min) splitData.Min=range.Min;
}
}
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度
var isPhoneModel=width<450*pixelTatio;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
if (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) defaultfloatPrecision = 0; //手机端指数不显示小数位数,太长了
if (this.FloatPrecision!=null) defaultfloatPrecision=this.FloatPrecision;
JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count} isPhoneModel=${isPhoneModel} defaultfloatPrecision=${defaultfloatPrecision} `);
this.Frame.Logarithmic=null;
this.Frame.MultiTextFormat=0;
var bFilter=true; //是否需要通过高度过滤刻度
splitData.IsFixedMaxMin=isFixedMaxMin;
splitData.IsFilter=bFilter;
if (ChartData.IsTickPeriod(this.Period))
{
this.SplitTickData(splitData,defaultfloatPrecision);
bFilter=splitData.IsFilter;
}
else if (FrameSplitKLinePriceY.SplitCustom)
{
FrameSplitKLinePriceY.SplitCustom(this,splitData,defaultfloatPrecision); //自定义分割
bFilter=false;
}
else
{
switch(this.CoordinateType)
{
case 1:
if (!this.SplitPercentage(splitData,defaultfloatPrecision,isFixedMaxMin))
{
this.SplitDefault(splitData,defaultfloatPrecision,isFixedMaxMin);
}
else
{
this.Frame.MultiTextFormat=this.PercentageTextFormat;
bFilter=false;
}
break;
case 3: //等比坐标 +10%/-10% 涨幅分割
if (!this.SplitIncrease(splitData,defaultfloatPrecision))
this.SplitDefault(splitData,defaultfloatPrecision);
else
bFilter=false;
break;
case 4: //等分坐标
this.SplitAverage(splitData,defaultfloatPrecision);
bFilter=false;
break;
case 5: //黄金分割
this.SplitGoldenSection(splitData,defaultfloatPrecision);
bFilter=false;
break;
case 2: //对数坐标
if (this.SplitLogarithmic(splitData,defaultfloatPrecision))
{
bFilter=false;
}
else
{
this.SplitDefault(splitData,defaultfloatPrecision);
}
break;
default:
if (this.SplitType==1)
{
this.SplitFixed(splitData,defaultfloatPrecision);
bFilter=false;
}
else if (this.SplitType==2)
{
this.SplitFixedV2(splitData,defaultfloatPrecision);
bFilter=false;
}
else
{
this.SplitDefault(splitData,defaultfloatPrecision,isFixedMaxMin);
}
break;
}
}
this.CustomCoordinate(defaultfloatPrecision);
if (bFilter) this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,false);
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
if (this.EnableZoomUpDown==true && !this.FixedYMaxMin)
this.FixedYMaxMin={ Max:splitData.Max, Min:splitData.Min };
/*
for(var i=0;i<this.Frame.HorizontalInfo.length;++i)
{
JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] ${i}=${this.Frame.HorizontalInfo[i].Message[0]}`);
}
*/
this.ReservedHeight(splitData); //预留高度
JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] fixed . Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count}`);
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
event.Callback(event,data,this);
}
}
}
this.SplitTickData=function(splitData,floatPrecision)
{
switch(this.CoordinateType)
{
case 1: //百分比
if (!this.SplitPercentage(splitData,floatPrecision,splitData.IsFixedMaxMin))
{
this.SplitDefault(splitData,floatPrecision,splitData.IsFixedMaxMin);
}
else
{
this.Frame.MultiTextFormat=this.PercentageTextFormat;
splitData.IsFilter=false;
}
break;
default:
if (this.SplitType==3)
{
this.SplitTickPrice(splitData,floatPrecision);
}
else
{
this.SplitDefault(splitData, floatPrecision, splitData.IsFixedMaxMin);
}
}
}
this.SplitTickPrice=function(splitData,floatPrecision)
{
var aryPrice=this.KLineChart.GetAllPrice();
this.Frame.HorizontalInfo=[];
for(var i in aryPrice)
{
var value=aryPrice[i];
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=value;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision);
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision);
}
}
this.SplitPercentage=function(splitData,floatPrecision,isFixedMaxMin) //百分比坐标
{
var firstOpenPrice=this.GetFirstOpenPrice();
if (!IFrameSplitOperator.IsNumber(firstOpenPrice)) return false;
splitData.Max=(splitData.Max-firstOpenPrice)/firstOpenPrice;
splitData.Min=(splitData.Min-firstOpenPrice)/firstOpenPrice;
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
if (!isFixedMaxMin) this.IntegerCoordinateSplit2(splitData);
var minValue=(1+splitData.Min)*firstOpenPrice;
var maxValue=(1+splitData.Max)*firstOpenPrice;
var textColor;
if (g_JSChartResource.Frame && g_JSChartResource.Frame.PercentageText)
{
var item=g_JSChartResource.Frame.PercentageText;
textColor={PriceColor:item.PriceColor, PercentageColor:item.PercentageColor, SplitColor:item.SplitColor, Font:item.Font };
}
var aryHorizontal=[];
for(var value=0;value<=splitData.Max; value+=splitData.Interval)
{
var price=(value+1)*firstOpenPrice;
var item=new CoordinateInfo();
item.Value=price;
if (this.IsShowLeftText) item.Message[0]=price.toFixed(floatPrecision); //左边价格坐标
if (this.IsShowRightText)
{
var strPrice=price.toFixed(floatPrecision);
var text=(value*100).toFixed(2); //右边百分比
text=IFrameSplitOperator.RemoveZero(text);
text+='%';
item.Message[1]=[text,strPrice];
item.ExtendData=textColor;
}
aryHorizontal.push(item);
}
for(var value=-splitData.Interval;value>=splitData.Min;value-=splitData.Interval)
{
var price=(value+1)*firstOpenPrice;
if (price<minValue || price>maxValue) continue;
var item=new CoordinateInfo();
item.Value=price;
if (this.IsShowLeftText) item.Message[0]=price.toFixed(floatPrecision); //左边价格坐标
if (this.IsShowRightText)
{
var strPrice=price.toFixed(floatPrecision);
var text=(value*100).toFixed(2); //右边百分比
text=IFrameSplitOperator.RemoveZero(text);
text+='%';
item.Message[1]=[text,strPrice];
item.ExtendData=textColor;
}
aryHorizontal.push(item);
}
aryHorizontal.sort((left, right)=>
{
return left.Value - right.Value;
});
this.Frame.HorizontalInfo=aryHorizontal;
splitData.Min=minValue; //最大最小值调整
splitData.Max=maxValue;
return true;
}
//等比坐标 当前屏最后第2根K线的收盘加为基准, 上下涨幅10%分割
this.SplitIncrease=function(splitData,floatPrecision)
{
var basePrice=this.GetLast2ndClose();
if (!IFrameSplitOperator.IsNumber(basePrice)) return false;
this.IntegerCoordinateSplit(splitData);
this.Frame.HorizontalInfo=[];
var increase=g_JSChartResource.FrameSplitIncrease.Increase;
var aryHorizontal=[];
for(var price=basePrice; price<splitData.Max; price=price*(1+increase))
{
var item= new CoordinateInfo();
item.Value=price;
var text=price.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=text;
if (this.IsShowRightText) item.Message[1]=text;
aryHorizontal.push(item);
}
for(var price=basePrice*0.9;price>splitData.Min; price=price*(1-increase))
{
var item= new CoordinateInfo();
item.Value=price;
var text=price.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=text;
if (this.IsShowRightText) item.Message[1]=text;
aryHorizontal.push(item);
}
this.Frame.HorizontalInfo=aryHorizontal;
return true;
}
//等分坐标:以画面显示的最高价、最低价为基准,对这个区域N等分,显示分割的数值线
this.SplitAverage=function(splitData,floatPrecision)
{
var max=splitData.Max;
var min=splitData.Min;
//this.IntegerCoordinateSplit(splitData);
this.Frame.HorizontalInfo=[];
var count=g_JSChartResource.FrameSplitAverage.Count;
var interval=(max-min)/count;
for(var i=0;i<=count;++i)
{
var item=new CoordinateInfo();
item.Value=min+interval*i;
var text=item.Value.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=text;
if (this.IsShowRightText) item.Message[1]=text;
this.Frame.HorizontalInfo[i]=item;
}
}
this.SplitGoldenSection=function(splitData,floatPrecision)
{
var max=splitData.Max;
var min=splitData.Min;
//this.IntegerCoordinateSplit(splitData);
this.Frame.HorizontalInfo=[];
var aryHorizontal=[];
var GOLDEN_ARRAY=g_JSChartResource.FrameGoldenSection.Golden;
for(var i in GOLDEN_ARRAY)
{
var value=(max-min)*GOLDEN_ARRAY[i]+min;
item=new CoordinateInfo();
item.Value=value;
var text=value.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=text;
if (this.IsShowRightText) item.Message[1]=text;
aryHorizontal.push(item);
}
this.Frame.HorizontalInfo=aryHorizontal;
}
this.SplitLogarithmic=function(splitData,floatPrecision) //对数坐标
{
var minInterval=g_JSChartResource.FrameLogarithmic.MinInterval; //最小间距
var firstOpenPrice=this.GetFirstOpenPrice(); //获取当前屏第1个K线的开盘价
if (!IFrameSplitOperator.IsNumber(firstOpenPrice)) return false;
var height=this.ChartBorder.GetHeightEx();
var ARRAY_INCREASE=[0.01, 0.02, 0.04, 0.08, 0.1, 0.2];
var increase=ARRAY_INCREASE[ARRAY_INCREASE.length-1];
for(var i=0; i<ARRAY_INCREASE.length;++i)
{
var value=ARRAY_INCREASE[i];
var interval=(firstOpenPrice*value)*(height/(splitData.Max-splitData.Min));
if (interval>minInterval)
{
increase=value;
break;
}
}
var aryUp=[];
var price=firstOpenPrice;
var i=increase;
do
{
var item={ Start:price };
price=firstOpenPrice*(1+i);
item.End=price;
aryUp.push(item);
i+=increase;
} while(price<splitData.Max);
var max=price;
var aryDown=[];
var price=firstOpenPrice;
var i=increase;
do
{
var item={ End:price };
price=firstOpenPrice*(1-i);
item.Start=price;
aryDown.push(item);
i+=increase;
} while(price>splitData.Min);
var min=price;
splitData.Max=max;
splitData.Min=min;
JSConsole.Chart.Log("[FrameSplitKLinePriceY::SplitLogarithmic] up, down", aryUp, aryDown);
this.Frame.HorizontalInfo=[];
var item=new CoordinateInfo();
item.Value=firstOpenPrice;
item.Font=g_JSChartResource.FrameLogarithmic.OpenPriceFont;
var strText=item.Value.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=strText; //左边价格坐标
if (this.IsShowRightText) item.Message[1]=strText; //右边价格坐标
this.Frame.HorizontalInfo.push(item);
for(var i in aryUp)
{
var item=new CoordinateInfo();
item.Value=aryUp[i].End;
var strText=item.Value.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=strText; //左边价格坐标
if (this.IsShowRightText) item.Message[1]=strText; //右边价格坐标
this.Frame.HorizontalInfo.push(item);
}
for(var i in aryDown)
{
var item=new CoordinateInfo();
item.Value=aryDown[i].End;
var strText=item.Value.toFixed(floatPrecision);
if (this.IsShowLeftText) item.Message[0]=strText; //左边价格坐标
if (this.IsShowRightText) item.Message[1]=strText; //右边价格坐标
this.Frame.HorizontalInfo.splice(0,0,item);
}
this.Frame.Logarithmic={ Up:aryUp, Down:aryDown, OpenPrice:firstOpenPrice };
return true;
}
this.SplitDefault=function(splitData,floatPrecision,isFixedMaxMin) //默认坐标
{
//固定最大最小值 不自动调整范围
if (!isFixedMaxMin) this.IntegerCoordinateSplit(splitData);
this.Frame.HorizontalInfo=[];
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=value;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision);
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision);
}
}
this.SplitFixed=function(splitData,floatPrecision) //固定分割坐标
{
this.Frame.HorizontalInfo=[];
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=value;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision);
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision);
}
}
this.SplitFixedV2=function(splitData,floatPrecision) //固定分割坐标
{
this.Frame.HorizontalInfo=[];
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=value;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision);
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision);
}
if (!splitData.IsFixedMaxMin) //缩放不需要调整大小
{
if (floatPrecision==0)
{
splitData.Max+=1;
splitData.Min-=1;
}
else if (floatPrecision==1)
{
splitData.Max+=0.1;
splitData.Min-=0.1;
}
else if (floatPrecision==2)
{
splitData.Max+=0.01;
splitData.Min-=0.01;
}
}
}
this.CustomCoordinate=function(floatPrecision)
{
if (!IFrameSplitOperator.IsNumber(floatPrecision))
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度
var isPhoneModel=width<450*pixelTatio;
floatPrecision=GetfloatPrecision(this.Symbol);
if (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) floatPrecision = 0; //手机端指数不显示小数位数,太长了
if (this.FloatPrecision!=null) floatPrecision=this.FloatPrecision;
}
this.Frame.CustomHorizontalInfo=[];
var data=this.InvokeCustomYCoordinateCallback();
if (data && data.PreventDefault==true) return;
var lastCoordinate, pageLastCoordinate;
for(var i=0; i<this.Custom.length; ++i)
{
var item=this.Custom[i];
if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.LATEST_VALUE_ID || item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_DATA_INCREASE || item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_LAST_PRICE_ID)
{
var dec=floatPrecision;
//外部设置小数位数
if (IFrameSplitOperator.IsNumber(item.FloatPrecision) && item.FloatPrecision>=0) dec=item.FloatPrecision;
var latestItem=this.GetLatestPrice(dec, item);
if (latestItem)
{
if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.LATEST_VALUE_ID)
lastCoordinate=latestItem;
else if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_LAST_PRICE_ID)
pageLastCoordinate=latestItem;
else
this.Frame.CustomHorizontalInfo.push(latestItem);
}
}
else if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.FIXED_VALUE_ID) //固定刻度
{
this.CustomFixedCoordinate(item);
}
else if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_LAST_INDEX_VALUE_ID) //当前屏指标最后一个数据
{
this.CustomLatestIndexDataCoordinate(item);
}
}
//当前页最后一个数据和最新数据刻度如果相同,只显示一个
if (lastCoordinate || pageLastCoordinate)
{
if (lastCoordinate && pageLastCoordinate && pageLastCoordinate.IsLast===true)
{
this.Frame.CustomHorizontalInfo.unshift(lastCoordinate);
}
else
{
if (lastCoordinate) this.Frame.CustomHorizontalInfo.unshift(lastCoordinate);
if (pageLastCoordinate) this.Frame.CustomHorizontalInfo.push(pageLastCoordinate);
}
}
}
this.GetLatestPrice=function(floatPrecision,option)
{
if (!this.Data || !this.Data.Data) return null;
if (this.Data.Data.length<=0) return null;
var latestItem=this.Data.Data[this.Data.Data.length-1];
var isLast=true;
if (option.Type==2) //当前屏最后的价格
{
var pageInfo=this.GetKLinePageInfo();
if (pageInfo)
{
latestItem=pageInfo.End.Item;
isLast=pageInfo.IsLast;
}
}
var info=new CoordinateInfo();
info.Type=0;
if (option && IFrameSplitOperator.IsNumber(option.Type)) info.Type=option.Type;
info.Value=latestItem.Close;
info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
info.LineType=2; //虚线
var strPrice=latestItem.Close.toFixed(floatPrecision);
//颜色
if (latestItem.Close>latestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
else if (latestItem.Close<latestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;
if (option.Type==3) //百分比显示
{
var pageInfo=this.GetKLinePageInfo();
if (pageInfo)
{
if (IFrameSplitOperator.IsNumber(pageInfo.Start.Item.YClose))
{
var value=(pageInfo.End.Item.Close-pageInfo.Start.Item.YClose)/pageInfo.Start.Item.YClose*100;
var strPrice=`${value.toFixed(2)}%`;
if (value>0) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
else if (value<0) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;
info.Value=pageInfo.End.Item.Close;
isLast=pageInfo.IsLast;
}
}
}
if (option.DateTime=='HH:MM' && ChartData.IsMinutePeriod(this.Period,true))
{
var strTime=IFrameSplitOperator.FormatTimeString(latestItem.Time,option.DateTime);
var aryText=[{Text:strPrice}, { Text:strTime} ];
if (option.Position=='left') info.Message[0]=aryText;
else info.Message[1]=aryText;
}
else if (IFrameSplitOperator.IsBool(option.CountDown)) //倒计时
{
var aryText=[ {Text:strPrice}, { Type:1 } ];
if (option.Position=='left') info.Message[0]=aryText;
else info.Message[1]=aryText;
}
else
{
if (option.Position=='left') info.Message[0]=strPrice
else info.Message[1]=strPrice;
}
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
if (IFrameSplitOperator.IsPlusNumber(option.LineWidth)) info.LineWidth=option.LineWidth;
if (option.LineDash) info.LineDash=option.LineDash;
if (option.IsShowLine==false) info.LineType=-1;
info.IsLast=isLast;//是否是最后一个数据
if (!isLast || option.PositionEx===1)
{
var config={};
if (!isLast) config.EmptyBGColor=g_JSChartResource.FrameLatestPrice.EmptyBGColor;
if (option.PositionEx===1) config.Position=1; //强制画在内部
info.ExtendData={ Custom:config };
}
return info;
}
this.GetFirstOpenPrice=function() //获取显示第1个数据的开盘价
{
if (!this.Data) return null;
var xPointCount=this.Frame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (ChartData.IsTickPeriod(this.Period))
return data.YClose;
else
return data.Open;
}
return null;
}
this.GetLast2ndClose=function() //获取最后第2根K线收盘加
{
if (!this.Data) return null;
if (this.Data.Data.length<=0) return null;
var xPointCount=this.Frame.XPointCount;
var endIndex=this.Data.DataOffset+xPointCount-1;
if (endIndex>=this.Data.Data.length) endIndex=this.Data.Data.length-1;
var price=null;
for(var i=endIndex, count=0; i>=0 && i<this.Data.Data.length; --i)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (count==0) price=data.Open;
else if (count==1) price=data.Close;
++count;
if (count>=2) break;
}
return price;
}
this.CustomFixedCoordinate=function(option) //固定坐标刻度
{
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
for(var i=0; i<option.Data.length; ++i)
{
var item=option.Data[i];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=item.TextColor;
info.LineColor=item.Color;
info.LineType=2; //虚线
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
if (IFrameSplitOperator.IsPlusNumber(option.LineWidth)) info.LineWidth=option.LineWidth;
if (option.LineDash) info.LineDash=option.LineDash;
if (option.IsShowLine==false) info.LineType=-1;
info.Value=item.Value;
var text;
if (item.Text) text=item.Text;
else text=info.Value.toFixed(defaultfloatPrecision);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
if (option.PositionEx===1) info.ExtendData={ Custom:{ Position:1 } }; //强制画在内部
if (IFrameSplitOperator.IsNonEmptyArray(item.ExtendLine)) info.ExtendLine=item.ExtendLine.slice();
this.Frame.CustomHorizontalInfo.push(info);
}
}
//////////////////////
// data.Min data.Max data.Interval data.Count
//
this.IntegerCoordinateSplit2=function(data)
{
var splitItem=this.FrameSplitData2.Find(data.Interval);
if (!splitItem) return false;
if (data.Interval==splitItem.FixInterval) return true;
//调整到整数倍数,不能整除的 +1
var fixMax=parseInt((data.Max/(splitItem.FixInterval)+0.5).toFixed(0))*splitItem.FixInterval;
var fixMin=parseInt((data.Min/(splitItem.FixInterval)-0.5).toFixed(0))*splitItem.FixInterval;
if (data.Min==0) fixMin=0; //最小值是0 不用调整了.
if (fixMin<0 && data.Min>0) fixMin=0; //都是正数的, 最小值最小调整为0
var count=0;
for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval)
{
++count;
}
data.Interval=splitItem.FixInterval;
data.Max=fixMax;
data.Min=fixMin;
data.Count=count;
return true;
}
}
function FrameSplitY()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.SplitCount=3; //刻度个数
this.FloatPrecision = 2; //坐标小数位数(默认2)
this.FLOATPRECISION_RANGE=[1,0.1,0.01,0.001,0.0001];
this.SplitType=0; //0=自动分割 1=固定分割 2=堆积图(0-100)
this.FilterType=0; //自动分割过滤算法
this.DefaultSplitType=0;
this.Custom=[]; //[{Type:0}]; 定制刻度
this.DefaultYMaxMin; //{ Max:null, Min:null }; //指定最大,最小, Y轴范围必须比最大值大, 比最小值小
this.EnableRemoveZero=g_JSChartResource.Frame.EnableRemoveZero;
this.LineType=null; //线段样式
this.IgnoreYValue = null; //在这个数组里的数字不显示在刻度上
this.FixedYMaxMin; //{ Max, Min} 固定Y轴最大最小值
this.EnableZoomUpDown=false;
this.IsBeforeData=false;
this.BeforeOpenData;
this.IsAfterData=false;
this.AfterCloseData;
this.ShareAfterVol=0;
this.MultiDayBeforeOpenData;
this.MultiDayAfterCloseData;
this.OverlayIdentify;
this.HQChart;
this.OverlayIndex; //叠加指标信息
this.IsEnableDragY=function()
{
return true;
}
this.Reset=function() //重置
{
this.EnableRemoveZero=g_JSChartResource.Frame.EnableRemoveZero;
this.StringFormat=g_JSChartResource.Frame.StringFormat;
}
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsNumber(option.FloatPrecision)) this.FloatPrecision=option.FloatPrecision;
if (IFrameSplitOperator.IsNumber(option.StringFormat)) this.StringFormat=option.StringFormat;
if (IFrameSplitOperator.IsBool(option.EnableRemoveZero)) this.EnableRemoveZero=option.EnableRemoveZero;
}
this.GetFloatPrecision=function(value,floatPrecision)
{
if (value>this.FLOATPRECISION_RANGE[0]) return floatPrecision;
if (floatPrecision<0) return 2;
for(;floatPrecision<this.FLOATPRECISION_RANGE.length;++floatPrecision)
{
if (value>this.FLOATPRECISION_RANGE[floatPrecision]) break;
}
return floatPrecision;
}
this.Operator=function()
{
var splitData={};
splitData.Max=this.Frame.HorizontalMax;
splitData.Min=this.Frame.HorizontalMin;
if (this.Frame.YMaxMin) //原始的数据范围
{
var item=this.Frame.YMaxMin;
if (IFrameSplitOperator.IsNumber(item.Max) && IFrameSplitOperator.IsNumber(item.Min))
{
splitData.Max=item.Max;
splitData.Min=item.Min;
}
}
if (splitData.Max==splitData.Min) //如果一样上下扩大下
{
if (splitData.Max==0)
{
splitData.Max=1;
splitData.Min=-1;
}
else
{
splitData.Max+=splitData.Max*0.01;
splitData.Min-=splitData.Min*0.01;
}
}
var isFixedMaxMin=false;
if (this.FixedYMaxMin && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Max) && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Min)) isFixedMaxMin=true;
if (isFixedMaxMin)
{
splitData.Max=this.FixedYMaxMin.Max;
splitData.Min=this.FixedYMaxMin.Min;
}
else if (this.DefaultYMaxMin) //指定最小的Y轴范围
{
var range=this.DefaultYMaxMin;
if (IFrameSplitOperator.IsNumber(range.Max))
{
if (splitData.Min>range.Max) splitData.Min=range.Max;
else if (splitData.Max<range.Max) splitData.Max=range.Max;
}
if (IFrameSplitOperator.IsNumber(range.Min))
{
if (splitData.Max<range.Min) splitData.Max=range.Min;
else if (splitData.Min>range.Min) splitData.Min=range.Min;
}
}
if(this.Frame.YSpecificMaxMin)
{
splitData.Count=this.Frame.YSpecificMaxMin.Count;
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
}
else if (this.SplitType==1 || isFixedMaxMin)
{
splitData.Count=this.SplitCount;
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
}
else if (this.SplitType==2)
{
splitData.Max=100;
splitData.Min=0;
splitData.Count=this.SplitCount;
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
}
else
{
splitData.Count=this.SplitCount;
splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
this.IntegerCoordinateSplit(splitData);
}
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
this.Frame.HorizontalInfo=[];
if (this.Frame.YSplitScale) //固定坐标
{
for(var i in this.Frame.YSplitScale)
{
var value=this.Frame.YSplitScale[i];
var coordinate=new CoordinateInfo();
coordinate.Value=value;
if (IFrameSplitOperator.IsNumber(this.LineType)) coordinate.LineType=this.LineType;
var absValue=Math.abs(value);
if (absValue<0.0000000001)
{
coordinate.Message[1]=0;
}
else if (absValue<this.FLOATPRECISION_RANGE[this.FLOATPRECISION_RANGE.length-1])
{
coordinate.Message[1] = value.toExponential(2).toString();
}
else
{
var floatPrecision=this.GetFloatPrecision(absValue,this.FloatPrecision); //数据比小数位数还小, 调整小数位数
coordinate.Message[1] = IFrameSplitOperator.FormatValueString(value, floatPrecision,this.LanguageID);
}
coordinate.Message[0]=coordinate.Message[1];
if (this.IsShowLeftText==false) this.Frame.HorizontalInfo[i].Message[0]=null;
if (this.IsShowRightText==false) this.Frame.HorizontalInfo[i].Message[1]=null;
this.Frame.HorizontalInfo.push(coordinate);
}
}
else
{
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
var coordinate=new CoordinateInfo();
this.Frame.HorizontalInfo[i]= coordinate;
coordinate.Value=value;
if (IFrameSplitOperator.IsNumber(this.LineType)) coordinate.LineType=this.LineType;
var text=this.FormatValueString(value);
this.Frame.HorizontalInfo[i].Message[0]=this.Frame.HorizontalInfo[i].Message[1]=text;
if (this.IsShowLeftText==false) this.Frame.HorizontalInfo[i].Message[0]=null;
if (this.IsShowRightText==false) this.Frame.HorizontalInfo[i].Message[1]=null;
//this.Frame.HorizontalInfo[i].Font="14px 微软雅黑";
//this.Frame.HorizontalInfo[i].TextColor="rgb(100,0,200)";
//this.Frame.HorizontalInfo[i].LineColor="rgb(220,220,220)";
}
}
this.FilterIgnoreYValue();
this.CustomCoordinate();
if (this.SplitType!=1)
this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,(splitData.Max>0 && splitData.Min<0), this.FilterType);
this.RightFrameSplitY();
this.MainOverlayFrameSplitY(); //主图Y轴绑定叠加Y轴坐标
this.CallAcutionSplitY(this.SplitCount,splitData);
if (this.EnableRemoveZero) this.RemoveZero(this.Frame.HorizontalInfo);
this.DynamicMessageText();
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
if (this.EnableZoomUpDown==true && !this.FixedYMaxMin)
this.FixedYMaxMin={ Max:splitData.Max, Min:splitData.Min };
this.ReservedHeight(splitData); //预留高度
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
if (this.OverlayIdentify) data.OverlayIdentify=this.OverlayIdentify;
event.Callback(event,data,this);
}
}
}
this.FormatValueString=function(value)
{
var text;
if (this.StringFormat==1) //手机端格式 如果有万,亿单位了 去掉小数
{
var floatPrecision=this.FloatPrecision;
if (IFrameSplitOperator.IsNumber(value) && Math.abs(value) > 1000) floatPrecision=0;
text=IFrameSplitOperator.FormatValueString(value,floatPrecision,this.LanguageID);
}
else if (this.StringFormat==2) //原始数据输出
{
text=`${value.toFixed(this.FloatPrecision)}`;
}
else
{
var absValue=Math.abs(value);
if (absValue<0.0000000001)
{
text=0;
}
else if (absValue<this.FLOATPRECISION_RANGE[this.FLOATPRECISION_RANGE.length-1])
{
text = value.toExponential(2).toString();
}
else
{
var floatPrecision=this.GetFloatPrecision(absValue,this.FloatPrecision); //数据比小数位数还小, 调整小数位数
text = IFrameSplitOperator.FormatValueString(value, floatPrecision,this.LanguageID);
}
}
return text;
}
this.FilterIgnoreYValue = function ()
{
if (!this.IgnoreYValue || this.IgnoreYValue.length <= 0) return;
var setValue = new Set(this.IgnoreYValue);
this.Frame.HorizontalInfo = this.Frame.HorizontalInfo.filter(item => !setValue.has(item.Value));
}
this.DynamicMessageText=function()
{
if (this.SplitType==2)
{
for(var i=0;i<this.Frame.HorizontalInfo.length; ++i)
{
var item=this.Frame.HorizontalInfo[i];
if (item.Message[0]) item.Message[0]+='%';
if (item.Message[1]) item.Message[1]+='%';
}
}
}
this.CallAcutionSplitY=function(count,splitData)
{
if (this.Frame.Identify!=1) return null;
var aryCallAcution=this.GetCallAcutionSplitY(count,splitData);
if (!aryCallAcution) return;
for(var i=0; i<this.Frame.HorizontalInfo.length; ++i) //把显示的数据迁移到 Message[2] Message[3]
{
var item=this.Frame.HorizontalInfo[i];
if (aryCallAcution.IsBeforeData)
{
item.Message[2]=item.Message[0];
item.Message[0]=null;
}
if (aryCallAcution.IsAfterData && (this.ShareAfterVol==0 || this.ShareAfterVol==2) )
{
item.Message[3]=item.Message[1];
item.Message[1]=null;
}
}
//集合竞价的坐标插入最后
for(var i=0; i<aryCallAcution.HorizontalInfo.length; ++i)
{
var item=aryCallAcution.HorizontalInfo[i];
this.Frame.HorizontalInfo.push(item);
}
}
this.GetCallAcutionSplitY=function(count,splitData)
{
if (this.Frame.Identify!=1) return null;
var isBeforeData=(this.IsBeforeData==true && this.BeforeOpenData && (this.BeforeOpenData.Ver==2.0 || this.BeforeOpenData.Ver==3.0));
var isAfterData=(this.IsAfterData==true && this.AfterCloseData && (this.AfterCloseData.Ver==2.0 || this.AfterCloseData.Ver==3.0));
if (isBeforeData || isAfterData)
{
var intervalY=(splitData.Max-splitData.Min)/(count-1);
if (isBeforeData) var intervalLeft=(this.BeforeOpenData.VolMax-this.BeforeOpenData.VolMin)/(count-1);
if (isAfterData) var intervalRight=(this.AfterCloseData.VolMax-this.AfterCloseData.VolMin)/(count-1);
var aryHorizontalInfo=[];
for(var i=0;i<count;++i)
{
var item=new CoordinateInfo();
var yValue=intervalY*i;
item.Value=yValue;
item.LineType=8;
if (isBeforeData )
{
var leftValue=intervalLeft*i;
item.Message[0]=this.FormatValueString(leftValue);
}
if (isAfterData && (this.ShareAfterVol==0 || this.ShareAfterVol==2) )
{
var rightValue=intervalRight*i;
item.Message[1]=this.FormatValueString(rightValue);
}
aryHorizontalInfo.push(item);
}
return { HorizontalInfo:aryHorizontalInfo, IsBeforeData:isBeforeData, IsAfterData:isAfterData };
}
var isMultiDayBeforeData=false;
var intervalLeft=null;
if (this.MultiDayBeforeOpenData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
{
isMultiDayBeforeData=true;
var firstDayData=this.MultiDayBeforeOpenData[0];
if (firstDayData.Ver==2.0 || firstDayData.Ver==3.0)
{
var intervalLeft=(firstDayData.VolMax-firstDayData.VolMin)/(count-1);
}
}
var isMultiDayAfterData=false;
var intervalRight=null;
if (this.MultiDayAfterCloseData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
{
isMultiDayAfterData=true;
var firstDayData=this.MultiDayAfterCloseData[0];
if (firstDayData.Ver==2.0 || firstDayData.Ver==3.0)
{
var intervalRight=(firstDayData.VolMax-firstDayData.VolMin)/(count-1);
}
}
if (isMultiDayBeforeData || isMultiDayAfterData)
{
var intervalY=(splitData.Max-splitData.Min)/(count-1);
var aryHorizontalInfo=[];
for(var i=0;i<count;++i)
{
var item=new CoordinateInfo();
var yValue=intervalY*i;
item.Value=yValue;
item.LineType=9;
var isVaild=false;
if (intervalLeft!=null)
{
var leftValue=intervalLeft*i;
item.Message[0]=this.FormatValueString(leftValue);
isVaild=true;
}
if (intervalRight!=null && (this.ShareAfterVol==0 || this.ShareAfterVol==2))
{
var rightValue=intervalRight*i;
item.Message[1]=this.FormatValueString(rightValue);
isVaild=true;
}
if (isVaild) aryHorizontalInfo.push(item);
}
if (IFrameSplitOperator.IsNonEmptyArray(aryHorizontalInfo))
return { HorizontalInfo:aryHorizontalInfo, IsBeforeData:isMultiDayBeforeData, IsAfterData:isMultiDayAfterData };
}
return null;
}
this.RightFrameSplitY=function()
{
if (!this.Frame.RightFrame) return;
var rightFrame=this.Frame.RightFrame;
if (rightFrame.YSplitOperator) rightFrame.YSplitOperator.Operator();
for(var i=0;i<this.Frame.HorizontalInfo.length;++i)
{
var item=this.Frame.HorizontalInfo[i];
var y=this.Frame.GetYFromData(item.Value);
var yValue=rightFrame.GetYData(y);
item.Message[1] = IFrameSplitOperator.FormatValueString(yValue, this.FloatPrecision,this.LanguageID);
}
}
this.MainOverlayFrameSplitY=function()
{
if (!this.Frame.GetMainOverlayFrame) return;
var aryOverlayFrame=this.Frame.GetMainOverlayFrame();
if (!aryOverlayFrame ) return;
if (aryOverlayFrame[1])
{
var rightFrame=aryOverlayFrame[1];
var ySplitOper=rightFrame.YSplitOperator;
if (ySplitOper) ySplitOper.Operator();
for(var i=0;i<this.Frame.HorizontalInfo.length;++i)
{
var item=this.Frame.HorizontalInfo[i];
var y=this.Frame.GetYFromData(item.Value);
var yValue=rightFrame.GetYData(y);
if (ySplitOper && ySplitOper.FormatValueString) item.Message[1] = ySplitOper.FormatValueString(yValue);
else item.Message[1] = this.FormatValueString(yValue);
}
}
if (aryOverlayFrame[0])
{
var leftFrame=aryOverlayFrame[0];
var ySplitOper=leftFrame.YSplitOperator
if (ySplitOper) ySplitOper.Operator();
for(var i=0;i<this.Frame.HorizontalInfo.length;++i)
{
var item=this.Frame.HorizontalInfo[i];
var y=this.Frame.GetYFromData(item.Value);
var yValue=leftFrame.GetYData(y);
if (ySplitOper && ySplitOper.FormatValueString) item.Message[0] = ySplitOper.FormatValueString(yValue);
else item.Message[0] = this.FormatValueString(yValue);
}
}
}
this.CustomCoordinate=function()
{
this.Frame.CustomHorizontalInfo=[];
var data=this.InvokeCustomYCoordinateCallback();
if (data && data.PreventDefault==true) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Custom)) return;
for(var i=0; i<this.Custom.length; ++i)
{
var item=this.Custom[i];
if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_LAST_INDEX_VALUE_ID) //当前屏最后一个数据
{
this.CustomLatestIndexDataCoordinate(item);
}
else if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.FIXED_VALUE_ID) //自定义刻度
{
this.CustomFixedCoordinate(item);
}
else if (item.Type==JSCHART_CUSTOM_YCOORDINATE_ID.PAGE_LAST_OVERLAY_INDEX_VALUE_ID) //叠加指标当前屏最后一个数据
{
this.CustomLatestOverlayIndexDataCoordinate(item);
}
}
}
this.CustomFixedCoordinate=function(option) //固定坐标刻度
{
if (!IFrameSplitOperator.IsNonEmptyArray(option.Data)) return;
var defaultfloatPrecision=2;
for(var i=0;i<option.Data.length; ++i)
{
var item=option.Data[i];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=item.TextColor;
info.LineColor=item.Color;
info.LineType=2; //虚线
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
if (option.IsShowLine==false) info.LineType=-1;
info.Value=item.Value;
var text;
if (item.Text) text=item.Text;
else text=info.Value.toFixed(defaultfloatPrecision);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
this.Frame.CustomHorizontalInfo.push(info);
}
}
}
function FrameSplitKLineX()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.Period; //周期
this.Symbol; //股票代码
this.MinTextDistance=50*GetDevicePixelRatio();
this.MinBarDistance=5; //刻度间最小的K线间距
this.SplitDateTime=function() //根据时间分割
{
this.Frame.VerticalInfo=[];
var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth;
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var lastYear=null, lastMonth=null;
var textDistance=0;
var barDistance=0;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length; ++i,++index)
{
textDistance+=itemWidth;
++barDistance;
var infoData=null;
if (i==0)
{
var date=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
infoData={Value:index-xOffset, Text:date};
}
else if (textDistance>this.MinTextDistance && barDistance>=this.MinBarDistance)
{
var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time);
infoData={Value:index-xOffset, Text:time};
}
if (infoData)
{
var info= new CoordinateInfo();
info.Value=infoData.Value;
if (this.ShowText) info.Message[0]=infoData.Text;
if (info.Value==0) info.LineType=-1; //第1个分割线不画
this.Frame.VerticalInfo.push(info);
textDistance=0;
barDistance=0;
if (i==0) textDistance=-(this.MinTextDistance/2);
}
}
}
this.SplitSecond=function() //根据时间分割
{
this.Frame.VerticalInfo=[];
var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth;
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var textDistance=0;
var barDistance=0;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length; ++i,++index)
{
textDistance+=itemWidth;
++barDistance;
var infoData=null;
if (i==0)
{
var date=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
infoData={Value:index-xOffset, Text:date};
}
else if (textDistance>this.MinTextDistance && barDistance>=this.MinBarDistance)
{
var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time,"HH:MM:SS");
infoData={Value:index-xOffset, Text:time};
}
if (infoData)
{
var info= new CoordinateInfo();
info.Value=infoData.Value;
if (this.ShowText) info.Message[0]=infoData.Text;
this.Frame.VerticalInfo.push(info);
textDistance=0;
barDistance=0;
if (i==0) textDistance=-(this.MinTextDistance/2);
}
}
}
this.SplitMilliSecond=function()
{
this.Frame.VerticalInfo=[];
var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth;
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var textDistance=0;
var barDistance=0;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length; ++i,++index)
{
textDistance+=itemWidth;
++barDistance;
var infoData=null;
if (i==0)
{
var date=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'HH:MM:SS.fff');
infoData={Value:index-xOffset, Text:date};
}
else if (textDistance>this.MinTextDistance && barDistance>=this.MinBarDistance)
{
var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time,"HH:MM:SS.fff");
infoData={Value:index-xOffset, Text:time};
}
if (infoData)
{
var info= new CoordinateInfo();
info.Value=infoData.Value;
if (this.ShowText) info.Message[0]=infoData.Text;
this.Frame.VerticalInfo.push(info);
textDistance=0;
barDistance=0;
if (i==0) textDistance=-(this.MinTextDistance/2);
}
}
}
this.SplitDate=function() //根据日期分割
{
this.Frame.VerticalInfo=[];
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var lastYear=null, lastMonth=null;
var minDistance=12;
var monthCount=0;
for(var i=0, index=xOffset, distance=minDistance;i<xPointCount && index<this.Frame.Data.Data.length ;++i,++index)
{
var year=parseInt(this.Frame.Data.Data[index].Date/10000);
var month=parseInt(this.Frame.Data.Data[index].Date/100)%100;
if (lastMonth!=month)
++monthCount;
if (distance<minDistance ||
(lastYear!=null && lastYear==year && lastMonth!=null && lastMonth==month))
{
lastMonth=month;
++distance;
continue;
}
var info= new CoordinateInfo();
info.Value=index-xOffset;
var text;
if (lastYear==null || lastYear!=year)
{
text=year.toString();
}
else if (lastMonth==null || lastMonth!=month)
{
text=month.toString()+'月';
text=g_JSChartLocalization.GetText(text, this.LanguageID);
}
lastYear=year;
lastMonth=month;
if (this.ShowText) info.Message[0]=text;
if (info.Value==0) info.LineType=-1; //第1个分割线不画
this.Frame.VerticalInfo.push(info);
distance=0;
}
if (this.Period==0 && monthCount<=2)
this.SplitShortDate();
}
//分隔在2个月一下的格式
this.SplitShortDate=function()
{
this.Frame.VerticalInfo=[];
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var minDistance=12;
var isFirstYear=true;
for(var i=0, index=xOffset, distance=minDistance;i<xPointCount && index<this.Frame.Data.Data.length ;++i,++index)
{
var year=parseInt(this.Frame.Data.Data[index].Date/10000);
//var month=parseInt(this.Frame.Data.Data[index].Date/100)%100;
//var day=parseInt(this.Frame.Data.Data[index].Date%100);
if (distance<minDistance)
{
++distance;
continue;
}
var info= new CoordinateInfo();
info.Value=index-xOffset;
var text;
if (isFirstYear)
{
text=year.toString();
isFirstYear=false;
}
else
{
text=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
}
if (this.ShowText) info.Message[0]=text;
if (info.Value==0) info.LineType=-1; //第1个分割线不画
this.Frame.VerticalInfo.push(info);
distance=0;
}
if (this.Frame.VerticalInfo.length==1) //只有1个刻度, 就显示年+月
{
var item=this.Frame.VerticalInfo[0];
var index=item.Value+xOffset;
var kitem=this.Frame.Data.Data[index];
var text=IFrameSplitOperator.FormatDateString(kitem.Date,'YYYY-MM');
if (this.ShowText) item.Message[0]=text;
}
}
this.Operator=function()
{
if (this.Frame.Data==null) return;
if (FrameSplitKLineX.SplitCustom) FrameSplitKLineX.SplitCustom(this); //自定义分割
else if (ChartData.IsMinutePeriod(this.Period, true)) this.SplitDateTime();
else if (ChartData.IsSecondPeriod(this.Period)) this.SplitSecond();
else if (ChartData.IsTickPeriod(this.Period)) this.SplitSecond();
else if (ChartData.IsMilliSecondPeriod(this.Period)) this.SplitMilliSecond();
else this.SplitDate();
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_XCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
event.Callback(event,data,this);
}
}
}
this.CreateCoordinateInfo=function()
{
return new CoordinateInfo();
}
}
//FrameSplitKLineX.SplitCustom=function(split) { }
function FrameSplitMinutePriceY()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.High=null; //最高最低价
this.Low=null;
this.YClose; //昨收
this.Data; //分钟数据
this.SourceData; //原始数据
this.OverlayChartPaint;
this.SplitCount=7;
this.Symbol;
this.SplitType=0; //0=默认根据最大最小值分割 1=涨跌停分割 2=数据最大最大值分割
this.DefaultSplitType=0;
this.LimitPrice; //{Max: Min:} 涨跌停价
this.Custom;
this.RightTextFormat=0; //右边刻度显示模式 0=百分比 1=价格
this.BeforeOpenData;
this.IsBeforeData=false;
this.AfterCloseData;
this.IsAfterData=false;
this.MultiDayBeforeOpenData;
this.MultiDayAfterCloseData;
this.DayOffset;
this.AverageData; //均线
this.DayCount=1;
this.GlobalOption;
this.HQChart;
this.IsEnableDragY=function()
{
return false;
}
this.Operator=function()
{
this.Frame.HorizontalInfo=[];
this.Frame.CustomHorizontalInfo=[];
if (!this.Data) return;
var range=this.GetMaxMin();
if (this.Symbol && MARKET_SUFFIX_NAME.IsUSA(this.Symbol.toUpperCase()))
{
this.USASplit(range);
}
else if (this.SplitType==2)
{
this.USASplit(range);
}
else
{
this.DefaultSplit(range);
}
this.CustomCoordinate();
this.ReservedHeight({ Max:this.Frame.HorizontalMax, Min:this.Frame.HorizontalMin }); //预留高度
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
event.Callback(event,data,this);
}
}
}
this.CustomCoordinate=function() //自定义刻度
{
this.Frame.CustomHorizontalInfo=[];
var data=this.InvokeCustomYCoordinateCallback();
if (data && data.PreventDefault==true) return;
if (!this.Custom) return;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
for(var i in this.Custom)
{
var item=this.Custom[i];
if (item.Type==1) this.CustomFixedCoordinate(item);
else if (item.Type==0)
{
var latestItem=this.GetLatestPrice(defaultfloatPrecision,item);
if (latestItem) this.Frame.CustomHorizontalInfo.push(latestItem);
}
}
}
this.GetLatestPrice=function(floatPrecision,option)
{
if (!this.Data || !this.Data.Data) return null;
if (this.Data.Data.length<=0) return null;
var price=this.Data.Data[this.Data.Data.length-1];
if (!IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(this.YClose)) return null;
var info=new CoordinateInfo();
info.Type=0;
info.Value=price;
info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
info.LineType=2; //虚线
var strPrice=price.toFixed(floatPrecision);
if (option.DateTime=='HH:MM')
{
var latestItem=this.Frame.Data.Data[this.Frame.Data.Data.length-1];
var strTime=IFrameSplitOperator.FormatTimeString(latestItem.Time,option.DateTime);
var aryText=[{Text:strPrice}, { Text:strTime} ];
if (option.Position=='left') info.Message[0]=aryText;
else info.Message[1]=aryText;
}
else
{
if (option.Position=='left') info.Message[0]=strPrice;
else info.Message[1]=strPrice;
}
if (price>this.YClose) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
else if (price<this.YClose) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
if (IFrameSplitOperator.IsPlusNumber(option.LineWidth)) info.LineWidth=option.LineWidth;
if (option.LineDash) info.LineDash=option.LineDash;
if (option.IsShowLine==false) info.LineType=-1;
if (option.PositionEx===1) info.ExtendData={ Custom:{ Position:1 } }; //强制画在内部
return info;
}
this.CustomFixedCoordinate=function(option) //固定坐标刻度
{
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
for(var i=0; i<option.Data.length; ++i)
{
var item=option.Data[i];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=item.TextColor;
info.LineColor=item.Color;
info.LineType=2; //虚线
if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
if (IFrameSplitOperator.IsPlusNumber(option.LineWidth)) info.LineWidth=option.LineWidth;
if (option.LineDash) info.LineDash=option.LineDash;
if (option.IsShowLine==false) info.LineType=-1;
if (option.PositionEx===1) info.ExtendData={ Custom:{ Position:1 } }; //强制画在内部
if (IFrameSplitOperator.IsNumber(item.Increase)) //涨幅计算价格
{
if (!IFrameSplitOperator.IsNumber(this.YClose)) continue;
info.Value=this.YClose*(1+item.Increase);
}
else
{
info.Value=item.Value;
}
var text;
if (item.Text) text=item.Text;
else text=info.Value.toFixed(defaultfloatPrecision);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
this.Frame.CustomHorizontalInfo.push(info);
}
}
this.GetCallAuctionMaxMin=function(callAuctionData, range)
{
for(var i in callAuctionData.Data)
{
var item=callAuctionData.Data[i];
if (!item) continue;
if (IFrameSplitOperator.IsNumber(item.Price))
{
if (range.Max==null) range.Max=item.Price;
if (range.Min==null) range.Min=item.Price;
if (range.Max<item.Price) range.Max=item.Price;
if (range.Min>item.Price) range.Min=item.Price;
}
//集合竞价均线统计
if (callAuctionData.Ver==3.0 && IFrameSplitOperator.IsNumber(item.AvPrice))
{
if (range.Max==null) range.Max=item.AvPrice;
if (range.Min==null) range.Min=item.AvPrice;
if (range.Max<item.AvPrice) range.Max=item.AvPrice;
if (range.Min>item.AvPrice) range.Min=item.AvPrice;
}
}
}
//多日分时图 集合竞价数据
this.GetMultiDayBeforeOpenData=function()
{
if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData)) return null;
if (!this.DayOffset) return this.MultiDayBeforeOpenData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
if (this.GlobalOption && this.GlobalOption.IsValueFullRange===true) return this.MultiDayBeforeOpenData;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayBeforeOpenData.slice(offset, offset+showCount);
return aryData;
}
this.GetMultiDayAfterCloseData=function()
{
if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData)) return null;
if (!this.DayOffset) return this.MultiDayAfterCloseData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
if (this.GlobalOption && this.GlobalOption.IsValueFullRange===true) return this.MultiDayAfterCloseData;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayAfterCloseData.slice(offset, offset+showCount);
return aryData;
}
this.GetMaxMin=function() //计算图中所有的数据的最大最小值
{
var max=this.YClose;
var min=this.YClose;
var data=this.Data;
var isBerforeData=false;
if (this.SourceData)
{
data=this.SourceData;
isBerforeData=true;
}
if (this.DayCount>1) //多日
{
var offset=this.DayOffset.DataOffset;
var showDataCount=this.DayOffset.ShowDataCount;
if (this.GlobalOption && this.GlobalOption.IsValueFullRange===true)
{
offset=0;
showDataCount=data.Data.length;
}
for(var i=offset, j=0; i<data.Data.length && j<showDataCount ;++i,++j)
{
var value=null;
if (isBerforeData)
{
var item=data.Data[i];
if (item.Before) value=item.Before.Close;
else value=item.Close;
}
else
{
value=data.Data[i];
}
if (value==null) continue;
if (max<value) max=value;
if (min>value) min=value;
}
if (this.AverageData)
{
for(var i=offset,j=0; i<this.AverageData.Data.length && j<showDataCount; ++i,++j)
{
if (this.AverageData.Data[i]==null) continue;
if (max<this.AverageData.Data[i]) max=this.AverageData.Data[i];
if (min>this.AverageData.Data[i]) min=this.AverageData.Data[i];
}
}
}
else
{
for(var i=0;i<data.Data.length;++i)
{
var value=null;
if (isBerforeData)
{
var item=data.Data[i];
if (item.Before) value=item.Before.Close;
else value=item.Close;
}
else
{
value=data.Data[i];
}
if (value==null) continue;
if (max<value) max=value;
if (min>value) min=value;
}
if (this.AverageData)
{
for(var i=0;i<this.AverageData.Data.length;++i)
{
if (this.AverageData.Data[i]==null) continue;
if (max<this.AverageData.Data[i]) max=this.AverageData.Data[i];
if (min>this.AverageData.Data[i]) min=this.AverageData.Data[i];
}
}
}
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
//if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue;
var range=item.GetMaxMin();
if (range.Max && range.Max>max) max=range.Max;
if (range.Min && range.Min<min) min=range.Min;
}
if (this.SplitType==1 && this.LimitPrice)
{
if (max<this.LimitPrice.Max) max=this.LimitPrice.Max;
if (min>this.LimitPrice.Min) min=this.LimitPrice.Min;
}
if (IFrameSplitOperator.IsNumber(this.High) && IFrameSplitOperator.IsNumber(this.Low))
{
if (max<this.High) max=this.High;
if (min>this.Low) min=this.Low;
}
var range={ Max:null, Min:null };
if (this.IsAfterData && this.AfterCloseData)
{
this.GetCallAuctionMaxMin(this.AfterCloseData,range);
}
if (this.IsBeforeData && this.BeforeOpenData)
{
this.GetCallAuctionMaxMin(this.BeforeOpenData,range);
}
var multiDayBeforeOpenData=this.GetMultiDayBeforeOpenData();
if (multiDayBeforeOpenData && this.ChartBorder.MultiDayMinute.Count>1 && this.ChartBorder.MultiDayMinute.Left>0)
{
for(var i=0;i<multiDayBeforeOpenData.length; ++i)
{
var dayItem=multiDayBeforeOpenData[i];
this.GetCallAuctionMaxMin(dayItem,range);
}
}
var multiDayAfterCloseData=this.GetMultiDayAfterCloseData();
if (multiDayAfterCloseData && this.ChartBorder.MultiDayMinute.Count>1 && this.ChartBorder.MultiDayMinute.Right>0)
{
for(var i=0;i<multiDayAfterCloseData.length; ++i)
{
var dayItem=multiDayAfterCloseData[i];
this.GetCallAuctionMaxMin(dayItem,range);
}
}
if (IFrameSplitOperator.IsNumber(range.Max) && max<range.Max) max=range.Max;
if (IFrameSplitOperator.IsNumber(range.Min) && min>range.Min) min=range.Min;
//叠加指标
var overlayRange=this.GetOverlayMaxMin();
if (overlayRange)
{
if (IFrameSplitOperator.IsNumber(overlayRange.Max) && overlayRange.Max>max) max=overlayRange.Max;
if (IFrameSplitOperator.IsNumber(overlayRange.Min) && overlayRange.Min<min) min=overlayRange.Min;
}
return { Max:max, Min:min };
}
//获取共享Y轴叠加指标最大,最小值
this.GetOverlayMaxMin=function()
{
if (!this.HQChart) return null;
if (!this.HQChart.Frame || !this.HQChart.Frame.SubFrame) return null;
var subFrame=this.HQChart.Frame.SubFrame[0];
if (!subFrame) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(subFrame.OverlayIndex)) return null;
var range={ Max:null, Min:null };
for(var i=0;i<subFrame.OverlayIndex.length;++i)
{
var item=subFrame.OverlayIndex[i];
if (!item || !item.Frame) continue;
var overlayFrame=item.Frame;
if (overlayFrame.IsShareY!=true) continue;
if (overlayFrame.IsCalculateYMaxMin===false) continue; //叠加坐标Y轴不调整
for(var j=0;j<item.ChartPaint.length; ++j)
{
var paint=item.ChartPaint[j];
if (paint.IsShow==false) continue;
var value=paint.GetMaxMin();
if (value==null || value.Max==null || value.Min==null) continue;
if (range.Max==null || range.Max<value.Max) range.Max=value.Max;
if (range.Min==null || range.Min>value.Min ) range.Min=value.Min;
}
}
return range;
}
this.USASplit=function(range)
{
var max=range.Max;
var min=range.Min;
if (max==min)
{
max=max+max*0.1;
min=min-min*0.1;
}
else
{
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var height=this.Frame.ChartBorder.GetHeight(); //画布的高度
var spacePrice=5*pixelTatio*(max-min)/height;
max+=spacePrice;
min-=spacePrice;
if (min<0) min=range.Min;
}
var showCount=this.SplitCount;
var distance=(max-min)/(showCount-1);
const minDistance=[1, 0.1, 0.01, 0.001, 0.0001];
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
if (distance<minDistance[defaultfloatPrecision])
{
distance=minDistance[defaultfloatPrecision];
max=min+distance*showCount;
//min=this.YClose-(distance*(showCount-1)/2);
}
for(var i=0;i<showCount;++i)
{
var price=min+(distance*i);
if (this.YClose && price==this.YClose) continue;
var coordinate=new CoordinateInfo();
coordinate.Value=price;
var strPrice=price.toFixed(defaultfloatPrecision); //价格刻度字符串
if (this.IsShowLeftText) coordinate.Message[0]=strPrice;
if (this.YClose && this.YClose!=0)
{
var per=(price/this.YClose-1)*100;
if (per>0) coordinate.TextColor=g_JSChartResource.UpTextColor;
else if (per<0) coordinate.TextColor=g_JSChartResource.DownTextColor;
if (this.IsShowRightText)
{
if (this.RightTextFormat==1) coordinate.Message[1]=strPrice;
else coordinate.Message[1]=IFrameSplitOperator.FormatValueString(per,2)+'%'; //百分比
}
}
this.Frame.HorizontalInfo.push(coordinate);
}
if (this.YClose>min && this.YClose<max) //前收盘线
{
var coordinate=new CoordinateInfo();
coordinate.Value=this.YClose;
coordinate.LineType=2;//中间的线画虚线
if (g_JSChartResource.FrameDotSplitPen) coordinate.LineColor=g_JSChartResource.FrameDotSplitPen;
var strPrice=this.YClose.toFixed(defaultfloatPrecision); //价格刻度字符串
if (this.IsShowLeftText) coordinate.Message[0]=strPrice;
if (this.IsShowRightText)
{
if (this.RightTextFormat==1) coordinate.Message[1]=strPrice;
else coordinate.Message[1]='0.00%'; //百分比
}
this.Frame.HorizontalInfo.push(coordinate);
}
this.Frame.HorizontalInfo.sort(function(a,b) { return a.Value-b.Value; });
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
this.DefaultSplit=function(range)
{
var max=range.Max;
var min=range.Min;
if (this.YClose==max && this.YClose==min)
{
max=this.YClose+this.YClose*0.1;
min=this.YClose-this.YClose*0.1
}
else
{
var distanceValue=Math.max(Math.abs(this.YClose-max),Math.abs(this.YClose-min));
max=this.YClose+distanceValue;
min=this.YClose-distanceValue;
if (min<0) min=range.Min;
}
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度
var isPhoneModel=width<450*pixelTatio;
JSConsole.Chart.Log('[FrameSplitMinutePriceY]'+ 'max='+ max + ' min='+ min +' isPhoneModel='+isPhoneModel);
var showCount=this.SplitCount;
var distance=(max-min)/(showCount-1);
const minDistance=[1, 0.1, 0.01, 0.001, 0.0001];
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
if (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) defaultfloatPrecision = 0; //手机端指数不显示小数位数,太长了
if (distance<minDistance[defaultfloatPrecision])
{
distance=minDistance[defaultfloatPrecision];
max=this.YClose+(distance*(showCount-1)/2);
min=this.YClose-(distance*(showCount-1)/2);
}
for(var i=0;i<showCount;++i)
{
var price=min+(distance*i);
var coordinate=new CoordinateInfo();
this.Frame.HorizontalInfo[i]=coordinate
coordinate.Value=price;
var strPrice=price.toFixed(defaultfloatPrecision); //价格刻度字符串
if (this.IsShowLeftText) coordinate.Message[0]=strPrice
if (IFrameSplitOperator.IsNumber(this.YClose) && this.YClose!=0)
{
var per=(price/this.YClose-1)*100;
if (per>0) coordinate.TextColor=g_JSChartResource.UpTextColor;
else if (per<0) coordinate.TextColor=g_JSChartResource.DownTextColor;
if (this.IsShowRightText)
{
if (this.RightTextFormat==1) coordinate.Message[1]=strPrice;
else coordinate.Message[1]=IFrameSplitOperator.FormatValueString(per,2)+'%'; //百分比
}
if (Math.abs(price-this.YClose) <0.00000000001) //小数有精度问题 使用差值
{
coordinate.LineType=2;//中间的线画虚线
coordinate.TextColor=g_JSChartResource.UnchagneTextColor;
if (g_JSChartResource.FrameDotSplitPen) coordinate.LineColor=g_JSChartResource.FrameDotSplitPen;
}
}
}
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
}
function FrameSplitMinuteX()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.Symbol=null; //股票代码 x轴刻度根据股票类型来调整
this.DayCount=1;
this.DateFormat=0; //0=MM-DD 1=MM/DD 2=MM/DD/Week
this.Operator=function()
{
this.Frame.VerticalInfo=[];
var xPointCount=this.Frame.XPointCount;
var width = this.Frame.ChartBorder.GetWidth();
var isHScreen=(this.Frame.IsHScreen===true);
if (isHScreen) width = this.Frame.ChartBorder.GetHeight();
width=width/GetDevicePixelRatio();
const minuteCoordinate = g_MinuteCoordinateData;
var xcoordinateData = minuteCoordinate.GetCoordinateData(this.Symbol,width);
var minuteCount=xcoordinateData.Count;
var minuteMiddleCount=xcoordinateData.MiddleCount>0? xcoordinateData.MiddleCount: parseInt(minuteCount/2);
var xcoordinate = xcoordinateData.Data;
this.Frame.XPointCount=minuteCount*this.DayCount; //计算一共显示的数据个数
this.Frame.MinuteCount=minuteCount;
this.Frame.VerticalInfo=[];
if (this.Frame.GlobalOption)
{
var item=this.Frame.GlobalOption;
if (IFrameSplitOperator.IsNumber(item.XDateFormat)) this.DateFormat=item.XDateFormat;
}
if (this.DayCount<=1)
{
//设置成1日的数据
this.DayOffset.DataOffset=0;
this.DayOffset.ShowDataCount=minuteCount;
this.DayOffset.PageInfo=null;
for(var i=0; i<xcoordinate.length; ++i)
{
var info=new CoordinateInfo();
var item=xcoordinate[i];
if (g_JSChartResource.Minute.FrameSplitTextColor) info.TextColor=g_JSChartResource.Minute.FrameSplitTextColor;
info.Value=item[0];
if (this.ShowText) info.Message[0]=item[3];
if (item[4]) info.LineColor=item[4]; //线段颜色
if (item[5]) info.TextBGColor=item[5]; //文字背景色
this.Frame.VerticalInfo[i]=info;
}
}
else
{
var offset=0, showDayCount=this.DayData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
this.DayOffset.DataOffset=offset*minuteCount;
this.DayOffset.ShowDataCount=this.DayOffset.ShowDayCount*minuteCount;
this.DayOffset.PageInfo={ Day:[] };
for(var i=this.DayData.length-1-offset, j=0; i>=0 && j<showDayCount; --i,++j)
{
var info=new CoordinateInfo();
info.Value=j*minuteCount+minuteMiddleCount;
info.LineType=-1; //线段不画
if (this.ShowText)
{
info.Message[0]=this.FormatDate(this.DayData[i].Date);
info.BG={ Index: { Start:j*minuteCount+1, End: (j+1)*minuteCount-1 }, Date:this.DayData[i].Date }; //背景设置
}
this.Frame.VerticalInfo.push(info);
var info=new CoordinateInfo();
info.Value=(j+1)*minuteCount;
this.Frame.VerticalInfo.push(info);
this.DayOffset.PageInfo.Day.push({ Date:this.DayData[i].Date, Index:i });
}
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_XCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
event.Callback(event,data,this);
}
}
}
this.FormatDate=function(date)
{
switch(this.DateFormat)
{
case 1:
return IFrameSplitOperator.FormatDateString(date, 'MM/DD');
case 2:
return IFrameSplitOperator.FormatDateString(date, 'MM/DD/W');
default: //MM-DD
return IFrameSplitOperator.FormatDateString(date, 'MM-DD');
}
}
}
function FrameSplitXData()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.Symbol; //股票代码
this.MinTextDistance=50*GetDevicePixelRatio();
this.MinBarDistance=5; //刻度间最小的K线间距
this.Operator=function()
{
if (this.Frame.Data==null || this.Frame.XData==null) return;
this.Frame.VerticalInfo=[];
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length ;++i,++index)
{
var info= new CoordinateInfo();
info.Value=index-xOffset;
if (this.ShowText)
info.Message[0]=this.Frame.XData[i];
this.Frame.VerticalInfo.push(info);
distance=0;
}
}
}
//深度图X轴价格信息
function FrameSplitXDepth()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.SplitCount=3;
this.Symbol;
this.LineType=3;
this.Operator=function()
{
var xRange=this.Frame.VerticalRange;
if (!xRange) return;
this.Frame.VerticalInfo=[];
var floatPrecision=2;
if (this.Symbol) floatPrecision=GetfloatPrecision(this.Symbol);
var xMax=xRange.Max;
var xMin=xRange.Min;
if (xRange.Bid)
{
var interval=(xRange.Bid.Max-xMin)/this.SplitCount;
for(var i=0;i<this.SplitCount;++i)
{
var info= new CoordinateInfo();
info.Value=xMin+(interval*i);
if (info.Value<=0) continue;
if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
if (this.ShowText) info.Message[0]=info.Value.toFixed(floatPrecision);
this.Frame.VerticalInfo.push(info);
}
}
var info=new CoordinateInfo();
info.Value=xRange.Center;
//if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
this.Frame.VerticalInfo.push(info);
if (xRange.Ask)
{
var interval=(xMax-xRange.Ask.Min)/this.SplitCount;
for(var i=1;i<=this.SplitCount;++i)
{
var info= new CoordinateInfo();
info.Value=xRange.Ask.Min+(interval*i);
if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
if (this.ShowText) info.Message[0]=info.Value.toFixed(floatPrecision);
this.Frame.VerticalInfo.push(info);
}
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_XCOORDINATE);
if (event && event.Callback)
{
var data={ID:this.Frame.Identify, Frame:this.Frame };
event.Callback(event,data,this);
}
}
}
}
//把X位置调整到有数据上面
function CallAcutionXOperator()
{
this.Frame;
this.Value;
this.Point;
this.ClientPos;
this.BeforOpeneData;
this.AfterCloseData;
this.X;
this.Item;
this.DataIndex;
this.DayIndex;
this.MultiDayBeforeOpenData;
this.MultiDayAfterCloseData;
this.DayOffset;
this.Operator=function()
{
this.Item=null;
this.DataIndex=null;
this.DayIndex=null;
if (this.ClientPos==2)
{
return this.GetBeforeOpenXIndex();
}
else if (this.ClientPos==3)
{
return this.GetAfterCloseXIndex();
}
else if (this.ClientPos>=200 && this.ClientPos<=299)
{
return this.GetMultiDayBeforeOpenXIndex();
}
else if (this.ClientPos>=300 && this.ClientPos<=399)
{
return this.GetMultiDayAfterCloseXIndex();
}
return false;
}
this.GetBeforeOpenXIndex=function()
{
if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
if (!this.BeforeOpenData || !this.BeforeOpenData.Data) return false;
var index=this.Frame.GetLeftExtendXData(this.Value, this.BeforeOpenData);
index=parseInt(index.toFixed(0));
if (index>=0 && index<this.BeforeOpenData.Data.length)
{
var item=this.BeforeOpenData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
this.Item=item;
this.X=this.Value;
this.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=this.BeforeOpenData.Data.length) index=this.BeforeOpenData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=this.BeforeOpenData.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0)
{
for(var i=index+1; i<this.BeforeOpenData.Data.length;++i)
{
var item=this.BeforeOpenData.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
}
if (findIndex<0) return false;
this.Item=item;
this.DataIndex=findIndex;
this.X=this.Frame.GetLeftExtendXFromIndex(findIndex, this.BeforeOpenData); //调整X轴坐标
return true;
}
this.GetMultiDayBeforeOpenData=function()
{
if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData)) return null;
if (!this.DayOffset) this.MultiDayBeforeOpenData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayBeforeOpenData.slice(offset, offset+showCount);
return aryData;
}
this.GetMultiDayBeforeOpenXIndex=function()
{
var multiDayBeforeOpenData=this.GetMultiDayBeforeOpenData();
if (!multiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(multiDayBeforeOpenData)) return false;
var dayIndex=this.ClientPos-200;
if (dayIndex<0 || dayIndex>=multiDayBeforeOpenData.length) return false;
var dayData=multiDayBeforeOpenData[dayIndex];
var indexData=this.Frame.GetLeftExtendXData(this.Value, multiDayBeforeOpenData);
if (!indexData || !IFrameSplitOperator.IsNumber(indexData.DataIndex)) return false;
var index=parseInt(indexData.DataIndex.toFixed(0));
var dayIndex=indexData.DayIndex;
if (index>=0 && index<dayData.Data.length)
{
var item=dayData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
this.Item=item;
this.X=this.Value;
this.DataIndex=index;
this.DayIndex=dayIndex;
return true;
}
}
if (index<0) index=0;
else if (index>=dayData.Data.length) index=dayData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=dayData.Data[i];
if (item && IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0) return false;
this.Item=item;
this.DataIndex=findIndex;
this.DayIndex=dayIndex;
this.X=this.Frame.GetLeftExtendXFromIndex(findIndex, dayData); //调整X轴坐标
return true;
}
this.GetAfterCloseXIndex=function()
{
if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
if (!this.AfterCloseData || !this.AfterCloseData.Data) return false;
var index=this.Frame.GetRightExtendXData(this.Value, this.AfterCloseData);
index=parseInt(index.toFixed(0));
if (index>=0 && index<this.AfterCloseData.Data.length)
{
var item=this.AfterCloseData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
this.Item=item;
this.X=this.Value;
this.DataIndex=index;
return true;
}
}
if (index<0) index=0;
else if (index>=this.AfterCloseData.Data.length) index=this.AfterCloseData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=this.AfterCloseData.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0)
{
for(var i=index+1; i<this.AfterCloseData.Data.length;++i)
{
var item=this.AfterCloseData.Data[i];
if (IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
}
if (findIndex<0) return false;
this.Item=item;
this.DataIndex=findIndex;
this.X=this.Frame.GetRightExtendXFromIndex(findIndex, this.AfterCloseData); //调整X轴坐标
return true;
}
this.GetMultiDayAfterCloseData=function()
{
if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData)) return null;
if (!this.DayOffset) this.MultiDayAfterCloseData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayAfterCloseData.slice(offset, offset+showCount);
return aryData;
}
this.GetMultiDayAfterCloseXIndex=function()
{
var multiDayAfterCloseData=this.GetMultiDayAfterCloseData();
if (!multiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(multiDayAfterCloseData)) return;
var dayIndex=this.ClientPos-300;
if (dayIndex<0 || dayIndex>=multiDayAfterCloseData.length) return;
var dayData=multiDayAfterCloseData[dayIndex];
var indexData=this.Frame.GetRightExtendXData(this.Value, multiDayAfterCloseData);
if (!indexData) return;
var index=parseInt(indexData.DataIndex.toFixed(0));
var dayIndex=indexData.DayIndex;
if (index>=0 && index<dayData.Data.length)
{
var item=dayData.Data[index];
if (IFrameSplitOperator.IsNumber(item.Price))
{
this.Item=item;
this.X=this.Value;
this.DataIndex=index;
this.DayIndex=dayIndex;
return true;
}
}
if (index<0) index=0;
else if (index>=dayData.Data.length) index=dayData.Data.length-1;
var findIndex=-1;
for(var i=index; i>=0; --i)
{
var item=dayData.Data[i];
if (item && IFrameSplitOperator.IsNumber(item.Price))
{
findIndex=i;
break;
}
}
if (findIndex<0) return false;
this.Item=item;
this.DataIndex=findIndex;
this.DayIndex=dayIndex;
this.X=this.Frame.GetRightExtendXFromIndex(findIndex, dayData); //调整X轴坐标
return true;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//十字光标
function ChartCorssCursor()
{
this.ClassName="ChartCorssCursor";
this.Frame;
this.Canvas; //画布
this.HPenColor=g_JSChartResource.CorssCursorHPenColor; //水平线颜色
this.HPenType=0; //水平线样式 0=虚线 1=实线
this.VPenColor=g_JSChartResource.CorssCursorVPenColor; //垂直线颜色
this.VPenType=0; //垂直线颜色 0=虚线 1=实线 2=K线宽度
this.VLineType=0; //垂直线 0=默认指标标题栏不画, 1=指标标题栏也画
this.Font=g_JSChartResource.CorssCursorTextFont; //字体
this.TextColor=g_JSChartResource.CorssCursorTextColor; //文本颜色
this.TextBGColor=g_JSChartResource.CorssCursorBGColor; //文本背景色
this.BorderColor=g_JSChartResource.CorssCursorBorderColor; //边框颜色
this.XRangeBGColor=g_JSChartResource.CorssCursorXRangeBGColor;
this.TextHeight=20; //文本字体高度
this.LastPoint;
this.LastValue; //{ Y:{ Value:, Extend: } }
this.CursorIndex;
this.IsOnlyDrawKLine=false; //是否只能画在K线上 (手机端)
this.IsOnlyDrawMinute=false; //是否只能画在走势图价格线上
this.IsFixXLastTime=false; //是否修正X轴,超出当前时间的,X轴调整到当前最后的时间.
this.IsDrawXRangeBG=false; //是否绘制十字光标背景
this.EnableNewIndex=false; //分时图是否使用最新的索引结构 (由外部chart容器传入)
this.CorssCursorIndex; //分时图新版本的索引结构 (由外部chart容器传入)
this.PointX;
this.PointY;
this.StringFormatX;
this.StringFormatY;
this.ShowTextMode={ Left:1, Right:1, Bottom:1 }; //0=不显示 1=显示在框架外 2=显示在框架内
this.TextFormat= { Right:0 }; //0=默认 1=价格显示(分时图才有用)
this.IsShowCorss=true; //是否显示十字光标
this.IsShow=true;
this.IsShowClose=false; //Y轴始终显示收盘价
this.ClientPos=-1;
this.CallAcutionXOperator;
this.EnableKeyboard=false; //是否支持键盘隐藏显示
this.OnChangeStatusCallback; //状态切换以后回调
this.RightButton=
{
Enable:false, Rect:null,
BGColor:g_JSChartResource.CorssCursor.RightButton.BGColor ,
PenColor:g_JSChartResource.CorssCursor.RightButton.PenColor,
Icon:g_JSChartResource.CorssCursor.RightButton.Icon
};
this.RightMargin={ Left:2, Right:2, Top:4, Bottom:3 };
CopyMarginConfig(this.RightMargin, g_JSChartResource.CorssCursor.RightMargin);
//内部使用
this.Close=null; //收盘价格
this.Status=0; //当前状态 0=隐藏 1=显示
this.ReloadResource=function(resource)
{
this.Font=g_JSChartResource.CorssCursorTextFont; //字体
this.HPenColor=g_JSChartResource.CorssCursorHPenColor; //水平线颜色
this.VPenColor=g_JSChartResource.CorssCursorVPenColor; //垂直线颜色
this.TextColor=g_JSChartResource.CorssCursorTextColor; //文本颜色
this.TextBGColor=g_JSChartResource.CorssCursorBGColor; //文本背景色
this.BorderColor=g_JSChartResource.CorssCursorBorderColor; //边框颜色
this.XRangeBGColor=g_JSChartResource.CorssCursorXRangeBGColor;
}
this.GetCloseYPoint=function(index)
{
if (!this.StringFormatX.Data) return null;
var data = this.StringFormatX.Data;
if (!data.Data || data.Data.length <= 0) return null;
var dataIndex = data.DataOffset + index;
if (dataIndex >= data.Data.length) dataIndex = data.Data.length - 1;
if (dataIndex < 0) return null;
var klineData = data.Data[dataIndex];
if (!klineData) return null;
this.Close=klineData.Close;
var yPoint = this.Frame.GetYFromData(this.Close);
return yPoint;
}
this.GetMinuteCloseYPoint=function(index)
{
if (this.EnableNewIndex && this.CorssCursorIndex)
{
if (!this.StringFormatX || !this.StringFormatX.GetMinuteCloseYPoint) return null;
var closeData=this.StringFormatX.GetMinuteCloseYPoint(this.CorssCursorIndex);
if (!closeData) return null;
this.Close=closeData.Price;
return closeData.Y;
}
else
{
if (!IFrameSplitOperator.IsNumber(index)) return null;
index=parseInt(index);
if (!this.StringFormatX.Data) return null;
var data = this.StringFormatX.Data;
if (!data.Data || data.Data.length <= 0) return null;
var dataIndex = data.DataOffset + index;
if (dataIndex >= data.Data.length) dataIndex = data.Data.length - 1;
if (dataIndex < 0) return null;
var close = data.Data[dataIndex];
if (!IFrameSplitOperator.IsNumber(index)) return null;
this.Close=close;
var yPoint = this.Frame.GetYFromData(this.Close);
return yPoint;
}
}
this.GetDateTimeRange=function(index, option)
{
if (!IFrameSplitOperator.IsNumber(index)) return null;
index=parseInt(index);
var data = this.StringFormatX.Data;
if (!data.Data || data.Data.length <= 0) return null;
var dataIndex = data.DataOffset + index;
if (dataIndex>=data.Data.length || dataIndex<0) return null;
if (!this.Frame || !this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return null;
var frame=this.Frame.SubFrame[0].Frame;
var dataWidth=frame.DataWidth;
var distanceWidth=frame.DistanceWidth;
var xPointCount=frame.XPointCount;
var kItem = data.Data[dataIndex];
if (!kItem) return null;
var date=kItem.Date*1000000;
var time=parseInt(kItem.Time/100)*100;
var startTime=date+time;
var endTime=date+time+59;
var endIndex=dataIndex;
for(var i=dataIndex; i<data.Data.length; ++i)
{
var item=data.Data[i];
var dateTime=item.Date*1000000+item.Time;
if (dateTime>endTime) break;
if (i-data.DataOffset>=xPointCount) break;
endIndex=i;
}
var startIndex=dataIndex;
for(var i=dataIndex;i>=0 && i>=data.DataOffset;--i)
{
var item=data.Data[i];
var dateTime=item.Date*1000000+item.Time;
if (dateTime<startTime) break;
startIndex=i;
}
var range={ StartIndex:startIndex, EndIndex:endIndex };
range.XStart=this.Frame.GetXFromIndex(startIndex-data.DataOffset);
range.XEnd=this.Frame.GetXFromIndex(endIndex-data.DataOffset);
range.XStart-=(distanceWidth+dataWidth)/2;
range.XEnd+=(distanceWidth+dataWidth)/2;
return range;
}
this.FixMinuteLastTimeXPoint=function(index)
{
if (!IFrameSplitOperator.IsNumber(index)) return null;
index=parseInt(index);
if (!this.StringFormatX.Data) return null;
var data = this.StringFormatX.Data;
if (!data.Data || data.Data.length <= 0) return null;
var dataIndex = data.DataOffset + index;
if (dataIndex<data.Data.length) return null;
dataIndex=data.Data.length - 1;
dataIndex-=data.DataOffset;
var xPoint=this.Frame.GetXFromIndex(dataIndex);
return { X:xPoint, Index:dataIndex };
}
//返回 -1=不在客户区 1=在主区域 2=左边扩展 3=右边扩展
this.PtInClient=function(x,y)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
var border=this.Frame.ChartBorder.GetHScreenBorder();
this.Canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
}
else
{
var border=this.Frame.ChartBorder.GetBorder();
this.Canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 1;
if (this.Frame.ChartBorder.LeftExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
}
else
{
this.Canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 2;
}
if (this.Frame.ChartBorder.RightExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
}
else
{
this.Canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 3;
}
return -1;
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
this.Draw=function()
{
this.Status=0;
this.RightButton.Rect=null;
this.LastValue=null;
if (!this.LastPoint) return;
this.Close=null;
var x=this.LastPoint.X;
var y=this.LastPoint.Y;
var clientPos=this.PtInClient(x,y);
this.PointY=null;
this.PointY==null;
this.ClientPos=clientPos;
if (clientPos<=0) return;
if (this.Frame.IsHScreen===true)
{
this.HScreenDraw();
return;
}
var border=this.Frame.ChartBorder.GetBorder();
var left=border.Left
var right=border.Right;
var top=border.TopTitle;
var bottom=border.Bottom;
var rightWidth=this.Frame.ChartBorder.Right;
var chartRight=border.ChartWidth;
if (this.IsOnlyDrawKLine) //手机端 十字只能画在K线上
{
x=this.Frame.GetXFromIndex(this.CursorIndex);
if (this.IsShowClose)
{
var yPoint = this.GetCloseYPoint(this.CursorIndex);
if (yPoint != null) y=yPoint;
}
}
else if (this.IsOnlyDrawMinute)
{
var yPoint = this.GetMinuteCloseYPoint(this.CursorIndex);
if (yPoint != null) y=yPoint;
}
if (this.CallAcutionXOperator)
{
this.CallAcutionXOperator.Value=x;
this.CallAcutionXOperator.Point={X:x, Y:y};
this.CallAcutionXOperator.ClientPos=clientPos;
if (this.CallAcutionXOperator.Operator())
{
x=this.CallAcutionXOperator.X;
}
}
if (this.IsFixXLastTime)
{
var value=this.FixMinuteLastTimeXPoint(this.CursorIndex)
if (value)
{
x=value.X;
this.CursorIndex=value.Index;
}
}
this.PointY=[[left,y],[right,y]];
this.PointX=[[x,top],[x,bottom]];
//十字线
if (this.IsShowCorss)
{
var rangeBG=null;
if (this.IsDrawXRangeBG)
{
rangeBG=this.GetDateTimeRange(this.CursorIndex);
}
var pixel=GetDevicePixelRatio();
if (this.HPenType==1 || this.HPenType==0) //0=实线 1=虚线
{
this.Canvas.strokeStyle=this.HPenColor;
if (this.HPenType==0) this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
//this.Canvas.lineWidth=0.5
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
if (this.HPenType==0) this.Canvas.setLineDash([]);
}
this.Canvas.save();
this.Canvas.strokeStyle=this.VPenColor;
if (this.VPenType==0)
{
this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
}
else if (this.VPenType==2)
{
let barWidth=this.Frame.SubFrame[0].Frame.DataWidth; //和K线一样宽度
if (barWidth>2*pixel) this.Canvas.lineWidth=barWidth;
}
this.Canvas.beginPath();
if (this.VLineType==1)
{
if (rangeBG)
{
this.Canvas.fillStyle=this.XRangeBGColor;
this.Canvas.fillRect(rangeBG.XStart, border.Top, (rangeBG.XEnd-rangeBG.XStart),(border.Bottom-border.Top));
}
this.Canvas.moveTo(ToFixedPoint(x),border.Top);
this.Canvas.lineTo(ToFixedPoint(x),border.Bottom);
}
else
{
if (this.Frame.SubFrame.length>0)
{
for(var i in this.Frame.SubFrame)
{
var frame=this.Frame.SubFrame[i].Frame;
var subBorder=frame.ChartBorder.GetBorder();
top=subBorder.TopTitle;
bottom=subBorder.Bottom;
if (rangeBG)
{
this.Canvas.fillStyle=this.XRangeBGColor;
this.Canvas.fillRect(rangeBG.XStart, top, (rangeBG.XEnd-rangeBG.XStart),(bottom-top));
}
this.Canvas.moveTo(ToFixedPoint(x),top);
this.Canvas.lineTo(ToFixedPoint(x),bottom);
}
}
else
{
this.Canvas.moveTo(ToFixedPoint(x),top);
this.Canvas.lineTo(ToFixedPoint(x),bottom);
}
}
this.Canvas.stroke();
this.Canvas.restore();
}
var xValue=this.Frame.GetXData(x);
var yValueExtend={};
var yValue=this.Frame.GetYData(y,yValueExtend);
if ( (this.IsOnlyDrawMinute || this.IsShowClose) && this.Close != null) yValue=this.Close;
this.LastValue={ Y:{ Value:yValue, Extend:yValueExtend }}; //缓存十字光标对应的数值
//this.StringFormatX.Value=xValue;
this.StringFormatX.Value=this.CursorIndex;
this.StringFormatX.Point={X:x, Y:y};
this.StringFormatX.ClientPos=clientPos;
this.StringFormatY.Value=yValue;
this.StringFormatY.RValue=yValueExtend.RightYValue; //右侧子坐标
this.StringFormatY.FrameID=yValueExtend.FrameID;
this.StringFormatY.Point={X:x, Y:y};
this.StringFormatY.ClientPos=clientPos;
this.Canvas.font=this.Font;
var textHeight=this.GetFontHeight();
if (textHeight>this.TextHeight) this.TextHeight=textHeight;
//Y轴
if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Left>=30) || this.ShowTextMode.Left==2 ||
(this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Right>=30) || this.ShowTextMode.Right==2 ) && this.StringFormatY.Operator() )
{
var text=this.StringFormatY.Text;
this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
var textSize={ Width:textWidth, Height:this.TextHeight, Text:[] };
var buttonData={Y:y, YValue:yValue, FrameID:yValueExtend.FrameID };
if (this.Frame.ChartBorder.Left>=30 && this.ShowTextMode.Left==1)
{
if (left<textWidth ) //左边空白的地方太少了画布下
{
this.DrawTextBGRect(ToFixedPoint(2),ToFixedPoint(y-this.TextHeight/2),ToFixedRect(textWidth),ToFixedRect(this.TextHeight));
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,2+2,y,textWidth);
}
else
{
this.DrawTextBGRect(left-2,y-this.TextHeight/2,-textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,left-4,y,textWidth);
}
}
else if (this.ShowTextMode.Left==2) //在框架内显示
{
this.DrawTextBGRect(left,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,left+2,y,textWidth);
}
var complexText=
{
ShowType:0, //0=单行(默认) 1=多行
Font:this.Font, Color:this.TextColor,
Text:[ { Text:text, Margin:this.RightMargin } ],
};
var yTop=y-this.TextHeight/2;
if (this.StringFormatY.PercentageText)
{
if (this.TextFormat.Right==0)
{
text=this.StringFormatY.PercentageText+'%';
complexText.Text[0].Text=text;
}
}
if (this.StringFormatY.RText)
{
text=this.StringFormatY.RText;
complexText.Text[0].Text=text;
}
if (this.StringFormatY.RComplexText && IFrameSplitOperator.IsNonEmptyArray(this.StringFormatY.RComplexText.Text))
{
complexText=this.StringFormatY.RComplexText;
if (!complexText.Font) complexText.Font=this.Font;
if (!complexText.Color) complexText.Color=this.TextColor;
}
this.CalculateComplexTextSize(complexText, textSize);
if (this.Frame.ChartBorder.Right>=30 && this.ShowTextMode.Right==1)
{
var isOverlayIndex=false; //是否有叠加子坐标
var overlayIndexInterval=null; //子坐标间距
if (yValueExtend.FrameID>=0)
{
var frame=this.Frame.SubFrame[yValueExtend.FrameID];
isOverlayIndex=frame.OverlayIndex.length>0;
overlayIndexInterval=null
if (isOverlayIndex)
{
for(var i=0;i<=frame.OverlayIndex.length;++i)
{
var item=frame.OverlayIndex[i];
if (!item || !item.Frame) continue;
if (item.Frame.IsShow===false) continue;
if (!item.Frame.GetXHorizontal) continue;
var overlayLeft=item.Frame.GetXHorizontal();
overlayIndexInterval=overlayLeft-right;
break;
}
}
}
//叠加坐标
if (isOverlayIndex && textSize.Width>overlayIndexInterval && overlayIndexInterval>0) //大于子坐标宽度
{
var drawRight=right+overlayIndexInterval;
if (drawRight>chartRight) drawRight=chartRight;
var itemLeft=drawRight-2-textSize.Width;
this.DrawTextBGRect(itemLeft,yTop,textSize.Width,textSize.Height);
this.DrawComplexTextV2(itemLeft, yTop, complexText, textSize);
if (this.RightButton.Enable) this.DrawRightButton(yTop, itemLeft,this.TextHeight,this.TextHeight,buttonData);
}
else if (rightWidth<textSize.Width) //右边空白显示不下,
{
var itemLeft=chartRight-2-textSize.Width;
this.DrawTextBGRect(itemLeft,yTop,textSize.Width,textSize.Height);
this.DrawComplexTextV2(itemLeft, yTop ,complexText, textSize);
if (this.RightButton.Enable) this.DrawRightButton(yTop, chartRight-2-textSize.Width,this.TextHeight,this.TextHeight,buttonData);
}
else
{
var itemLeft=right+2;
this.DrawTextBGRect(itemLeft,yTop,textSize.Width,textSize.Height);
this.DrawComplexTextV2(itemLeft,yTop,complexText,textSize);
if (this.RightButton.Enable) this.DrawRightButton(yTop, right+2,this.TextHeight,this.TextHeight,buttonData);
}
/*
if (this.StringFormatY.RExtendText && this.StringFormatY.RExtendText.length>0)
{
var yOffset=0;
for(var i in this.StringFormatY.RExtendText)
{
var item=this.StringFormatY.RExtendText[i];
var rText='--.--'
if (item.YText) rText=item.YText;
else if (IFrameSplitOperator.IsNumber(item.Y)) rText=item.Y.toFixed(0);
var rTextWidth=this.Canvas.measureText(rText).width+4; //前后各空2个像素
if (rightWidth<rTextWidth)
{
this.DrawTextBGRect(chartRight-2-rTextWidth,y+yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(rText,chartRight-4,y+yOffset+this.TextHeight,rTextWidth);
}
else
{
this.DrawTextBGRect(right+2,y+yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(rText,right+4,y+yOffset+this.TextHeight,rTextWidth);
}
yOffset+=this.TextHeight;
}
}
*/
}
else if (this.ShowTextMode.Right==2)
{
this.Canvas.fillStyle=this.TextBGColor;
var showLeft=right-textSize.Width;
this.DrawTextBGRect(showLeft,yTop,textSize.Width,textSize.Height);
this.DrawComplexTextV2(showLeft,yTop,complexText,textSize);
if (this.RightButton.Enable) this.DrawRightButton(yTop, showLeft,this.TextHeight,this.TextHeight,buttonData);
}
}
//X轴 Bottom==8 自定义
if ((this.ShowTextMode.Bottom==1 || this.ShowTextMode.Bottom==2 || this.ShowTextMode.Bottom==8) && this.StringFormatX.Operator())
{
var text=this.StringFormatX.Text;
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.TextBGColor;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
var yCenter=bottom+2+this.TextHeight/2;
var yTop=bottom+2;
var bShowText=true;
if (this.ShowTextMode.Bottom==2)
{
yCenter=bottom-this.TextHeight/2-2;
yTop=bottom-this.TextHeight-2;
}
else if (this.ShowTextMode.Bottom==8)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_CORSSCURSOR_POSITION);
if (event && event.Callback)
{
var sendData={ YCenter:yCenter, YTop:yTop, Height:this.TextHeight, IsShowText:bShowText };
event.Callback(event, sendData, this);
yCenter=sendData.YCenter;
yTop=sendData.YTop;
bShowText=sendData.IsShowText;
}
}
//JSConsole.Chart.Log('[ChartCorssCursor::Draw] ',yCenter);
if (bShowText)
{
if (x-textWidth/2<3) //左边位置不够了, 顶着左边画
{
this.DrawTextBGRect(x-1,yTop,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,x+1,yCenter,textWidth);
}
else if (x+textWidth/2>=right)
{
this.DrawTextBGRect(right-textWidth,yTop,textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,right-2,yCenter,textWidth);
}
else
{
this.DrawTextBGRect(x-textWidth/2,yTop,textWidth,this.TextHeight);
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,x,yCenter,textWidth);
}
}
}
//子坐标Y轴
if (yValueExtend.FrameID>=0)
{
var frame=this.Frame.SubFrame[yValueExtend.FrameID];
var overlayLeft=right;
this.Canvas.font=this.Font;
for(var i=0; i<frame.OverlayIndex.length; ++i)
{
var item=frame.OverlayIndex[i];
if (item.Frame.IsShow===false) continue;
if (!item.Frame.GetXHorizontal) continue;
overlayLeft=item.Frame.GetXHorizontal();
//if (overlayLeft+30>chartRight) break;
var yValue=item.Frame.GetYData(y);
var text=IFrameSplitOperator.FormatValueString(yValue,2);
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
/*
for(var j=2;j>=0;--j)
{
var text=IFrameSplitOperator.FormatValueString(yValue,j);
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
if (textWidth<frame.Interval) break;
}
*/
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(overlayLeft+1,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,overlayLeft+4,y,textWidth);
}
}
this.Status=1;
}
this.DrawComplexTextV2=function(left, yTop, complexText, size)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var showType=0;
if (complexText.ShowType==1) showType=complexText.ShowType;
if (showType==1) //多行
{
var xLeft=left;
var yText=yTop; //顶
for(var i=0; i<complexText.Text.length; ++i)
{
var item=complexText.Text[i];
var itemSize=size.Text[i];
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=complexText.Font;
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=complexText.Color;
var y=yText+itemSize.Height;
var x=xLeft;
if (item.Margin)
{
var margin=item.Margin;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) y-=margin.Bottom;
if (IFrameSplitOperator.IsNumber(margin.Left)) x+=margin.Left;
}
this.Canvas.fillText(item.Text,x,y,itemSize.Width);
yText+=itemSize.Height;
}
}
else //水平 单行
{
var xText=left;
var yBottom=yTop+size.Height;
for(var i=0; i<complexText.Text.length; ++i)
{
var item=complexText.Text[i];
var itemSize=size.Text[i];
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=complexText.Font;
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=complexText.Color;
var y=yBottom;
var x=xText;
if (item.Margin)
{
var margin=item.Margin;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) y-=margin.Bottom;
if (IFrameSplitOperator.IsNumber(margin.Left)) x+=margin.Left;
}
this.Canvas.fillText(item.Text,x,y,itemSize.Width);
xText+=itemSize.Width;
}
}
}
this.CalculateComplexTextSize=function(complexText, size)
{
if (!complexText || !IFrameSplitOperator.IsNonEmptyArray(complexText.Text)) return;
var showType=0;
if (complexText.ShowType==1) showType=complexText.ShowType;
if (showType==1) //多行
{
var textWidth=0, textHeight=0;
for(var i=0; i<complexText.Text.length; ++i)
{
var item=complexText.Text[i];
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=complexText.Font;
var itemWidth=this.Canvas.measureText(item.Text).width; //前后各空2个像素
var itemHeight=this.Canvas.measureText("擎").width;
if (item.Margin)
{
var margin=item.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) itemWidth+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) itemWidth+=margin.Right;
if (IFrameSplitOperator.IsNumber(margin.Top)) itemHeight+=margin.Top;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) itemHeight+=margin.Bottom;
}
size.Text[i]={ Width:itemWidth, Height:itemHeight }; //保存所有文字的大小信息
if (textWidth<itemWidth) textWidth=itemWidth;
textHeight+=itemHeight;
}
size.Width=textWidth;
size.Height=textHeight;
}
else //水平 单行
{
var textWidth=0, textHeight=0;
for(var i=0; i<complexText.Text.length; ++i)
{
var item=complexText.Text[i];
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=complexText.Font;
var itemWidth=this.Canvas.measureText(item.Text).width; //前后各空2个像素
var itemHeight=this.Canvas.measureText("擎").width;
if (item.Margin)
{
var margin=item.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) itemWidth+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) itemWidth+=margin.Right;
if (IFrameSplitOperator.IsNumber(margin.Top)) itemHeight+=margin.Top;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) itemHeight+=margin.Bottom;
}
size.Text[i]={ Width:itemWidth, Height:itemHeight }; //保存所有文字的大小信息
textWidth+=itemWidth;
if (textHeight<itemHeight) textHeight=itemHeight;
}
size.Width=textWidth;
size.Height=textHeight;
}
}
this.DrawRightButton=function(drawTop, drawRight, drawWidth, drawHeight, data)
{
this.Canvas.fillStyle=this.RightButton.BGColor;
var rtButton={Left:drawRight-drawWidth, Top:drawTop, Width:drawWidth, Height:drawHeight };
rtButton.Right=rtButton.Left+rtButton.Width;
rtButton.Bottom=rtButton.Top+rtButton.Height;
this.RightButton.Rect=rtButton;
this.RightButton.Data=data;
this.Canvas.fillRect(ToFixedPoint(rtButton.Left+1),ToFixedPoint(rtButton.Top),ToFixedRect(rtButton.Width),ToFixedRect(rtButton.Height));
var pixelRatio=GetDevicePixelRatio();
var spaceWidth=3;
var yCenter=(rtButton.Top+spaceWidth)+(rtButton.Height-spaceWidth*2)/2;
var xCenter=(rtButton.Left+spaceWidth)+(rtButton.Width-spaceWidth*2)/2;
if (this.RightButton.Icon)
{
var icon=this.RightButton.Icon;
this.Canvas.font=`${icon.Size*pixelRatio}px ${icon.Family}`;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=icon.Color;
this.Canvas.fillText("\ue6a3",xCenter,yCenter);
}
else
{
//画加号
this.Canvas.strokeStyle=this.RightButton.PenColor;
var x=rtButtom.Left+spaceWidth;
var y=rtButtom.Top+spaceWidth;
this.Canvas.save();
this.Canvas.linewidth=1*pixelRatio;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x), ToFixedPoint(yCenter));
this.Canvas.lineTo(ToFixedPoint(x+rtButton.Width-spaceWidth*2), ToFixedPoint(yCenter));
this.Canvas.moveTo(ToFixedPoint(xCenter),ToFixedPoint(y));
this.Canvas.lineTo(ToFixedPoint(xCenter), ToFixedPoint(y+rtButton.Height-spaceWidth*2));
this.Canvas.stroke();
this.Canvas.restore();
}
}
this.PtInButton=function(x,y)
{
if (!this.RightButton.Enable) return null;
if (!this.RightButton.Rect) return null;
var rect=this.RightButton.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { Data:this.RightButton.Data, Rect:rect };
}
}
this.DrawTextBGRect=function(x,y, height, width)
{
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(height),ToFixedRect(width));
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(height),ToFixedRect(width))
}
}
this.HScreenDraw=function()
{
var x=this.LastPoint.X;
var y=this.LastPoint.Y;
if (this.IsOnlyDrawKLine) //手机端 十字只能画在K线上
{
y=this.Frame.GetXFromIndex(this.CursorIndex);
if (this.IsShowClose)
{
var yPoint = this.GetCloseYPoint(this.CursorIndex);
if (yPoint != null) x=yPoint;
}
}
else if (this.IsOnlyDrawMinute)
{
var yPoint = this.GetMinuteCloseYPoint(this.CursorIndex);
if (yPoint != null) x=yPoint;
}
var border=this.Frame.ChartBorder.GetHScreenBorder();
var left=border.Left;
var right=border.Right;
var top=border.Top;
var bottom=border.Bottom;
var bottomWidth=this.Frame.ChartBorder.Bottom;
if (this.CallAcutionXOperator)
{
this.CallAcutionXOperator.Value=y;
this.CallAcutionXOperator.Point={X:x, Y:y};
this.CallAcutionXOperator.ClientPos=this.ClientPos;
if (this.CallAcutionXOperator.Operator())
{
y=this.CallAcutionXOperator.X;
}
}
this.PointY=[[left,y],[right,y]];
this.PointX=[[x,top],[x,bottom]];
//十字线
if (this.IsShowCorss)
{
var pixel=GetDevicePixelRatio();
this.Canvas.save();
this.Canvas.strokeStyle=this.HPenColor;
if (this.HPenType==0) this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
//画竖线
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x),top);
this.Canvas.lineTo(ToFixedPoint(x),bottom);
this.Canvas.stroke();
this.Canvas.restore();
//画横线
this.Canvas.save();
this.Canvas.strokeStyle=this.VPenColor;
if (this.VPenType==0)
{
this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
}
else if (this.VPenType==2)
{
let barWidth=this.Frame.SubFrame[0].Frame.DataWidth; //和K线一样宽度
if (barWidth>2*pixel) this.Canvas.lineWidth=barWidth;
}
this.Canvas.beginPath();
if (this.VLineType==1)
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
else
{
if (this.Frame.SubFrame.length>0)
{
for(var i in this.Frame.SubFrame)
{
var frame=this.Frame.SubFrame[i].Frame;
var subBorder=frame.ChartBorder.GetHScreenBorder();
this.Canvas.moveTo(subBorder.Left,ToFixedPoint(y));
this.Canvas.lineTo(subBorder.RightEx,ToFixedPoint(y));
}
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
}
this.Canvas.stroke();
this.Canvas.restore();
}
var xValue=this.Frame.GetXData(y);
var yValueExtend={};
var yValue=this.Frame.GetYData(x,yValueExtend);
this.StringFormatX.Value=xValue;
this.StringFormatX.Point={X:x, Y:y};
this.StringFormatX.ClientPos=this.ClientPos;
this.StringFormatY.Value=yValue;
this.StringFormatY.FrameID=yValueExtend.FrameID;
this.StringFormatY.RValue=yValueExtend.RightYValue; //右侧子坐标
this.StringFormatY.Point={X:x, Y:y};
this.StringFormatY.ClientPos=this.ClientPos;
this.Canvas.font=this.Font;
var textHeight=this.GetFontHeight();
if (textHeight>this.TextHeight) this.TextHeight=textHeight;
if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Top>=30) || this.ShowTextMode.Left==2 ||
(this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Bottom>=30) || this.ShowTextMode.Right==2) && this.StringFormatY.Operator() )
{
var text=this.StringFormatY.Text;
this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
if (this.Frame.ChartBorder.Top>=30 && this.ShowTextMode.Left==1)
{
var xText=x;
var yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillStyle=this.TextBGColor;
if (top>=textWidth)
{
this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,-2,0,textWidth);
}
else
{
this.Canvas.fillRect((textWidth-top),-(this.TextHeight/2),-textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,(textWidth-top)-2,0,textWidth);
}
this.Canvas.restore();
}
else if (this.ShowTextMode.Left==2)
{
var xText=x;
var yText=top;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,2,0,textWidth);
this.Canvas.restore();
}
if (this.StringFormatY.RText)
{
text=this.StringFormatY.RText;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
}
if (this.Frame.ChartBorder.Bottom>=30 && this.ShowTextMode.Right==1)
{
var xText=x;
var yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillStyle=this.TextBGColor;
if (bottomWidth>textWidth)
{
this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,2,0,textWidth);
}
else
{
this.Canvas.fillRect((bottomWidth-textWidth),-(this.TextHeight/2),textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,(bottomWidth-textWidth)+2,0,textWidth);
}
if (this.StringFormatY.RExtendText && this.StringFormatY.RExtendText.length>0)
{
var yOffset=0;
for(var i in this.StringFormatY.RExtendText)
{
var item=this.StringFormatY.RExtendText[i];
var rText='--.--'
if (item.YText) rText=item.YText;
else if (IFrameSplitOperator.IsNumber(item.Y)) rText=item.Y.toFixed(0);
var rTextWidth=this.Canvas.measureText(rText).width+4; //前后各空2个像素
this.Canvas.fillStyle=item.TextBGColor;
if (bottomWidth>rTextWidth)
{
this.Canvas.fillRect(0,yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(rText,2,yOffset+this.TextHeight,rTextWidth);
}
else
{
var rTextLeft=bottomWidth-rTextWidth;
this.Canvas.fillRect(rTextLeft,yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(rText,rTextLeft+2,yOffset+this.TextHeight,rTextWidth);
}
yOffset+=this.TextHeight;
}
}
this.Canvas.restore();
}
else if (this.ShowTextMode.Right==2)
{
var xText=x;
var yText=bottom;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,-2,0,textWidth);
this.Canvas.restore();
}
}
//X轴 Bottom=8 自定义X轴文字位置
if ((this.ShowTextMode.Bottom===1 || this.ShowTextMode.Bottom==8) && this.StringFormatX.Operator())
{
var text=this.StringFormatX.Text;
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.TextBGColor;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
var xText=left;
var bShowText=true;
if (this.ShowTextMode.Bottom==8)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_CORSSCURSOR_POSITION);
if (event && event.Callback)
{
var sendData={ XText:xText, Height:this.TextHeight, IsShowText:bShowText };
event.Callback(event, sendData, this);
xText=sendData.XText;
bShowText=sendData.IsShowText;
}
}
if (bShowText)
{
if (y-textWidth/2<3) //左边位置不够了, 顶着左边画
{
var yText=y;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillRect(0,0,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,2,this.TextHeight/2,textWidth);
this.Canvas.restore();
}
else if (y+textWidth/2>=bottom)
{
var yText=y;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillRect(-textWidth,0,textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,-2,this.TextHeight/2,textWidth);
this.Canvas.restore();
}
else
{
var yText=y;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.fillRect(-textWidth/2,0,textWidth,this.TextHeight);
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,0,this.TextHeight/2,textWidth);
this.Canvas.restore();
}
}
}
this.Status=1;
}
//data={ e:e, PreventDefault:false, KeyID, Draw:是否需要重绘 }
this.OnKeyDown=function(data)
{
if (!this.EnableKeyboard) return;
var keyID=data.KeyID;
if (keyID==27) //ESC 隐藏十字线
{
if (!this.IsShowCorss) return;
this.IsShowCorss=false;
data.Draw=true;
if (this.OnChangeStatusCallback) this.OnChangeStatusCallback({ Type:1, IsShowCorss:this.IsShowCorss }, this);
}
else if (keyID==37 || keyID==39) //left, right 显示十字线
{
if (this.IsShowCorss) return;
this.IsShowCorss=true;
data.Draw=true;
if (this.OnChangeStatusCallback) this.OnChangeStatusCallback({ Type:1, IsShowCorss:this.IsShowCorss }, this);
}
}
}
////////////////////////////////////////////////////////////////////////////////
//深度图十字光标
function DepthChartCorssCursor()
{
this.Frame;
this.HQChart;
this.Canvas; //画布
this.Data;
this.Symbol;
this.HPenType=0; //水平线样式 0=虚线 1=实线
this.VPenType=0; //垂直线颜色 0=虚线 1=实线
this.LineDash=g_JSChartResource.DepthCorss.LineDash;
this.IsShowTooltip=true;
this.AskColor=g_JSChartResource.DepthCorss.AskColor.Line; //卖
this.BidColor=g_JSChartResource.DepthCorss.BidColor.Line; //买
this.LineWidth=g_JSChartResource.DepthCorss.LineWidth;
this.ClassName="DepthChartCorssCursor";
this.Tooltip=
{
Border:
{
Top:g_JSChartResource.DepthCorss.Tooltip.Border.Top,
Left:g_JSChartResource.DepthCorss.Tooltip.Border.Left,
Right:g_JSChartResource.DepthCorss.Tooltip.Border.Right,
Bottom:g_JSChartResource.DepthCorss.Tooltip.Border.Bottom,
ItemSpace: g_JSChartResource.DepthCorss.Tooltip.Border.ItemSpace
},
Font:g_JSChartResource.DepthCorss.Tooltip.Font,
TextColor:g_JSChartResource.DepthCorss.Tooltip.TextColor,
BGColor:g_JSChartResource.DepthCorss.Tooltip.BGColor
}; // Width: Height:
this.Font=g_JSChartResource.CorssCursorTextFont; //字体
this.TextColor=g_JSChartResource.CorssCursorTextColor; //文本颜色
this.TextBGColor=g_JSChartResource.CorssCursorBGColor; //文本背景色
this.TextHeight=20; //文本字体高度
this.LastPoint;
this.PointX;
this.PointY;
this.StringFormatX;
this.StringFormatY;
this.IsShowCorss=true; //是否显示十字光标
this.IsShow=true;
//this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; //多语言
this.GetVol=function(price, isAsk)
{
if (!this.Data) return null;
var aryData=isAsk? this.Data.Asks:this.Data.Bids;
if (!aryData || !Array.isArray(aryData) || aryData.length<=0) return null;
for(var i in aryData)
{
var item=aryData[i];
if (item.Price==price) return item.Vol;
}
return null;
}
this.Draw=function()
{
this.Status=0;
if (!this.LastPoint) return;
if (!this.Data) return;
if (!this.IsShow) return;
var x=this.LastPoint.X;
var y=this.LastPoint.Y;
var isInClient=false;
this.Canvas.beginPath();
this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight());
isInClient=this.Canvas.isPointInPath(x,y);
this.PointY=null;
this.PointY==null;
if (!isInClient) return;
if (this.Frame.IsHScreen===true)
{
return;
}
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var top=this.Frame.ChartBorder.GetTopTitle();
var bottom=this.Frame.ChartBorder.GetBottom();
var rightWidth=this.Frame.ChartBorder.Right;
var chartRight=this.Frame.ChartBorder.GetChartWidth();
var xValue=this.Frame.GetXData(x);
var xInfo=this.Frame.GetXFromPrice(xValue); //调整价格到有数据的点上
if (!xInfo) return;
var yVol=this.GetVol(xInfo.Price, xInfo.IsAsk);
y=this.Frame.GetYFromData(yVol); //调整Y轴, 让它在线段上
xInfo.Vol=yVol;
xInfo.Y=y;
this.PointY=[[left,y],[right,y]];
this.PointX=[[x,top],[x,bottom]];
if (this.IsShowCorss)
{
if (xInfo.IsAsk) this.Canvas.strokeStyle=this.AskColor;
else this.Canvas.strokeStyle=this.BidColor;
var lineWidthBackup=this.Canvas.lineWidth;
var pixel=GetDevicePixelRatio();
this.Canvas.lineWidth=this.LineWidth*pixel;
var lineWidth=this.Canvas.lineWidth;
if (this.HPenType==1 || this.HPenType==0) //0=实线 1=虚线
{
if (this.HPenType==0) this.Canvas.setLineDash(this.LineDash); //虚线
var yFix=ToFixedPoint2(lineWidth, y);
this.Canvas.beginPath();
this.Canvas.moveTo(left,yFix);
this.Canvas.lineTo(right,yFix);
this.Canvas.stroke();
if (this.HPenType==0) this.Canvas.setLineDash([]);
}
if (this.VPenType==0) this.Canvas.setLineDash(this.LineDash); //虚线
var xFix=ToFixedPoint2(lineWidth, xInfo.X);
this.Canvas.beginPath();
this.Canvas.moveTo(xFix,top);
this.Canvas.lineTo(xFix,bottom);
this.Canvas.stroke();
if (this.VPenType==0) this.Canvas.setLineDash([]);
this.Canvas.lineWidth=lineWidthBackup;
}
if (this.HQChart)
{
var event=this.HQChart.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_DEPTH_TOOLTIP);
if (event)
{
event.Callback(event,xInfo,this);
}
}
if (this.IsShowTooltip)
{
var aryText=this.GetFormatTooltip(xInfo);
this.DrawTooltip(aryText,xInfo);
}
}
//[{Title:, TitleColor:, Text:, Color:}]
this.GetFormatTooltip=function(drawData)
{
var aryText=[];
var floatPrecision=2;
if (this.Symbol) floatPrecision=GetfloatPrecision(this.Symbol); //价格小数位数
var item=
{
Title:g_JSChartLocalization.GetText('Depth-Price',this.HQChart.LanguageID),
TitleColor:this.Tooltip.TextColor,
Text:drawData.Price.toFixed(floatPrecision),
Color:this.Tooltip.TextColor
};
aryText.push(item);
var item=
{
Title:g_JSChartLocalization.GetText('Depth-Sum',this.HQChart.LanguageID),
TitleColor:this.Tooltip.TextColor,
Text:drawData.Vol.toFixed(4),
Color:this.Tooltip.TextColor
};
aryText.push(item);
return aryText;
}
this.DrawTooltip=function(aryText, data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryText)) return;
this.Canvas.font=this.Tooltip.Font;
var maxWidth=0, lineCount=0, itemCount=0;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
if (!item) continue;
var isVaild=false;
if (item.Title)
{
var textWidth=this.Canvas.measureText(item.Title).width;
if (maxWidth<textWidth) maxWidth=textWidth;
++lineCount;
isVaild=true;
}
if (item.Text)
{
var textWidth=this.Canvas.measureText(item.Text).width;
if (maxWidth<textWidth) maxWidth=textWidth;
++lineCount;
isVaild=true;
}
if (isVaild) ++itemCount;
}
if (maxWidth<=0 || lineCount<=0) return;
this.Tooltip.LineHeight=this.Canvas.measureText("擎").width+2;
var pixel=GetDevicePixelRatio();
var border=this.Tooltip.Border;
this.Tooltip.Width=maxWidth+(border.Left+border.Right)*pixel;
this.Tooltip.Height=this.Tooltip.LineHeight*lineCount + (border.Top+border.Bottom)*pixel + (border.ItemSpace*pixel)*(itemCount-1)
var chartRight=this.Frame.ChartBorder.GetRight();
var chartTop=this.Frame.ChartBorder.GetTop();
var left=data.X;
var top=data.Y-this.Tooltip.Height
if (left+this.Tooltip.Width>=chartRight) left=data.X-this.Tooltip.Width;
if (top<chartTop) top=data.Y;
this.Canvas.fillStyle=this.Tooltip.BGColor;
this.Canvas.fillRect(left,top,this.Tooltip.Width,this.Tooltip.Height);
this.Canvas.textBaseline="top";
this.Canvas.textAlign="left";
var x=border.Left*pixel+left;
var y=border.Top*pixel+top;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
var isVaild=false;
if (item.Title)
{
if (item.TitleColor) this.Canvas.fillStyle=item.TitleColor;
else this.Canvas.fillStyle=this.Tooltip.TextColor;
this.Canvas.fillText(item.Title,x,y);
y+=this.Tooltip.LineHeight;
isVaild=true;
}
if (item.Text)
{
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.Tooltip.TextColor;
this.Canvas.fillText(item.Text,x,y);
y+=this.Tooltip.LineHeight;
isVaild=true;
}
if (isVaild) y+=border.ItemSpace*pixel;
}
}
this.PtInButton=function(x,y)
{
return null;
}
}
////////////////////////////////////////////////////////////////////////////////
// 等待提示
function ChartSplashPaint()
{
this.Frame;
this.Canvas; //画布
this.Font=g_JSChartResource.SplashScreen.Font; //字体
this.TextColor=g_JSChartResource.SplashScreen.TextColor; //文本颜色
this.IsEnableSplash=false;
this.SplashTitle='数据加载中';
this.HQChart;
this.Position=0; //显示位置 0=中间 1=第1个窗口中间
this.EnableSplash=function(bEnable)
{
this.IsEnableSplash=bEnable;
if (this.HQChart)
{
var event=this.HQChart.GetEventCallback(JSCHART_EVENT_ID.ON_ENABLE_SPLASH_DRAW);
if (event)
{
var data={ Enable:bEnable };
event.Callback(event,data,this);
}
}
}
this.SetTitle=function(title)
{
this.SplashTitle=title;
}
this.Draw=function()
{
if (!this.IsEnableSplash) return;
if (this.Frame.IsHScreen===true)
{
this.HScreenDraw();
return;
}
var xCenter=null, yCenter=null;
if (this.Position==1)
{
if (this.HQChart.Frame && this.HQChart.Frame.SubFrame && this.HQChart.Frame.SubFrame[0])
{
var frame=this.HQChart.Frame.SubFrame[0].Frame;
if (frame)
{
xCenter = (frame.ChartBorder.GetLeft() + frame.ChartBorder.GetRight()) / 2;
yCenter = (frame.ChartBorder.GetTop() + frame.ChartBorder.GetBottom()) / 2;
}
}
}
if (!IFrameSplitOperator.IsNumber(xCenter) || !IFrameSplitOperator.IsNumber(yCenter))
{
var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2;
var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2;
}
this.Canvas.textAlign='center';
this.Canvas.textBaseline='middle';
this.Canvas.fillStyle=this.TextColor;
this.Canvas.font=this.Font;
this.Canvas.fillText(this.SplashTitle,xCenter,yCenter);
}
this.HScreenDraw=function() //横屏
{
var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2;
var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2;
this.Canvas.save();
this.Canvas.translate(xCenter, yCenter);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.textAlign='center';
this.Canvas.textBaseline='middle';
this.Canvas.fillStyle=this.TextColor;
this.Canvas.font=this.Font;
this.Canvas.fillText(this.SplashTitle,0,0);
this.Canvas.restore();
}
}
/////////////////////////////////////////////////////////////////////////////////
//
function IChangeStringFormat()
{
this.Data;
this.Value; //数据
this.Text; //输出字符串
this.Operator=function()
{
return false;
}
//多日分时图 集合竞价数据
this.GetMultiDayBeforeOpenData=function()
{
if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData)) return null;
if (!this.DayOffset) this.MultiDayBeforeOpenData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayBeforeOpenData.slice(offset, offset+showCount);
return aryData;
}
this.GetMultiDayAfterCloseData=function()
{
if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData)) return null;
if (!this.DayOffset) this.MultiDayAfterCloseData;
if (!IFrameSplitOperator.IsNumber(this.DayOffset.Offset) || !IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) return null;
var showCount= this.DayOffset.ShowDayCount;
var offset=this.DayOffset.Offset;
var aryData=this.MultiDayAfterCloseData.slice(offset, offset+showCount);
return aryData;
}
}
//数值放大
var ZOOM_VALUE= [1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000];
function HQPriceStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Symbol;
this.FrameID;
this.Frame;
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.YClose; //收盘价
this.PercentageText; //百分比
this.RValue; //右边值
this.RText;
this.RComplexText; //{ Space:2 间距, Text:[ {Color:, Text: }] } 支持单行多颜色
this.Point;
this.ClientPos=-1;
this.ExtendChartPaint;
this.RExtendText=[];
this.BeforeOpenData;
this.AfterCloseData;
this.MultiDayBeforeOpenData;
this.MultiDayAfterCloseData;
this.ShareAfterVol=0; //1=主图共享 2=盘前共享
this.PriceFormatType=0; //主窗口格式 0=默认 1=科学计数
this.DataFormatType=0; //副图指标格式 0=默认 1=科学计数
this.GetEventCallback
//盘前集合竞价
this.GetBeforeOpen=function()
{
if (!this.Frame) return false;
var item=this.Frame.SubFrame[this.FrameID];
if (!item || !item.Frame) return false;
if (!this.BeforeOpenData) return false;
var range={ Max:this.BeforeOpenData.VolMax, Min:this.BeforeOpenData.VolMin };
var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
var value=item.Frame.GetLeftExtendYData(y,false,{ Range:range } );
var defaultfloatPrecision=2; //价格小数位数
if (IFrameSplitOperator.IsNumber(value))
{
this.RText=this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
}
}
//收盘集合竞价
this.GetAfterClose=function()
{
if (!this.Frame) return false;
var item=this.Frame.SubFrame[this.FrameID];
if (!item || !item.Frame) return false;
if (!this.AfterCloseData) return false;
var range={ Max:this.AfterCloseData.VolMax, Min:this.AfterCloseData.VolMin };
var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
var value=item.Frame.GetRightExtendYData(y,false,{ Range:range } );
var defaultfloatPrecision=2; //价格小数位数
if (IFrameSplitOperator.IsNumber(value))
{
this.RText=this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
}
}
this.GetMultiDayBeforeOpen=function()
{
if (!this.Frame) return false;
var item=this.Frame.SubFrame[this.FrameID];
if (!item || !item.Frame) return false;
var multiDayBeforeOpenData=this.GetMultiDayBeforeOpenData();
if (!multiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(multiDayBeforeOpenData)) return;
var dayIndex=this.ClientPos-200;
if (dayIndex<0 || dayIndex>=multiDayBeforeOpenData.length) return false;
var dayData=multiDayBeforeOpenData[dayIndex];
var range={ Max:dayData.VolMax, Min:dayData.VolMin };
var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
var value=item.Frame.GetLeftExtendYData(y,false,{ Range:range } );
var defaultfloatPrecision=2; //价格小数位数
if (IFrameSplitOperator.IsNumber(value))
{
this.RText=this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
}
}
this.GetMultiDayAfterClose=function()
{
if (!this.Frame) return false;
var item=this.Frame.SubFrame[this.FrameID];
if (!item || !item.Frame) return false;
var multiDayAfterCloseData=this.GetMultiDayAfterCloseData();
if (!multiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(multiDayAfterCloseData)) return;
var dayIndex=this.ClientPos-300;
if (dayIndex<0 || dayIndex>=multiDayAfterCloseData.length) return false;
var dayData=multiDayAfterCloseData[dayIndex];
var range={ Max:dayData.VolMax, Min:dayData.VolMin };
var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
var value=item.Frame.GetRightExtendYData(y,false,{ Range:range } );
var defaultfloatPrecision=2; //价格小数位数
if (IFrameSplitOperator.IsNumber(value))
{
this.RText=this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
}
}
this.Operator=function()
{
this.RText=null;
this.RComplexText=null;
this.RExtendText=[];
if (IFrameSplitOperator.IsString(this.RValue)) this.RText=this.RValue;
if (!this.Value) return false;
this.PercentageText=null;
var defaultfloatPrecision=2; //价格小数位数
if (this.FrameID==0) //第1个窗口显示原始价格
{
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
if (this.PriceFormatType==1)
this.Text=IFrameSplitOperator.FormatValueThousandsString(this.Value,defaultfloatPrecision);
else
this.Text=this.Value.toFixed(defaultfloatPrecision);
if (this.YClose>0) this.PercentageText=((this.Value-this.YClose)*100/this.YClose).toFixed(2); //走势图右边坐标显示百分比
this.GetExtendPaintData(defaultfloatPrecision);
}
else if (this.FrameID==1)
{
if (this.DataFormatType==1)
{
this.Text=IFrameSplitOperator.FormatValueThousandsString(this.Value,defaultfloatPrecision);
if (IFrameSplitOperator.IsNumber(this.RValue)) this.RText=IFrameSplitOperator.FormatValueString(this.RValue,defaultfloatPrecision,this.LanguageID);
}
else
{
this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID);
if (IFrameSplitOperator.IsNumber(this.RValue)) this.RText=IFrameSplitOperator.FormatValueString(this.RValue,defaultfloatPrecision,this.LanguageID);
}
if (this.ClientPos==2)
{
this.GetBeforeOpen();
}
else if (this.ClientPos==3)
{
if (this.ShareAfterVol==0 || this.ShareAfterVol==2)
this.GetAfterClose();
}
else if (this.ClientPos>=200 && this.ClientPos<=299)
{
this.GetMultiDayBeforeOpen();
}
else if (this.ClientPos>=300 && this.ClientPos<=399 )
{
if (this.ShareAfterVol==0 || this.ShareAfterVol==2)
this.GetMultiDayAfterClose();
}
}
else
{
if (this.DataFormatType==1) this.Text=IFrameSplitOperator.FormatValueThousandsString(this.Value,defaultfloatPrecision);
else this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID);
if (IFrameSplitOperator.IsNumber(this.RValue)) this.RText=IFrameSplitOperator.FormatValueString(this.RValue,defaultfloatPrecision,this.LanguageID);
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_CORSSCURSOR_Y_TEXT);
if (event)
{
var data={ Value:this.Value, FrameID:this.FrameID, PreventDefault:false };
event.Callback(event,data,this);
if (data.PreventDefault==true) return false;
}
}
return true;
}
//深度图刻度
this.GetExtendPaintData=function(floatPrecision)
{
var value=parseInt(this.Value*ZOOM_VALUE[floatPrecision]);
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName=='DepthMapPaint' && item.FrameID==this.FrameID)
{
var aryData=item.GetYValueByXValue(value,floatPrecision);
for(var j in aryData)
{
this.RExtendText.push(aryData[j]);
}
}
}
}
}
function HQDateStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.DateFormatType=0; //0=YYYY-MM-DD 1=YYYY/MM/DD 2=YYYY/MM/DD/W 3=DD/MM/YYYY
this.LanguageID=0;
this.Operator=function()
{
if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
if (!this.Data) return false;
var index=this.Value;
index=parseInt(index.toFixed(0));
if (this.Data.DataOffset+index>=this.Data.Data.length) return false;
var currentData = this.Data.Data[this.Data.DataOffset+index];
var dateFormatString="YYYY-MM-DD";
if (this.DateFormatType==1) dateFormatString="YYYY/MM/DD";
else if (this.DateFormatType==2) dateFormatString="YYYY/MM/DD/W";
else if (this.DateFormatType==3) dateFormatString="DD/MM/YYYY";
this.Text=IFrameSplitOperator.FormatDateString(currentData.Date, dateFormatString,this.LanguageID);
if (ChartData.IsMinutePeriod(this.Data.Period,true) ) // 分钟周期
{
var time = IFrameSplitOperator.FormatTimeString(currentData.Time);
this.Text = this.Text + " " + time;
}
else if (ChartData.IsSecondPeriod(this.Data.Period))
{
var time = IFrameSplitOperator.FormatTimeString(currentData.Time,'HH:MM:SS');
this.Text = this.Text + " " + time;
}
else if (ChartData.IsMilliSecondPeriod(this.Data.Period))
{
var time = IFrameSplitOperator.FormatTimeString(currentData.Time,'HH:MM:SS.fff');
this.Text = this.Text + " " + time;
}
else if (ChartData.IsTickPeriod(this.Data.Period)) //分笔
{
var time = IFrameSplitOperator.FormatTimeString(currentData.Time);
this.Text = this.Text + " " + time;
}
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_CORSSCURSOR_X_TEXT);
if (event)
{
var data={ Item:currentData, Period:this.Data.Period, Date:currentData.Date, Time:currentData.Time,Index:this.Data.DataOffset+index, PreventDefault:false };
event.Callback(event,data,this);
if (data.PreventDefault==true) return false;
}
}
return true;
}
}
function HQMinuteTimeStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="HQMinuteTimeStringFormat";
this.Frame;
this.Symbol;
this.Point;
this.ClientPos=-1;
this.BeforeOpenData; //单日分时图 盘前数据
this.AfterCloseData; //单日分时图 收盘数据
this.MultiDayBeforeOpenData; //多日分时图 盘前数据
this.MultiDayAfterCloseData; //多日分时图 收盘数据
this.GetEventCallback
this.GetBeforeOpen=function()
{
if (!this.BeforeOpenData || !this.BeforeOpenData.Data) return false;
var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
var index=this.Frame.GetLeftExtendXData(x, this.BeforeOpenData);
index=parseInt(index.toFixed(0));
if (index>=this.BeforeOpenData.Data.length) return false;
var item=this.BeforeOpenData.Data[index];
this.Text=this.FormatCallAcutionDateTime(item, this.BeforeOpenData);
return true;
}
this.GetAfterClose=function()
{
if (!this.AfterCloseData || !this.AfterCloseData.Data) return false;
var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
var index=this.Frame.GetRightExtendXData(x, this.AfterCloseData);
index=parseInt(index.toFixed(0));
if (index>=this.AfterCloseData.Data.length) return false;
var item=this.AfterCloseData.Data[index];
this.Text=this.FormatCallAcutionDateTime(item, this.AfterCloseData);
return true;
}
this.GetMultiDayBeforeOpen=function()
{
var multiDayBeforeOpenData=this.GetMultiDayBeforeOpenData();
if (!multiDayBeforeOpenData) return false;
if (this.Frame.ChartBorder.MultiDayMinute.Count<=1 || this.Frame.ChartBorder.MultiDayMinute.Left<=0) return false;
var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
var index=this.Frame.GetLeftExtendXData(x, multiDayBeforeOpenData);
if (!index) return false;
if (index.DayIndex>=multiDayBeforeOpenData.length) return false;
var dayItem=multiDayBeforeOpenData[index.DayIndex];
index.DataIndex=parseInt(index.DataIndex.toFixed(0));
if (index.DataIndex>=dayItem.Data.length || index.DataIndex<0) return false;
var item=dayItem.Data[index.DataIndex];
this.Text=this.FormatCallAcutionDateTime(item, dayItem);
return true;
}
this.GetMultiDayAfterClose=function()
{
var multiDayAfterCloseData=this.GetMultiDayAfterCloseData();
if (!multiDayAfterCloseData) return false;
if (this.Frame.ChartBorder.MultiDayMinute.Count<=1 || this.Frame.ChartBorder.MultiDayMinute.Right<=0) return false;
var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
var index=this.Frame.GetRightExtendXData(x, multiDayAfterCloseData);
if (!index) return false;
if (index.DayIndex>=multiDayAfterCloseData.length) return false;
var dayItem=multiDayAfterCloseData[index.DayIndex];
index.DataIndex=parseInt(index.DataIndex.toFixed(0));
if (index.DataIndex>=dayItem.Data.length) return false;
var item=dayItem.Data[index.DataIndex];
this.Text=this.FormatCallAcutionDateTime(item, dayItem);
return true;
}
this.FormatCallAcutionDateTime=function(item, callAcutionData)
{
var time=item.Time;
if (callAcutionData.Ver==1.0)
return IFrameSplitOperator.FormatTimeString(time,"HH:MM");
else
return IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
}
this.Operator=function()
{
if (this.ClientPos==2) return this.GetBeforeOpen();
else if (this.ClientPos==3) return this.GetAfterClose();
else if (this.ClientPos>=200 && this.ClientPos<=299) return this.GetMultiDayBeforeOpen();
else if (this.ClientPos>=300 && this.ClientPos<=399) return this.GetMultiDayAfterClose();
if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
var index=Math.abs(this.Value);
index=parseInt(index.toFixed(0));
var showIndex=index;
if (this.Frame && this.Frame.MinuteCount) showIndex=index%this.Frame.MinuteCount;
var timeStringData=g_MinuteTimeStringData;
var timeData=timeStringData.GetTimeData(this.Symbol);
if (!timeData) return false;
if (showIndex<0) showIndex=0;
else if (showIndex>timeData.length) showIndex=timeData.length-1;
if (this.Frame && index>=this.Frame.XPointCount)
showIndex=timeData.length-1;
var time=timeData[showIndex];
this.Text=IFrameSplitOperator.FormatTimeString(time);
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_CORSSCURSOR_X_TEXT);
if (event)
{
var data={ Time:time, Index:showIndex, PreventDefault:false };
event.Callback(event,data,this);
if (data.PreventDefault==true) return false;
}
}
return true;
}
this.GetMinuteCloseYPoint=function(cursorIndexData)
{
var type=cursorIndexData.Type;
if (type==1 || type==2 || type==3) //单日 1=主图 2=盘前 3=盘后
{
if (type==1)
{
if (!this.Data || this.Data.Data.length <= 0) return null;
var index=cursorIndexData.DataIndex;
if (index<0 || index>=this.Data.Data.length) index=this.Data.Data.length-1;
var close = this.Data.Data[index];
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
else if (type==2)
{
if (!this.BeforeOpenData || !this.BeforeOpenData.Data) return false;
if (cursorIndexData.DataIndex<0 || cursorIndexData.DataIndex>=this.BeforeOpenData.Data.length) return null;
var item=this.BeforeOpenData.Data[cursorIndexData.DataIndex];
var close=item.Price;
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
else if (type==3)
{
if (!this.AfterCloseData || !this.AfterCloseData.Data) return false;
if (cursorIndexData.DataIndex<0 || cursorIndexData.DataIndex>=this.AfterCloseData.Data.length) return null;
var item=this.AfterCloseData.Data[cursorIndexData.DataIndex];
var close=item.Price;
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
}
else if (type==10 || type==20 || type==30) //多日 10=主图 20=盘前 30=盘后
{
if (type==10)
{
if (!this.Data || this.Data.Data.length <= 0) return null;
var index=this.Frame.MinuteCount*cursorIndexData.DayIndex+cursorIndexData.DataIndex;
if (index<0 || index>=this.Data.Data.length) index=this.Data.Data.length-1;
var close = this.Data.Data[index];
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
else if (type==20)
{
var multiDayBeforeOpenData=this.GetMultiDayBeforeOpenData();
if (!multiDayBeforeOpenData) return null;
if (cursorIndexData.DayIndex<0 || cursorIndexData.DayIndex>=multiDayBeforeOpenData.length) return null;
var dayItem=multiDayBeforeOpenData[cursorIndexData.DayIndex];
if (cursorIndexData.DataIndex<0 || cursorIndexData.DataIndex>=dayItem.Data.length) return null;
var item=dayItem.Data[cursorIndexData.DataIndex];
var close=item.Price;
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
else if (type==30)
{
var multiDayAfterCloseData=this.GetMultiDayAfterCloseData();
if (!multiDayAfterCloseData) return null;
if (cursorIndexData.DayIndex<0 || cursorIndexData.DayIndex>=multiDayAfterCloseData.length) return null;
var dayItem=multiDayAfterCloseData[cursorIndexData.DayIndex];
if (cursorIndexData.DataIndex<0 || cursorIndexData.DataIndex>=dayItem.Data.length) return null;
var item=dayItem.Data[cursorIndexData.DataIndex];
var close=item.Price;
var yPoint = this.Frame.GetYFromData(close);
return { Price:close, Y:yPoint };
}
}
return null;
}
}
//行情tooltip提示信息格式
var WEEK_NAME=["日","一","二","三","四","五","六"];
function HistoryDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="HistoryDataStringFormat";
this.Symbol;
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.VolColor=g_JSChartResource.Title.VolColor;
this.AmountColor=g_JSChartResource.Title.AmountColor;
this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor;
this.PositionColor=g_JSChartResource.Title.PositionColor;
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.LineCount=0; //一共几行
this.LineHeight=g_JSChartResource.PCTooltip.LineHeight; //单行高度
this.Width=157; //宽度
this.Height=this.LineHeight*5; //高度
this.Operator=function()
{
var data=this.Value.Data;
if (!data) return false;
this.Width=157;
if (this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) this.Width=180;
var titleData=this.GetFormatTitle(data);
if (!titleData) return false;
var outData=this.GenerateTitleHtml(titleData);
if (!outData) return false;
this.Text=outData.Html;
this.Height=outData.LineCount*this.LineHeight;
return true;
/*
var date=new Date(parseInt(data.Date/10000),(data.Date/100%100-1),data.Date%100);
var strDate=IFrameSplitOperator.FormatDateString(data.Date);
var title2=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],this.LanguageID);
var isTickPeriod=ChartData.IsTickPeriod(this.Value.ChartPaint.Data.Period);
if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期
{
title2=IFrameSplitOperator.FormatTimeString(data.Time);
}
else if (ChartData.IsSecondPeriod(this.Value.ChartPaint.Data.Period) || isTickPeriod)
{
title2=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS');
}
var upperSymbol=this.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
var increase=null;
if (data.YClose>0) increase=(data.Close-data.YClose)/data.YClose*100;
if (isTickPeriod)
{
var strText=
"<span class='tooltip-title'>"+strDate+"&nbsp&nbsp"+title2+"</span>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Price',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetColor(data.Open,data.YClose)+";'>"+data.Open.toFixed(defaultfloatPrecision)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID)+"</span>"+
(increase==null? "<span class='tooltip-num' style='color:"+this.GetColor(0,0)+";'>"+'--'+"</span><br/>" :
"<span class='tooltip-num' style='color:"+this.GetColor(increase,0)+";'>"+increase.toFixed(2)+'%'+"</span><br/>");
this.LineCount=4;
}
else if (data.IsNonTrade) //非交易日就显示日期
{
var strText= `<span class='tooltip-title'>${strDate}&nbsp&nbsp${title2}</span>`;
this.LineCount=2;
}
else
{
var vol=data.Vol;
if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
var eventUnchangeKLine=null; //定制平盘K线颜色事件
if (this.GetEventCallback) eventUnchangeKLine=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_UNCHANGE_KLINE_TITLE_COLOR);
var strText=
"<span class='tooltip-title'>"+strDate+"&nbsp&nbsp"+title2+"</span>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Open',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetPriceColor("DivTooltip-Open",data.Open,data.YClose,data,eventUnchangeKLine)+";'>"+ (IFrameSplitOperator.IsNumber(data.Open)? data.Open.toFixed(defaultfloatPrecision):'--') +"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-High',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetPriceColor("DivTooltip-High",data.High,data.YClose,data,eventUnchangeKLine)+";'>"+ (IFrameSplitOperator.IsNumber(data.High)? data.High.toFixed(defaultfloatPrecision):'--') +"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Low',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetPriceColor('DivTooltip-Low',data.Low,data.YClose,data,eventUnchangeKLine)+";'>"+ (IFrameSplitOperator.IsNumber(data.Low)? data.Low.toFixed(defaultfloatPrecision):'--') +"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Close',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetPriceColor('DivTooltip-Close',data.Close,data.YClose,data,eventUnchangeKLine)+";'>"+ (IFrameSplitOperator.IsNumber(data.Close)? data.Close.toFixed(defaultfloatPrecision):'--') +"</span><br/>"+
//"<span style='color:"+this.YClose+";font:微软雅黑;font-size:12px'>&nbsp;前收: "+IFrameSplitOperator.FormatValueString(data.YClose,2)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Vol',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.VolColor+";'>"+ (IFrameSplitOperator.IsNumber(vol)? IFrameSplitOperator.FormatValueString(vol,2,this.LanguageID):'--') +"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Amount',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.AmountColor+";'>"+ (IFrameSplitOperator.IsNumber(data.Amount)? IFrameSplitOperator.FormatValueString(data.Amount,2,this.LanguageID):'--') +"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID)+"</span>"+
(increase==null? "<span class='tooltip-num' style='color:"+this.GetColor(0,0)+";'>"+'--'+"</span><br/>" :
"<span class='tooltip-num' style='color:"+this.GetColor(increase,0)+";'>"+increase.toFixed(2)+'%'+"</span><br/>");
this.LineCount=8;
if(MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && data.FlowCapital>0) //换手率
{
var value=data.Vol/data.FlowCapital*100;
strText+= "<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Exchange',this.LanguageID)+"</span>" +
"<span class='tooltip-num' style='color:"+this.TurnoverRateColor+";'>"+value.toFixed(2)+'%'+"</span><br/>";
++this.LineCount;
}
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(data.Position))
{
strText+= "<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Position',this.LanguageID)+"</span>" +
"<span class='tooltip-num' style='color:"+this.PositionColor+";'>"+data.Position+"</span><br/>";
++this.LineCount;
}
//叠加股票
if (this.Value.ChartPaint.Name=="Overlay-KLine")
{
var title="<span style='color:rgb(0,0,0);font:微软雅黑;font-size:12px;text-align:center;display: block;'>"+this.Value.ChartPaint.Title+"</span>";
strText=title+strText;
++this.LineCount;
}
}
this.Text=strText;
this.Height=this.LineCount*this.LineHeight;
return true;
*/
}
this.GenerateTitleHtml=function(data)
{
var lineCount=0;
var strHtml="", text;
if (data.Name)
{
text=`<span style='color:rgb(0,0,0);font:微软雅黑;font-size:12px;text-align:center;display: block;'>${data.Name}</span>`;
strHtml+=text;
++lineCount;
}
if (data.Title)
{
if (Array.isArray(data.Title))
{
for(var i=0;i<data.Title.length;++i)
{
var item=data.Title[i];
text=`<span class='tooltip-title'>${item}</span>`;
strHtml+=text;
++lineCount;
}
}
else
{
text=`<span class='tooltip-title'>${data.Title}</span>`;
strHtml+=text;
++lineCount;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(data.AryText))
{
for(var i=0;i<data.AryText.length;++i)
{
var item=data.AryText[i];
if (i>0) strHtml+='<br/>';
var text=`<span class='tooltip-con'>${item.Title}</span><span class='tooltip-num' style='color:${item.Color};'>${item.Text}</span>`;
strHtml+=text;
++lineCount;
}
}
return { Html:strHtml, LineCount:lineCount };
}
this.GetFormatTitle=function(data)
{
if (!data) return null;
var upperSymbol=this.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
var date=new Date(parseInt(data.Date/10000),(data.Date/100%100-1),data.Date%100);
var strDate=IFrameSplitOperator.FormatDateString(data.Date);
var title=strDate,value;
var isTickPeriod=ChartData.IsTickPeriod(this.Value.ChartPaint.Data.Period);
if (ChartData.IsDayPeriod(this.Value.ChartPaint.Data.Period,true)) //日线
{
value=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],this.LanguageID);
title=`${strDate}&nbsp&nbsp${value}`;
}
else if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期
{
value=IFrameSplitOperator.FormatTimeString(data.Time);
title=`${strDate}&nbsp&nbsp${value}`;
}
else if (ChartData.IsSecondPeriod(this.Value.ChartPaint.Data.Period) || isTickPeriod)
{
value=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS');
title=`${strDate}&nbsp&nbsp${value}`;
}
else if (ChartData.IsMilliSecondPeriod(this.Value.ChartPaint.Data.Period))
{
value=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS.fff');
title=
[
`${strDate}&nbsp&nbsp${g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],this.LanguageID)}`,
value
];
}
var result={ AryText:null, Title:title, Name:null };
if (isTickPeriod)
{
var aryText=
[
{
Title:g_JSChartLocalization.GetText('DivTooltip-Price',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.Open)? data.Open.toFixed(defaultfloatPrecision):'--',
Color:this.GetColor(data.Open,data.YClose)
},
];
if (IFrameSplitOperator.IsNumber(data.YClose))
{
var increase=(data.Close-data.YClose)/data.YClose*100;
var item=
{
Title:g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID),
Text:`${increase.toFixed(2)}%`,
Color:this.GetColor(increase,0)
}
aryText.push(item);
}
result.AryText=aryText;
}
else if (data.IsNonTrade)
{
}
else
{
var vol=data.Vol;
if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
var eventUnchangeKLine=null; //定制平盘K线颜色事件
if (this.GetEventCallback) eventUnchangeKLine=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_UNCHANGE_KLINE_TITLE_COLOR);
var aryText=
[
{
Title:g_JSChartLocalization.GetText('DivTooltip-Open',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.Open)? data.Open.toFixed(defaultfloatPrecision):'--',
Color:this.GetPriceColor("DivTooltip-Open",data.Open,data.YClose,data,eventUnchangeKLine),
},
{
Title:g_JSChartLocalization.GetText('DivTooltip-High',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.High)? data.High.toFixed(defaultfloatPrecision):'--',
Color:this.GetPriceColor("DivTooltip-High",data.High,data.YClose,data,eventUnchangeKLine)
},
{
Title:g_JSChartLocalization.GetText('DivTooltip-Low',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.Low)? data.Low.toFixed(defaultfloatPrecision):'--',
Color:this.GetPriceColor('DivTooltip-Low',data.Low,data.YClose,data,eventUnchangeKLine)
},
{
Title:g_JSChartLocalization.GetText('DivTooltip-Close',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.Close)? data.Close.toFixed(defaultfloatPrecision):'--',
Color:this.GetPriceColor('DivTooltip-Close',data.Close,data.YClose,data,eventUnchangeKLine)
},
{
Title:g_JSChartLocalization.GetText('DivTooltip-Vol',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(vol)? IFrameSplitOperator.FormatValueString(vol,2,this.LanguageID):'--',
Color:this.VolColor
},
{
Title:g_JSChartLocalization.GetText('DivTooltip-Amount',this.LanguageID),
Text:IFrameSplitOperator.IsNumber(data.Amount)? IFrameSplitOperator.FormatValueString(data.Amount,2,this.LanguageID):'--',
Color:this.AmountColor
}
];
if (IFrameSplitOperator.IsNumber(data.YClose))
{
var increase=(data.Close-data.YClose)/data.YClose*100;
var item=
{
Title:g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID),
Text:`${increase.toFixed(2)}%`,
Color:this.GetColor(increase,0)
}
aryText.push(item);
}
if(MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && data.FlowCapital>0) //换手率
{
var value=data.Vol/data.FlowCapital*100;
var item=
{
Title:g_JSChartLocalization.GetText('DivTooltip-Exchange',this.LanguageID),
Text:`${value.toFixed(2)}%`,
Color:this.TurnoverRateColor
}
aryText.push(item);
}
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(data.Position))
{
var item=
{
Title:g_JSChartLocalization.GetText('DivTooltip-Position',this.LanguageID),
Text:`${data.Position}`,
Color:this.PositionColor
}
}
//叠加股票
if (this.Value.ChartPaint.Name=="Overlay-KLine")
{
result.Name=this.Value.ChartPaint.Title;
}
result.AryText=aryText;
}
return result;
}
this.GetColor=function(price,yclse)
{
if(price>yclse) return this.UpColor;
else if (price<yclse) return this.DownColor;
else return this.UnchagneColor;
}
this.GetPriceColor=function(titleName, price, yClose, item, event)
{
var color=this.GetColor(price, yClose);
if (price==yClose && event && event.Callback)
{
var sendData={ Item:item, TitleName:titleName, DefaultColor:color, TitleColor:null, ClassName:this.ClassName };
event.Callback(event, sendData);
if (sendData.TitleColor) color=sendData.TitleColor;
}
return color;
}
}
//K线信息地雷提示信息格式
function KLineInfoDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.Width=500;
this.Operator=function()
{
if (!this.Value) return false;
var infoList=this.Value.Data.Data; //数据
var infoType=this.Value.Data.Type; //类型
var strText='';
for(var i in infoList)
{
var item=infoList[i];
var tempText='';
switch(infoType)
{
case KLINE_INFO_TYPE.BLOCKTRADING:
tempText=this.BlockTradingFormat(item);
break;
case KLINE_INFO_TYPE.TRADEDETAIL:
tempText=this.TradeDetailFormat(item);
break;
case KLINE_INFO_TYPE.RESEARCH:
tempText=this.ResearchFormat(item);
break;
case KLINE_INFO_TYPE.PFORECAST:
tempText=this.PerformanceForecastFormat(item);
break;
default:
tempText=this.DefaultFormat(item);
break;
}
strText+=tempText;
}
var html="<div class='title-length'>"+strText+"</div>";
if(infoList.length > 8)
{
var strBox="<div class='total-list'>共"+infoList.length+"条</div>";
html+=strBox;
}
this.Text=html;
return true;
}
this.DefaultFormat=function(item)
{
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
if (IFrameSplitOperator.IsNumber(item.Time))
{
var strTime=IFrameSplitOperator.FormatTimeString(item.Time);
strDate+=" "+strTime;
}
var strText=`<span>${strDate}&nbsp;&nbsp;&nbsp;${item.Title}</span>`;
return strText;
}
//大宗交易
this.BlockTradingFormat=function(item)
{
var showPriceInfo = item.ExtendData;
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span><i class='date-tipbox'>"+strDate+"</i>&nbsp;&nbsp;<i class='tipBoxTitle'>成交价:&nbsp;"+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价:&nbsp;"+showPriceInfo.ClosePrice.toFixed(2)+
"</i><br/><i class='rate-discount tipBoxTitle'>溢折价率:&nbsp;<strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股):&nbsp;"+showPriceInfo.Vol.toFixed(2)+"</i></span>";
return strText;
}
//龙虎榜
this.TradeDetailFormat=function(item)
{
/*var detail=
[
"日价格涨幅偏离值达到9.89%",
"日价格涨幅偏离值达格涨幅偏离值达格涨幅偏离值达到9.89%"
]
*/
var detail=item.ExtendData.Detail;
//格式:日期 上榜原因: detail[0].TypeExplain
// detail[1].TypeExplain
// 一周后涨幅: xx 四周后涨幅: xx
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var reasons = [];
for(var i in detail)
{
reasons += "<i>"+detail[i].TypeExplain+"</i><br/>"
// reasons += detail[i] + "<br/>"
}
var strText= "<span><i class='trade-time'>"+strDate+"&nbsp;&nbsp;&nbsp;上榜原因:&nbsp;&nbsp;</i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅:&nbsp;<strong style='color:"+
this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
"%</strong>&nbsp;&nbsp;&nbsp;四周后涨幅:&nbsp;<strong style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+";'>"+
item.ExtendData.FWeek.Week4.toFixed(2)+"%</strong></i></span>";
return strText;
}
//调研
this.ResearchFormat=function(item)
{
var levels=item.ExtendData.Level;
var recPerson='';
if(levels.length==0)
{
recPerson = "<i>一般调研</i>"
}
else
{
for(var j in levels)
{
if(levels[j]==0) recPerson+="<i style='color:#00a0e9'>证券代表&nbsp;&nbsp;&nbsp;</i>";
else if(levels[j]==1) recPerson+="<i>董秘&nbsp;&nbsp;&nbsp;</i>";
else if(levels[j]==2) recPerson+="<i style='color:#00a0e9'>总经理&nbsp;&nbsp;&nbsp;</i>";
else if(levels[j]==3) recPerson+="<i style='color:#00a0e9'>董事长&nbsp;&nbsp;&nbsp;</i>";
}
recPerson='接待:&nbsp;&nbsp;&nbsp;'+recPerson;
}
var researchType='';
if (item.ExtendData.Type && item.ExtendData.Type!='其他')
{
researchType='&nbsp;&nbsp;&nbsp;'+'<i>'+item.ExtendData.Type+'</i>';
if (levels.length==0) recPerson='';
}
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span>"+strDate+"&nbsp;&nbsp;&nbsp;"+researchType+recPerson+"</span>";
return strText;
}
//业绩预测
this.PerformanceForecastFormat=function(item)
{
var reportDate=item.ExtendData.ReportDate;
var year=parseInt(reportDate/10000); //年份
var day=reportDate%10000; //比较 这个去掉年份的日期
var reportType;
if(day == 1231){
reportType = "年报"
}else if(day == 331){
reportType = "一季度报"
}else if(day == 630){
reportType = "半年度报"
}else if(day == 930){
reportType = "三季度报"
}
var weekData="";
if (item.ExtendData.FWeek)
{
if (item.ExtendData.FWeek.Week1!=null) weekData+="一周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%</i>";
if (item.ExtendData.FWeek.Week4!=null) weekData+="&nbsp;四周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%</i>";
if (weekData.length>0) weekData="<br/>&nbsp;&nbsp;<i class='prorecast-week'>"+weekData+"</i>";
}
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span>"+strDate+"&nbsp;&nbsp;"+year+reportType+item.Title+"&nbsp;"+weekData+"</span>";
return strText;
}
this.GetColor=function(price)
{
if(price>0) return this.UpColor;
else if (price<0) return this.DownColor;
else return this.UnchagneColor;
}
}
//交易信息提示信息格式
function KLineTradeDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=120;
this.Operator=function()
{
var data=this.Value.Data;
if (!data) return false;
var item=data.Data;
var title=`<span class='tooltip-index-name'>${item.Name}${item.Param}:</span>`;
var content;
if (item.Type==1) content=`<span class='tooltip-index-buy'>买入</span>`;
else content=`<span class='tooltip-index-sell'>卖出</span>`;
this.Text=title+content;
return true;
}
}
//分时图异动信息格式化
function MinuteInfoDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=200;
this.Operator=function()
{
var data=this.Value.Data;
if (!data) return false;
var item=data.Data.Item;
var strTime=IFrameSplitOperator.FormatTimeString(item.Time);
var time=`<span class='tooltip-minuteinfo-time'>${strTime} </span>`;
var content=`<span class='tooltip-minuteinfo-content'>${item.Title}</span>`;
if (item.Content) content=`<span class='tooltip-minuteinfo-content'>${item.Content}</span>`;
this.Text=time+content;
return true;
}
}
function IconDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=200;
this.Operator=function()
{
if (!this.Value || !this.Value.Data) return false;
var data=this.Value.Data;
if (!data.Item) return false;
if (!data.Item.Text) return false;
this.Text=data.Item.Text;
return true;
}
}
function ChartDrawSVGDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=200;
this.Operator=function()
{
if (!this.Value || !this.Value.Data) return false;
var data=this.Value.Data;
if (!data.Item) return false;
if (!data.Item.Tooltip || !data.Item.Tooltip.Text) return false;
this.Text=data.Item.Tooltip.Text;
return true;
}
}
//分时图异动信息格式化
function ChartOXDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=200;
this.Period=0;
this.Operator=function()
{
var data=this.Value.Data;
if (!data || !data.Data) return false;
if (ChartData.IsDayPeriod(this.Period, true))
{
var strStartDate=IFrameSplitOperator.FormatDateString(data.Data.Start.Date);
var strEndDate=IFrameSplitOperator.FormatDateString(data.Data.End.Date);
if (strStartDate==strEndDate)
{
this.Text=`<span class='tooltip-minuteinfo-content'>${strStartDate}</span>`;
return true;
}
var content=`<span class='tooltip-minuteinfo-content'>起始时间:${strStartDate}</span>`;
var content2=`<span class='tooltip-minuteinfo-content'>结束时间:${strEndDate}</span>`;
this.Text=content+"<br>"+content2;
return true;
}
else if (ChartData.IsMinutePeriod(this.Period, true))
{
var strStartDate=IFrameSplitOperator.FormatDateString(data.Data.Start.Date);
var strStartTime=IFrameSplitOperator.FormatTimeString(data.Data.Start.Time,"HH:MM");
var strEndDate=IFrameSplitOperator.FormatDateString(data.Data.End.Date);
var strEndTime=IFrameSplitOperator.FormatTimeString(data.Data.End.Time,"HH:MM");
var content=`<span class='tooltip-minuteinfo-content'>起始时间:${strStartDate} ${strStartTime}</span>`;
var content2=`<span class='tooltip-minuteinfo-content'>结束时间:${strEndDate} ${strEndTime}</span>`;
this.Text=content+"<br>"+content2;
return true;
}
return false;
}
}
function ScatterPlotDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.Width=200;
this.Operator=function()
{
var data=this.Value.Data;
if (!data || !data.Data) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(data.Data.Tooltip)) return false;
this.Text="";
for(var i=0;i<data.Data.Tooltip.length;++i)
{
var item=data.Data.Tooltip[i];
var content=`<span class='tooltip-minuteinfo-content'>${item}</span>`;
this.Text+=content+"<br>";
}
return true;
}
}
function DivTooltipDataForamt()
{
this.DataMap=new Map(
[
["KLineTradeDataStringFormat", { Create:function() { return new KLineTradeDataStringFormat(); } }],
["MinuteInfoDataStringFormat", { Create:function() { return new MinuteInfoDataStringFormat(); } }],
["HistoryDataStringFormat", { Create:function() { return new HistoryDataStringFormat(); } }],
["KLineInfoDataStringFormat", { Create:function() { return new KLineInfoDataStringFormat(); } }],
["IconDataStringFormat", { Create:function() { return new IconDataStringFormat(); } }],
["ChartOXDataStringFormat", { Create:function() { return new ChartOXDataStringFormat(); } }],
["ScatterPlotDataStringFormat", { Create:function() { return new ScatterPlotDataStringFormat(); }}],
["ChartDrawSVGDataStringFormat", { Create:function() { return new ChartDrawSVGDataStringFormat(); }}],
["CorssCursor_XStringFormat", { Create:function() { return new HQDateStringFormat(); } }],
["CorssCursor_YStringFormat", { Create:function() { return new HQPriceStringFormat(); } }],
["CorssCursor_Minute_XStringFormat", { Create:function() { return new HQMinuteTimeStringFormat(); }} ]
]
);
this.Create=function(name)
{
if (!this.DataMap.has(name)) return null;
var item=this.DataMap.get(name);
return item.Create();
}
}
var g_DivTooltipDataForamt=new DivTooltipDataForamt();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 标题
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IChartTitlePainting()
{
this.Frame;
this.Data=new Array();
this.Canvas; //画布
this.IsDynamic=false; //是否是动态标题
this.Position=0; //标题显示位置 0 框架里的标题 1 框架上面
this.CursorIndex; //数据索引
this.LastPoint; //鼠标位置
this.Font=g_JSChartResource.TitleFont;
this.Title; //固定标题(可以为空)
this.TitleColor=g_JSChartResource.DefaultTextColor;
this.ClassName='IChartTitlePainting';
this.DrawStatus;
this.GetEventCallback;
this.GlobalOption;
this.ReloadResource=function()
{
this.Font=g_JSChartResource.TitleFont;
this.TitleColor=g_JSChartResource.DefaultTextColor;
}
}
//var PERIOD_NAME=["日线","周线","月线","年线","1分","5分","15分","30分","60分","季线","分笔", "2小时","4小时","双周","",""];
var RIGHT_NAME=['不复权','前复权','后复权'];
function DynamicKLineTitlePainting()
{
this.newMethod=IChartTitlePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DynamicKLineTitlePainting';
this.IsDynamic=true;
this.IsShow=true; //是否显示
this.Period; //周期
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.VolColor=g_JSChartResource.Title.VolColor;
this.AmountColor=g_JSChartResource.Title.AmountColor;
this.DateTimeColor=g_JSChartResource.Title.DateTimeColor;
this.NameColor = g_JSChartResource.Title.NameColor;
this.SettingColor=g_JSChartResource.Title.SettingColor; //周期 复权
this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor; //换手率
this.PositionColor=g_JSChartResource.Title.PositionColor; //持仓
this.Symbol;
this.Name;
this.SpaceWidth=2*GetDevicePixelRatio(); //获取设备的分辨率;
this.OverlayChartPaint; //叠加画法
this.IsShowName=true; //是否显示股票名称
this.IsShowSettingInfo=true; //是否显示设置信息(周期 复权)
this.IsShowDateTime=true; //是否显示日期
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.OnDrawEvent;
this.OnMouseMoveEvent;
this.HQChart;
this.ReloadResource=function()
{
this.Font=g_JSChartResource.TitleFont;
this.TitleColor=g_JSChartResource.DefaultTextColor;
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.VolColor=g_JSChartResource.Title.VolColor;
this.AmountColor=g_JSChartResource.Title.AmountColor;
this.DateTimeColor=g_JSChartResource.Title.DateTimeColor;
this.NameColor = g_JSChartResource.Title.NameColor;
this.SettingColor=g_JSChartResource.Title.SettingColor;
this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor; //换手率
this.PositionColor=g_JSChartResource.Title.PositionColor; //持仓
}
this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据
{
if (this.CursorIndex==null || !this.Data) return null;
if (this.Data.length<=0) return null;
var index=this.CursorIndex;
index=parseInt(index.toFixed(0));
var dataIndex=this.Data.DataOffset+index;
if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1;
if (dataIndex<0) return null;
var item=this.Data.Data[dataIndex];
return item;
}
this.GetFormatTitle=function(data)
{
if (!data || !data.Data) return;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
var upperSymbol=this.Symbol.toUpperCase();
var item=data.Data;
var aryText=[];
var result={ AryText:aryText };
if (this.IsShowName) aryText.push({ Text:this.Name, Color:this.NameColor });
if (this.IsShowSettingInfo)
{
var periodName='';
if (this.Data.Period>CUSTOM_MINUTE_PERIOD_START && this.Data.Period<=CUSTOM_MINUTE_PERIOD_END)
periodName=(this.Data.Period-CUSTOM_MINUTE_PERIOD_START)+g_JSChartLocalization.GetText('自定义分钟',this.LanguageID);
else if (this.Data.Period>CUSTOM_DAY_PERIOD_START && this.Data.Period<=CUSTOM_DAY_PERIOD_END)
periodName=(this.Data.Period-CUSTOM_DAY_PERIOD_START)+g_JSChartLocalization.GetText('自定义日线',this.LanguageID);
else if (this.Data.Period>CUSTOM_SECOND_PERIOD_START && this.Data.Period<=CUSTOM_SECOND_PERIOD_END)
periodName=(this.Data.Period-CUSTOM_SECOND_PERIOD_START)+g_JSChartLocalization.GetText('自定义秒',this.LanguageID);
else if (this.Data.Period>CUSTOM_MILLISECOND_PERIOD_START&& this.Data.Period<=CUSTOM_MILLISECOND_PERIOD_END)
periodName=(this.Data.Period-CUSTOM_MILLISECOND_PERIOD_START)+g_JSChartLocalization.GetText('自定义毫秒',this.LanguageID);
else
periodName=g_JSChartLocalization.GetText(ChartData.GetPeriodName(this.Data.Period),this.LanguageID);
var rightName=g_JSChartLocalization.GetText(RIGHT_NAME[this.Data.Right],this.LanguageID);
var text="("+periodName+" "+rightName+")";
if (!MARKET_SUFFIX_NAME.IsEnableRight(this.Data.Period, this.Symbol, this.HQChart.RightFormula)) text="("+periodName+")";
aryText.push({ Text:text, Color:this.SettingColor });
}
var text=this.GetKLineCalculateTitle();
if (text) aryText.push({ Text:text, Color:this.NameColor });
if (this.IsShowDateTime) //是否显示日期
{
var text=IFrameSplitOperator.FormatDateString(item.Date);
aryText.push({ Text:text, Color:this.DateTimeColor });
}
var isTickPeriod=ChartData.IsTickPeriod(this.Period);
if (ChartData.IsMinutePeriod(this.Period,true) && IFrameSplitOperator.IsNumber(item.Time))
{
var text=IFrameSplitOperator.FormatTimeString(item.Time);
aryText.push({ Text:text, Color:this.DateTimeColor });
}
else if (ChartData.IsSecondPeriod(this.Period) && IFrameSplitOperator.IsNumber(item.Time))
{
var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
aryText.push({ Text:text, Color:this.DateTimeColor });
}
else if (ChartData.IsMilliSecondPeriod(this.Period) && IFrameSplitOperator.IsNumber(item.Time))
{
var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS.fff");
aryText.push({ Text:text, Color:this.DateTimeColor });
}
else if (isTickPeriod)
{
var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
aryText.push({ Text:text, Color:this.DateTimeColor });
}
if (isTickPeriod)
{
var color=this.GetColor(item.Open,item.YClose);
var text=g_JSChartLocalization.GetText('KTitle-Price',this.LanguageID)+item.Open.toFixed(defaultfloatPrecision);
aryText.push({ Text:text, Color:color});
if (IFrameSplitOperator.IsNumber(item.YClose) && item.YClose!=0)
{
var value=(item.Close-item.YClose)/item.YClose*100;
var color = this.GetColor(value, 0);
var text = g_JSChartLocalization.GetText('KTitle-Increase',this.LanguageID) + value.toFixed(2)+'%';
aryText.push({ Text:text, Color:color});
}
return result;
}
if (item.IsNonTrade) return result; //非交易日 没数据 不显示
var eventUnchangeKLine=null; //定制平盘K线颜色事件
if (this.GetEventCallback) eventUnchangeKLine=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_UNCHANGE_KLINE_TITLE_COLOR);
if (IFrameSplitOperator.IsNumber(item.Open))
{
var color=this.GetColor(item.Open,item.YClose);
var text=g_JSChartLocalization.GetText('KTitle-Open',this.LanguageID)+item.Open.toFixed(defaultfloatPrecision);
if (item.Open==item.YClose && eventUnchangeKLine)
{
var sendData={ Item:item, TitleName:"KTitle-Open", DefaultColor:color, TitleColor:null };
if (this.OnUnchangeTitleColor(eventUnchangeKLine, sendData)) color=sendData.TitleColor;
}
aryText.push({ Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(item.High))
{
var color=this.GetColor(item.High,item.YClose);
var text=g_JSChartLocalization.GetText('KTitle-High',this.LanguageID)+item.High.toFixed(defaultfloatPrecision);
if (item.High==item.YClose && eventUnchangeKLine)
{
var sendData={ Item:item, TitleName:"KTitle-High", DefaultColor:color, TitleColor:null };
if (this.OnUnchangeTitleColor(eventUnchangeKLine, sendData)) color=sendData.TitleColor;
}
aryText.push({ Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(item.Low))
{
var color=this.GetColor(item.Low,item.YClose);
var text=g_JSChartLocalization.GetText('KTitle-Low',this.LanguageID)+item.Low.toFixed(defaultfloatPrecision);
if (item.Low==item.YClose && eventUnchangeKLine)
{
var sendData={ Item:item, TitleName:"KTitle-Low", DefaultColor:color, TitleColor:null };
if (this.OnUnchangeTitleColor(eventUnchangeKLine, sendData)) color=sendData.TitleColor;
}
aryText.push({ Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(item.Close))
{
var color=this.GetColor(item.Close,item.YClose);
var text=g_JSChartLocalization.GetText('KTitle-Close',this.LanguageID)+item.Close.toFixed(defaultfloatPrecision);
if (item.Close==item.YClose && eventUnchangeKLine)
{
var sendData={ Item:item, TitleName:"KTitle-Close", DefaultColor:color, TitleColor:null };
if (this.OnUnchangeTitleColor(eventUnchangeKLine, sendData)) color=sendData.TitleColor;
}
aryText.push({ Text:text, Color:color});
}
//涨幅
if (item.YFClose>0 && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol))
{
var value=(item.Close-item.YFClose)/item.YFClose*100;
var color = this.GetColor(value, 0);
var text = g_JSChartLocalization.GetText('KTitle-Increase',this.LanguageID) + value.toFixed(2)+'%';
aryText.push({ Text:text, Color:color});
}
else if (item.YClose>0)
{
var value=(item.Close-item.YClose)/item.YClose*100;
var color = this.GetColor(value, 0);
var text = g_JSChartLocalization.GetText('KTitle-Increase',this.LanguageID) + value.toFixed(2)+'%';
aryText.push({ Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(item.Vol)) //成交量
{
var vol=item.Vol;
if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股原始单位股, 转成股
var text=g_JSChartLocalization.GetText('KTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
aryText.push({ Text:text, Color:this.VolColor});
}
if (IFrameSplitOperator.IsNumber(item.Amount)) //成交金额
{
var text=g_JSChartLocalization.GetText('KTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID);
aryText.push({ Text:text, Color:this.AmountColor});
}
if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && item.FlowCapital>0) //A股有换手率
{
var value=item.Vol/item.FlowCapital*100; //成交量/流通A股*100
var text=g_JSChartLocalization.GetText('KTitle-Exchange',this.LanguageID)+IFrameSplitOperator.FormatValueString(value,2,this.LanguageID)+'%';
aryText.push({ Text:text, Color:this.TurnoverRateColor});
}
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position)) //持仓量
{
var text=g_JSChartLocalization.GetText('KTitle-Position',this.LanguageID)+item.Position;
aryText.push({ Text:text, Color:this.PositionColor});
}
//叠加股票的名字
if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
{
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol || !item.Title) continue;
var clrText=item.Color;
var text=`[${item.Title}]`;
aryText.push({ Text:text, Color:clrText});
}
}
return result;
}
this.DrawItem=function(item)
{
var isHScreen=this.Frame.IsHScreen===true;
var left=this.Frame.ChartBorder.GetLeft();
var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2;
var right=this.Frame.ChartBorder.GetRight();
//var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
//var upperSymbol=this.Symbol.toUpperCase();
var pixelRatio=GetDevicePixelRatio();
if (isHScreen)
{
if (this.Frame.ChartBorder.Right<5*pixelRatio) return;
var left=2;
var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示
var right=this.Frame.ChartBorder.GetHeight();
var xText=this.Frame.ChartBorder.GetChartWidth();
var yText=this.Frame.ChartBorder.GetTop();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
}
else
{
if (this.Frame.ChartBorder.Top<5*pixelRatio) return;
}
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.font=this.Font;
var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
var titleData=this.GetFormatTitle({ Data:item });
if (titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
{
for(var i=0;i<titleData.AryText.length;++i)
{
var item=titleData.AryText[i];
if (!this.DrawText(item.Text,item.Color,position)) break;
}
}
}
this.Draw=function()
{
if (!this.IsShow) return;
if (this.CursorIndex==null || !this.Data || this.Data.length<=0)
{
this.OnDrawEventCallback(null);
return;
}
this.Canvas.font=this.Font;
this.SpaceWidth = this.Canvas.measureText('0').width;
var index=this.CursorIndex;
index=parseInt(index.toFixed(0));
var dataIndex=this.Data.DataOffset+index;
if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1;
if (dataIndex<0)
{
this.OnDrawEventCallback(null);
return;
}
if (this.IsShowLastData()) //鼠标不在图形上 显示最后一条数据
{
dataIndex=this.Data.Data.length-1;
}
var item=this.Data.Data[dataIndex];
this.OnDrawEventCallback(item);
this.Canvas.save();
this.DrawItem(item);
this.Canvas.restore();
}
this.OnDrawEventCallback=function(drawData)
{
var bDrawEvent=(this.OnDrawEvent && this.OnDrawEvent.Callback);
var bMouseMoveEvent= (this.OnMouseMoveEvent && this.OnMouseMoveEvent.Callback);
if (!bDrawEvent && !bMouseMoveEvent) return;
var data={ Draw: drawData, Name:this.ClassName};
if (this.Data && this.Data.Data)
{
var index=Math.abs(this.CursorIndex);
index=parseInt(index.toFixed(0));
var dataIndex=this.Data.DataOffset+index;
var dataCount=this.Data.Data.length;
data.DataIndex=dataIndex;
data.DataCount=dataCount;
}
//叠加股票
if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
{
data.OverlayStock=[];
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol || !item.Title) continue;
data.OverlayStock.push({ Symbol:item.Symbol, Name:item.Title, Data:item.Data, Color:item.Color });
}
}
if (bDrawEvent)
this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
if (bMouseMoveEvent)
this.OnMouseMoveEvent.Callback(this.OnMouseMoveEvent,data,this);
}
this.GetColor=function(price,yclse)
{
if(price>yclse) return this.UpColor;
else if (price<yclse) return this.DownColor;
else return this.UnchagneColor;
}
this.OnUnchangeTitleColor=function(event, sendData)
{
if (!event || !event.Callback) return false;
sendData.ClassName=this.ClassName;
event.Callback(event, sendData, this);
if (sendData && sendData.TitleColor) return true;
return false;
}
this.DrawText=function(title,color,position)
{
if (!title) return true;
var isHScreen=this.Frame.IsHScreen===true;
var right = this.Frame.ChartBorder.GetRight();
if (isHScreen) right=this.Frame.ChartBorder.GetHeight();
this.Canvas.fillStyle = color;
var textWidth = this.Canvas.measureText(title).width;
if (position.Left + textWidth > right) return false;
if (this.IsShow) this.Canvas.fillText(title, position.Left, position.Bottom, textWidth);
position.Left += textWidth + this.SpaceWidth;
return true;
}
//计算K线指标标题信息
this.GetKLineCalculateTitle=function()
{
if (!this.HQChart) return null;
var klineCalulate=this.HQChart.GetKLineCalulate();
if (!klineCalulate || !klineCalulate.GetTitle) return null;
return klineCalulate.GetTitle();
}
this.IsShowLastData=function()
{
var isShow=false;
if (this.DrawStatus && this.DrawStatus.IsTitleShowLatestData)
{
var status=this.DrawStatus;
if (!IFrameSplitOperator.IsNumber(status.FrameID) || status.FrameID<0)
isShow=true;
else if (status.CorssCursorTouchEnd && status.IsOnTouch==false)
isShow=true;
}
return isShow;
}
}
function DynamicMinuteTitlePainting()
{
this.newMethod=DynamicKLineTitlePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DynamicMinuteTitlePainting';
this.SpaceWidth=1*GetDevicePixelRatio();
this.YClose;
this.IsShowDate=false; //标题是否显示日期
this.IsShowTime=true; //标题是否显示时间
this.IsShowName=true; //标题是否显示股票名字
this.IsShowAveragePrice=true; //是否显示均线价格
this.OverlayChartPaint; //叠加画法
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.LastShowData; //保存最后显示的数据 给tooltip用
this.OnDrawEvent;
this.PointInfo=null;
this.IsAlwaysShowLastData=false; //始终显示最后一个数据
this.ShowLastDataFormat=0; //0=默认 1=更新时间替换时间
this.MultiDayBeforeOpenData; //多日分时图 盘前数据
this.MultiDayAfterCloseData; //多日分时图 收盘数据
this.TitleBaseLine=1; //0=top 1=middle 2=bottom
this.TimeFormat; //显示时间格式 "HH:MM:SS", "hh:MM", "HH:MM:SS.fff"
this.CallAuctionShowTitle=new Set(
[
"MTitle-AC-Price",
"MTitle-AC-Vol",
"MTitle-AC-NotMatchVol",
"MTitle-AC-Increase",
"MTitle-AC-AvPrice"
]);
this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据
{
if (this.LastShowData) return this.LastShowData;
if (this.CursorIndex==null || !this.Data) return null;
if (this.Data.length<=0) return null;
var index=Math.abs(this.CursorIndex);
index=parseInt(index.toFixed(0));
var dataIndex=this.Data.DataOffset+index;
if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1;
if (dataIndex<0) return null;
var item=this.Data.Data[dataIndex];
return item;
}
this.GetCurrentAuctionData=function() //获取当前鼠标所在位置的盘前盘后数据
{
var isHScreen=this.Frame.IsHScreen===true;
//空数据 返回坐标信息
var emptyData={ ClientPos:this.PointInfo.ClientPos, X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y };
if (this.PointInfo.ClientPos==2)
{
if (!this.BeforeOpenData) return emptyData;
if (!this.CallAcutionXOperator) return emptyData;
this.CallAcutionXOperator.Value=isHScreen?this.PointInfo.Point.Y:this.PointInfo.Point.X;
this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
if (!this.CallAcutionXOperator.Operator()) return emptyData;
var callbackData={Explain:"BeforeOpen", Data:null, DataIndex:null, DataTotalCount:this.BeforeOpenData.TotalCount };
callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
callbackData.Data=this.CallAcutionXOperator.Item;
callbackData.Ver=this.BeforeOpenData.Ver;
return callbackData;
}
else if (this.PointInfo.ClientPos==3)
{
if (!this.AfterCloseData) return emptyData;
if (!this.CallAcutionXOperator) return emptyData;
this.CallAcutionXOperator.Value=isHScreen?this.PointInfo.Point.Y:this.PointInfo.Point.X;
this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
if (!this.CallAcutionXOperator.Operator()) return emptyData;
var callbackData={Explain:"AfterClose", Data:null, DataIndex:null, DataTotalCount:this.AfterCloseData.TotalCount };
callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
callbackData.Data=this.CallAcutionXOperator.Item;
callbackData.Ver=this.AfterCloseData.Ver;
return callbackData;
}
else if (this.PointInfo.ClientPos>=200 && this.PointInfo.ClientPos<=299)
{
if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData) ) return emptyData;
var x=this.Frame.IsHScreen==true?this.PointInfo.Point.Y:this.PointInfo.Point.X;
this.CallAcutionXOperator.Value=x;
this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
if (!this.CallAcutionXOperator.Operator()) return emptyData;
var dayItem=this.MultiDayBeforeOpenData[this.CallAcutionXOperator.DayIndex];
var callbackData={Explain:"MultiDayBeforeOpen", Data:null, DataIndex:null };
callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
callbackData.DayIndex=this.CallAcutionXOperator.DayIndex;
callbackData.Data=this.CallAcutionXOperator.Item;
callbackData.Ver=dayItem.Ver;
return callbackData;
}
else if (this.PointInfo.ClientPos>=300 && this.PointInfo.ClientPos<=399)
{
if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData) ) return emptyData;
var x=this.Frame.IsHScreen==true?this.PointInfo.Point.Y:this.PointInfo.Point.X;
this.CallAcutionXOperator.Value=x;
this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
if (!this.CallAcutionXOperator.Operator()) return emptyData;
var dayItem=this.MultiDayAfterCloseData[this.CallAcutionXOperator.DayIndex];
var callbackData={Explain:"MultiDayAfterClose", Data:null, DataIndex:null };
callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
callbackData.DayIndex=this.CallAcutionXOperator.DayIndex;
callbackData.Data=this.CallAcutionXOperator.Item;
callbackData.Ver=dayItem.Ver;
return callbackData;
}
return emptyData;
}
this.GetLatestKLineData=function(bCallAuction) //获取最新一个K线数据 bCallAuction=是否包含集合竞价数据
{
var beforeItem=null;
var beforeDataVer=1;
var beforeExplain;
if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
{
var item=this.MultiDayBeforeOpenData[this.MultiDayBeforeOpenData.length-1];
if (item && IFrameSplitOperator.IsNonEmptyArray(item.Data))
{
beforeDataVer=item.Ver;
beforeItem=item.Data[item.Data.length-1];
beforeExplain="MultiDayBeforeOpen";
}
}
else if (this.BeforeOpenData && IFrameSplitOperator.IsNonEmptyArray(this.BeforeOpenData.Data))
{
beforeItem=this.BeforeOpenData.Data[this.BeforeOpenData.Data.length-1];
beforeDataVer=this.BeforeOpenData.Ver;
beforeExplain="BeforeOpen";
}
var afterItem=null;
var afterDataVer=1;
var afterExplain
if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
{
var item=this.MultiDayAfterCloseData[this.MultiDayAfterCloseData.length-1];
if (item && IFrameSplitOperator.IsNonEmptyArray(item.Data))
{
afterDataVer=item.Ver;
afterItem=item.Data[item.Data.length-1];
afterExplain="MultiDayAfterClose";
if (item.Data.length==item.TotalCount) afterItem=null; //收盘以后,显示最后的1分钟价格就可以
}
}
else if (this.AfterOpenData && IFrameSplitOperator.IsNonEmptyArray(this.AfterOpenData.Data))
{
afterItem=this.AfterOpenData.Data[this.AfterOpenData.Data.length-1];
afterDataVer=this.AfterOpenData.Ver;
afterExplain="AfterClose"
}
var dataItem=null;
if (this.Data && IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
var count=this.Data.Data.length;
dataItem=this.Data.Data[count-1];
}
if (!beforeItem && !afterItem && !dataItem) return null;
if (!bCallAuction) return { Type:0, Data:dataItem };
if (!dataItem) return { Type:1 , Data:beforeItem ,Ver: beforeDataVer, Explain:beforeExplain };
if (beforeItem && dataItem) //盘前数据
{
if (beforeItem.Date>dataItem.Date || (beforeItem.Date==dataItem.Date && beforeItem.Time>dataItem.Time && beforeDataVer==1.0)
|| (beforeItem.Date==dataItem.Date && parseInt(beforeItem.Time>dataItem.Time) && beforeDataVer==2.0))
return { Type:2, Data:beforeItem, Ver: beforeDataVer, Explain:beforeExplain};
}
if (afterItem && dataItem) //盘后数据
{
if (afterItem.Date>=dataItem.Date) return { Type:1, Data:afterItem, Ver:afterDataVer, Explain:afterExplain };
}
return { Type:0 ,Data:dataItem };
}
this.GetFormatTitle=function(data) //{ Data:, IsLastOne: }
{
if (!data || !data.Data) return;
var upperSymbol=this.Symbol.toUpperCase();
var defaultfloatPrecision=GetfloatPrecision(this.Symbol); //价格小数位数
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
var item=data.Data;
var isLastOne=data.IsLastOne;
var aryText=[]; //{Color:, Text: }
if(this.IsShowName) aryText.push({Text:this.Name, Color:this.NameColor});
if (this.IsShowDate || this.IsShowTime)
{
var bShowUpdateTime=false; //是否显示了更新时间
if (isLastOne && this.ShowLastDataFormat==1)
{
if (this.Data && this.Data.UpdateTime && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Date) && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Time))
{
var text=IFrameSplitOperator.FormatTimeString(this.Data.UpdateTime.Time, "HH:MM:SS");
aryText.push({Text:text, Color:this.DateTimeColor});
bShowUpdateTime=true;
}
}
if (!bShowUpdateTime)
{
if (this.TimeFormat) //指定时间格式
{
var strDate=null, strTime=null, text=null;
if (this.IsShowDate) strDate=IFrameSplitOperator.FormatDateString("YYYY-MM-DD", item.Date);
if (this.IsShowTime) strTime=IFrameSplitOperator.FormatTimeString(item.Time,this.TimeFormat);
if (strDate && strTime) text=`${strDate} ${strTime}`;
else if (strDate) text=strDate;
else if (strTime) text=strTime;
if (text) aryText.push({Text:text, Color:this.DateTimeColor});
}
else
{
var text=IFrameSplitOperator.FormatDateTimeString(item.DateTime,this.IsShowDate, this.IsShowTime);
aryText.push({Text:text, Color:this.DateTimeColor});
}
}
}
var close=item.Close;
var increase=item.Increase;
var vol=item.Vol;
var amount=item.Amount;
var yClose=item.YClose;
if (!IFrameSplitOperator.IsNumber(yClose)) yClose=this.YClose;
if (isFutures && IFrameSplitOperator.IsNumber(item.YClearing)) yClose=item.YClearing; //期货使用昨结算
if (IFrameSplitOperator.IsNumber(close))
{
var color=this.GetColor(close,yClose);
var text=g_JSChartLocalization.GetText('MTitle-Close',this.LanguageID)+close.toFixed(defaultfloatPrecision);
aryText.push({Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(increase))
{
var color=this.GetColor(increase,0);
var text=g_JSChartLocalization.GetText('MTitle-Increase',this.LanguageID)+increase.toFixed(2)+'%';
aryText.push({Text:text, Color:color});
}
var isShowAvPrice=true;
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsET(upperSymbol) && !MARKET_SUFFIX_NAME.IsETShowAvPrice(upperSymbol)) isShowAvPrice=false;
else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) isShowAvPrice=false;
if (IFrameSplitOperator.IsNumber(item.AvPrice) && isShowAvPrice && this.IsShowAveragePrice)
{
var color=this.GetColor(item.AvPrice,yClose);
var text=g_JSChartLocalization.GetText('MTitle-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision);
aryText.push({Text:text, Color:color});
}
if (IFrameSplitOperator.IsNumber(vol))
{
var text=g_JSChartLocalization.GetText('MTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
aryText.push({Text:text, Color:this.VolColor});
}
if (IFrameSplitOperator.IsNumber(amount))
{
var text=g_JSChartLocalization.GetText('MTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(amount,2,this.LanguageID);
aryText.push({Text:text, Color:this.AmountColor});
}
if (IFrameSplitOperator.IsNumber(item.Position))
{
var text=g_JSChartLocalization.GetText('MTitle-Position',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Position,2,this.LanguageID);
aryText.push({Text:text, Color:this.VolColor});
}
if (isLastOne && this.ShowLastDataFormat==0) //显示数据最后的更新时间
{
if (this.Data && this.Data.UpdateTime && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Date) && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Time))
{
var text=g_JSChartLocalization.GetText('MTitle-UpdateTime',this.LanguageID)+IFrameSplitOperator.FormatTimeString(this.Data.UpdateTime.Time, "HH:MM:SS");
aryText.push({Text:text, Color:this.DateTimeColor});
}
}
//叠加股票的名字
if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
{
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol || !item.Title) continue;
var clrText=item.Color;
var text=`[${item.Title}]`;
aryText.push({Text:text, Color:clrText});
}
}
return { AryText:aryText };
}
this.DrawItem=function(item, isLastOne) //isLastOne 是否是最后一个数据
{
if (!item) return;
var pixelRatio=GetDevicePixelRatio();
var isHScreen=this.Frame.IsHScreen===true;
var border=this.Frame.GetBorder();
var left=border.Left;
var bottom=border.Top-this.Frame.ChartBorder.Top/2;
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
this.Canvas.font=this.Font;
if (isHScreen)
{
if (this.Frame.ChartBorder.Right<5*pixelRatio) return;
var left=2;
var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示
var xText=border.ChartWidth;
var yText=border.Top;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
}
else
{
if (this.Frame.ChartBorder.Top<5*pixelRatio) return;
}
this.Canvas.textAlign="left";
if (this.TitleBaseLine==0) //上
{
this.Canvas.textBaseline="top";
bottom=2*pixelRatio;
}
else if (this.TitleBaseLine==2) //下
{
this.Canvas.textBaseline="bottom";
var bottom=border.Top
}
else //中
{
this.Canvas.textBaseline="middle";
}
var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
var titleData=this.GetFormatTitle({ Data:item, IsLastOne:isLastOne });
if (titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
{
for(var i=0;i<titleData.AryText.length;++i)
{
var item=titleData.AryText[i];
if (!this.DrawText(item.Text,item.Color,position)) break;
}
}
}
//盘前 盘后数据格式化
this.FormatCallAuctionTitle=function(data)
{
var aryText=[] //{ Color: Text: }
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
//股票名称
if (this.IsShowName) aryText.push({Text:this.Name, Color:this.NameColor});
if (data && data.Data)
{
var item=data.Data;
var text, strTime, strDate;
strDate=IFrameSplitOperator.FormatDateString(item.Date);
var yClose=item.YClose;
//时间
if (data.Ver==1.0) strTime=IFrameSplitOperator.FormatTimeString(item.Time,"HH:MM");
else strTime=IFrameSplitOperator.FormatTimeString(item.Time,"HH:MM:SS");
if (data.Explain=="MultiDayBeforeOpen"|| data.Explain=="MultiDayAfterClose") text=`${strDate} ${strTime}`;
else text=strTime;
aryText.push({Text:text, Color:this.DateTimeColor});
//匹配价
if(IFrameSplitOperator.IsNumber(item.Price) && this.CallAuctionShowTitle.has("MTitle-AC-Price"))
{
var color=this.GetColor(item.Price,yClose);
var filedName='MTitle-AC-Price';
if (data.Ver==1.0) filedName="MTitle-Close";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+item.Price.toFixed(defaultfloatPrecision);
aryText.push({Text:text, Color:color});
}
//竞价涨幅
if (IFrameSplitOperator.IsPlusNumber(yClose) && IFrameSplitOperator.IsNumber(item.Price) && this.CallAuctionShowTitle.has("MTitle-AC-Increase"))
{
var value=(item.Price-yClose)/yClose*100;
var color=this.GetColor(value,0);
var filedName='MTitle-AC-Increase';
if (data.Ver==1.0) filedName="MTitle-Increase";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+value.toFixed(2)+"%";
aryText.push({Text:text, Color:color});
}
//均价
if (IFrameSplitOperator.IsNumber(item.AvPrice) && this.CallAuctionShowTitle.has("MTitle-AC-AvPrice"))
{
var color=this.GetColor(item.AvPrice,yClose);
var text=g_JSChartLocalization.GetText('MTitle-AC-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision);
aryText.push({Text:text, Color:color});
}
//匹配量
if (IFrameSplitOperator.IsNumber(item.Vol[0]) && this.CallAuctionShowTitle.has("MTitle-AC-Vol"))
{
var filedName='MTitle-AC-Vol';
if (data.Ver==1.0) filedName="MTitle-Vol";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[0],2);
aryText.push({Text:text, Color:this.VolColor});
}
//未匹配量
if (IFrameSplitOperator.IsNumber(item.Vol[1]) && this.CallAuctionShowTitle.has("MTitle-AC-NotMatchVol"))
{
var text=g_JSChartLocalization.GetText('MTitle-AC-NotMatchVol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[1],2);
aryText.push({Text:text, Color:this.VolColor});
}
if (item.ExtendData && IFrameSplitOperator.IsNonEmptyArray(item.ExtendData.Amount))
{
var aryAmount=item.ExtendData.Amount;
if (IFrameSplitOperator.IsNumber(aryAmount[0]) && this.CallAuctionShowTitle.has("MTitle-AC-Amount")) //匹配量金额
{
var text=g_JSChartLocalization.GetText('MTitle-AC-Amount',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(aryAmount[0],2);
aryText.push({Text:text, Color:this.AmountColor});
}
if (IFrameSplitOperator.IsNumber(aryAmount[1]) && this.CallAuctionShowTitle.has("MTitle-AC-NotMatchAmount")) //未匹配量金额
{
var text=g_JSChartLocalization.GetText('MTitle-AC-NotMatchAmount',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(aryAmount[1],2);
aryText.push({Text:text, Color:this.AmountColor});
}
}
}
return { AryText:aryText };
}
this.DrawCallAuction=function() //集合竞价标题
{
var isHScreen=this.Frame.IsHScreen===true;
var border=this.Frame.GetBorder();
var pixelRatio=GetDevicePixelRatio();
var left=border.Left;
var bottom=border.Top-this.Frame.ChartBorder.Top/2;
var bDraw=true;
if (isHScreen)
{
if (this.Frame.ChartBorder.Right<5*pixelRatio) return;
var left=2;
var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示
var xText=border.ChartWidth;
var yText=border.Top;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
}
else
{
if (this.Frame.ChartBorder.Top<5) bDraw=false;
}
this.Canvas.textAlign="left";
this.Canvas.font=this.Font;
if (this.TitleBaseLine==0) //上
{
this.Canvas.textBaseline="top";
bottom=2*pixelRatio;
}
else if (this.TitleBaseLine==2) //下
{
this.Canvas.textBaseline="bottom";
var bottom=border.Top
}
else //中
{
this.Canvas.textBaseline="middle";
}
var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
var auctionData=this.GetCurrentAuctionData();
var titleData=this.FormatCallAuctionTitle(auctionData);
if (bDraw && titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
{
for(var i=0;i<titleData.AryText.length;++i)
{
var item=titleData.AryText[i];
if (!this.DrawText(item.Text,item.Color,position)) break;
}
}
this.OnDrawCallAuctionEventCallback(auctionData);
}
this.OnDrawCallAuctionEventCallback=function(drawData)
{
if (this.OnDrawEvent && this.OnDrawEvent.Callback)
{
var data={ Draw: drawData, Name:this.ClassName };
this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
}
if (this.OnMouseMoveEvent && this.OnMouseMoveEvent.Callback)
{
var data={ Draw: drawData, Name:this.ClassName };
this.OnMouseMoveEvent.Callback(this.OnDrawEvent,data,this);
}
}
this.DrawNone=function()
{
this.OnDrawEventCallback(null);
if (this.IsAlwaysShowLastData)
{
this.Canvas.save();
this.DrawLastDataItem();
this.Canvas.restore();
}
}
this.Draw=function()
{
this.LastShowData=null;
this.GlobalOption=this.Frame.GlobalOption;
if (!this.IsShow)
{ //隐藏标题 并且没有回调事件
var bEvent=(this.OnDrawEvent && this.OnDrawEvent.Callback) || (this.OnMouseMoveEvent && this.OnMouseMoveEvent.Callback);
if (!bEvent) return;
}
if (this.PointInfo &&
( this.PointInfo.ClientPos==2 || this.PointInfo.ClientPos==3 ||
(this.PointInfo.ClientPos>=200&& this.PointInfo.ClientPos<=299) ||
(this.PointInfo.ClientPos>=300&& this.PointInfo.ClientPos<=399) ) )
{ //集合竞价区域
this.Canvas.save();
this.DrawCallAuction();
this.Canvas.restore();
return;
}
if (!this.Data || !this.Data.Data || this.Data.Data.length<=0)
{
this.DrawNone();
return;
}
if (this.CursorIndex==null && !(this.GlobalOption && this.GlobalOption.IsDisplayLatest))
{
this.DrawNone();
return;
}
this.Canvas.font=this.Font;
this.SpaceWidth = this.Canvas.measureText('0').width;
var isShowLastData=false;
if (this.DrawStatus && this.DrawStatus.IsTitleShowLatestData)
{
var status=this.DrawStatus;
if (!IFrameSplitOperator.IsNumber(status.FrameID) || status.FrameID<0)
isShowLastData=true;
else if (status.CorssCursorTouchEnd && status.IsOnTouch==false)
isShowLastData=true;
}
else if (this.GlobalOption && this.GlobalOption.IsDisplayLatest)
{
isShowLastData=true;
}
var isLastOne=false;
if (isShowLastData)
{
var item=null;
var lastItem=this.GetLatestKLineData(true);
if (lastItem && lastItem.Type==0) item=lastItem.Data;
isLastOne=true;
}
else
{
//var index=Math.abs(this.CursorIndex-0.5);
var index=this.CursorIndex;
index=parseInt(index.toFixed(0));
var dataIndex=index+this.Data.DataOffset;
if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1;
var item=this.Data.Data[dataIndex];
if (dataIndex==this.Data.Data.length-1) isLastOne=true;
}
this.LastShowData=item;
this.Canvas.save();
this.OnDrawEventCallback(item);
if (this.IsAlwaysShowLastData)
{
this.DrawLastDataItem();
}
else
{
this.DrawItem(item,isLastOne);
}
this.Canvas.restore();
}
this.DrawCallAuctionItem=function(callAuctionItem, isLastOne)
{
if (!callAuctionItem) return;
var item=callAuctionItem.Data;
var dataVersion=callAuctionItem.Ver;
var isHScreen=this.Frame.IsHScreen===true;
var border=this.Frame.GetBorder();
var left=border.Left;
var bottom=border.Top-this.Frame.ChartBorder.Top/2;
//var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
var bDraw=true;
if (isHScreen)
{
var left=2;
var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示
var xText=border.ChartWidth;
var yText=border.Top;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
}
else
{
if (this.Frame.ChartBorder.Top<5) bDraw=false;
}
this.Canvas.textAlign="left";
this.Canvas.font=this.Font;
if (this.TitleBaseLine==0) //上
{
this.Canvas.textBaseline="top";
bottom=2*GetDevicePixelRatio();
}
else if (this.TitleBaseLine==2) //下
{
this.Canvas.textBaseline="bottom";
var bottom=border.Top
}
else //中
{
this.Canvas.textBaseline="middle";
}
var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
var titleData=this.FormatCallAuctionTitle(callAuctionItem);
if (bDraw && titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
{
for(var i=0;i<titleData.AryText.length;++i)
{
var item=titleData.AryText[i];
if (!this.DrawText(item.Text,item.Color,position)) break;
}
}
/*
if(bDraw && this.IsShowName)
{
if (!this.DrawText(this.Name,this.NameColor,position)) return;
}
var time=item.Time;
var strTime;
if (dataVersion==1.0) strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM");
else strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
strTime=`${strDate} ${strTime}`;
if (bDraw && this.IsShowTime && strTime )
{
if (!this.DrawText(strTime,this.DateTimeColor,position)) return;
}
//匹配价
if (bDraw && item && IFrameSplitOperator.IsNumber(item.Price) && this.CallAuctionShowTitle.has("MTitle-AC-Price"))
{
var color=this.GetColor(item.Price,this.YClose);
var filedName='MTitle-AC-Price';
if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Close";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+item.Price.toFixed(defaultfloatPrecision);
if (!this.DrawText(text,color,position)) return;
}
//竞价涨幅
if (bDraw && item && IFrameSplitOperator.IsPlusNumber(this.YClose) && IFrameSplitOperator.IsNumber(item.Price) && this.CallAuctionShowTitle.has("MTitle-AC-Increase"))
{
var value=(item.Price-this.YClose)/this.YClose*100;
var color=this.GetColor(value,0);
var filedName='MTitle-AC-Increase';
if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Increase";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+value.toFixed(2)+"%";
if (!this.DrawText(text,color,position)) return;
}
if (dataVersion==3.0)
{
if (bDraw && item && IFrameSplitOperator.IsNumber(item.AvPrice) && this.CallAuctionShowTitle.has("MTitle-AC-AvPrice"))
{
var color=this.GetColor(item.Price,this.YClose);
var text=g_JSChartLocalization.GetText('MTitle-AC-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision);
if (!this.DrawText(text,color,position)) return;
}
}
//匹配量
if (bDraw && IFrameSplitOperator.IsNumber(item.Vol[0]) && this.CallAuctionShowTitle.has("MTitle-AC-Vol"))
{
var filedName='MTitle-AC-Vol';
if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Vol";
var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[0],2);
if (!this.DrawText(text,this.VolColor,position)) return;
}
//未匹配量
if (bDraw && IFrameSplitOperator.IsNumber(item.Vol[1]) && this.CallAuctionShowTitle.has("MTitle-AC-NotMatchVol"))
{
var text=g_JSChartLocalization.GetText('MTitle-AC-NotMatchVol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[1],2);
if (!this.DrawText(text,this.VolColor,position)) return;
}
if (bDraw)
{
if (item.ExtendData && IFrameSplitOperator.IsNonEmptyArray(item.ExtendData.Amount))
{
var aryAmount=item.ExtendData.Amount;
if (IFrameSplitOperator.IsNumber(aryAmount[0]) && this.CallAuctionShowTitle.has("MTitle-AC-Amount")) //匹配量金额
{
var text=g_JSChartLocalization.GetText('MTitle-AC-Amount',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(aryAmount[0],2);
if (!this.DrawText(text,this.AmountColor,position)) return;
}
if (IFrameSplitOperator.IsNumber(aryAmount[1]) && this.CallAuctionShowTitle.has("MTitle-AC-NotMatchAmount")) //未匹配量金额
{
var text=g_JSChartLocalization.GetText('MTitle-AC-NotMatchAmount',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(aryAmount[1],2);
if (!this.DrawText(text,this.AmountColor,position)) return;
}
}
}
*/
}
this.DrawLastDataItem=function()
{
var lastItem=this.GetLatestKLineData(true);
if (lastItem)
{
if (lastItem.Type==0)
this.DrawItem(lastItem.Data, true);
else if (lastItem.Type==1 || lastItem.Type==2)
this.DrawCallAuctionItem(lastItem, true);
}
}
}
//字符串输出格式
var STRING_FORMAT_TYPE =
{
DEFAULT: 1, //默认 2位小数 单位自动转化 (万 亿)
ORIGINAL:2, //原始数据
INTEGER:3, //整形数据输出 如果不是整形使用 DEFAULT
THOUSANDS:21, //千分位分割
};
function DynamicTitleData(data,name,color)
{
this.Data=data;
this.Name=name;
this.Color=color; //字体颜色
this.DataType; //数据类型
this.ChartClassName; //图形类名
this.StringFormat=STRING_FORMAT_TYPE.DEFAULT; //字符串格式
this.FloatPrecision=2; //小数位数
this.IsShow=true; //是否显示
this.Callback; //绘制标题回调
this.ExtendData; //扩展数据
}
function DynamicChartTitlePainting()
{
this.newMethod=IChartTitlePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DynamicChartTitlePainting';
this.IsDynamic=true;
this.Data=[];
this.Explain;
this.ColorIndex; //五彩K线名字 {Name:'名字'}
this.IsShowColorIndexTitle=true;
this.IsShowUpDownArrow=true; //指标数据是否显示 上涨下跌箭头
this.TitleArrowType=0; //指标数据上涨下跌箭头类型 0=独立颜色 1=跟指标颜色一致
this.IsShowIndexName=true; //是否显示指标名字
this.IsShowIndexTitle=true; //是否显示指标标题信息
this.IsShowNameArrow=false;
this.NameArrowConfig=CloneData(g_JSChartResource.IndexTitle.NameArrow);
this.TradeIndex; //专家系统名字{Name:'名字', Param:'参数'}
this.IsShowTradeIndexTitle=true;
this.OverlayIndex=new Map(); //叠加指标 key=Identify value={ Data:数据, Title:标题, Identify:标识}
this.IsShowOverlayIndexName=true; //是否显示叠加指标名字
this.OverlayIndexType={ Position:0, LineSpace:5, BGColor:g_JSChartResource.OverlayIndexTitleBGColor }; //Position 0=主图指标后面显示 1=叠加指标单行显示
//LineSpace 行间距
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.TitleRect; //指标名字显示区域
this.IsDrawTitleBG=false; //是否绘制指标名字背景色
this.BGColor=g_JSChartResource.IndexTitleBGColor;
this.BGBorderColor=g_JSChartResource.IndexTitleBorderColor;
this.BGBorderMoveOnColor=g_JSChartResource.IndexTitleBorderMoveOnColor;
this.BorderRoundRadius=2; //圆角矩形角度
this.NameButtonStyle=g_JSChartResource.IndexTitleBorderStyle,
this.OnDrawEvent;
this.ParamSpace=2; //参数显示的间距
this.TitleSpace=2; //指标名字和参数之间的间距
this.TitleColor=g_JSChartResource.IndexTitleColor; //指标名字颜色
this.SelectedColor=g_JSChartResource.IndexTitleSelectedColor;
this.IsKLineFrame=false; //是否是K线框架标题
this.IsMinuteFrame=false;
this.Identify; //指标ID
this.SelectedChart; //选中的图形
this.ArgumentsText; //参数信息
this.MerginLeft=g_JSChartResource.IndexTitleMerginLeft; //标题输出左边间距
this.Buttons=[]; //按钮
this.UpDownArrowConfig=
{
UpColor:g_JSChartResource.IndexTitle.UpDownArrow.UpColor,
DownColor:g_JSChartResource.IndexTitle.UpDownArrow.DownColor,
UnchangeColor:g_JSChartResource.IndexTitle.UpDownArrow.UnchangeColor
};
//动态标题
//动态标题
this.DynamicTitle={ OutName:null, OutValue:null };
this.OverlayDynamicTitle=new Map(); //key , value={ OutName, OutValue }
this.IsShowMainIndexTitle=true; //是否显示主图指标标题
this.MainTitlePaint=null; //主标题
this.ReloadResource=function()
{
this.Font=g_JSChartResource.TitleFont;
this.TitleColor=g_JSChartResource.DefaultTextColor;
this.OverlayIndexType.BGColor=g_JSChartResource.OverlayIndexTitleBGColor;
}
this.SetDynamicTitleData=function(outName, args, data)
{
if (!data.OutName) data.OutName=new Map();
else data.OutName.clear();
if (!data.OutValue) data.OutValue=new Map();
else data.OutValue.clear();
var mapArgs=new Map();
for(var i in args)
{
var item=args[i];
mapArgs.set(`{${item.Name}}`, item);
}
for(var i in outName)
{
var item=outName[i];
if (item.DynamicName)
{
var aryFond = item.DynamicName.match(/{\w*}/i);
if (!aryFond || aryFond.length<=0)
{
data.OutName.set(item.Name, item.DynamicName);
}
else
{
var dyName=item.DynamicName;
var bFind=true;
for(var j=0;j<aryFond.length;++j)
{
var findItem=aryFond[j];
if (mapArgs.has(findItem))
{
var value=mapArgs.get(findItem).Value;
dyName=dyName.replace(findItem,value.toString());
}
else
{
bFind=false;
break;
}
}
if (bFind) data.OutName.set(item.Name, dyName);
}
}
if (item.DynamicValue)
{
data.OutValue.set(item.Name, item.DynamicValue);
}
}
}
this.SetDynamicTitle=function(outName, args, overlayID)
{
if (IFrameSplitOperator.IsString(overlayID))
{
var dynamicTitle=null;
if (this.OverlayDynamicTitle.has(overlayID))
{
dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
}
else
{
dynamicTitle={ OutName:null, OutValue:null };
this.OverlayDynamicTitle.set(overlayID, dynamicTitle);
}
this.SetDynamicTitleData(outName, args, dynamicTitle);
}
else
{
this.SetDynamicTitleData(outName, args, this.DynamicTitle);
}
}
this.GetDynamicOutName=function(key, overlayID)
{
if (IFrameSplitOperator.IsString(overlayID))
{
if (!this.OverlayDynamicTitle.has(overlayID)) return null;
var dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
var outName=dynamicTitle.OutName;
}
else
{
var outName=this.DynamicTitle.OutName;
}
if (!outName || outName.size<=0) return null;
if (!outName.has(key)) return null;
return outName.get(key);
}
this.GetDynamicOutValue=function(key, value)
{
var outValue=this.DynamicTitle.OutValue;
if (!outValue || outValue.size<=0) return null;
if (!outValue.has(key)) return null;
var strFormat=outValue.get(key);
strFormat=strFormat.replace('{Value}',value);
return strFormat;
}
this.IsClickTitle=function(x,y) //是否点击了指标标题
{
if (!this.TitleRect) return false;
if (x>this.TitleRect.Left && x<this.TitleRect.Left+this.TitleRect.Width && y>this.TitleRect.Top && y<this.TitleRect.Top+this.TitleRect.Height)
{
return true;
}
return false;
}
this.FormatValue=function(value,item)
{
if (item.StringFormat==STRING_FORMAT_TYPE.DEFAULT)
return IFrameSplitOperator.FormatValueString(value,item.FloatPrecision,this.LanguageID);
else if (item.StringFormat==STRING_FORMAT_TYPE.THOUSANDS)
return IFrameSplitOperator.FormatValueThousandsString(value,item.FloatPrecision);
else if (item.StringFormat==STRING_FORMAT_TYPE.ORIGINAL)
return value.toFixed(item.FloatPrecision).toString();
else if (item.StringFormat==STRING_FORMAT_TYPE.INTEGER)
return IFrameSplitOperator.FromatIntegerString(value,item.FloatPrecision,this.LanguageID);
}
this.FormatMultiReport=function(data,format)
{
var text="";
for(var i in data)
{
var item = data[i];
let quarter=item.Quarter;
let year=item.Year;
let value=item.Value;
if (text.length>0) text+=',';
text+=year.toString();
switch(quarter)
{
case 1:
text+='一季报 ';
break;
case 2:
text+='半年报 ';
break;
case 3:
text+='三季报 ';
break;
case 4:
text+='年报 ';
break;
}
text+=this.FormatValue(value,format);
}
return text;
}
this.FromatMultiDataLine=function(value, dataInfo)
{
var text="";
if (Array.isArray(value))
{
for(var i=0;i<value.length;++i)
{
var item=value[i];
if (item.Type==0) continue;
if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
var strValue=this.FormatValue(item.Value,dataInfo);
if (text.length>0) text+=',';
text+=strValue;
}
}
else
{
if (value.Type!=0 && IFrameSplitOperator.IsNumber(value.Value))
{
text=this.FormatValue(value.Value,dataInfo);
}
}
if (text.length<=0) return null;
return text;
}
//多变量输出
this.FromatStackedBarTitle=function(aryBar, dataInfo)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryBar)) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(dataInfo.Color)) return null;
var aryText=[];
for(var i=0;i<aryBar.length;++i)
{
var value=aryBar[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var item={ Text:value.toFixed(2) };
if (dataInfo.Name && dataInfo.Name[i]) item.Name=dataInfo.Name[i];
item.Color=dataInfo.Color[i];
aryText.push(item);
}
if (aryText.length<=0) return null;
return aryText;
}
this.ForamtMultiLineTitle=function(dataIndex, dataInfo)
{
if (!IFrameSplitOperator.IsNonEmptyArray(dataInfo.Lines)) return null;
var aryText=[];
for(var i=0;i<dataInfo.Lines.length;++i)
{
var line=dataInfo.Lines[i];
for(var j=0;j<line.Point.length;++j)
{
var item=line.Point[j];
if (item.Index==dataIndex)
{
var item={ Text:item.Value.toFixed(2)};
if (aryText.length==0) item.Name=dataInfo.Name;
item.Color=line.Color;
aryText.push(item);
break;
}
}
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryText)) return null;
return aryText;
}
this.ForamtMultiPointTitle=function(dataIndex, dataInfo)
{
if (!IFrameSplitOperator.IsNonEmptyArray(dataInfo.PointGroup)) return null;
var aryText=[];
for(var i=0;i<dataInfo.PointGroup.length;++i)
{
var groupItem=dataInfo.PointGroup[i];
for(var j=0;j<groupItem.Point.length;++j)
{
var item=groupItem.Point[j];
if (item.Index==dataIndex)
{
var item={ Text:item.Value.toFixed(2)};
if (aryText.length==0) item.Name=dataInfo.Name;
item.Color=groupItem.BGColor;
aryText.push(item);
break;
}
}
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryText)) return null;
return aryText;
}
this.FormatVPVRTitle=function(pt, dataInfo)
{
var chart=dataInfo.Chart;
var aryText=[];
if (chart.VolType==0)
{
var item={ Text:" Up/Down ", Color:this.TitleColor };
aryText.push(item);
}
else
{
var item={ Text:" Total ",Color:this.TitleColor };
aryText.push(item);
}
if (!IFrameSplitOperator.IsNumber(pt.Y)) return aryText;
var top=this.Frame.ChartBorder.GetTopEx();
var bottom=this.Frame.ChartBorder.GetBottomEx();
if (pt.Y<top || pt.Y>bottom) return aryText;
var yPrice=this.Frame.GetYData(pt.Y);
var find=null;
for(var i=0; i<dataInfo.Data.Data.length; ++i)
{
var item=dataInfo.Data.Data[i];
if (yPrice>=item.Price-dataInfo.Data.PriceOffset/2 && yPrice<item.Price+dataInfo.Data.PriceOffset/2)
{
find=item;
break;
}
}
if (!find) return null;
if (chart.VolType==0)
{
var total=0;
for(var i=0;i<find.Vol.length;++i)
{
var volItem=find.Vol[i];
if (!IFrameSplitOperator.IsNumber(volItem.Value)) continue;
var item={ Text:IFrameSplitOperator.FormatVolString(volItem.Value,this.LanguageID) };
total+=volItem.Value;
if (IFrameSplitOperator.IsNumber(volItem.ColorID)) item.Color=chart.BarColor[volItem.ColorID];
else if (volItem.Color) item.Color=volItem.Color;
aryText.push(item);
}
var item={Text:IFrameSplitOperator.FormatVolString(total,this.LanguageID),Color:this.TitleColor};
aryText.push(item);
}
else
{
if (find.TotalVol && IFrameSplitOperator.IsNumber(find.TotalVol.Value))
{
var item={Text:IFrameSplitOperator.FormatVolString(find.TotalVol.Value,this.LanguageID) };
if (IFrameSplitOperator.IsNumber(find.TotalVol.ColorID)) item.Color=chart.BarColor[find.TotalVol.ColorID];
else if (find.TotalVol.Color) item.Color=find.TotalVol.Color;
aryText.push(item);
}
}
return aryText;
}
this.IsShowLastData=function()
{
var isShowLastData=false;
if (this.DrawStatus && this.DrawStatus.IsTitleShowLatestData)
{
var status=this.DrawStatus;
if (!IFrameSplitOperator.IsNumber(status.FrameID) || status.FrameID<0)
isShowLastData=true;
else if (status.CorssCursorTouchEnd && status.IsOnTouch==false)
isShowLastData=true;
}
else if (this.GlobalOption && this.GlobalOption.IsDisplayLatest)
{
isShowLastData=true;
}
return isShowLastData;
}
this.OnDrawTitleEvent=function()
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
if (!event) return;
var data={ Index:null, Data:this.Data ,Title:this.Title, Script:this.Script, FrameID:this.Frame.Identify, OverlayIndex:this.OverlayIndex, IsShowTitleOnly:false };
if (this.ArgumentsText) data.ArgumentsText=this.ArgumentsText;
if (this.Frame && this.Frame.ChartBorder) data.IsShowTitleOnly=this.Frame.ChartBorder.IsShowTitleOnly;
if (IFrameSplitOperator.IsNumber(this.CursorIndex))
{
var index=Math.abs(this.CursorIndex);
index=parseInt(index.toFixed(0));
data.Index=index; //当前屏数据索引
}
var pixelTatio = GetDevicePixelRatio();
var border=this.Frame.GetBorder();
data.Left=border.LeftEx/pixelTatio;
data.Top=border.Top/pixelTatio;
data.Right=border.RightEx/pixelTatio;
event.Callback(event,data,this);
}
this.IsSelectedChart=function(id)
{
if (!id) return false;
if (!this.SelectedChart) return false
if (!this.SelectedChart.Selected) return false
return this.SelectedChart.Selected.Identify==id;
}
this.Draw=function(moveonPoint, mouseStatus)
{
this.Buttons=[];
if (this.Frame.IsMinSize) return;
this.IsKLineFrame= this.Frame.IsKLineFrame(false);
this.IsMinuteFrame=this.Frame.IsMinuteFrame(false);
this.IsDrawTitleBG=this.Frame.IsDrawTitleBG;
this.IsShowNameArrow=this.Frame.IsShowNameArrow;
this.IsShowUpDownArrow=this.Frame.IsShowTitleArrow;
this.TitleArrowType=this.Frame.TitleArrowType;
this.IsShowIndexName=this.Frame.IsShowIndexName;
this.IsShowOverlayIndexName=this.Frame.IsShowOverlayIndexName;
this.OverlayIndexType.Position=this.Frame.OverlayIndexType.Position;
this.OverlayIndexType.LineSpace=this.Frame.OverlayIndexType.LineSpace;
this.ParamSpace=this.Frame.IndexParamSpace;
this.TitleSpace=this.Frame.IndexTitleSpace;
this.TitleRect=null;
this.GlobalOption=this.Frame.GlobalOption;
this.OnDrawTitleEvent();
if (this.Frame.IsShowIndexTitle==false) return;
if (g_JSChartResource.IsDOMFrameTitle===true) return;
if (!this.Data) return;
if (this.Frame.ChartBorder.TitleHeight<5) return;
if (this.CursorIndex==null && !(this.GlobalOption && this.GlobalOption.IsDisplayLatest)) return;
if (this.Frame.IsHScreen===true)
{
this.Canvas.save();
this.HScreenDraw();
this.Canvas.restore();
/* 测试用
if (this.TitleRect)
{
this.Canvas.strokeStyle='rgba(200,0,50,0.5)';
this.Canvas.strokeRect(ToFixedPoint(this.TitleRect.Left),ToFixedPoint(this.TitleRect.Top),ToFixedRect(this.TitleRect.Width),ToFixedRect(this.TitleRect.Height));
}
*/
return;
}
var left=this.Frame.ChartBorder.GetLeft()+this.MerginLeft;
var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2; //上下居中显示
var right=this.Frame.ChartBorder.GetRight();
var toolbarInfo={ Width:0, YCenter:bottom };
this.DrawToolbar(toolbarInfo,moveonPoint, mouseStatus);
left+=toolbarInfo.Width;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.font=this.Font;
var pixelRatio=GetDevicePixelRatio();
if (this.Title && this.IsShowIndexName && this.IsShowMainIndexTitle)
{
if (this.IsDrawTitleBG)
{
var rtButton={ Left:left, YCenter:bottom, Width:0 };
this.DrawNameButton(rtButton, moveonPoint, mouseStatus);
this.Buttons.push({ ID:JSCHART_BUTTON_ID.INDEX_NAME_BUTTON, Rect:rtButton, FrameID:this.Frame.Identify, Type:2 }); //Type 0=主图按钮 1=附图按钮 2=主图指标名字按钮
if (this.IsSelectedChart(this.Identify))
this.DrawSelectedLine(left, bottom, textWidth);
this.TitleRect=rtButton;
left+=rtButton.Width+3*pixelRatio;
left+=this.TitleSpace;
}
else
{
var textWidth=this.Canvas.measureText(this.Title).width+2;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(this.Title,left,bottom,textWidth);
if (this.IsSelectedChart(this.Identify))
this.DrawSelectedLine(left, bottom, textWidth);
left+=textWidth;
left+=this.TitleSpace;
}
}
if (this.ArgumentsText && this.IsShowIndexName && this.IsShowMainIndexTitle)
{
var textWidth=this.Canvas.measureText(this.ArgumentsText).width+2;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(this.ArgumentsText,left,bottom,textWidth);
left+=textWidth;
left+=this.TitleSpace;
}
var isShowLastData=this.IsShowLastData();
var lockRect=this.Frame.GetLockRect();
if (lockRect) //指标上锁区域不显示动态标题
{
var index=Math.abs(this.CursorIndex);
if (this.IsKLineFrame) index=this.CursorIndex;
var x=this.Frame.GetXFromIndex(index.toFixed(0));
if (x>=lockRect.Left) return;
if (isShowLastData) return;
}
var rtText={ Left:left, Right:left };
if (this.IsMinuteFrame && this.PointInfo && ( this.PointInfo.ClientPos==2 || this.PointInfo.ClientPos==3 || (this.PointInfo.ClientPos>=200&& this.PointInfo.ClientPos<=299) || (this.PointInfo.ClientPos>=300&& this.PointInfo.ClientPos<=399) ))
{
var result={ PreventDefault:false }
this.DrawMainCallAuction({ Left:left, Right:right, Bottom:bottom }, rtText, result);
if (result.PreventDefault===false) this.DrawMainIndexTitle({ Left:left, Right:right, Bottom:bottom }, isShowLastData, rtText);
}
else
{
this.DrawMainIndexTitle({ Left:left, Right:right, Bottom:bottom }, isShowLastData, rtText);
}
left=rtText.Left;
if (this.Explain) //说明信息
{
this.Canvas.fillStyle=this.TitleColor;
var text="说明:"+this.Explain;
var textWidth=this.Canvas.measureText(text).width+2;
if (left+textWidth<right)
{
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
if (this.ColorIndex && this.IsShowColorIndexTitle)
{
this.Canvas.fillStyle=g_JSChartResource.Title.ColorIndexColor;
var tradeName=this.ColorIndex.Name+this.ColorIndex.Param;
var textWidth=this.Canvas.measureText(tradeName).width+2; //后空2个像素
this.Canvas.fillText(tradeName,left,bottom,textWidth);
left+=textWidth;
}
if (this.TradeIndex && this.IsShowTradeIndexTitle)
{
this.Canvas.fillStyle=g_JSChartResource.Title.TradeIndexColor;
var tradeName=this.TradeIndex.Name+this.TradeIndex.Param;
var textWidth=this.Canvas.measureText(tradeName).width+2; //后空2个像素
this.Canvas.fillText(tradeName,left,bottom,textWidth);
left+=textWidth;
}
if (this.OverlayIndexType.Position==1)
{
if (!this.Frame.ChartBorder.IsShowTitleOnly)
this.DrawOverlayIndexSingleLine(moveonPoint, mouseStatus);
}
else
{
var xOffset=10*GetDevicePixelRatio(); //主指标区分开 间距多空点
if (!this.IsShowMainIndexTitle) xOffset=0;
this.DrawOverlayIndex(left+xOffset);
}
}
this.GetTitleItem=function(item, isShowLastData, titleIndex)
{
if (!item || !item.Data || !item.Data.Data) return null;;
if (Array.isArray(item.Data.Data) && item.Data.Data.length<=0) return null;
if (item.IsShow===false) return null;
if (item.IsVisible===false) return null;
var valueText=null; //单值
var aryText=null; //多值
var value=null;
var preVaildItem=null;
if (item.DataType=="StraightLine") //直线只有1个数据
{
value=item.Data.Data[0];
valueText=this.FormatValue(value,item);
}
else if (item.ChartClassName=="ChartVolProfileVisibleRange")
{
aryText=this.FormatVPVRTitle(this.LastPoint, item);
if (!aryText) return null;
return { Text:null, ArrayText:aryText };
}
else
{
if (isShowLastData)
{
var dataIndex=item.Data.Data.length-1; //显示最后一个数据
}
else
{
var index=Math.abs(this.CursorIndex);
index=parseInt(index.toFixed(0));
if (this.IsKLineFrame) index=this.CursorIndex;
var dataIndex=item.Data.DataOffset+index;
if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1;
if (dataIndex<0) return null;
}
if (item.DataType=="ChartMultiLine") //多线段数据
{
aryText=this.ForamtMultiLineTitle(dataIndex, item);
if (!aryText) return null;
return { Text:null, ArrayText:aryText };
}
else if (item.DataType=="ChartMultiPoint")
{
aryText=this.ForamtMultiPointTitle(dataIndex, item);
if (!aryText) return null;
return { Text:null, ArrayText:aryText };
}
value=item.Data.Data[dataIndex];
if (value==null && item.ChartClassName=="ChartStepLine") //当前值无效,上一个值延续
{
preVaildItem=this.GetPreVaildItem(item.Data.Data, dataIndex);
if (!preVaildItem) return null;
preText=this.FormatValue(preVaildItem.Item,item);
if (item.Name)
{
var dyValue=this.GetDynamicOutValue(item.Name, preText);
if (dyValue) preText=dyValue;
}
valueText=`--(${preText})`;
return { Text:valueText, ArrayText:aryText };
}
if (value==null) return null;
if (item.DataType=="HistoryData-Vol")
{
value=value.Vol;
valueText=this.FormatValue(value,item);
}
else if (item.DataType=="MultiReport")
{
valueText=this.FormatMultiReport(value,item);
}
else if (item.DataType=="MULTI_POINT_LINE")
{
valueText=this.FromatMultiDataLine(value, item);
if (!valueText) return null;
}
else if (item.DataType=="ChartStackedBar")
{
aryText=this.FromatStackedBarTitle(value, item);
if (!aryText) return null;
return { Text:null, ArrayText:aryText };
}
else if (g_ScriptIndexChartFactory.Has(item.DataType)) //外部挂接
{
var find=g_ScriptIndexChartFactory.Get(item.DataType);
if (find && find.FormatTitleCallback)
return find.FormatTitleCallback(value, item, dataIndex);
}
else
{
if (this.GetEventCallback)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_INDEX_OUT_TEXT);
if (event)
{
var data=
{
Item:item, Index:titleIndex, Data:this.Data, FrameID:this.Frame.Identify,
DataIndex:dataIndex, Value:value,
Out:null
};
event.Callback(event,data,this);
if (data.Out) return data.Out;
}
}
if (item.DataType=="ChartBand") //默认不输出
return null;
var arrowSuper=null; //独立颜色
if (this.IsShowUpDownArrow)
{
var preValue=null;
if (dataIndex-1>=0) preValue=item.Data.Data[dataIndex-1];
if (IFrameSplitOperator.IsNumber(preValue))
{
if (preValue>value) arrowSuper={ Text:'↓', TextColor:this.UpDownArrowConfig.DownColor };
else if (preValue<value) arrowSuper={ Text:'↑', TextColor:this.UpDownArrowConfig.UpColor};
else arrowSuper={ Text:'→', TextColor:this.UpDownArrowConfig.UnchangeColor };
if (this.TitleArrowType==1) arrowSuper.TextColor=item.Color;
}
}
valueText=this.FormatValue(value,item);
if (item.Name)
{
var dyValue=this.GetDynamicOutValue(item.Name, valueText);
if (dyValue) valueText=dyValue;
}
if (arrowSuper)
{
var outItem={ Name:null, Text:valueText, Color:item.Color, TextEx:[arrowSuper] };
if (item.Name)
{
var text=item.Name;
var dyTitle=this.GetDynamicOutName(item.Name); //动态标题
if (dyTitle) text=dyTitle;
outItem.Name=text;
}
//outItem.BG='rgb(100,100,100)';
aryText=[outItem];
valueText=null;
}
}
}
return { Text:valueText, ArrayText:aryText };
}
//绘制主图指标 rtText 返回画完以后的区域
this.DrawMainIndexTitle=function(positionInfo, isShowLastData, rtText)
{
if (!this.IsShowMainIndexTitle) return;
var left=positionInfo.Left;
var right=positionInfo.Right;
var bottom=positionInfo.Bottom;
for(var i=0; i<this.Data.length; ++i)
{
var item=this.Data[i];
var outText=this.GetTitleItem(item, isShowLastData, i);
if (!outText) continue;
var valueText=outText.Text;
var aryText=outText.ArrayText;
if (aryText) //多变量输出
{
var text;
for(var k=0;k<aryText.length;++k)
{
var titleItem=aryText[k];
if (titleItem.Name) text=titleItem.Name+":"+titleItem.Text;
else text=titleItem.Text;
var space=this.ParamSpace*GetDevicePixelRatio();
var indexTextWidth=this.Canvas.measureText(text).width; //标题+数值长度
var textWidth=indexTextWidth;
if (IFrameSplitOperator.IsNonEmptyArray(titleItem.TextEx))
{
var xLeft=left;
for(var n=0; n<titleItem.TextEx.length; ++n)
{
var outItem=titleItem.TextEx[n];
var outTextWidth=this.Canvas.measureText(outItem.Text).width+2;
outItem.Width=outTextWidth;
outItem.Left=xLeft;
textWidth+=outTextWidth;
xLeft+=outTextWidth;
}
}
if ((left+textWidth+space)>right) break;
if (titleItem.BG) //背景
{
var textHeight=this.Canvas.measureText("擎").width+2;
var rtBG={ Left:left, Top:bottom-textHeight/2, Width:textWidth, Height:textHeight };
this.Canvas.fillStyle=titleItem.BG;
this.Canvas.fillRect(rtBG.Left,rtBG.Top-1, rtBG.Width, rtBG.Height);
this.Canvas.fillStyle=titleItem.Color;
this.Canvas.fillText(text,rtBG.Left+1,bottom,indexTextWidth);
left+=indexTextWidth;
if (IFrameSplitOperator.IsNonEmptyArray(titleItem.TextEx))
{
for(var n=0; n<titleItem.TextEx.length; ++n)
{
var outItem=titleItem.TextEx[n];
this.Canvas.fillStyle=outItem.TextColor;
this.Canvas.fillText(outItem.Text,left,bottom,outItem.Width);
left+=outItem.Width;
}
}
left+=space;
}
else
{
this.Canvas.fillStyle=titleItem.Color;
this.Canvas.fillText(text,left,bottom,indexTextWidth);
left+=indexTextWidth;
if (IFrameSplitOperator.IsNonEmptyArray(titleItem.TextEx))
{
for(var n=0; n<titleItem.TextEx.length; ++n)
{
var outItem=titleItem.TextEx[n];
this.Canvas.fillStyle=outItem.TextColor;
this.Canvas.fillText(outItem.Text,left,bottom,outItem.Width);
left+=outItem.Width;
}
}
left+=space;
}
}
}
else
{
this.Canvas.fillStyle=item.Color;
var text=valueText;
if (item.Name)
{
var dyTitle=this.GetDynamicOutName(item.Name);
if (dyTitle) text=dyTitle+":"+valueText;
else text=item.Name+":"+valueText;
}
var space=this.ParamSpace*GetDevicePixelRatio();
var textWidth=this.Canvas.measureText(text).width+space;
if ((left+textWidth)>right) break;
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
rtText.Left=left;
}
//集合竞价
this.DrawMainCallAuction=function(positionInfo, rtText, result)
{
if (!this.IsShowMainIndexTitle) return;
if (!this.MainTitlePaint) return;
var auctionData=this.MainTitlePaint.GetCurrentAuctionData(); //集合竞价分时数据
if (!auctionData || !auctionData.Data) return;
if (!this.GetEventCallback) return;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_CALL_AUCTION_INDEX_TITLE);
if (!event) return;
var data={ AuctionData:auctionData, Data:this.Data, FrameID:this.Frame.Identify, Out:null, PreventDefault:false };
event.Callback(event,data,this);
result.PreventDefault=data.PreventDefault;
if (!IFrameSplitOperator.IsNonEmptyArray(data.Out)) return;
var left=positionInfo.Left;
var right=positionInfo.Right;
var bottom=positionInfo.Bottom;
var pixelRatio=GetDevicePixelRatio();
var aryText=data.Out; //[{Text:, Color, Space:间距 }]
for(var i=0; i<aryText.length; ++i)
{
var item=aryText[i];
if (!item.Text) continue;
var textWidth=this.Canvas.measureText(item.Text).width+2;
if (left+textWidth>right) break;
if (item.BGColor) //背景
{
var textHeight=this.Canvas.measureText("擎").width+2;
var rtBG={ Left:left, Top:bottom-textHeight/2, Width:textWidth, Height:textHeight };
this.Canvas.fillStyle=item.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top-1, rtBG.Width, rtBG.Height);
left+=1;
}
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(item.Text,left,bottom,textWidth);
left+=textWidth;
if (IFrameSplitOperator.IsPlusNumber(item.Space)) left+=item.Space*pixelRatio;
}
rtText.Left=left;
}
this.GetCallAuctionTitleItem=function(item, titleIndex, auctionData)
{
if (item.IsShow===false) return null;
if (item.IsVisible===false) return null;
if (!item || !item.Data || !item.Data.Data) return null;
if (g_ScriptIndexChartFactory.Has(item.DataType)) //外部挂接
{
var find=g_ScriptIndexChartFactory.Get(item.DataType);
if (find && find.FormatTitleCallback)
return find.FormatTitleCallback(value, item, dataIndex);
}
}
//获取上一个有效数据
this.GetPreVaildItem=function(data, start)
{
for(var i=start; i>=0;--i)
{
var item=data[i];
if (item) return { Item:item, Index:i };
}
return null;
}
this.DrawSelectedLine=function(left, bottom, textWidth)
{
this.Canvas.save();
var fontHeight=this.GetFontHeight();
this.Canvas.strokeStyle=this.SelectedColor;
var lineWidth=4;
var lineBottom=ToFixedPoint2(lineWidth, (bottom+fontHeight/2));
this.Canvas.lineWidth=lineWidth;
this.Canvas.beginPath();
this.Canvas.moveTo(left,lineBottom);
this.Canvas.lineTo(left+textWidth,lineBottom);
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawOverlayIndexSingleLine=function(moveonPoint, mouseStatus) //叠加指标1个指标一行
{
var pixelRatio=GetDevicePixelRatio();
var border=this.Frame.GetBorder();
if (this.Frame.IsHScreen===true)
{
var left=1;
var top=2*pixelRatio;
var right=this.Frame.ChartBorder.GetHeight();
var bottom=this.Frame.ChartBorder.GetWidthEx();
}
else
{
var top=border.TopTitle+2*pixelRatio;
if (!this.IsShowMainIndexTitle) top=this.Frame.ChartBorder.GetTop()+2*pixelRatio;
var left=this.Frame.ChartBorder.GetLeft()+this.MerginLeft;
var right=border.Right;
var bottom=border.Bottom;
}
var lineSpace=this.OverlayIndexType.LineSpace*pixelRatio;
var x=left, y=top;
var fontHeight=GetFontHeight(this.Canvas,this.Font,"擎");
y=top+fontHeight/2;
for(item of this.OverlayIndex)
{
var overlayItem=item[1];
var overlayID=item[0];
var toolbarInfo={ Width:0, YCenter:y, ID:overlayID };
this.DrawOverlayToolbar(overlayItem,toolbarInfo,moveonPoint, mouseStatus);
if (!overlayItem.IsShowIndexTitle) continue;
if (!overlayItem.Frame.IsShowIndexTitle) continue;
x=left+toolbarInfo.Width;
this.Canvas.font=this.Font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
if (overlayItem.Title && this.IsShowOverlayIndexName)
{
var textWidth=this.Canvas.measureText(overlayItem.Title).width+2;
if ((x+textWidth)<right)
{
if (this.OverlayIndexType.BGColor)
{
this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
var rtBG={Left:x, Top:y-fontHeight/2, Width:textWidth, Height: fontHeight+lineSpace }; //保存下标题的坐标
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
if (this.IsSelectedChart(overlayID)) this.DrawSelectedLine(x, y,textWidth, overlayItem.Title );
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(overlayItem.Title,x,y,textWidth);
}
x+=textWidth;
}
for(var i=0; i<overlayItem.Data.length; ++i)
{
var item=overlayItem.Data[i];
if (!item || !item.Data || !item.Data.Data || !item.Name) continue;
if (item.IsVisible===false) continue;
if (item.Data.Data.length<=0) continue;
var value=null;
var valueText=null;
var aryText=null;
if (item.DataType=="StraightLine") //直线只有1个数据
{
value=item.Data.Data[0];
valueText=this.FormatValue(value,item);
}
else
{
var index=Math.abs(this.CursorIndex-0.5);
index=parseInt(index.toFixed(0));
if (this.IsKLineFrame) index=this.CursorIndex;
var dataIndex=item.Data.DataOffset+index;
if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1;
if (dataIndex<0) continue;
value=item.Data.Data[dataIndex];
if (value==null) continue;
if (item.DataType=="HistoryData-Vol")
{
value=value.Vol;
valueText=this.FormatValue(value,item);
}
else if (item.DataType=="MultiReport")
{
valueText=this.FormatMultiReport(value,item);
}
else if (item.DataType=="ChartStackedBar")
{
aryText=this.FromatStackedBarTitle(value, item);
if (!aryText) continue;
}
else
{
valueText=this.FormatValue(value,item);
}
}
if (aryText)
{
var text;
for(var k=0;k<aryText.length;++k)
{
var titleItem=aryText[k];
if (titleItem.Name) text=titleItem.Name+":"+titleItem.Text;
else text=titleItem.Text;
var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素
if ((x+textWidth)>right) break;
if (this.OverlayIndexType.BGColor)
{
this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
var rtBG={Left:x, Top:y-fontHeight/2, Width:textWidth, Height: fontHeight+lineSpace }; //保存下标题的坐标
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
this.Canvas.fillStyle=titleItem.Color;
this.Canvas.fillText(text,x,y,textWidth);
x+=textWidth;
}
}
else
{
var text=valueText;
if (item.Name)
{
var dyTitle=this.GetDynamicOutName(item.Name,overlayID);
if (dyTitle) text=dyTitle+":"+valueText;
else text=item.Name+":"+valueText;
}
var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素
if ((x+textWidth)>right) break;
if (this.OverlayIndexType.BGColor)
{
this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
var rtBG={Left:x, Top:y-fontHeight/2, Width:textWidth, Height: fontHeight+lineSpace }; //保存下标题的坐标
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
}
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(text,x,y,textWidth);
x+=textWidth;
}
}
y+=fontHeight+lineSpace;
if ((y+fontHeight+lineSpace)>=bottom) break;
}
}
this.DrawOverlayIndex=function(left) //叠加指标标题
{
var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2; //上下居中显示
var right=this.Frame.ChartBorder.GetRight();
if (this.Frame.IsHScreen===true)
{
bottom=-this.Frame.ChartBorder.TitleHeight/2;
right=this.Frame.ChartBorder.GetHeight();
}
if (left>right) return;
var spaceWidth=5*GetDevicePixelRatio();
var drawLeft=left;
var indexCount=0;
for(item of this.OverlayIndex)
{
if (indexCount>0) left+=spaceWidth;
var overlayItem=item[1];
var overlayID=item[0];
if (overlayItem.Title && this.IsShowOverlayIndexName)
{
this.Canvas.fillStyle=this.TitleColor;
var textWidth=this.Canvas.measureText(overlayItem.Title).width+2;
drawLeft=left;
left+=textWidth;
if (left>right) break;
this.Canvas.fillText(overlayItem.Title,drawLeft,bottom,textWidth);
if (this.IsSelectedChart(overlayID)) this.DrawSelectedLine(drawLeft, bottom, textWidth);
}
for(var i in overlayItem.Data)
{
var item=overlayItem.Data[i];
if (!item || !item.Data || !item.Data.Data || !item.Name) continue;
if (item.Data.Data.length<=0) continue;
var value=null;
var valueText=null;
if (item.DataType=="StraightLine") //直线只有1个数据
{
value=item.Data.Data[0];
valueText=this.FormatValue(value,item);
}
else
{
var index=Math.abs(this.CursorIndex-0.5);
index=parseInt(index.toFixed(0));
if (this.IsKLineFrame) index=this.CursorIndex;
var dataIndex=item.Data.DataOffset+index;
if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1;
if (dataIndex<0) continue;
value=item.Data.Data[dataIndex];
if (value==null) continue;
if (item.DataType=="HistoryData-Vol")
{
value=value.Vol;
valueText=this.FormatValue(value,item);
}
else if (item.DataType=="MultiReport")
{
valueText=this.FormatMultiReport(value,item);
}
else
{
valueText=this.FormatValue(value,item);
}
}
this.Canvas.fillStyle=item.Color;
var text=item.Name+":"+valueText;
var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素
drawLeft=left;
left+=textWidth;
if (left>right) break;
this.Canvas.fillText(text,drawLeft,bottom,textWidth);
}
if (left>right) break;
++indexCount;
}
}
this.HScreenDraw=function()
{
var border=this.Frame.ChartBorder.GetHScreenBorder();
var xText=this.Frame.ChartBorder.GetRightTitle();
var yText=border.TopEx;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
var left=1;
var bottom=-this.Frame.ChartBorder.TitleHeight/2; //上下居中显示
var right=this.Frame.ChartBorder.GetHeight();
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.font=this.Font;
var pixelRatio=GetDevicePixelRatio();
if (this.Title && this.IsShowIndexName)
{
var textWidth=this.Canvas.measureText(this.Title).width+2;
if (this.IsDrawTitleBG)
{
var title=this.Title;
var textWidth=this.Canvas.measureText(title).width;
var arrowWidth=0;
if (this.IsShowNameArrow && this.NameArrowConfig)
{
arrowWidth=this.Canvas.measureText(this.NameArrowConfig.Symbol).width;
if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) arrowWidth+=this.NameArrowConfig.Space;
}
var bgHeight=this.Canvas.measureText("擎").width+4*pixelRatio;
var bgWidth=textWidth+arrowWidth+4*pixelRatio;
this.TitleRect=
{
Top:border.Top,
Left:this.Frame.ChartBorder.GetRightTitle()+this.Frame.ChartBorder.TitleHeight/2-bgHeight/2,
Width:bgHeight,
Height:bgWidth
}; //保存下标题的坐标
this.Canvas.fillStyle=this.BGColor;
var drawRect={ Left:left, Top:bottom-bgHeight/2, Width:bgWidth, Height:bgHeight };
this.Canvas.fillRect(drawRect.Left,drawRect.Top,drawRect.Width,drawRect.Height);
if (this.BGBorderColor)
{
this.Canvas.strokeStyle=this.BGBorderColor;
this.Canvas.strokeRect(ToFixedPoint(drawRect.Left),ToFixedPoint(drawRect.Top),ToFixedRect(drawRect.Width),ToFixedRect(drawRect.Height));
}
var xText=left+2*pixelRatio;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(title,xText,bottom);
xText+=textWidth;
if (this.IsShowNameArrow && this.NameArrowConfig)
{
if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) xText+=this.NameArrowConfig.Space;
this.Canvas.fillStyle=this.NameArrowConfig.Color;
this.Canvas.fillText(this.NameArrowConfig.Symbol,xText,bottom);
}
left+=bgWidth+2*pixelRatio;
left+=this.TitleSpace;
}
else
{
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(this.Title,left,bottom);
left+=textWidth;
left+=this.TitleSpace;
}
}
if (this.ArgumentsText && this.IsShowIndexName)
{
var textWidth=this.Canvas.measureText(this.ArgumentsText).width+2;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(this.ArgumentsText,left,bottom,textWidth);
left+=textWidth;
left+=this.TitleSpace;
}
var isShowLastData=this.IsShowLastData();
var lockRect=this.Frame.GetLockRect();
if (lockRect) //指标上锁区域不显示动态标题
{
var index=Math.abs(this.CursorIndex-0.5);
if (this.IsKLineFrame) index=this.CursorIndex;
var x=this.Frame.GetXFromIndex(index.toFixed(0));
if (x>=lockRect.Top) return;
if (isShowLastData) return;
}
for(var i in this.Data)
{
var item=this.Data[i];
var outText=this.GetTitleItem(item, isShowLastData);
if (!outText) continue;
var valueText=outText.Text;
var aryText=outText.ArrayText;
if (aryText)
{
var text;
for(var k=0;k<aryText.length;++k)
{
var titleItem=aryText[k];
if (titleItem.Name) text=titleItem.Name+":"+titleItem.Text;
else text=titleItem.Text;
var space=this.ParamSpace*GetDevicePixelRatio();
var textWidth=this.Canvas.measureText(text).width+space;
if ((left+textWidth)>right) break;
this.Canvas.fillStyle=titleItem.Color;
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
else
{
this.Canvas.fillStyle=item.Color;
var text=valueText;
if (item.Name)
{
var dyTitle=this.GetDynamicOutName(item.Name);
if (dyTitle) text=dyTitle+":"+valueText;
else text=item.Name+":"+valueText;
}
var space=this.ParamSpace*GetDevicePixelRatio();
var textWidth=this.Canvas.measureText(text).width+space; //后空2个像素
if ((left+textWidth)>right) break;
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
if (this.Explain) //说明信息
{
this.Canvas.fillStyle=this.TitleColor;
var text="说明:"+this.Explain;
var textWidth=this.Canvas.measureText(text).width+2;
if (left+textWidth<right)
{
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
if (this.OverlayIndexType.Position==1)
{
if (!this.Frame.ChartBorder.IsShowTitleOnly)
this.DrawOverlayIndexSingleLine();
}
else
{
this.DrawOverlayIndex(left+5*GetDevicePixelRatio()); //间距都空点 和主指标区分开
}
}
this.OnDrawEventCallback=function(drawData)
{
if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return;
var data={ Draw: drawData, Name:'DynamicChartTitlePainting'};
this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
//指标名字按钮
this.DrawNameButton=function(rtButton, moveonPoint, mouseStatus)
{
var pixelRatio=GetDevicePixelRatio();
var title=this.Title;
var textWidth=this.Canvas.measureText(title).width;
var arrowWidth=0;
if (this.IsShowNameArrow && this.NameArrowConfig)
{
arrowWidth=this.Canvas.measureText(this.NameArrowConfig.Symbol).width;
if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) arrowWidth+=this.NameArrowConfig.Space;
}
var bgHeight=this.Canvas.measureText("擎").width+4*pixelRatio;
var roundRadius=this.BorderRoundRadius*pixelRatio;
var bgWidth=textWidth+arrowWidth+4*pixelRatio+roundRadius*2;
rtButton.Top=rtButton.YCenter-bgHeight/2-1,
rtButton.Width=bgWidth;
rtButton.Height=bgHeight;
rtButton.Right=rtButton.Left+rtButton.Width;
rtButton.Bottom=rtButton.Top+rtButton.Height;
var borderColor=this.BGBorderColor;
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
if (this.BGBorderMoveOnColor) borderColor=this.BGBorderMoveOnColor;
if (mouseStatus)
{
var btnItem={ ID:JSCHART_BUTTON_ID.INDEX_NAME_BUTTON };
mouseStatus.MouseOnToolbar={ ID:"IndexNameButton", Rect:rtButton, Item:btnItem, Frame:this.Frame, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
}
if (this.Canvas.roundRect && this.NameButtonStyle==1) //判断下是否支持roundRect
{
this.Canvas.beginPath();
this.Canvas.roundRect(ToFixedPoint(rtButton.Left), ToFixedPoint(rtButton.Top), ToFixedRect(rtButton.Width), ToFixedRect(rtButton.Height), [roundRadius]);
this.Canvas.closePath();
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill();
if (borderColor)
{
this.Canvas.strokeStyle=borderColor;
this.Canvas.stroke();
}
}
else
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtButton.Left, rtButton.Top, rtButton.Width, rtButton.Height);
if (borderColor)
{
this.Canvas.strokeStyle=borderColor;
this.Canvas.strokeRect(ToFixedPoint(rtButton.Left), ToFixedPoint(rtButton.Top), ToFixedRect(rtButton.Width), ToFixedRect(rtButton.Height), [roundRadius]);
}
}
var xText=rtButton.Left+roundRadius+2*pixelRatio;
this.Canvas.fillStyle=this.TitleColor;
this.Canvas.fillText(title,xText,rtButton.YCenter);
xText+=textWidth;
if (this.IsShowNameArrow && this.NameArrowConfig)
{
if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) xText+=this.NameArrowConfig.Space;
this.Canvas.fillStyle=this.NameArrowConfig.Color;
this.Canvas.fillText(this.NameArrowConfig.Symbol,xText,rtButton.YCenter);
}
}
//绘制按钮
this.DrawButton=function(item, rtButton, moveonPoint, mouseStatus)
{
var size=item.Style.Size;
if (IFrameSplitOperator.IsNumber(item.Style.YMoveOffset)) rtButton.YCenter+=item.Style.YMoveOffset;
var font=`${size}px ${item.Style.Family}`;
rtButton.Top=rtButton.YCenter-size/2;
rtButton.Width=size+item.Style.MerginLeft;
rtButton.Height=size;
rtButton.Bottom=rtButton.Top+rtButton.Height;
rtButton.Right=rtButton.Left+rtButton.Width;
var color=item.Style.Color;
if (moveonPoint && (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom))
{
color=item.Style.MoveOnColor;
if (mouseStatus)
mouseStatus.MouseOnToolbar={ ID:"TitleButton", Rect:rtButton, Item:item, Frame:this.Frame, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
}
this.Canvas.fillStyle=color;
this.Canvas.font=font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Style.Text, rtButton.Left, rtButton.YCenter);
return true;
}
this.DrawToolbar=function(toolbarInfo, moveonPoint, mouseStatus)
{
toolbarInfo.Width=0;
if (!this.Frame || !this.Frame.GetLeftToolbar) return;
var aryButton=this.Frame.GetLeftToolbar();
if (!IFrameSplitOperator.IsNonEmptyArray(aryButton)) return;
if (this.Frame.IsHScreen===true)
{
}
else
{
var border=this.Frame.GetBorder();
var right=border.Right-3;
var left=border.Left+3;
var yCenter=toolbarInfo.YCenter;
for(var i=0;i<aryButton.length;++i)
{
var item=aryButton[i];
var rtButton={ Left:left, YCenter:yCenter };
this.DrawButton(item, rtButton, moveonPoint, mouseStatus);
this.Buttons.push({ ID:item.ID, Rect:rtButton, FrameID:this.Frame.Identify, Type:0, Data:item.Data }); //Type 0=主图按钮 1=附图按钮 2=主图指标名字按钮
left=rtButton.Right;
toolbarInfo.Width+=rtButton.Width;
}
if (toolbarInfo.Width>0) toolbarInfo.Width+=3;
}
}
this.DrawOverlayToolbar=function(overlayItem, toolbarInfo, moveonPoint, mouseStatus)
{
toolbarInfo.Width=0;
if (!overlayItem || !overlayItem.Frame || !overlayItem.Frame.GetLeftToolbar) return;
var frame=overlayItem.Frame;
var aryButton=frame.GetLeftToolbar({ Overlay:overlayItem, OverlayID:toolbarInfo.ID });
if (!IFrameSplitOperator.IsNonEmptyArray(aryButton)) return;
if (this.Frame.IsHScreen===true)
{
}
else
{
var border=frame.GetBorder();
var right=border.Right-3;
var left=border.Left+3;
var yCenter=toolbarInfo.YCenter;
for(var i=0;i<aryButton.length;++i)
{
var item=aryButton[i];
var rtButton={ Left:left, YCenter:yCenter };
this.DrawButton(item, rtButton, moveonPoint, mouseStatus);
this.Buttons.push({ ID:item.ID, Rect:rtButton, FrameID:this.Frame.Identify, Type:1, OverlayID:toolbarInfo.ID, Title:overlayItem.Title, Data:item.Data });
left=rtButton.Right;
toolbarInfo.Width+=rtButton.Width;
}
if (toolbarInfo.Width>0) toolbarInfo.Width+=3;
}
}
this.PtInButtons=function(x,y)
{
for(var i=0;i<this.Buttons.length;++i)
{
var item=this.Buttons[i];
if (!item.Rect) continue;
var rect=item.Rect;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
{
var result= { ID:item.ID, Rect:rect, FrameID:item.FrameID, Type:item.Type, Data:item.Data };
if (item.Type==1)
{
result.Title=item.Title;
result.OverlayID=item.OverlayID;
}
return result;
}
}
return null;
}
}
//画图工具
function IChartDrawPicture()
{
this.Frame;
this.Canvas;
this.Point=new Array() //画图的点
this.Value=new Array(); //XValue,YValue
this.LinePoint=[];
this.PointCount=2; //画点的个数
this.Status=0; //0=开始画 1=完成第1个点 2=完成第2个点 3=完成第3个点 10=完成 20=移动
this.PointStatus=0; //2=第2个点完成
this.MovePointIndex=null; //移动哪个点 0-10 对应Point索引 100 整体移动
this.ClassName='IChartDrawPicture';
this.FinishedCallback; //画图完成回调通知
this.Guid=Guid(); //ID标识
this.Symbol; //对应的股票
this.Period; //对应的周期
this.Right; //对应的复权
this.IsSelected=false; //是否选中
this.Option; //全局配置 对应外部 ChartDrawOption
this.EnableMove=true; //是否可以移动
this.EnableSave=true; //是否允许保存
this.EnableCtrlMove=false; //是否按住Ctrl才能移动
this.OnlyMoveXIndex=false; //只能在X轴刻度上移动
this.IsSupportMagnet=false; //是否支持磁吸
this.EnableMoveCheck=true; //允许移动时监测是否超出边界
this.IsDrawFirst=false;
this.IsShowYCoordinate=false; //是否在Y轴显示点的刻度
this.IsShow=true; //是否显示
this.LineColor=g_JSChartResource.DrawPicture.LineColor[0]; //线段颜色
//this.LineColor="#1e90ff"; //线段颜色,input type="color" 不支持rgb和rgba 的格式
this.LineWidth=2; //线段宽度
this.BackupLineWidth=null;
this.AreaColor='rgba(25,25,25,0.4)'; //面积颜色
this.PointColor=g_JSChartResource.DrawPicture.PointColor[0];
this.MoveOnPointColor=g_JSChartResource.DrawPicture.PointColor[1];
this.PointBGColor=g_JSChartResource.DrawPicture.PointColor[2];
this.PointRadius=5; //圆点半径
this.SquareSize=8; //方框点大小
this.PointType=g_JSChartResource.DrawPicture.PointType; // 0=圆点 1=方框 2= 空心圆
this.IsShowPoint=g_JSChartResource.DrawPicture.IsShowPoint; //是否始终显示点
this.LimitFrameID; //限制在指定窗口绘图
//接口函数
this.SetLastPoint=null; //this.SetLastPoint=function(obj) obj={X:,Y:}
this.Update=null; //更新数据回调
this.GetActiveDrawPicture=null;
this.GetYCoordinatePoint=null;
this.Draw=function()
{
}
this.SetOption=function(option)
{
if (!option) return;
if (option.LineColor) this.LineColor=option.LineColor;
if (option.LineWidth>0) this.LineWidth=option.LineWidth;
if (option.AreaColor) this.AreaColor=option.AreaColor;
if (option.PointColor) this.PointColor=option.PointColor;
if (option.MoveOnPointColor) this.MoveOnPointColor=option.MoveOnPointColor;
if (option.PointRadius) this.PointRadius=option.PointRadius;
if (IFrameSplitOperator.IsNumber(option.SquareSize)) this.SquareSize=option.SquareSize;
if (IFrameSplitOperator.IsBool(option.IsShowPoint)) this.IsShowPoint=option.IsShowPoint;
if (IFrameSplitOperator.IsNumber(option.LimitFrameID)) this.LimitFrameID=option.LimitFrameID;
if (IFrameSplitOperator.IsBool(option.EnableCtrlMove)) this.EnableCtrlMove=option.EnableCtrlMove;
if (IFrameSplitOperator.IsBool(option.IsShowYCoordinate)) this.IsShowYCoordinate=option.IsShowYCoordinate;
}
this.ReloadResource=function(resource)
{
if (!resource)
{
this.PointColor=g_JSChartResource.DrawPicture.PointColor[0];
this.MoveOnPointColor=g_JSChartResource.DrawPicture.PointColor[1];
this.PointBGColor=g_JSChartResource.DrawPicture.PointColor[2];
}
}
this.SetLineWidth=function()
{
this.BackupLineWidth=null;
if (this.LineWidth>0)
{
this.BackupLineWidth=this.Canvas.lineWidth;
this.Canvas.lineWidth=this.LineWidth*GetDevicePixelRatio();
}
}
this.GetFontHeight=function(font)
{
return GetFontHeight(this.Canvas, font, "擎");
}
this.RestoreLineWidth=function()
{
if (this.BackupLineWidth!=null)
{
this.Canvas.lineWidth=this.BackupLineWidth;
}
}
//磁吸K线
this.PointMagnetKLine=function()
{
if (!this.IsSupportMagnet) return false;
if (!this.Frame) return false;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame") return false;
if (this.Frame.Identify!=0) return false;
var pointIndex=-1;
if (this.Status==2) pointIndex=1;
else if (this.Status==1) pointIndex=0;
else if (IFrameSplitOperator.IsNumber(this.MovePointIndex)) pointIndex=this.MovePointIndex;
if (pointIndex<0) return false;
if (this.Option && this.Option.Magnet && this.Option.Magnet.Enable)
{
var option=
{
IsFixedX:false,
Magnet:
{
Enable:true,
PointIndex:pointIndex,
Distance:this.Option.Magnet.Distance,
Type:this.Option.Magnet.Type
}
}
return this.AdjustPoint(this.Point,option)
}
return false;
}
//Point => Value
this.PointToValue=function()
{
if (!this.Frame) return false;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
{
return this.PointToValue_Minute();
}
else
{
return this.PointToValue_KLine();
}
}
this.PointToKLine=function(aryPoint)
{
if (!this.Frame) return null;
var data=this.Frame.Data;
if (!data) return null;
var kLine=[];
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i in aryPoint)
{
var item=aryPoint[i];
var xValue=parseInt(this.Frame.GetXData(item.Y))+data.DataOffset;
var yValue=this.Frame.GetYData(item.X);
var valueItem={ XValue:xValue, YValue:yValue };
var kline=data.Data[xValue];
valueItem.DateTime={ Date:kline.Date };
if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;
kLine[i]=valueItem;
}
}
else
{
for(var i in aryPoint)
{
var item=aryPoint[i];
var index=parseInt(this.Frame.GetXData(item.X,false));
var xValue=index+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length)
{
xValue=data.Data.length-1;
index=xValue-data.DataOffset;
}
var yValue=this.Frame.GetYData(item.Y,false);
var valueItem={ XValue:xValue, YValue:yValue, XIndex:index };
var kline=data.Data[xValue];
valueItem.DateTime={ Date:kline.Date };
if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;
kLine[i]=valueItem;
}
}
return kLine;
}
this.PointToValue_KLine=function()
{
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i=0; i<this.Point.length; ++i)
{
var item=this.Point[i];
var xValue=parseInt(this.Frame.GetXData(item.Y,false))+data.DataOffset;
var yValue=this.Frame.GetYData(item.X,false);
var valueItem={ XValue:xValue, YValue:yValue };
var kline=data.Data[xValue];
valueItem.DateTime={ Date:kline.Date };
if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;
this.Value[i]=valueItem;
}
}
else
{
for(var i=0; i<this.Point.length; ++i)
{
var item=this.Point[i];
var xValue=parseInt(this.Frame.GetXData(item.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yValue=this.Frame.GetYData(item.Y,false);
var valueItem={ XValue:xValue, YValue:yValue };
var kline=data.Data[xValue];
valueItem.DateTime={ Date:kline.Date };
if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;
this.Value[i]=valueItem;
}
}
return true;
}
this.PointToValue_Minute=function()
{
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i=0; i<this.Point.length; ++i)
{
var item=this.Point[i];
var xValue=parseInt(this.Frame.GetXData(item.Y,false));
var yValue=this.Frame.GetYData(item.X,false);
var valueItem={ XValue:xValue, YValue:yValue };
var minuteItem=data.Data[xValue];
valueItem.DateTime={ Date:minuteItem.Date ,Time:minuteItem.Time};
this.Value[i]=valueItem;
}
}
else
{
var xDatetime=g_MinuteTimeStringData.GetTimeData(this.Symbol);
for(var i=0; i<this.Point.length; ++i)
{
var item=this.Point[i];
var xValue=parseInt(this.Frame.GetXData(item.X,false));
var yValue=this.Frame.GetYData(item.Y,false);
if (xValue>=data.Data.length) //超过当前数据,直接读固定时间
{
var index=xValue%xDatetime.length;
var dataIndex=data.Data.length-1;
var valueItem={ XValue:xValue, YValue:yValue };
var minuteItem=data.Data[dataIndex];
var timeItem=xDatetime[index];
valueItem.DateTime={ Date:minuteItem.Date, Time:timeItem };
this.Value[i]=valueItem;
}
else
{
var valueItem={ XValue:xValue, YValue:yValue };
var minuteItem=data.Data[xValue];
valueItem.DateTime={ Date:minuteItem.Date, Time:minuteItem.Time };
this.Value[i]=valueItem;
}
}
}
return true;
}
this.IsPointIn=function(x, y, option)
{
return false;
}
//Value => Point
this.ValueToPoint=function()
{
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
//this.UpdateXValue();
var isHScreen=this.Frame.IsHScreen;
this.Point=[];
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset, false);
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
this.Point[i]=pt;
}
}
this.UpdateXValue=function() //通过datetime更新x的索引
{
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
var aryDateTime=[];
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
if (!item.DateTime) break;
var dateTime={ Date:item.DateTime.Date };
if (IFrameSplitOperator.IsNumber(item.DateTime.Time)) dateTime.Time=item.DateTime.Time;
aryDateTime[i]=dateTime;
}
data.FindDataIndexByDateTime(aryDateTime);
for(var i=0; i<aryDateTime.length; ++i)
{
var findItem=aryDateTime[i];
var valueItem=this.Value[i];
if (findItem.Index>=0) valueItem.XValue=findItem.Index;
}
}
//重置X索引数据
this.ResetXValue=function()
{
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
item.XValue=null;
}
return true;
}
//xStep,yStep 移动的偏移量
this.Move=function(xStep,yStep)
{
if (this.Status!=20) return false;
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
if (this.MovePointIndex==null) return false;
var index=parseInt(this.MovePointIndex);
if (index===100) //整体移动
{
if (this.IsMoveOutOfBounds(this.Point, xStep, yStep)) return false;
for(var i in this.Point)
{
this.Point[i].X+=xStep;
this.Point[i].Y+=yStep;
}
}
else if (index===0 || index===1 || index===2 || index===3 || index===4 || index===5)
{
if (index<this.Point.length)
{
this.Point[index].X+=xStep;
this.Point[index].Y+=yStep;
}
}
else
{
return false;
}
}
//是否超出边界了
this.IsMoveOutOfBounds=function(aryPoint,xStep,yStep)
{
if (!this.EnableMoveCheck) return false;
if (!this.Frame) return false;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
return false;
var data=this.Frame.Data;
if (!data) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(data.Data)) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
//TODO:横屏以后再做
return false;
}
else
{
var offset=data.DataOffset;
var startIndex=0-offset;
var endIndex=data.Data.length-offset;
if (xStep>0)
{
var xEnd=this.Frame.GetXFromIndex(endIndex-1,false);
for(var i=0;i<aryPoint.length;++i)
{
var item=aryPoint[i];
if (item.X+xStep>xEnd) return true;
}
}
else if (xStep<0)
{
var xStart=this.Frame.GetXFromIndex(startIndex,false);
for(var i=0;i<aryPoint.length;++i)
{
var item=aryPoint[i];
if (item.X+xStep<xStart) return true;
}
}
return false;
}
}
this.ClipFrame=function()
{
if (this.Frame.IsHScreen)
{
var left=this.Frame.ChartBorder.GetLeftEx();
var top=this.Frame.ChartBorder.GetTop();
var width=this.Frame.ChartBorder.GetWidthEx();
var height=this.Frame.ChartBorder.GetHeight();
}
else
{
var left=this.Frame.ChartBorder.GetLeft();
var top=this.Frame.ChartBorder.GetTopEx();
var width=this.Frame.ChartBorder.GetWidth();
var height=this.Frame.ChartBorder.GetHeightEx();
}
this.Canvas.save();
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
this.Canvas.clip();
}
//计算需要画的点的坐标option:{IsCheckX:是否检测X值, IsCheckY:是否检测Y值}
this.CalculateDrawPoint=function(option)
{
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
var drawPoint=[];
if (this.Status==10)
{
var data=this.Frame.Data;
if (!data) return null;
var showCount=this.Frame.XPointCount;
var invaildX=0; //超出范围的x点个数
var isHScreen=this.Frame.IsHScreen;
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
if (!IFrameSplitOperator.IsNumber(item.XValue)) return null; //无效索引 不显示
var dataIndex=item.XValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=showCount) ++invaildX;
var pt=new Point();
if (isHScreen) //横屏X,Y对调
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
drawPoint.push(pt);
}
if (option && option.IsCheckX===true)
{
if (invaildX==this.Value.length) return null;
}
}
else //移动中
{
for(var i=0;i<this.Point.length;++i)
{
var item=this.Point[i];
drawPoint.push({ X:item.X, Y:item.Y });
}
if (this.OnlyMoveXIndex)
{
var option= { IsFixedX:this.OnlyMoveXIndex };
JSConsole.Chart.Log(`[IChartDrawPicture::CalculateDrawPoint] Status=${this.Status} MovePointIndex=${this.MovePointIndex} Identify=${this.Frame.Identify}`);
//磁吸功能
if (this.Option && this.Option.Magnet && this.Option.Magnet.Enable && this.IsSupportMagnet && this.Frame.Identify==0)
{
var pointIndex=-1;
if (this.Status==2) pointIndex=1; //创建第2个点
if (IFrameSplitOperator.IsNumber(this.MovePointIndex)) pointIndex=this.MovePointIndex;
if (pointIndex>=0)
{
option.Magnet=
{
Enable:true,
PointIndex:pointIndex,
Distance:this.Option.Magnet.Distance,
Type:this.Option.Magnet.Type
}
}
}
this.AdjustPoint(drawPoint,option)
}
}
return drawPoint;
}
//修正X, Y轴坐标
this.AdjustPoint=function(aryPoint, option)
{
if (!this.Frame) return false;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
return false;
return this.AdjustPoint_KLine(aryPoint, option);
}
this.AdjustPoint_KLine=function(aryPoint, option)
{
if (!option) return false;
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
var xValue=parseInt(this.Frame.GetXData(item.Y))+data.DataOffset;
}
}
else
{
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
var index=parseInt(this.Frame.GetXData(item.X,false));
var xValue=index+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
if (option.IsFixedX)
{
index=xValue-data.DataOffset;
item.X=this.Frame.GetXFromIndex(index,false);
}
//磁吸
if (option.Magnet && option.Magnet.Enable && i==option.Magnet.PointIndex)
{
var kline=data.Data[xValue];
var aryKValue=[kline.Open, kline.High, kline.Low, kline.Close];
var yMinDistance=null, yKLine=null;
for(var j=0; j<aryKValue.length; ++j)
{
var yPrice=this.Frame.GetYFromData(aryKValue[j]);
var value=Math.abs(item.Y-yPrice);
if (!IFrameSplitOperator.IsNumber(yMinDistance) || yMinDistance>value)
{
yMinDistance=value;
yKLine=yPrice;
}
}
if (option.Magnet.Type==1) //只能在K线上
{
if (IFrameSplitOperator.IsNumber(yKLine))
item.Y=yKLine;
}
else
{
if (yMinDistance<option.Magnet.Distance && IFrameSplitOperator.IsNumber(yKLine))
item.Y=yKLine;
}
}
}
}
}
this.IsYValueInFrame=function(yValue)
{
if (!this.Frame) return false;
if (yValue>this.Frame.HorizontalMax || yValue<this.Frame.HorizontalMin) return false;
return true;
}
this.DrawPoint=function(aryPoint)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return;
var color=this.PointColor;
var isMoveOn=false;
if (this.IsShowPoint)
{
}
else
{
if (this.GetActiveDrawPicture)
{
var active=this.GetActiveDrawPicture();
if (active.Move.Guid!=this.Guid && active.Select.Guid!=this.Guid && active.MoveOn.Guid!=this.Guid)
return;
if (active.Select.Guid!=this.Guid && active.MoveOn.Guid==this.Guid)
{
isMoveOn=true;
color=this.MoveOnPointColor;
}
}
}
//画点
this.ClipFrame();
var pixel=GetDevicePixelRatio();
this.Canvas.fillStyle=color; //填充颜色
if (this.PointType==2)
{
this.Canvas.fillStyle=this.PointBGColor; //背景填充颜色
this.Canvas.strokeStyle=this.PointColor;
if (isMoveOn) this.Canvas.lineWidth=1*pixel;
else this.Canvas.lineWidth=2*pixel;
}
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
if (this.PointType==1) //正方形
{
var value=this.SquareSize*pixel;
var x=item.X-value/2;
var y=item.Y-value/2;
this.Canvas.fillRect(x,y,value,value); //画一个背景色, 不然是一个黑的背景
}
else if (this.PointType==2) //空心圆
{
var path=new Path2D();
path.arc(item.X,item.Y,this.PointRadius*pixel,0,360,false);
this.Canvas.fill(path);
this.Canvas.stroke(path);
}
else //实心圆
{
this.Canvas.beginPath();
this.Canvas.arc(item.X,item.Y,this.PointRadius*pixel,0,360,false);
this.Canvas.fill(); //画实心圆
this.Canvas.closePath();
}
}
this.Canvas.restore();
}
this.DrawArrow=function(ptStart,ptEnd)
{
//计算箭头
var theta=35; //三角斜边一直线夹角
var headlen=10; //三角斜边长度
var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
this.Canvas.beginPath();
var arrowX = ptEnd.X + topX;
var arrowY = ptEnd.Y + topY;
this.Canvas.moveTo(arrowX,arrowY);
this.Canvas.lineTo(ptEnd.X, ptEnd.Y);
arrowX = ptEnd.X + botX;
arrowY = ptEnd.Y + botY;
this.Canvas.lineTo(arrowX,arrowY);
this.Canvas.stroke();
}
//计算2个点线的,左右的延长线的点
this.CalculateExtendLinePoint=function(ptStart,ptEnd)
{
var result={};
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var top=this.Frame.ChartBorder.GetTopEx();
var bottom=this.Frame.ChartBorder.GetBottom();
var a=ptEnd.X-ptStart.X;
var b=ptEnd.Y-ptStart.Y;
if (a>0)
{
var b2=bottom-ptStart.Y;
var a2=a*b2/b;
var pt=new Point();
pt.X=ptStart.X+a2;
pt.Y=bottom;
result.End=pt;
var b2=ptEnd.Y-top;
var a2=a*b2/b;
var pt2=new Point();
pt2.Y=top;
pt2.X=ptEnd.X-a2;
result.Start=pt2;
}
else
{
var b2=bottom-ptStart.Y;
var a2=Math.abs(a)*b2/b;
var pt=new Point();
pt.X=ptStart.X-a2;;
pt.Y=bottom;
result.End=pt;
var b2=ptEnd.Y-top;
var a2=Math.abs(a)*b2/b;
var pt2=new Point();
pt2.Y=top;
pt2.X=ptEnd.X+a2;
result.Start=pt2;
}
return result;
}
//计算2个点线的,点0->点1->延长线的点
this.CalculateExtendLineEndPoint=function(aryPoint)
{
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var bottom=this.Frame.ChartBorder.GetBottomEx();
var top=this.Frame.ChartBorder.GetTopEx();
var a=aryPoint[1].X-aryPoint[0].X;
var b=aryPoint[1].Y-aryPoint[0].Y;
if (a>0)
{
var a1=right-aryPoint[0].X;
var b1=a1*b/a;
var y=b1+aryPoint[0].Y;
if (y>=top && y<=bottom)
{
var pt=new Point();
pt.X=right;
pt.Y=y;
return pt;
}
if (b>0)
{
var b2=bottom-aryPoint[0].Y;
var a2=a*b2/b;
var x=a2+aryPoint[0].X;
var pt2=new Point();
pt2.X=x;
pt2.Y=bottom;
return pt2;
}
else if (b==0)
{
var pt2=new Point();
pt2.X=right;
pt2.Y=aryPoint[0].Y;
return pt2;
}
else
{
var b2=top-aryPoint[0].Y;
var a2=a*b2/b;
var x=a2+aryPoint[0].X;
var pt2=new Point();
pt2.X=x;
pt2.Y=top;
return pt2;
}
}
else
{
var a1=aryPoint[0].X-left;
var b1=a1*b/Math.abs(a);
var y=b1+aryPoint[0].Y;
if (y>=top && y<=bottom)
{
var pt=new Point();
pt.X=left;
pt.Y=y;
return pt;
}
if (b>0)
{
var b2=bottom-aryPoint[0].Y;
var a2=a*b2/b;
var x=a2+aryPoint[0].X;
var pt2=new Point();
pt2.X=x;
pt2.Y=bottom;
return pt2;
}
else if (b==0)
{
var pt2=new Point();
pt2.X=left;
pt2.Y=aryPoint[0].Y;
return pt2;
}
else
{
var b2=top-aryPoint[0].Y;
var a2=a*b2/b;
var x=a2+aryPoint[0].X;
var pt2=new Point();
pt2.X=x;
pt2.Y=top;
return pt2;
}
}
}
//坐标是否在点上 返回在第几个点上
this.IsPointInXYValue=function(x, y, option)
{
if (!this.Frame) return -1;
var data=this.Frame.Data;
if (!data) return -1;
if (!this.Value) return -1;
var radius=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) radius+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) radius+=this.Option.Zoom;
var isHScreen=this.Frame.IsHScreen;
radius*=GetDevicePixelRatio();
for(var i=0;i<this.Value.length; ++i) //是否在点上
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.X=this.Frame.GetYFromData(item.YValue);
}
else
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.Y=this.Frame.GetYFromData(item.YValue);
}
this.Canvas.beginPath();
this.Canvas.arc(pt.X,pt.Y,radius,0,360);
if (this.Canvas.isPointInPath(x,y)) return i;
}
return -1;
}
//坐标是否在线段上 返回在第几个线段上
this.IsPointInLine=function(x, y, option)
{
if (!this.LinePoint) return -1;
var lineWidth=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) lineWidth+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) lineWidth+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
lineWidth*=pixel;
for(var i=0;i<this.LinePoint.length; ++i)
{
var item=this.LinePoint[i];
var ptStart=item.Start;
var ptEnd=item.End;
this.Canvas.beginPath();
if (ptStart.X==ptEnd.X) //竖线
{
this.Canvas.moveTo(ptStart.X-lineWidth,ptStart.Y);
this.Canvas.lineTo(ptStart.X+lineWidth,ptStart.Y);
this.Canvas.lineTo(ptEnd.X+lineWidth,ptEnd.Y);
this.Canvas.lineTo(ptEnd.X-lineWidth,ptEnd.Y);
}
else
{
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
}
this.Canvas.closePath();
//this.Canvas.fillStyle='RGB(22,100,100)';
//this.Canvas.fill();
if (this.Canvas.isPointInPath(x,y))
return i;
}
return -1;
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn_XYValue_Line=function(x, y, option)
{
if (this.Status!=10) return -1;
var value=this.IsPointInXYValue(x,y,option);
if (value>=0) return value;
value=this.IsPointInLine(x,y,option);
if (value>=0) return 100;
return -1;
}
this.DrawLine=function(ptStart,ptEnd,isDottedline)
{
if (isDottedline) this.Canvas.setLineDash([5,10]);
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
if (isDottedline) this.Canvas.setLineDash([]);
}
this.CreateLineData=function(ptStart,ptEnd)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=ptEnd.Y;
line.End.X=ptEnd.X;
return line;
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=
{
ClassName:this.ClassName,
Symbol:this.Symbol, Guid:this.Guid, Period:this.Period,Value:[] ,
FrameID:this.Frame.Identify, LineColor:this.LineColor, AreaColor:this.AreaColor,
LineWidth:this.LineWidth, Right:this.Right, EnableSave:this.EnableSave,
IsShowYCoordinate:this.IsShowYCoordinate
};
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
storageData.Value.push({ XValue:item.XValue, YValue:item.YValue, DateTime:item.DateTime });
}
if (this.Text) storageData.Text=this.Text; //如果有文本, 也导出
if (this.FontOption) storageData.FontOption=this.FontOption; //字体也导出
return storageData;
}
//导出基础的配置 不包含点
this.ExportBaseData=function()
{
var data=
{
ClassName:this.ClassName, Guid:this.Guid, FrameID:this.Frame.Identify,
Symbol:this.Symbol, Period:this.Period,Right:this.Right,
LineColor:this.LineColor,
LineWidth:this.LineWidth,
EnableSave:this.EnableSave, IsShowYCoordinate:this.IsShowYCoordinate
};
if (this.AreaColor) data.AreaColor=this.AreaColor;
if (this.Text) data.Text=this.Text; //如果有文本, 也导出
if (this.FontOption)
{
data.FontOption={};
this.SetFont(data.FontOption, this.FontOption); //字体也导出
}
return data;
}
this.IsFrameMinSize=function() //框架是否是最小化模式
{
return this.Frame && this.Frame.IsMinSize;
}
this.PointRange=function(aryPoint)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return null;
if (aryPoint.length==1)
{
var data=
{
Points:[ { X:aryPoint[0].X, Y:aryPoint[0].Y } ]
};
return data;
}
else
{
var xMax=aryPoint[0].X;
var xMin=xMax;
var yMax=aryPoint[0].Y;
var yMin=yMax;
var aryData=[{ X:aryPoint[0].X, Y:aryPoint[0].Y }];
for(var i=1;i<aryPoint.length;++i)
{
if (xMax<aryPoint[i].X) xMax=aryPoint[i].X;
if (xMin>aryPoint[i].X) xMin=aryPoint[i].X;
if (yMax<aryPoint[i].Y) yMax=aryPoint[i].Y;
if (yMin>aryPoint[i].Y) yMin=aryPoint[i].Y;
aryData.push({X:aryPoint[i].X, Y:aryPoint[i].Y});
}
var data=
{
X: { Max: { X:xMax }, Min: { X:xMin} },
Y: { Max: { Y:yMax}, Min: { Y:yMin} },
Points: aryData //所有的点
};
return data;
}
}
this.GetXYCoordinate_default=function()
{
if (this.IsFrameMinSize()) return null;
if (!this.IsShow) return null;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
return this.PointRange(drawPoint);
}
this.GetXYCoordinate=function()
{
return null;
}
this.CopyData_default=function()
{
if (!this.Frame) return null;
var data=this.ExportStorageData();
if (!data) return null;
var dataOffset=0;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
{
}
else
{
var kData=this.Frame.Data;
if (!kData) return null;
dataOffset=kData.DataOffset;
}
var height=this.Frame.ChartBorder.GetHeight();
var yFirst=this.Frame.ChartBorder.GetBottomEx()-this.Point[0].Y;
for(var i=0;i<data.Value.length; ++i)
{
var item=data.Value[i];
var itemPoint=this.Point[i];
item.XIndex=item.XValue-dataOffset+1;
if (i==0)
{
item.XOffset=0;
item.YOffset=0;
}
else
{
var preItem=data.Value[i-1];
var prePoint=this.Point[i-1];
item.XOffset=item.XValue-preItem.XValue;
item.YOffset=itemPoint.Y-prePoint.Y;
}
}
data.DataOffset=dataOffset;
data.YFristScale=yFirst/height;
data.Height=height; //Y轴最大-最小差值
return data;
}
this.SetFont=function(destFont, srcFont)
{
if (!srcFont) return;
if (!destFont) return;
if (srcFont.Family) destFont.Family=srcFont.Family;
if (srcFont.Weight) destFont.Weight=srcFont.Weight;
if (srcFont.Style) destFont.Style=srcFont.Style;
if (IFrameSplitOperator.IsNumber(srcFont.Size)) destFont.Size=srcFont.Size;
}
this.GetFontString=function(fontOption)
{
const defaultFont=16*GetDevicePixelRatio() +"px 微软雅黑";
if (!fontOption || !fontOption.Family || !IFrameSplitOperator.IsPlusNumber(fontOption.Size)) return defaultFont;
var font='';
if (fontOption.Color) font+=fontOption.Color+' ';
if (fontOption.Style) font+=fontOption.Style+' ';
if (fontOption.Weight) font+=fontOption.Weight+' ';
font+=fontOption.Size*GetDevicePixelRatio()+'px ';
font+=fontOption.Family;
return font;
}
//获得多行文本
this.GetMultiLineText=function(text, maxWidth, font , option)
{
if (font) this.Canvas.font=font;
var textWidth=this.Canvas.measureText(text).width;
if (textWidth<=maxWidth) return { AryText:[{Text:text }] };
var singleWidth=this.Canvas.measureText("擎").width;
var estimateCount=parseInt(maxWidth/singleWidth); //预估个数
var endPos=0;
var aryText=[];
while(endPos<text.length-1)
{
var count=estimateCount;
var pos=endPos+count;
if (pos>=text.length)
{
pos=text.length-1;
count=pos-endPos;
}
var subText=text.slice(endPos,endPos+count);
var textWidth=this.Canvas.measureText(subText).width;
if (textWidth>maxWidth)
{
for(var i=count; i>=0 ;--i)
{
subText=text.slice(endPos, endPos+i);
textWidth=this.Canvas.measureText(subText).width;
if (textWidth<maxWidth)
{
aryText.push({Text:subText});
endPos+=i;
break;
}
}
}
else if (textWidth<maxWidth)
{
var bFind=false;
for(var i=count;(i+endPos)<=text.length;++i)
{
subText=text.slice(endPos, endPos+i);
textWidth=this.Canvas.measureText(subText).width;
if (textWidth>maxWidth)
{
subText=text.slice(endPos, endPos+i-1);
aryText.push({Text:subText});
endPos+=i-1;
bFind=true;
break;
}
}
if (!bFind)
{
aryText.push({Text:subText});
endPos=text.length-1;
}
}
else
{
aryText.push({Text:subText});
endPos+=count;
}
}
return { AryText:aryText };
}
this.CloneArrayText=function(aryText)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryText)) return [];
var aryValue=[];
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
if (!item) continue;
aryValue.push({ Text:item.Text });
}
return aryValue;
}
//计算角度
this.CalculateAngle=function(x1, y1, x2,y2)
{
var x = Math.abs(x1 - x2);
var y = Math.abs(y1 - y2);
var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
var cos = x / z;
var radina = Math.acos(cos); //用反三角函数求弧度
var angle = 180 / (Math.PI / radina);//将弧度转换成角度
if (x2 == x1 && y2 < y1)
return 90;
if (x2 == x1 && y2 > y1)
return 270;
if (x2 > x1 && y2 == y1)
return 0;
if (x2 < x1 && y2 == y1)
return 180;
if (x2 > x1 && y2 > y1) //第四象限
return 360 - angle;
if (x2 < x1 && y2 > y1) //第三象限
return 180 + angle;
if (x2 < x1 && y2 < y1) //第二象限
return 180 - angle;
return angle;
}
//复制
//this.CopyData=function() { }
//this.PtInButtons=function(x, y) { }
//计算标签页大小
this.CalculateLabelSize=function(labelInfo)
{
var config=labelInfo.Config;
this.Canvas.font=config.Font;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
var lineHeight=this.Canvas.measureText("擎").width+2;
var maxWidth=0, lineCount=0, labelHeight=config.Mergin.Top+config.Mergin.Bottom;
for(var i=0;i<labelInfo.AryText.length;++i)
{
if (i>0) labelHeight+=config.LineSpace;
var item=labelInfo.AryText[i];
item.NameWidth=0;
item.TextWidth=0;
if (item.Name) item.NameWidth=this.Canvas.measureText(item.Name).width+2;
if (item.Text) item.TextWidth=this.Canvas.measureText(item.Text).width+2;
var itemWidth=item.NameWidth+item.TextWidth;
if (maxWidth<itemWidth) maxWidth=itemWidth;
++lineCount;
labelHeight+=lineHeight;
}
var labelWidth=maxWidth+config.Mergin.Left+config.Mergin.Right;
labelInfo.Width=labelWidth;
labelInfo.Height=labelHeight;
labelInfo.LineHeight=lineHeight;
}
this.DrawDefaultLabel=function(labelInfo, rtBG)
{
var config=labelInfo.Config;
if (config.BGColor)
{
this.Canvas.fillStyle=config.BGColor
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top),ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
}
var xText=rtBG.Left+config.Mergin.Left;
var yText=rtBG.Top+config.Mergin.Top;
for(var i=0;i<labelInfo.AryText.length;++i)
{
var item=labelInfo.AryText[i];
if (i>0) yText+=config.LineSpace;
if (item.Name)
{
this.Canvas.fillStyle=item.NameColor;
this.Canvas.fillText(item.Name,xText,yText);
}
if (item.Text)
{
var xOut=xText+item.NameWidth;
if (config.TextAlign==1) //右对齐
xOut=rtBG.Right-config.Mergin.Right-item.TextWidth;
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(item.Text,xOut ,yText);
}
yText+=labelInfo.LineHeight;
}
}
}
IChartDrawPicture.ColorToRGBA=function(color,opacity)
{
var reg = /^(rgb|RGB)/;
if (reg.test(color))
{
var strHex = "#";
var colorArr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); // 把RGB的3个数值变成数组
// 转成16进制
for (var i = 0; i < colorArr.length; i++)
{
var hex = Number(colorArr[i]).toString(16);
if (hex === "0") hex += hex;
strHex += hex;
}
color=strHex;
}
return "rgba(" + parseInt("0x" + color.slice(1, 3)) + "," + parseInt("0x" + color.slice(3, 5)) + "," + parseInt("0x" + color.slice(5, 7)) + "," + opacity + ")";
}
IChartDrawPicture.RGBToHex=function(rgb)
{
// Choose correct separator
let sep = rgb.indexOf(",") > -1 ? "," : " ";
// Turn "rgb(r,g,b)" into [r,g,b]
rgb = rgb.substr(4).split(")")[0].split(sep);
let r = (+rgb[0]).toString(16),
g = (+rgb[1]).toString(16),
b = (+rgb[2]).toString(16);
if (r.length == 1)
r = "0" + r;
if (g.length == 1)
g = "0" + g;
if (b.length == 1)
b = "0" + b;
return "#" + r + g + b;
}
//16进制颜色转rgb
IChartDrawPicture.HexToRGB=function(color)
{
color = color.toLowerCase();
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
if (color && reg.test(color))
{
if (color.length === 4)
{
var sColorNew = "#";
for (var i=1; i<4; i+=1)
{
sColorNew += color.slice(i, i+1).concat(color.slice(i, i+1));
}
color = sColorNew;
}
//处理六位的颜色值
var sColorChange = [];
for (var i=1; i<7; i+=2)
{
sColorChange.push(parseInt("0x"+color.slice(i, i+2)));
}
return "rgb(" + sColorChange.join(",") + ")";
}
return null;
}
IChartDrawPicture.ArrayDrawPricture=
[
{ Name:"线段", ClassName:'ChartDrawPictureLine', Create:function() { return new ChartDrawPictureLine(); } },
{ Name:"射线", ClassName:'ChartDrawPictureHaflLine', Create:function() { return new ChartDrawPictureHaflLine(); } },
{ Name:"箭头", ClassName:"ChartDrawArrowLine", Create:function() { return new ChartDrawArrowLine(); } },
{ Name:"水平线", ClassName:'ChartDrawPictureHorizontalLine', Create:function() { return new ChartDrawPictureHorizontalLine(); }},
{ Name:"水平射线", ClassName:"ChartDrawPictureHorizontalRay", Create:function() { return new ChartDrawPictureHorizontalRay(); }},
{ Name:"趋势线", ClassName:'ChartDrawPictureTrendLine', Create:function() { return new ChartDrawPictureTrendLine(); }},
{ Name:"矩形", ClassName:'ChartDrawPictureRect', Create:function() { return new ChartDrawPictureRect(); }},
{ Name:"圆弧线", ClassName:'ChartDrawPictureArc', Create:function() { return new ChartDrawPictureArc(); }},
{ Name:"M头W底", ClassName:'ChartDrawPictureWaveMW', Create:function() { return new ChartDrawPictureWaveMW(); }},
{ Name:"头肩型", ClassName:"ChartDrawHeadShouldersBT", Create:function() { return new ChartDrawHeadShouldersBT(); }},
{ Name:"平行线", ClassName:'ChartDrawPictureParallelLines', Create:function() { return new ChartDrawPictureParallelLines(); }},
{ Name:"平行通道", ClassName:'ChartDrawPictureParallelChannel', Create:function() { return new ChartDrawPictureParallelChannel(); }},
{ Name:"价格通道线", ClassName:'ChartDrawPicturePriceChannel', Create:function() { return new ChartDrawPicturePriceChannel(); }},
{ Name:"文本", ClassName:'ChartDrawPictureText', Create:function() { return new ChartDrawPictureText(); }},
{ Name:"江恩角度线", ClassName:'ChartDrawPictureGannFan', Create:function() { return new ChartDrawPictureGannFan(); }},
{ Name:"江恩角度线2", ClassName:'ChartDrawPictureGannFan', Create:function() { return new ChartDrawPictureGannFanV2(); }},
{ Name:"阻速线", ClassName:'ChartDrawPictureResistanceLine', Create:function() { return new ChartDrawPictureResistanceLine(); }},
{ Name:"阻速线2", ClassName:'ChartDrawPictureResistanceLineV2', Create:function() { return new ChartDrawPictureResistanceLineV2(); }},
{ Name:"黄金分割", ClassName:'ChartDrawPictureGoldenSection', Create:function() { return new ChartDrawPictureGoldenSection(); }},
{ Name:"百分比线", ClassName:'ChartDrawPicturePercentage', Create:function() { return new ChartDrawPicturePercentage(); }},
{ Name:"波段线", ClassName:'ChartDrawPictureWaveBand', Create:function() { return new ChartDrawPictureWaveBand(); }},
{ Name:"三角形", ClassName:'ChartDrawPictureTriangle', Create:function() { return new ChartDrawPictureTriangle(); }},
{ Name:"对称角度", ClassName:'ChartDrawPictureSymmetryAngle', Create:function() { return new ChartDrawPictureSymmetryAngle(); }},
{ Name:"圆", ClassName:'ChartDrawPictureCircle', Create:function() { return new ChartDrawPictureCircle(); }},
{ Name:"平行四边形", ClassName:'ChartDrawPictureQuadrangle', Create:function() { return new ChartDrawPictureQuadrangle(); }},
{ Name:"斐波那契周期线", ClassName:'ChartDrawPictureFibonacci', Create:function() { return new ChartDrawPictureFibonacci(); }},
{ Name:"线形回归线", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression(); } },
{ Name:"线形回归带", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression({ IsShowMaxMinLine:true }); } },
{ Name:"延长线形回归带", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression({ IsShowMaxMinLine:true, IsShowExtendLine:true }); } },
{ Name:"尺子", ClassName:"ChartDrawRuler", Create:function() { return new ChartDrawRuler(); } },
{ Name:"标价线", ClassName:"ChartDrawPriceLine", Create:function() { return new ChartDrawPriceLine(); } },
{ Name:"标价线2", ClassName:"ChartDrawPriceLineV2", Create:function() { return new ChartDrawPriceLineV2(); } },
{ Name:"垂直线", ClassName:"ChartDrawVerticalLine", Create:function() { return new ChartDrawVerticalLine(); } },
{ Name:"十字线", ClassName:"ChartDrawCrosshair", Create:function() { return new ChartDrawCrosshair(); } },
{ Name:"波浪尺", ClassName:"ChartDrawWaveRuler", Create:function() { return new ChartDrawWaveRuler(); } },
{ Name:"AB波浪尺", ClassName:"ChartDrawWaveRuler2Point", Create:function() { return new ChartDrawWaveRuler2Point(); } },
{ Name:"箱型线", ClassName:"ChartDrawBox", Create:function() { return new ChartDrawBox(); } },
{ Name:"2点画图例子", ClassName:"ChartDrawTwoPointDemo", Create:function() { return new ChartDrawTwoPointDemo(); } },
{ Name:"3点画图例子", ClassName:"ChartDrawThreePointDemo", Create:function() { return new ChartDrawThreePointDemo(); } },
{ Name:"水平线段", ClassName:"ChartDrawHLineSegment", Create:function() { return new ChartDrawHLineSegment();} },
{ Name:"平行射线", ClassName:"ChartDrawParallelRaysLines", Create:function() { return new ChartDrawParallelRaysLines();}},
{ ClassName:'ChartDrawPictureIconFont', Create:function() { return new ChartDrawPictureIconFont(); }},
//涂鸦 不绑定K线坐标
{ Name:"涂鸦线段", ClassName:'ChartDrawGraffitiLine', Create:function() { return new ChartDrawGraffitiLine(); } },
{ Name:"固定范围成交量分布图", ClassName:"ChartDrawVolProfile", Create:function() { return new ChartDrawVolProfile(); }},
{ Name:"DisjointChannel", ClassName:"ChartDrawDisjontChannel", Create:function() { return new ChartDrawDisjontChannel();}},
{ Name:"FlatTop", ClassName:"ChartDrawFlatTop", Create:function() { return new ChartDrawFlatTop();}},
{ Name:"水平线2", ClassName:"ChartDrawHLine", Create:function() { return new ChartDrawHLine(); }},
{ Name:"MonitorLine", ClassName:"ChartDrawMonitorLine", Create:function() { return new ChartDrawMonitorLine(); }},
//trading view样式
{ Name:"Note", ClassName:"ChartDrawNote", Create:function() { return new ChartDrawNote(); } },
{ Name:"AnchoredText", ClassName:"ChartDrawAnchoredText", Create:function() { return new ChartDrawAnchoredText();} },
{ Name:"PriceLabel", ClassName:"ChartDrawPriceLabel", Create:function() { return new ChartDrawPriceLabel();} },
{ Name:"PriceNote", ClassName:"ChartDrawPriceNote", Create:function() { return new ChartDrawPriceNote();} },
{ Name:"FibWedge", ClassName:"ChartDrawFibWedge", Create:function(){ return new ChartDrawFibWedge(); }},
{ Name:"FibRetracement", ClassName:"ChartFibRetracement", Create:function() { return new ChartFibRetracement(); }}, //斐波那契回测
{ Name:"FibSpeedResistanceFan", ClassName:"ChartFibSpeedResistanceFan", Create:function() { return new ChartFibSpeedResistanceFan(); }}, //斐波那契扇形
{ Name:"PriceRange", ClassName:"ChartPriceRange", Create:function() { return new ChartPriceRange(); }},
{ Name:"DateRange", ClassName:"ChartDateRange", Create:function() { return new ChartDateRange(); }},
{ Name:"DatePriceRange", ClassName:"ChartDatePriceRange", Create:function() { return new ChartDatePriceRange(); }},
{ Name:"InfoLine", ClassName:"ChartInfoLine", Create:function() { return new ChartInfoLine(); }},
{ Name:"TrendAngle", ClassName:"ChartTrendAngle", Create:function() { return new ChartTrendAngle(); }},
{ Name:"ArrowMarker", ClassName:"ChartArrowMarker", Create:function() { return new ChartArrowMarker(); } },
{ Name:"BarsPattern", ClassName:"ChartBarsPattern", Create:function() { return new ChartBarsPattern(); } },
];
IChartDrawPicture.MapIonFont=new Map(
[
["icon-arrow_up", { Text:'\ue683', Color:'#318757', Family:"iconfont"}],
["icon-arrow_down", { Text:'\ue681', Color:'#db563e', Family:"iconfont"}],
["icon-arrow_right", { Text:'\ue682', Color:'#318757', Family:"iconfont"}],
["icon-arrow_left", { Text:'\ue680',Color:'#318757', Family:"iconfont"}]
]);
IChartDrawPicture.GetDrawPictureByName=function(value)
{
for(var i in IChartDrawPicture.ArrayDrawPricture)
{
var item=IChartDrawPicture.ArrayDrawPricture[i];
if (item.Name==value) return item;
}
return null;
}
IChartDrawPicture.GetDrawPictureByClassName=function(value)
{
for(var i in IChartDrawPicture.ArrayDrawPricture)
{
var item=IChartDrawPicture.ArrayDrawPricture[i];
if (item.ClassName==value) return item;
}
return null;
}
//注册一个新的画图工具 {Name:中文名字, ClassName:类名, Create:function()}
IChartDrawPicture.RegisterDrawPicture=function(obj)
{
if (!obj.Name || !obj.ClassName || !obj.Create) return false;
var item={ Name:obj.Name, ClassName:obj.ClassName, Create:obj.Create };
IChartDrawPicture.ArrayDrawPricture.push(item);
JSConsole.Chart.Log('[IChartDrawPicture.RegisterDrawPicture] registered new draw picture class. item=',item);
return true;
}
//注册一个新图标 {Name:, Text: , Color:, Family:}
IChartDrawPicture.RegisterIonFont=function(obj)
{
if (!obj.Name || !obj.Text || !obj.Family) return false;
var isOverwirte=IChartDrawPicture.MapIonFont.has(obj.Name);
IChartDrawPicture.MapIonFont.set(obj.Name, obj);
JSConsole.Chart.Log('[IChartDrawPicture.RegisterIonFont] registered new icon font, obj=, isOverwirte=',obj, isOverwirte);
return true;
}
IChartDrawPicture.CreateChartDrawPicture=function(obj) //创建画图工具
{
var item=IChartDrawPicture.GetDrawPictureByClassName(obj.ClassName);
if (!item) return null;
var chartDraw=item.Create();
//TODO:后面都放到每一个SetOptin里面
if (obj.Period>=0) chartDraw.Period=obj.Period;
if (obj.Right>=0) chartDraw.Right=obj.Right;
if (obj.Guid) chartDraw.Guid=obj.Guid;
if (obj.Symbol) chartDraw.Symbol=obj.Symbol;
if (obj.Value) chartDraw.Value=obj.Value;
if (obj.Text) chartDraw.Text=obj.Text;
if (obj.LineColor) chartDraw.LineColor=obj.LineColor;
if (obj.AreaColor) chartDraw.AreaColor=obj.AreaColor;
if (obj.FontOption) chartDraw.FontOption=obj.FontOption;
if (obj.Label) chartDraw.Label=obj.Label;
if (obj.LineWidth>0) chartDraw.LineWidth=obj.LineWidth;
if (obj.EnableMove===false) chartDraw.EnableMove=obj.EnableMove;
if (IFrameSplitOperator.IsBool(obj.EnableSave)) chartDraw.EnableSave=obj.EnableSave;
if (IFrameSplitOperator.IsNumber(obj.ChannelWidth)) chartDraw.ChannelWidth=obj.ChannelWidth;
if (IFrameSplitOperator.IsBool(obj.IsShowYCoordinate)) chartDraw.IsShowYCoordinate=obj.IsShowYCoordinate;
if (chartDraw.SetOption) chartDraw.SetOption(obj);
return chartDraw;
}
//画图工具-线段
function ChartDrawPictureLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureLine';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.IsShowYCoordinate=false;
this.CopyData=this.CopyData_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:false} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
/*
if (this.IsSelected)
{
this.Canvas.strokeStyle='rgba(255,0,0,0.5)';
this.Canvas.lineWidth=20 * GetDevicePixelRatio();
this.Canvas.stroke();
}
*/
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.GetYCoordinatePoint=function()
{
if (this.IsFrameMinSize()) return null;
if (!this.IsShow) return null;
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
if (this.Status!=10) return null;
//完成
var aryPoint=[];
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
var y=this.Frame.GetYFromData(item.YValue,false);
aryPoint.push({ Y:y, YValue:item.YValue, Item:item, Color:this.PointColor });
}
return aryPoint;
}
}
//趋势线角度
function ChartTrendAngle()
{
this.newMethod=ChartDrawPictureLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartTrendAngle';
this.AngleLineLength=100;
this.AngleLineDash=[3,3];
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (IFrameSplitOperator.IsNumber(option.AngleLineLength)) this.AngleLineLength=option.AngleLineLength;
if (option.Font) this.Font=option.Font;
if (option.AngleLineDash) this.AngleLineDash=option.AngleLineDash;
}
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:false} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
this.DrawAngle(ptStart, ptEnd);
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawAngle=function(ptStart, ptEnd)
{
var pixelRatio=GetDevicePixelRatio();
var angle=this.CalculateAngle(ptStart.X, ptStart.Y, ptEnd.X, ptEnd.Y); //角度
var lineLength=this.AngleLineLength*pixelRatio; //角度线长度
var ptRight={ X:ptStart.X+lineLength, Y:ptStart.Y };
if (this.AngleLineDash) this.Canvas.setLineDash(this.AngleLineDash); //画虚线
this.Canvas.lineWidth=1*GetDevicePixelRatio();
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(ptStart.X),ToFixedPoint(ptStart.Y));
this.Canvas.lineTo(ToFixedPoint(ptRight.X),ToFixedPoint(ptRight.Y));
this.Canvas.stroke();
this.Canvas.beginPath();
if (angle<=180)
{
this.Canvas.arc(ptStart.X,ToFixedPoint(ptStart.Y),lineLength,0,(Math.PI / 180)*(360-angle), true);
var text=`${angle.toFixed(0)}°`;
}
else
{
this.Canvas.arc(ptStart.X,ToFixedPoint(ptStart.Y),lineLength,0,(Math.PI / 180)*(360-angle), false);
var text=`${(angle-360).toFixed(0)}°`;
}
this.Canvas.stroke();
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.LineColor;
if (this.AngleLineDash) this.Canvas.setLineDash([]);
this.Canvas.fillText(text,ptRight.X+5,ptRight.Y);
}
}
//画图工具-涂鸦线段 Y轴关联数值, X轴不关联
function ChartDrawGraffitiLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawGraffitiLine';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=null;
this.PointCount=2; //画点的个数
this.EnableMoveCheck=false; //允许移动时不监测是否超出边界
this.PointToValue=function()
{
if (!this.Frame) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i=0;i<this.Point.length;++i)
{
var item=this.Point[i];
var yValue=this.Frame.GetYData(item.X);
var valueItem={ XValue:item.Y, YValue:yValue };
this.Value[i]=valueItem;
}
}
else
{
for(var i=0;i<this.Point.length;++i)
{
var item=this.Point[i];
var yValue=this.Frame.GetYData(item.Y);
var valueItem={ XValue:item.X, YValue:yValue };
this.Value[i]=valueItem;
}
}
return true;
}
//Value => Point
this.ValueToPoint=function()
{
if (!this.Frame) return false;
var isHScreen=this.Frame.IsHScreen;
this.Point=[];
for(var i in this.Value)
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=item.XValue;
pt.X=this.Frame.GetYFromData(item.YValue);
}
else
{
pt.X=item.XValue;
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
this.Point[i]=pt;
}
}
this.UpdateXValue=function() //通过datetime更新x的索引
{
}
this.CalculateDrawPoint=function(option)
{
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
var drawPoint=[];
if (this.Status==10)
{
var isHScreen=this.Frame.IsHScreen;
for(var i in this.Value)
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen) //横屏X,Y对调
{
pt.Y=item.XValue;
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
pt.X=item.XValue;
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
drawPoint.push(pt);
}
}
else
{
drawPoint=this.Point;
}
return drawPoint;
}
//坐标是否在点上 返回在第几个点上
this.IsPointInXYValue=function(x,y,option)
{
if (!this.Frame) return -1;
if (!this.Value) return -1;
var radius=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) radius+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) radius+=this.Option.Zoom;
var isHScreen=this.Frame.IsHScreen;
radius*=GetDevicePixelRatio();
for(var i=0;i<this.Value.length; ++i) //是否在点上
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=item.XValue;
pt.X==this.Frame.GetYFromData(item.YValue);
}
else
{
pt.X=item.XValue;
pt.Y=this.Frame.GetYFromData(item.YValue);
}
this.Canvas.beginPath();
this.Canvas.arc(pt.X,pt.Y,radius,0,360);
if (this.Canvas.isPointInPath(x,y)) return i;
}
return -1;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
/*
if (this.IsSelected)
{
this.Canvas.strokeStyle='rgba(255,0,0,0.5)';
this.Canvas.lineWidth=20 * GetDevicePixelRatio();
this.Canvas.stroke();
}
*/
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
}
//画图工具-箭头线
function ChartDrawArrowLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawArrowLine';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.ArrawLineWidth=5;
this.ArrawLength=15; //三角斜边长度
this.ArrawAngle=35; //三角斜边一直线夹角
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
//计算箭头
var theta=this.ArrawAngle; //三角斜边一直线夹角
var headlen=this.ArrawLength; //三角斜边长度
var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.Canvas.beginPath();
var arrowX = ptEnd.X + topX;
var arrowY = ptEnd.Y + topY;
this.Canvas.moveTo(arrowX,arrowY);
this.Canvas.lineTo(ptEnd.X, ptEnd.Y);
arrowX = ptEnd.X + botX;
arrowY = ptEnd.Y + botY;
this.Canvas.lineTo(arrowX,arrowY);
this.Canvas.lineWidth=this.ArrawLineWidth*GetDevicePixelRatio();
this.Canvas.stroke();
this.RestoreLineWidth();
/*
if (this.IsSelected)
{
this.Canvas.strokeStyle='rgba(255,0,0,0.5)';
this.Canvas.lineWidth=20 * GetDevicePixelRatio();
this.Canvas.stroke();
}
*/
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint([drawPoint[0]]); //画点
this.Canvas.restore();
}
}
function ChartArrowMarker()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartArrowMarker';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.InsideLineConfig={ Angle:25, MaxWidth:70, WidthRate:0.3 };
this.InsideWidth=70;
this.OutLineConfig={ Angle:35, MaxWidth:100, WidthRate:0.4 };
this.OutWidth=100;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
this.Super_SetOption(option);
if (option.AreaColor) this.AreaColor=option.AreaColor;
else this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor, 0.6);
}
this.CalculatePoint=function(angle, ptStart, ptEnd, lineWidth)
{
var theta=angle; //三角斜边一直线夹角
var headlen=lineWidth; //三角斜边长度
var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
return { Top:{X:topX+ptEnd.X, Y:topY+ptEnd.Y}, Bottom:{X:botX+ptEnd.X, Y:botY+ptEnd.Y} };
}
this.CalculateLineWidth=function(ptStart, ptEnd)
{
var a=ptStart.X-ptEnd.X;
var b=ptStart.Y-ptEnd.Y;
var c=Math.sqrt(a*a+b*b);
this.InsideWidth=c*this.InsideLineConfig.WidthRate;
this.OutWidth=c*this.OutLineConfig.WidthRate;
if (this.InsideWidth>this.InsideLineConfig.MaxWidth) this.InsideWidth=this.InsideLineConfig.MaxWidth;
if (this.OutWidth>this.OutLineConfig.MaxWidth) this.OutWidth=this.OutLineConfig.MaxWidth;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.CalculateLineWidth(ptStart, ptEnd);
//计算箭头 的两条边线坐标
var outArrow=this.CalculatePoint(this.OutLineConfig.Angle, ptStart, ptEnd, this.OutWidth);
var insideArrow=this.CalculatePoint(this.InsideLineConfig.Angle, ptStart, ptEnd, this.InsideWidth);
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(insideArrow.Top.X,insideArrow.Top.Y);
this.Canvas.lineTo(outArrow.Top.X,outArrow.Top.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.lineTo(outArrow.Bottom.X,outArrow.Bottom.Y);
this.Canvas.lineTo(insideArrow.Bottom.X,insideArrow.Bottom.Y);
this.Canvas.lineTo(ptStart.X,ptStart.Y);
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.stroke();
this.Canvas.closePath();
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.fill();
/*
if (this.IsSelected)
{
this.Canvas.strokeStyle='rgba(255,0,0,0.5)';
this.Canvas.lineWidth=20 * GetDevicePixelRatio();
this.Canvas.stroke();
}
*/
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint([ptStart,ptEnd]); //画点
this.Canvas.restore();
}
}
//画图工具-射线
function ChartDrawPictureHaflLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureHaflLine';
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.FullLine;
this.IsPointIn=function(x, y, option)
{
var result=this.IsPointIn_XYValue_Line(x,y,option);
if (result>=0) return result;
if (!this.FullLine) return result;
var ptStart=this.FullLine.Start;
var ptEnd=this.FullLine.End;
var pixel=GetDevicePixelRatio();
var lineWidth=5*pixel;
this.Canvas.beginPath();
if (ptStart.X==ptEnd.X) //竖线
{
this.Canvas.moveTo(ptStart.X-lineWidth,ptStart.Y);
this.Canvas.lineTo(ptStart.X+lineWidth,ptStart.Y);
this.Canvas.lineTo(ptEnd.X+lineWidth,ptEnd.Y);
this.Canvas.lineTo(ptEnd.X-lineWidth,ptEnd.Y);
}
else
{
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
}
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return 100;
return result;
}
this.Draw=function()
{
this.LinePoint=[];
this.FullLine=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:false, IsCheckY:false});
if (!drawPoint || drawPoint.length!=2) return;
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
this.Canvas.moveTo(drawPoint[0].X,drawPoint[0].Y);
this.Canvas.lineTo(drawPoint[1].X,drawPoint[1].Y);
var endPoint=this.CalculateExtendLineEndPoint(drawPoint);
this.Canvas.lineTo(endPoint.X,endPoint.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
this.FullLine={Start:drawPoint[0], End:endPoint};
}
}
// 画图工具-水平线 支持横屏
function ChartDrawPictureHorizontalLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureHorizontalLine';
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsDrawFirst=true;
this.LineWidth=1;
this.Super_SetOption=this.SetOption; //父类函数
this.Super_ExportStorageData=this.ExportStorageData;
this.LabelConfig=
{
Left:{ IsShow:true, Margin:{ Left:5, Top:4, Bottom:2, Right:5 } },
Right:{ IsShow:true, Margin:{ Left:5, Top:4, Bottom:2, Right:5 } },
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`, TextColor:"rgb(255,255,255)"
};
this.InsideLabelConfig=
{
Position:0, //0=左, 1=右
Font:`${14*GetDevicePixelRatio()}px 微软雅黑`,
Margin:{ Left:5, Top:4, Bottom:2, Right:5 },
TextColor:"rgb(255,255,255)",
BGAlpha:0.8, //背景色透明度
}
this.LabelTitle;
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.LabelTitle) this.LabelTitle=option.LabelTitle;
if (option.Label)
{
var item=option.Label;
if (item.Left)
{
var subItem=item.Left;
if (IFrameSplitOperator.IsBool(subItem.IsShow)) this.LabelConfig.Left.IsShow=subItem.IsShow;
}
if (item.Right)
{
var subItem=item.Right;
if (IFrameSplitOperator.IsBool(subItem.IsShow)) this.LabelConfig.Right.IsShow=subItem.IsShow;
}
if (item.Font) this.LabelConfig.Font=item.Font;
if (item.TextColor) this.LabelConfig.FoTextColornt=item.TextColor;
}
if (option.InsideLabel)
{
var item=option.InsideLabel;
if (item.Font) this.InsideLabelConfig.Font=item.Font;
if (item.TextColor) this.InsideLabelConfig.TextColor=item.TextColor;
if (IFrameSplitOperator.IsNumber(item.Position)) this.InsideLabelConfig.Position=item.Position;
if (IFrameSplitOperator.IsNumber(item.BGAlpha)) this.InsideLabelConfig.BGAlpha=item.BGAlpha;
}
}
}
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
if (this.LabelTitle) storageData.LabelTitle=this.LabelTitle;
}
return storageData;
}
/*
this.GetXYCoordinate=function()
{
if (this.IsFrameMinSize()) return null;
var drawPoint=this.CalculateDrawPoint();
return this.PointRange(drawPoint);
}
*/
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint || drawPoint.length!=1) return;
if (!this.Frame) return;
if (this.Value.length!=1) return;
if (!this.IsYValueInFrame(this.Value[0].YValue)) return null;
var isHScreen=this.Frame.IsHScreen;
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
if (isHScreen)
{
left=this.Frame.ChartBorder.GetTop();
right=this.Frame.ChartBorder.GetBottom();
}
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(drawPoint[0].X,left);
this.Canvas.lineTo(drawPoint[0].X,right);
}
else
{
var yFixed=ToFixedPoint2(this.LineWidth,drawPoint[0].Y);
this.Canvas.moveTo(left,yFixed);
this.Canvas.lineTo(right,yFixed);
}
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:new Point(), End:new Point()};
if (isHScreen)
{
line.Start.X=drawPoint[0].X;
line.Start.Y=left;
line.End.X=drawPoint[0].X;
line.End.Y=right;
}
else
{
line.Start.X=left;
line.Start.Y=drawPoint[0].Y;
line.End.X=right;
line.End.Y=drawPoint[0].Y;
}
this.LinePoint.push(line);
//画点
this.DrawPoint(drawPoint);
//显示价格
this.DrawInsideLabel(drawPoint[0])
this.Canvas.restore();
this.DrawValueLabel(drawPoint[0]);
}
this.DrawValueLabel=function(point)
{
if (!point) return;
if (this.Frame.IsHScreen) return; //不支持横屏
var y=point.Y;
var yValue=this.Frame.GetYData(y);
var text=yValue.toFixed(2);
var border=this.Frame.GetBorder();
var config=this.LabelConfig;
this.Canvas.font=config.Font;
var textHeight=this.Canvas.measureText("擎").width;
var textWidth=this.Canvas.measureText(text).width;
if (config.Left.IsShow && this.Frame.ChartBorder.Left>5)
{
var margin=config.Left.Margin;
var rtBG={ Right:border.Left-1, Height:textHeight+margin.Top+margin.Bottom, Width:textWidth+margin.Left+margin.Right };
rtBG.Top=y-textHeight/2-margin.Top;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Left=rtBG.Right-rtBG.Width;
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "top";
var xText=rtBG.Left+margin.Left;
var yText=rtBG.Top+margin.Top;
this.Canvas.fillStyle=config.TextColor;
this.Canvas.fillText(text,xText,yText);
}
if (config.Right.IsShow && this.Frame.ChartBorder.Right>5)
{
var margin=config.Right.Margin;
var rtBG={ Left:border.Right+1, Height:textHeight+margin.Top+margin.Bottom, Width:textWidth+margin.Left+margin.Right };
rtBG.Top=y-textHeight/2-margin.Top;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "top";
var xText=rtBG.Left+margin.Left;
var yText=rtBG.Top+margin.Top;
this.Canvas.fillStyle=config.TextColor;
this.Canvas.fillText(text,xText,yText);
}
}
this.DrawInsideLabel=function(point)
{
if (!point) return;
var isHScreen=this.Frame.IsHScreen;
var config=this.InsideLabelConfig;
if (config.Position!=0 && config.Position!=1) return;
var margin=config.Margin;
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=config.Font;
var textHeight=this.Canvas.measureText("擎").width;
var border=this.Frame.GetBorder();
if (isHScreen)
{
var yValue=this.Frame.GetYData(point.X);
var text=yValue.toFixed(2);
if (this.LabelTitle) text=this.LabelTitle+text;
var textWidth=this.Canvas.measureText(text).width;
var rtBG=null;
if (config.Position==0) //左
{
var rtBG={ Top:border.Top+1, Width:textHeight+margin.Top+margin.Bottom, Height:textWidth+margin.Left+margin.Right, Left:point.X };
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else if (config.Position==1) //右
{
var rtBG={ Bottom:border.Bottom-1, Width:textHeight+margin.Top+margin.Bottom, Height:textWidth+margin.Left+margin.Right, Left:point.X };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
}
var bgColor=this.LineColor;
if (config.BGAlpha<1) bgColor=IChartDrawPicture.ColorToRGBA(this.LineColor, config.BGAlpha);
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
var xText=rtBG.Right-margin.Top;
var yText=rtBG.Top+margin.Left;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.fillStyle=config.TextColor;
this.Canvas.fillText(text,0,0);
}
else
{
var yValue=this.Frame.GetYData(point.Y);
var text=yValue.toFixed(2);
if (this.LabelTitle) text=this.LabelTitle+text;
var textWidth=this.Canvas.measureText(text).width;
var rtBG=null;
if (config.Position==0) //左
{
var rtBG={ Left:border.Left+1, Height:textHeight+margin.Top+margin.Bottom, Width:textWidth+margin.Left+margin.Right, Bottom:point.Y };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else if (config.Position==1) //右
{
var rtBG={ Right:border.Right-1, Height:textHeight+margin.Top+margin.Bottom, Width:textWidth+margin.Left+margin.Right, Bottom:point.Y };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Left=rtBG.Right-rtBG.Width;
}
var bgColor=this.LineColor;
if (config.BGAlpha<1) bgColor=IChartDrawPicture.ColorToRGBA(this.LineColor, config.BGAlpha);
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
var xText=rtBG.Left+margin.Left;
var yText=rtBG.Top+margin.Top;
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "top";
this.Canvas.fillStyle=config.TextColor;
this.Canvas.fillText(text,xText,yText);
}
}
}
// 画图工具-水平射线线 支持横屏
function ChartDrawPictureHorizontalRay()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureHorizontalRay';
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsDrawFirst=true;
this.LineWidth=1;
this.Super_SetOption=this.SetOption; //父类函数
this.Super_ExportStorageData=this.ExportStorageData;
this.LabelConfig=
{
Right:{ IsShow:true, Margin:{ Left:5, Top:4, Bottom:2, Right:5 } },
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`, TextColor:"rgb(255,255,255)"
};
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.LabelTitle) this.LabelTitle=option.LabelTitle;
if (option.Label)
{
var item=option.Label;
if (item.Right)
{
var subItem=item.Right;
if (IFrameSplitOperator.IsBool(subItem.IsShow)) this.LabelConfig.Right.IsShow=subItem.IsShow;
}
if (item.Font) this.LabelConfig.Font=item.Font;
if (item.TextColor) this.LabelConfig.FoTextColornt=item.TextColor;
}
}
}
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
}
return storageData;
}
this.GetXYCoordinate=function()
{
if (this.IsFrameMinSize()) return null;
var drawPoint=this.CalculateDrawPoint();
var data=this.PointRange(drawPoint);
if (data) data.IsShowYCoordinate=false;
return data;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint || drawPoint.length!=1) return;
if (!this.Frame) return;
if (this.Value.length!=1) return;
if (!this.IsYValueInFrame(this.Value[0].YValue)) return null;
var isHScreen=this.Frame.IsHScreen;
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
if (isHScreen)
{
left=this.Frame.ChartBorder.GetTop();
right=this.Frame.ChartBorder.GetBottom();
}
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(drawPoint[0].X,drawPoint[0].Y);
this.Canvas.lineTo(drawPoint[0].X,right);
}
else
{
var yFixed=ToFixedPoint2(this.LineWidth,drawPoint[0].Y);
this.Canvas.moveTo(drawPoint[0].X,yFixed);
this.Canvas.lineTo(right,yFixed);
}
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:new Point(), End:new Point()};
if (isHScreen)
{
line.Start.X=drawPoint[0].X;
line.Start.Y=drawPoint[0].Y;
line.End.X=drawPoint[0].X;
line.End.Y=right;
}
else
{
line.Start.X=drawPoint[0].X;
line.Start.Y=drawPoint[0].Y;
line.End.X=right;
line.End.Y=drawPoint[0].Y;
}
this.LinePoint.push(line);
//画点
this.DrawPoint(drawPoint);
this.Canvas.restore();
this.DrawValueLabel(drawPoint[0]);
}
this.DrawValueLabel=function(point)
{
if (!point) return;
if (this.Frame.IsHScreen) return; //不支持横屏
var y=point.Y;
var yValue=this.Frame.GetYData(y);
var text=yValue.toFixed(2);
var border=this.Frame.GetBorder();
var config=this.LabelConfig;
this.Canvas.font=config.Font;
var textHeight=this.Canvas.measureText("擎").width;
var textWidth=this.Canvas.measureText(text).width;
if (config.Right.IsShow && this.Frame.ChartBorder.Right>5)
{
var margin=config.Right.Margin;
var rtBG={ Left:border.Right+1, Height:textHeight+margin.Top+margin.Bottom, Width:textWidth+margin.Left+margin.Right };
rtBG.Top=y-textHeight/2-margin.Top;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
this.Canvas.textAlign="left";
this.Canvas.textBaseline = "top";
var xText=rtBG.Left+margin.Left;
var yText=rtBG.Top+margin.Top;
this.Canvas.fillStyle=config.TextColor;
this.Canvas.fillText(text,xText,yText);
}
}
}
//水平线2
function ChartDrawHLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.Super_SetOption=this.SetOption; //父类函数
this.Super_ExportStorageData=this.ExportStorageData;
//this.Label; //{Text:文本, Position: 0=左, 1=右 2=中间 }
//this.Label={ Text:"xxxxxxx", Position:1};
this.LineWidth=1;
this.Precision=2; //小数位数
this.ValueTextColor='rgb(250,250,250)';
this.IsShowCorssCursor=true; //画的时候是否显示十字光标
this.GetLabelCallback; //绘制标题回调函数
this.PointCount=1;
this.ClassName='ChartDrawHLine';
this.Font=14*GetDevicePixelRatio() +"px 微软雅黑";
this.TextFont=12*GetDevicePixelRatio() +"px 微软雅黑";
this.RightSpaceWidth=50;
this.ButtonPosition=0; //按钮位置, 0=价格后面, 1=价格上面 2=价格上面 左对齐 3=垂直排列
this.ButtonBGColor='rgb(190,190,190)';
this.ButtonSpace=3;
this.TextMargin={ Left:0, Right:0, Top:0, Bottom:0, YOffset:4*GetDevicePixelRatio() };
this.AlwaysShowLab=false; //总是显示标签
this.Button=
{
CloseIcon: { Text:'\ue62b', Color:'rgb(255,255,255)', Family:"iconfont", Size:16, ID:JSCHART_BUTTON_ID.DRAW_PICTURE_DELETE, TooltipText:null, Margin:{ Left:2, Right:2 } },
SettingIcon: { Text:'\ue623',Color:'rgb(255,255,255)', Family:"iconfont", Size:16, ID:JSCHART_BUTTON_ID.DRAW_PICTURE_SETTING, TooltipText:null, Margin:{ Left:2, Right:2 } }
//修改ID, Text , TooltipText 可以外部定制按钮
}
this.CustomButton=[]; //自定义的按钮 { Text:'\ue62b', Color:'rgb(255,255,255)', Family:"iconfont", Size:16, ID:JSCHART_BUTTON_ID.DRAW_PICTURE_BUTTON_1, TooltipText:null, Data:null }
this.AryShowButton=[]; //需要显示的按钮 { Data:, Width }
this.AryButton=[];
this.ExtendData; //扩展数据
this.ShowPriceTextConfig=
{
IsShow:[false, false, true], //[0]=left内 [1]=right内 [2]=right外
Font:
[
`${12*GetDevicePixelRatio()}px 微软雅黑`,
`${12*GetDevicePixelRatio()}px 微软雅黑`,
],
};
this.LableInfo; //{ Position:2=右侧外部 }
//内部变量
this.ColseButtonSize=0;
this.SettingButtonSize=0;
this.ButtonBGWidth=0;
this.VerticalButtonInfo={ Width:0, Height:0 }; //垂直按钮信息
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.GetLabelCallback)
{
this.GetLabelCallback=option.GetLabelCallback;
}
if (IFrameSplitOperator.IsNumber(option.Precision)) this.Precision=option.Precision;
if (option.Font) this.Font=option.Font;
if (option.ValueTextColor) this.ValueTextColor=option.ValueTextColor;
if (option.ButtonBGColor) this.ButtonBGColor=option.ButtonBGColor;
if (IFrameSplitOperator.IsNumber(option.ButtonPosition)) this.ButtonPosition=option.ButtonPosition;
if (IFrameSplitOperator.IsNumber(option.RightSpaceWidth)) this.RightSpaceWidth=option.RightSpaceWidth;
if (IFrameSplitOperator.IsBool(option.AlwaysShowLab)) this.AlwaysShowLab=option.AlwaysShowLab;
if (option.Button)
{
var item=option.Button;
if (item.CloseIcon)
{
this.Button.CloseIcon=CloneData(item.CloseIcon);
if (!this.Button.CloseIcon.ID) this.Button.CloseIcon.ID=JSCHART_BUTTON_ID.DRAW_PICTURE_DELETE;
}
else if (item.CloseIcon===null)
{
this.Button.CloseIcon=null;
}
if (item.SettingIcon)
{
this.Button.SettingIcon=CloneData(item.SettingIcon);
if (!this.Button.SettingIcon.ID) this.Button.SettingIcon.ID=JSCHART_BUTTON_ID.DRAW_PICTURE_SETTING;
}
else if (item.SettingIcon===null)
{
this.Button.SettingIcon=null;
}
}
if (option.ExtendData) this.ExtendData=option.ExtendData;
if (IFrameSplitOperator.IsNonEmptyArray(option.IsShowPriceText))
{
for(var i=0;i<option.IsShowPriceText.length && i<3;++i)
{
var value=option.IsShowPriceText[i]
if (IFrameSplitOperator.IsBool(value)) this.ShowPriceTextConfig.IsShow[i]=value;
}
}
if (option.TextMargin)
{
var item=option.TextMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.TextMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Right)) this.TextMargin.Right=item.Right;
if (IFrameSplitOperator.IsNumber(item.Top)) this.TextMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.TextMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.TextMargin.YOffset=item.YOffset;
}
}
}
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
if (this.Label) storageData.Label=this.Label;
}
return storageData;
}
/*
this.GetXYCoordinate=function()
{
if (this.IsFrameMinSize()) return null;
var drawPoint=this.CalculateDrawPoint();
return this.PointRange(drawPoint);
}
*/
this.IsDrawMain=function() //选中绘制在动态绘图上, 没有选中绘制在背景上
{
if (!this.GetActiveDrawPicture) return true;
var active=this.GetActiveDrawPicture();
if (active.Select.Guid==this.Guid) return false;
return true;
}
this.MainDraw=function()
{
this.Draw();
}
//获取需要显示的按钮 系统按钮+自定义按钮
this.GetShowButton=function()
{
var aryButton=[];
var item=this.Button.SettingIcon;
if (item && item.Text) aryButton.push({ Data:item, Width:null });
item=this.Button.CloseIcon;
if (item && item.Text) aryButton.push({ Data:item, Width:null });
if (IFrameSplitOperator.IsNonEmptyArray(this.CustomButton))
{
for(var i=0;i<this.CustomButton.length;++i)
{
item=this.CustomButton[i];
if (item && item.Text) aryButton.push({ Data:item, Width:null });
}
}
return aryButton;
}
this.Draw=function(moveonPoint, mouseStatus)
{
this.AryShowButton=[];
this.LinePoint=[];
this.AryButton=[];
this.ColseButtonSize=0;
this.SettingButtonSize=0;
this.ButtonBGWidth=0;
this.LableInfo=null;
this.VerticalButtonInfo.Width=0;
this.VerticalButtonInfo.Height=0;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint || drawPoint.length!=1) return;
if (!this.Frame) return;
if (this.Value.length!=1) return;
var bVisibleRange=this.IsYValueInFrame(this.Value[0].YValue); //是否在可视范围
if (!this.AlwaysShowLab && !bVisibleRange) return;
var isHScreen=this.Frame.IsHScreen;
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
if (isHScreen)
{
left=this.Frame.ChartBorder.GetTop();
right=this.Frame.ChartBorder.GetBottom();
}
this.ClipFrame();
//画线段
if (bVisibleRange)
{
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
if (isHScreen)
{
this.Canvas.moveTo(drawPoint[0].X,left);
this.Canvas.lineTo(drawPoint[0].X,right);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(drawPoint[0].Y));
this.Canvas.lineTo(right,ToFixedPoint(drawPoint[0].Y));
}
this.Canvas.stroke();
this.RestoreLineWidth();
}
//画水平线段
var line={Start:new Point(), End:new Point()};
if (isHScreen)
{
line.Start.X=drawPoint[0].X;
line.Start.Y=left;
line.End.X=drawPoint[0].X;
line.End.Y=right;
}
else
{
line.Start.X=left;
line.Start.Y=drawPoint[0].Y;
line.End.X=right;
line.End.Y=drawPoint[0].Y;
}
this.LinePoint.push(line);
if (bVisibleRange) //在可视范围内
{
var yValue=this.Frame.GetYData(drawPoint[0].Y, false);
var strPrice=yValue.toFixed(this.Precision);
if (this.ShowPriceTextConfig.IsShow[0])
{
this.DrawPriceText(strPrice, line.Start, line.End, 0);
}
if (this.ShowPriceTextConfig.IsShow[1])
{
this.DrawPriceText(strPrice, line.Start, line.End, 1);
}
}
if (this.GetLabelCallback) this.LableInfo=this.GetLabelCallback(this);
this.AryShowButton=this.GetShowButton(); //获取按钮
if (bVisibleRange) this.DrawInternalLabel(drawPoint[0].Y); //内部价格标签
//画中心点
if (bVisibleRange)
{
var xCenter=left+(right-left)/2;
var point={ X:xCenter, Y: drawPoint[0].Y };
this.DrawPoint([point]);
}
this.Canvas.restore();
//外部右侧显示价格
if (this.ShowPriceTextConfig.IsShow[2])
{
var rtDraw={ };
this.CalculateButtonSize();
this.DrawRightLabel(drawPoint[0].Y);
if (bVisibleRange) this.DrawCustomHLine(drawPoint[0].Y);
}
//鼠标是否在按钮上
if (moveonPoint && mouseStatus)
{
for(var i=0;i<this.AryButton.length;++i)
{
var item=this.AryButton[i];
var rtButton=item.Rect;
if (moveonPoint.X>=rtButton.Left && moveonPoint.X<rtButton.Right && moveonPoint.Y>=rtButton.Top && moveonPoint.Y<=rtButton.Bottom)
{
mouseStatus.MouseOnToolbar={ Rect:rtButton, Item:item, Frame:this.Frame, Point:{X:moveonPoint.X, Y:moveonPoint.Y} };
break;
}
}
}
}
this.CalculateLabSize=function(labInfo)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.font=this.TextFont;
var lineHeight=this.Canvas.measureText("擎").width+2;
var maxNameWidth=0, maxTextWidth=0;
var lineCount=0;
var lineSpace=0;
if (IFrameSplitOperator.IsNumber(labInfo.LineSpace)) lineSpace=labInfo.LineSpace;
var maxNameWidth=0, maxTextWidth=0;
var lineCount=0;
var maxWidth=0;
for(var i=0;i<labInfo.AryText.length;++i)
{
var item=labInfo.AryText[i];
item.NameWidth=0;
item.TextWidth=0;
if (item.Name) item.NameWidth=this.Canvas.measureText(item.Name).width+2;
if (item.Text) item.TextWidth=this.Canvas.measureText(item.Text).width+2;
if (maxNameWidth<item.NameWidth) maxNameWidth=item.NameWidth;
if (maxTextWidth<item.TextWidth) maxTextWidth=item.TextWidth;
var itemWidth=item.NameWidth+item.TextWidth;
if (maxWidth<itemWidth) maxWidth=itemWidth;
++lineCount;
}
var size={ Width:maxWidth, Height:lineCount*lineHeight+(lineCount-1)*lineSpace, NameWidth:maxNameWidth, TextWidth:maxTextWidth, LineHeight:lineHeight };
if (labInfo.LabelMargin)
{
var item=labInfo.LabelMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) size.Width+=item.Left;
if (IFrameSplitOperator.IsNumber(item.Right)) size.Width+=item.Right;
if (IFrameSplitOperator.IsNumber(item.Top)) size.Height+=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) size.Height+=item.Bottom;
}
return size;
}
//绘制窗口内部标签
this.DrawInternalLabel=function(y)
{
if (!this.LableInfo || !IFrameSplitOperator.IsNonEmptyArray(this.LableInfo.AryText)) return;
if (this.LableInfo.Position==2) return;
var border=this.Frame.GetBorder();
var left=border.Left;
var right=border.Right;
var labSize=this.CalculateLabSize(this.LableInfo);
var drawLeft=right-labSize.Width;
var drawRight=drawLeft+labSize.Width;
var drawTop=y-labSize.Height-1;
if (drawTop<=border.TopEx) drawTop=y+1;
var rtLabel={ Left:drawLeft, Right:drawRight, Top:drawTop, Width:labSize.Width, Height:labSize.Height };
rtLabel.Bottom=rtLabel.Top+rtLabel.Height;
this.DrawLabel(this.LableInfo, labSize, rtLabel);
}
//绘制标签页
this.DrawLabel=function(labelInfo, labelSize, rtLabel)
{
//背景色
if (labelInfo.BGColor)
{
this.Canvas.fillStyle=labelInfo.BGColor;
this.Canvas.fillRect(ToFixedRect(rtLabel.Left),ToFixedRect(rtLabel.Top),ToFixedRect(rtLabel.Width),ToFixedRect(rtLabel.Height));
}
var labelMargin=labelInfo.LabelMargin;
var lineSpace=0;
if (IFrameSplitOperator.IsNumber(labelInfo.LineSpace)) lineSpace=labelInfo.LineSpace;
var yText=rtLabel.Top;
var xText=rtLabel.Left;
var yRightText=rtLabel.Right;
if (labelMargin)
{
if (IFrameSplitOperator.IsNumber(labelMargin.Left)) xText+=labelMargin.Left;
if (IFrameSplitOperator.IsNumber(labelMargin.Right)) yRightText-=labelMargin.Right;
if (IFrameSplitOperator.IsNumber(labelMargin.Top)) yText+=labelMargin.Top;
}
this.Canvas.font=this.TextFont;
this.Canvas.textBaseline="top";
for(var i=0;i<labelInfo.AryText.length;++i)
{
if (i>0) yText+=lineSpace;
var item=labelInfo.AryText[i];
if (item.Name)
{
this.Canvas.textAlign="left";
this.Canvas.fillStyle=item.NameColor;
this.Canvas.fillText(item.Name,xText,yText);
}
if (item.Text)
{
this.Canvas.textAlign="right";
this.Canvas.fillStyle=item.TextColor;
this.Canvas.fillText(item.Text,yRightText,yText);
}
yText+=labelSize.LineHeight;
}
}
this.DrawRightLabel=function(y)
{
var rtDraw={ };
if (!this.LableInfo || !IFrameSplitOperator.IsNonEmptyArray(this.LableInfo.AryText) || this.LableInfo.Position!=2)
{
this.DrawValueText(y, rtDraw);
return;
}
var priceSize=this.CalculateValueText(y);
var labSize=this.CalculateLabSize(this.LableInfo);
var border=this.Frame.GetBorder();
var yTop=y-priceSize.Height/2;
var totalHeight=priceSize.Height+labSize.Height;
var yBottom=yTop+totalHeight;
var option={ };
if (yBottom>border.Bottom) //超过窗口底部, 标签位置不动
{
yBottom=border.Bottom;
yTop=yBottom-totalHeight;
option.Top=yTop;
}
this.DrawValueText(y, rtDraw, option);
var drawLeft=rtDraw.Right-labSize.Width;
if (drawLeft<rtDraw.Left) drawLeft=rtDraw.Left;
var drawRight=drawLeft+labSize.Width;
var drawTop=rtDraw.Bottom;
var rtLabel={ Left:drawLeft, Right:drawRight, Top:drawTop, Width:labSize.Width, Height:labSize.Height };
rtLabel.Bottom=rtLabel.Top+rtLabel.Height;
this.DrawLabel(this.LableInfo, labSize, rtLabel);
this.DrawVerticalButton(rtLabel);
}
this.DrawCustomHLine=function(yLine)
{
if (!this.LableInfo) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.LableInfo.AryLine)) return;
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var pixelRatio=GetDevicePixelRatio();
var yMax=yLine, yMin=yLine;
for(var i=0;i<this.LableInfo.AryLine.length;++i)
{
var item=this.LableInfo.AryLine[i];
if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
if (item.Width<0) continue;
var y=this.Frame.GetYFromData(item.Value);
var yFixed=ToFixedPoint(y);
var xRight=right;
if (IFrameSplitOperator.IsPlusNumber(item.Width))
{
if (item.Width<1) xRight=left+(item.Width*(right-left)); //0.3 百分比
else xRight=left+item.Width*pixelRatio; //>1 实际数值就是长度
}
if (item.Color) this.Canvas.strokeStyle=item.Color;
else this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,yFixed);
this.Canvas.lineTo(xRight,yFixed);
this.Canvas.stroke();
if (yMax<yFixed) yMax=yFixed;
if (yMin>yFixed) yMin=yFixed;
}
if (yMax!=yMin && this.LableInfo.VLine)
{
var item=this.LableInfo.VLine;
var x=left+20*pixelRatio;
if (IFrameSplitOperator.IsNumber(item.XOffset)) x=left+item.XOffset*pixelRatio;
x=ToFixedPoint(x);
if (item.Color) this.Canvas.strokeStyle=item.Color;
else this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,yMax);
this.Canvas.lineTo(x,yMin);
this.Canvas.stroke();
}
}
this.DrawValueText=function(y, rtDraw, option)
{
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var top=this.Frame.ChartBorder.GetTopEx();
var bottom=this.Frame.ChartBorder.GetBottomEx();
var pixelTatio = GetDevicePixelRatio();
var labInfo=this.LabelInfo;
if (labInfo && IFrameSplitOperator.IsNumber(labInfo.TopOffset)) top-=labInfo.TopOffset;
if (labInfo && IFrameSplitOperator.IsNumber(labInfo.BottomOffset)) bottom+=labInfo.BottomOffset;
var yValue=this.Frame.GetYData(y,false);
var strValue=yValue.toFixed(this.Precision);
if (labInfo &&labInfo.PriceSuffixText) strValue+=labInfo.PriceSuffixText;
var bVisibleRange=true;
if (y<top)
{
y=top;
bVisibleRange=false;
}
else if (y>bottom)
{
y=bottom;
bVisibleRange=false;
}
if (this.RightSpaceWidth>0)
{
if (!bVisibleRange) this.Canvas.setLineDash([2*pixelTatio,3*pixelTatio]); //虚线
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(right,ToFixedPoint(y));
this.Canvas.lineTo(right+this.RightSpaceWidth,ToFixedPoint(y));
this.Canvas.stroke();
if (!bVisibleRange) this.Canvas.setLineDash([]);
}
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(strValue).width;
var lineHeight=this.GetFontHeight();
var rtBG={ Left:right+this.RightSpaceWidth, YCenter:y, Width:textWidth, Height:lineHeight };
rtBG.Height+=(this.TextMargin.Top+this.TextMargin.Bottom);
rtBG.Width+=(this.TextMargin.Left+this.TextMargin.Right);
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Top=rtBG.YCenter-rtBG.Height/2;
rtBG.Bottom=rtBG.Top+rtBG.Height;
if (option && IFrameSplitOperator.IsNumber(option.Top))
{
rtBG.Top=option.Top;
rtBG.Bottom=rtBG.Top+rtBG.Height;
}
var xText=rtBG.Left+this.TextMargin.Left;
var yText=rtBG.Top+this.TextMargin.Top+this.TextMargin.YOffset;
if (this.ButtonPosition==1)
{
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top), ToFixedRect(rtBG.Width+this.ButtonBGWidth),ToFixedRect(rtBG.Height));
}
else
{
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top), ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
}
this.Canvas.fillStyle=this.ValueTextColor
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.fillText(strValue,xText,yText);
rtDraw.Left=rtBG.Left;
rtDraw.Top=rtBG.Top;
rtDraw.Bottom=rtBG.Bottom;
rtDraw.Right=rtBG.Right;
this.DrawButton(rtBG.Top, rtBG.Right, lineHeight, rtDraw);
}
//计算右侧价格标签大小
this.CalculateValueText=function(y)
{
var yValue=this.Frame.GetYData(y,false);
var strValue=yValue.toFixed(this.Precision);
if (this.LableInfo &&this.LableInfo.PriceSuffixText) strValue+=this.LableInfo.PriceSuffixText;
this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(strValue).width;
var lineHeight=this.GetFontHeight();
var size={ Width:textWidth, Height:lineHeight };
size.Height+=(this.TextMargin.Top+this.TextMargin.Bottom);
size.Width+=(this.TextMargin.Left+this.TextMargin.Right);
return size;
}
this.DrawPriceText=function(text, ptStart, ptEnd, position)
{
if (position!=1 && position!=0) return;
var font=this.ShowPriceTextConfig.Font[position];
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=font;
var textWidth=this.Canvas.measureText(text).width;
var lineHeight=this.GetFontHeight();
var rtBG=null;
if (position==1)
{
var rtBG={ Left:ptStart.X, Top:ptStart.Y-lineHeight/2, Width:textWidth+4, Height:lineHeight };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
}
else if (position==0)
{
var rtBG={ Right:ptEnd.X, Top:ptEnd.Y-lineHeight/2, Width:textWidth+4, Height:lineHeight };
rtBG.Left=rtBG.Right-rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
}
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top), ToFixedRect(rtBG.Width+this.ButtonBGWidth),ToFixedRect(rtBG.Height));
this.Canvas.fillStyle=this.ValueTextColor
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillText(text,rtBG.Left+2,ptStart.Y);
}
this.CalculateButtonSize=function()
{
var pixelRatio=GetDevicePixelRatio();
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryShowButton)) return;
var totalWidth=0;
for(var i=0;i<this.AryShowButton.length;++i)
{
var item=this.AryShowButton[i];
var icon=item.Data;
var font=`${icon.Size*pixelRatio}px ${icon.Family}`;
this.Canvas.font=font;
item.Width=this.Canvas.measureText(icon.Text).width+2;
item.Height=item.Width;
if (icon.Margin)
{
var margin=icon.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) item.Width+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) item.Width+=margin.Right;
if (IFrameSplitOperator.IsNumber(margin.Top)) item.Height+=margin.Top;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) item.Height+=margin.Bottom;
}
if (this.VerticalButtonInfo.Width<item.Width) this.VerticalButtonInfo.Width=item.Width;
this.VerticalButtonInfo.Height+=item.Height;
totalWidth+=item.Width;
}
this.ButtonBGWidth=totalWidth;
}
//垂直排列按钮
this.DrawVerticalButton=function(rtLab)
{
if (this.ButtonPosition!=3) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryShowButton)) return;
if (this.VerticalButtonInfo.Height<=0) return;
var rtBG={ Left:rtLab.Right, Top:rtLab.Top, Width:this.VerticalButtonInfo.Width, Height:this.VerticalButtonInfo.Height };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
this.Canvas.fillStyle=this.ButtonBGColor;
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top), ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
var pixelRatio=GetDevicePixelRatio();
var yTop=rtLab.Top;
for(var i=0;i<this.AryShowButton.length;++i)
{
var item=this.AryShowButton[i];
var icon=item.Data;
var rtButton={Left:rtBG.Left, Top:yTop, Width:this.VerticalButtonInfo.Width, Height:item.Height };
rtButton.Right=rtButton.Left+rtButton.Width;
rtButton.Bottom=rtButton.Top+rtButton.Height;
var yCenter=rtButton.Top+rtButton.Height/2;
var xCenter=rtButton.Left+rtButton.Width/2;
var font=`${icon.Size*pixelRatio}px ${icon.Family}`;
this.Canvas.font=font;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=icon.Color;
this.Canvas.fillText(icon.Text,xCenter,yCenter);
this.AryButton.push({Rect:rtButton,ID:icon.ID, TooltipText:icon.TooltipText, Data:icon.Data });
yTop=rtButton.Bottom;
}
}
this.DrawButton=function(drawTop, drawLeft, drawHeight, rtDraw)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryShowButton)) return;
if (this.ButtonPosition==3) return; //垂直按钮在DrawVerticalButton()调用
if (this.ButtonPosition==1)
{
drawTop-=drawHeight;
var chartWidth=this.Frame.ChartBorder.GetChartWidth();
var chartLeft=this.Frame.ChartBorder.GetRight()+this.RightSpaceWidth;
if (drawLeft+this.ButtonBGWidth>chartWidth) //右边不够了 往左移动
{
drawLeft=chartWidth-this.ButtonBGWidth;
}
if (rtDraw.Left>drawLeft) drawLeft=rtDraw.Left;
}
else if (this.ButtonPosition==2)
{
drawTop-=drawHeight;
drawLeft=rtDraw.Left;
}
this.Canvas.fillStyle=this.LineColor;
var left=drawLeft;
var rtBG={ Left:drawLeft, Top:drawTop, Width:this.ButtonBGWidth, Height:drawHeight };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
this.Canvas.fillStyle=this.ButtonBGColor;
this.Canvas.fillRect(ToFixedRect(rtBG.Left),ToFixedRect(rtBG.Top), ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
var pixelRatio=GetDevicePixelRatio();
for(var i=0;i<this.AryShowButton.length;++i)
{
var item=this.AryShowButton[i];
var icon=item.Data;
var rtButton={Left:left, Top:drawTop, Width:item.Width, Height:drawHeight };
rtButton.Right=rtButton.Left+rtButton.Width;
rtButton.Bottom=rtButton.Top+rtButton.Height;
var yCenter=rtButton.Top+rtButton.Height/2;
var xCenter=rtButton.Left+rtButton.Width/2;
var font=`${icon.Size*pixelRatio}px ${icon.Family}`;
this.Canvas.font=font;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=icon.Color;
this.Canvas.fillText(icon.Text,xCenter,yCenter);
this.AryButton.push({Rect:rtButton,ID:icon.ID, TooltipText:icon.TooltipText, Data:icon.Data });
left=rtButton.Right;
}
}
this.PtInButtons=function(x,y)
{
for(var i=0;i<this.AryButton.length;++i)
{
var item=this.AryButton[i];
if (!item.Rect) continue;
var rect=item.Rect;
this.Canvas.beginPath();
this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
if (this.Canvas.isPointInPath(x,y))
{
return { ID:item.ID, Rect:rect, Data:item.Data };
}
}
return null;
}
}
//趋势线
function ChartDrawPictureTrendLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureTrendLine';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:false, IsCheckY:false});
if (!drawPoint || drawPoint.length!=2) return;
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
this.Canvas.moveTo(extendLine.Start.X,extendLine.Start.Y);
this.Canvas.lineTo(extendLine.End.X,extendLine.End.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
}
//画图工具-矩形
function ChartDrawPictureRect()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureRect';
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.Draw=function()
{
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=2) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.SetLineWidth();
this.Canvas.beginPath();
this.Canvas.rect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y);
this.Canvas.stroke();
this.RestoreLineWidth();
//透明背景
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.fillRect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y);
this.Canvas.restore();
//画点
this.DrawPoint(drawPoint);
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y,option)
{
if (this.IsFrameMinSize()) return -1;
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
var nIndex=this.IsPointInXYValue(x,y,option);
if (nIndex>=0) return nIndex;
var aryPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!aryPoint || aryPoint.length!=2) return -1;
//是否在矩形边框上
var linePoint=[ {X:aryPoint[0].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[0].Y}];
if (this.IsPointInLine(linePoint,x,y,option))
return 100;
linePoint=[ {X:aryPoint[1].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[1].Y}];
if (this.IsPointInLine2(linePoint,x,y,option))
return 100;
linePoint=[ {X:aryPoint[1].X,Y:aryPoint[1].Y},{X:aryPoint[0].X,Y:aryPoint[1].Y}];
if (this.IsPointInLine(linePoint,x,y,option))
return 100;
linePoint=[ {X:aryPoint[0].X,Y:aryPoint[1].Y},{X:aryPoint[0].X,Y:aryPoint[0].Y}];
if (this.IsPointInLine2(linePoint,x,y,option))
return 100;
return -1;
}
//点是否在线段上 水平线段
this.IsPointInLine=function(aryPoint,x,y,option)
{
var radius=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) radius+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) radius+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
radius*=pixel;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X,aryPoint[0].Y+radius);
this.Canvas.lineTo(aryPoint[0].X,aryPoint[0].Y-radius);
this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y-radius);
this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y+radius);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return true;
}
//垂直线段
this.IsPointInLine2=function(aryPoint,x,y,option)
{
var radius=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) radius+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) radius+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
radius*=pixel;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X-radius,aryPoint[0].Y);
this.Canvas.lineTo(aryPoint[0].X+radius,aryPoint[0].Y);
this.Canvas.lineTo(aryPoint[1].X+radius,aryPoint[1].Y);
this.Canvas.lineTo(aryPoint[1].X-radius,aryPoint[1].Y);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return true;
}
}
//画图工具-弧形
function ChartDrawPictureArc()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureArc';
this.Draw=function()
{
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint || drawPoint.length!=2) return;
this.ClipFrame();
//this.Canvas.beginPath();
//this.Canvas.rect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y);
this.SetLineWidth();
if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第一象限
{
var a = drawPoint[1].X - drawPoint[0].X;
var b = drawPoint[0].Y - drawPoint[1].Y;
var step = (a > b) ? 1/a : 1 / b;
var xcenter = drawPoint[0].X;
var ycenter = drawPoint[1].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y);
for (var i = 1.5*Math.PI; i < 2*Math.PI; i+=step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter+b*Math.sin(i)*-1);
}
for (var j = 0; j <= 0.5*Math.PI; j += step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(j), ycenter+b*Math.sin(j)*-1);
}
}
else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第二象限
{
var a = drawPoint[0].X - drawPoint[1].X;
var b = drawPoint[0].Y - drawPoint[1].Y;
var step = (a > b) ? 1/a:1/b;
var xcenter = drawPoint[1].X;
var ycenter = drawPoint[0].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y);
for (var i = 0; i <= Math.PI; i += step)
{
this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
}
else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第三象限
{
var a = drawPoint[0].X - drawPoint[1].X;
var b = drawPoint[1].Y - drawPoint[0].Y;
var step = (a > b) ? 1/a:1/b;
var xcenter = drawPoint[0].X;
var ycenter = drawPoint[1].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y);
for (var i = 0.5*Math.PI; i <= 1.5*Math.PI; i += step)
{
this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
}
else if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第四象限
{
var a = drawPoint[1].X - drawPoint[0].X;
var b = drawPoint[1].Y - drawPoint[0].Y;
var step = (a > b) ? 1/a : 1/b;
var xcenter = drawPoint[1].X;
var ycenter = drawPoint[0].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y);
for (var i = Math.PI; i <= 2*Math.PI; i += step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.stroke();
this.RestoreLineWidth();
//this.Canvas.closePath();
this.Canvas.restore();
//画点
this.DrawPoint(drawPoint);
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y,option)
{
if (this.IsFrameMinSize()) return -1;
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
//是否在点上
var nIndex=this.IsPointInXYValue(x,y,option);
if (nIndex>=0) return nIndex;
var aryPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!aryPoint || aryPoint.length!=2) return -1;
//是否在弧线上
var ArcPoint=[ {X:aryPoint[0].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[1].Y}];
if (this.IsPointInArc(ArcPoint, x, y))
return 100;
return -1;
}
this.IsPointInArc=function(aryPoint,x,y)
{
if (aryPoint.length != 2)
return false;
if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第一象限
{
var a = aryPoint[1].X - aryPoint[0].X;
var b = aryPoint[0].Y - aryPoint[1].Y;
var step = (a > b) ? 1/a : 1 / b;
var ainer = a * 0.8;
var biner = b * 0.8;
var stepiner = (ainer > biner) ? 1/ainer : 1/biner;
var xcenter = aryPoint[0].X;
var ycenter = aryPoint[1].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y);
for (var i = 1.5*Math.PI; i < 2*Math.PI; i+=step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter+b*Math.sin(i)*-1);
}
for (var j = 0; j <= 0.5*Math.PI; j += step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(j), ycenter+b*Math.sin(j)*-1);
}
for (var k = 0.5*Math.PI; k >= 0; k -= stepiner)
{
this.Canvas.lineTo(xcenter+ainer*Math.cos(k), ycenter + biner*Math.sin(j)*-1);
}
for (var l = 2*Math.PI; l >= 1.5*Math.PI; l -= stepiner)
{
this.Canvas.lineTo(xcenter + ainer*Math.cos(l), ycenter + biner*Math.sin(l)*-1);
}
this.Canvas.closePath();
}
else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第二象限
{
var a = aryPoint[0].X - aryPoint[1].X;
var b = aryPoint[0].Y - aryPoint[1].Y;
var step = (a > b) ? 1/a:1/b;
var ainer = a * 0.8;
var biner = b * 0.8;
var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner;
var xcenter = aryPoint[1].X;
var ycenter = aryPoint[0].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y);
for (var i = 0; i <= Math.PI; i += step)
{
this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
for (var j = Math.PI; j >= 0; j -= stepiner)
{
this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner*Math.sin(j)*-1);
}
this.Canvas.closePath();
}
else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第三象限
{
var a = aryPoint[0].X - aryPoint[1].X;
var b = aryPoint[1].Y - aryPoint[0].Y;
var step = (a > b) ? 1/a:1/b;
var ainer = a * 0.8;
var biner = b * 0.8;
var stepiner = (ainer > biner) ? 1/ainer : 1/biner;
var xcenter = aryPoint[0].X;
var ycenter = aryPoint[1].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y);
for (var i = 0.5*Math.PI; i <= 1.5*Math.PI; i += step)
{
this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
for (var j = 1.5*Math.PI; j >= 0.5*Math.PI; j -= stepiner)
{
this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner*Math.sin(j)*-1);
}
this.Canvas.closePath();
}
else if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第四象限
{
var a = aryPoint[1].X - aryPoint[0].X;
var b = aryPoint[1].Y - aryPoint[0].Y;
var step = (a > b) ? 1/a : 1/b;
var ainer = a * 0.8;
var biner = b * 0.8;
var stepiner = (ainer > biner) ? 1/ainer : 1/biner;
var xcenter = aryPoint[1].X;
var ycenter = aryPoint[0].Y;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y);
for (var i = Math.PI; i <= 2*Math.PI; i += step)
{
this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter + b*Math.sin(i)*-1);
}
for (var j = 2*Math.PI; j >= Math.PI; j -= stepiner)
{
this.Canvas.lineTo(xcenter + ainer*Math.cos(j), ycenter + biner*Math.sin(j)*-1);
}
this.Canvas.closePath();
}
if (this.Canvas.isPointInPath(x,y))
return true;
else
return false;
}
}
//M头W底 支持横屏
function ChartDrawPictureWaveMW()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureWaveMW';
this.PointCount=5;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.IsHScreen=false;
this.Draw=function()
{
this.LinePoint=[];
if (!this.Frame) return;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
this.IsHScreen=this.Frame.IsHScreen;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
//var points=drawPoint.slice(0);
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
this.CalculateLines(drawPoint);
this.SetLineWidth();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.CalculateLines=function(points)
{
if (!this.Frame) return;
if (points.length<2) return;
if (this.Status==2)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
var xMove=points[1].X-points[0].X;
var yMove=points[1].Y-points[0].Y;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[1].Y+yMove;
line.End.X=points[0].X;
}
else
{
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[0].Y;
line.End.X=points[1].X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[2]=newPt;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=ptStart.Y+yMove;
line.End.X=points[1].X;
}
else
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=points[1].Y;
line.End.X=ptStart.X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[3]=newPt;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=ptStart.Y+yMove;
line.End.X=points[0].X;
}
else
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=points[0].Y;
line.End.X=ptStart.X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[4]=newPt;
this.PointCount=this.Point.length;
}
else if (points.length==5)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[2].Y;
line.End.X=points[2].X;
this.LinePoint.push(line);
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[2].Y;
line.Start.X=points[2].X;
line.End.Y=points[3].Y;
line.End.X=points[3].X;
this.LinePoint.push(line);
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[3].Y;
line.Start.X=points[3].X;
line.End.Y=points[4].Y;
line.End.X=points[4].X;
this.LinePoint.push(line);
}
}
}
//头肩 头肩顶(Head and shoulders top)以及头肩底(Head and shoulders bottom)两种形态
//支持横屏
function ChartDrawHeadShouldersBT()
{
this.newMethod=ChartDrawPictureWaveMW; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawHeadShouldersBT';
this.CalculateLines_Backup=this.CalculateLines;
this.CalculateLines=function(points)
{
if (!this.Frame) return;
if (points.length<2) return;
if (this.Status==2)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
var xMove=points[1].X-points[0].X;
var yMove=points[1].Y-points[0].Y;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[1].Y+yMove;
line.End.X=points[0].X-xMove;
}
else
{
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[0].Y-yMove;
line.End.X=points[1].X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[2]=newPt;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=ptStart.Y+yMove;
line.End.X=points[1].X;
}
else
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=points[1].Y;
line.End.X=ptStart.X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[3]=newPt;
line={Start:new Point(), End:new Point()};
if (this.IsHScreen)
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=ptStart.Y+yMove;
line.End.X=points[0].X;
}
else
{
line.Start.Y=ptStart.Y;
line.Start.X=ptStart.X;
line.End.Y=points[0].Y;
line.End.X=ptStart.X+xMove;
}
this.LinePoint.push(line);
var ptStart=line.End;
var newPt=new Point();
newPt.X=ptStart.X;
newPt.Y=ptStart.Y;
this.Point[4]=newPt;
this.PointCount=this.Point.length;
}
else
{
return this.CalculateLines_Backup(points);
}
}
}
//平行线
function ChartDrawPictureParallelLines()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureParallelLines';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointCount=3;
this.LastPoint;
//中心线
this.CenterLine={ LineDash:[2*GetDevicePixelRatio(),3*GetDevicePixelRatio()], Line:null, IsShow:false };
this.Super_SetOption=this.SetOption; //父类函数
this.Super_ExportStorageData=this.ExportStorageData;
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.CenterLine)
{
var item=option.CenterLine;
if (IFrameSplitOperator.IsNonEmptyArray(item.LineDash)) this.CenterLine.LineDash=item.LineDash.slice(0);
if (IFrameSplitOperator.IsBool(item.IsShow)) this.CenterLine.IsShow=item.IsShow;
}
}
}
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
if (this.CenterLine)
{
storageData.CenterLine={ IsShow:this.CenterLine.IsShow, LineDash:this.CenterLine.LineDash.slice(0) };
}
}
return storageData;
}
this.Draw=function()
{
this.LinePoint=[];
this.CenterLine.Line=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:false, IsCheckY:false}); //不检测x,y
if (!drawPoint) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
var points=drawPoint.slice(0);
this.CalculateLines(points);
this.ClipFrame();
this.DrawArea();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
if (this.CenterLine.IsShow && this.CenterLine.Line)
{
var item=this.CenterLine.Line;
this.Canvas.setLineDash(this.CenterLine.LineDash);
this.DrawLine(item.Start,item.End);
this.Canvas.setLineDash([]);
}
this.DrawPoint(points); //画点
this.Canvas.restore();
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.DrawArea=function()
{
if (this.LinePoint.length!=2) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y);
this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y);
this.Canvas.lineTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
var linePoint=this.CalculateExtendLinePoint(points[0],points[1]);
this.LinePoint.push(linePoint);
}
else if (points.length==3)
{
var linePoint=this.CalculateExtendLinePoint(points[0],points[1]);
this.LinePoint.push(linePoint);
//计算平行线
var xMove=points[2].X-points[1].X;
var yMove=points[2].Y-points[1].Y;
var ptStart=new Point();
var ptEnd=new Point();
ptStart.X=points[0].X+xMove;
ptStart.Y=points[0].Y+yMove;
ptEnd.X=points[1].X+xMove;
ptEnd.Y=points[1].Y+yMove;
linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd);
this.LinePoint.push(linePoint);
//中心线
var ptStart=new Point();
var ptEnd=new Point();
ptStart.X=points[0].X+xMove/2;
ptStart.Y=points[0].Y+yMove/2;
ptEnd.X=points[1].X+xMove/2;
ptEnd.Y=points[1].Y+yMove/2;
linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd);
this.CenterLine.Line=linePoint;
}
}
}
//FlatTop/Bottom 平滑顶/底
function ChartDrawFlatTop()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawFlatTop';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.PointCount=3;
this.LastPoint;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
var points=drawPoint.slice(0);
this.CalculateLines(points);
this.ClipFrame();
for(var i=0;i<this.LinePoint.length; ++i)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.DrawArea();
this.DrawPoint(points); //画点
this.Canvas.restore();
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.DrawArea=function()
{
if (this.LinePoint.length!=2) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y);
this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y);
this.Canvas.lineTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var ptSecond=points[1];
var pt=new Point();
pt.X=ptSecond.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
this.LinePoint.push({ Start:points[0], End:points[1]});
}
else if (points.length==3)
{
this.LinePoint.push({ Start:points[0], End:points[1]});
//计算水平线
var ptThrid=points[2];
ptThrid.X=points[1].X;
var ptStart={ X:points[0].X, Y:ptThrid.Y };
var ptEnd={ X:points[1].X, Y:ptThrid.Y };
this.LinePoint.push({ Start:ptStart, End:ptEnd});
}
}
}
//Disjont Channel 不相交通道 (未完成)
function ChartDrawDisjontChannel()
{
this.newMethod=ChartDrawFlatTop; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawDisjontChannel';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.PointCount=3;
this.LastPoint;
}
//平行射线
function ChartDrawParallelRaysLines()
{
this.newMethod=ChartDrawPictureParallelLines; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawParallelRaysLines';
this.DrawArea=function()
{
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
var endPoint=this.CalculateExtendLineEndPoint([points[0],points[1]]);
this.LinePoint.push({ Start:points[0], End:endPoint });
}
else if (points.length==3)
{
var endPoint=this.CalculateExtendLineEndPoint([points[0],points[1]]);
this.LinePoint.push({ Start:points[0], End:endPoint });
//计算平行线
var xMove=points[2].X-points[1].X;
var yMove=points[2].Y-points[1].Y;
var ptStart=new Point();
var ptEnd=new Point();
ptStart.X=points[0].X+xMove;
ptStart.Y=points[0].Y+yMove;
ptEnd.X=points[1].X+xMove;
ptEnd.Y=points[1].Y+yMove;
endPoint=this.CalculateExtendLineEndPoint([ptStart,ptEnd]);
this.LinePoint.push({ Start:points[2], End:endPoint });
}
}
}
//价格通道线
function ChartDrawPicturePriceChannel()
{
this.newMethod=ChartDrawPictureParallelLines; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPicturePriceChannel';
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
var linePoint=this.CalculateExtendLinePoint(points[0],points[1]);
this.LinePoint.push(linePoint);
}
else if (points.length==3)
{
var linePoint=this.CalculateExtendLinePoint(points[0],points[1]);
this.LinePoint.push(linePoint);
//计算平行线
var xMove=points[2].X-points[1].X;
var yMove=points[2].Y-points[1].Y;
var ptStart=new Point();
var ptEnd=new Point();
ptStart.X=points[0].X+xMove;
ptStart.Y=points[0].Y+yMove;
ptEnd.X=points[1].X+xMove;
ptEnd.Y=points[1].Y+yMove;
linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd);
this.LinePoint.push(linePoint);
var ptStart=new Point();
var ptEnd=new Point();
ptStart.X=points[0].X-xMove;
ptStart.Y=points[0].Y-yMove;
ptEnd.X=points[1].X-xMove;
ptEnd.Y=points[1].Y-yMove;
linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd);
this.LinePoint.push(linePoint);
}
}
this.DrawArea=function()
{
if (this.LinePoint.length!=3) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y);
this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y);
this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y);
this.Canvas.lineTo(this.LinePoint[2].Start.X,this.LinePoint[2].Start.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
}
//平行通道
function ChartDrawPictureParallelChannel()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureParallelChannel';
this.ChannelWidth=50;
this.AreaColor='rgba(25,25,25,0.4)';
this.LinePoint=[];
//中心线
this.CenterLine={ LineDash:[2*GetDevicePixelRatio(),3*GetDevicePixelRatio()], Line:null, IsShow:false };
this.Super_SetOption=this.SetOption; //父类函数
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
storageData.ChannelWidth=this.ChannelWidth;
storageData.Value=[];
//只保存2个点就可以了
for(var i=0; i<this.Value.length && i<2; ++i)
{
var item=this.Value[i];
storageData.Value.push({ XValue:item.XValue, YValue:item.YValue, DateTime:item.DateTime });
}
if (this.CenterLine)
{
storageData.CenterLine={ IsShow:this.CenterLine.IsShow, LineDash:this.CenterLine.LineDash.slice(0) };
}
return storageData;
}
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (IFrameSplitOperator.IsNumber(option.ChannelWidth)) this.ChannelWidth=option.ChannelWidth;
if (option.CenterLine)
{
var item=option.CenterLine;
if (IFrameSplitOperator.IsNonEmptyArray(item.LineDash)) this.CenterLine.LineDash=item.LineDash.slice(0);
if (IFrameSplitOperator.IsBool(item.IsShow)) this.CenterLine.IsShow=item.IsShow;
}
}
}
//计算需要画的点的坐标
this.CalculateDrawPoint=function()
{
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
var data=this.Frame.Data;
if (!data) return null;
var drawPoint=[];
if (this.Status==10) //完成
{
for(var i=0; i<2; ++i)
{
var item=this.Value[i];
var pt=new Point();
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset, false);
pt.Y=this.Frame.GetYFromData(item.YValue, false);
drawPoint.push(pt);
}
}
else
{
for(var i=0; i<this.Point.length; ++i)
{
var item=this.Point[i];
var pt=new Point();
pt.X=item.X;
pt.Y=item.Y;
drawPoint.push(pt);
}
}
if (drawPoint.length>=2)
{
var linePoint={Start:new Point(), End:new Point() };
linePoint.Start.X=drawPoint[0].X;
linePoint.Start.Y=drawPoint[0].Y;
linePoint.End.X=drawPoint[1].X;
linePoint.End.Y=drawPoint[1].Y;
this.LinePoint.push(linePoint);
if (drawPoint.length==3 || this.Status==10)
{
var x=linePoint.End.X-linePoint.Start.X;
var y=linePoint.End.Y-linePoint.Start.Y;
var angle=Math.atan(Math.abs(x/y));
var yMove=this.ChannelWidth/Math.sin(angle);
//JSConsole.Chart.Log('[ChartDrawPictureParallelChannel::CalculateDrawPoint]',xMove);
linePoint={Start:new Point(), End:new Point() };
linePoint.Start.X=drawPoint[0].X;
linePoint.Start.Y=drawPoint[0].Y-yMove;
linePoint.End.X=drawPoint[1].X;
linePoint.End.Y=drawPoint[1].Y-yMove;
this.LinePoint.push(linePoint);
var ptCenter=new Point();
ptCenter.X=linePoint.Start.X+(linePoint.End.X-linePoint.Start.X)/2;
ptCenter.Y=linePoint.Start.Y+(linePoint.End.Y-linePoint.Start.Y)/2;
drawPoint[2]=ptCenter;
this.Point[2]=ptCenter;
var xValue=parseInt(this.Frame.GetXData(ptCenter.X))+data.DataOffset;
var yValue=this.Frame.GetYData(ptCenter.Y);
this.Value[2]={XValue:xValue,YValue:yValue};
this.PointCount=this.Point.length; //完成以后是3个点
linePoint={Start:new Point(), End:new Point() };
linePoint.Start.X=drawPoint[0].X;
linePoint.Start.Y=drawPoint[0].Y-yMove/2;
linePoint.End.X=drawPoint[1].X;
linePoint.End.Y=drawPoint[1].Y-yMove/2;
this.CenterLine.Line=linePoint;
}
}
return drawPoint;
}
this.DrawArea=function(pt,pt2,pt3,pt4)
{
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(pt.X,pt.Y);
this.Canvas.lineTo(pt2.X,pt2.Y);
this.Canvas.lineTo(pt3.X,pt3.Y);
this.Canvas.lineTo(pt4.X,pt4.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
if (this.LinePoint.length==2)
{
this.DrawArea(this.LinePoint[0].Start,this.LinePoint[0].End,this.LinePoint[1].End,this.LinePoint[1].Start);
}
for(var i=0;i<this.LinePoint.length; ++i)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
if (this.CenterLine.IsShow && this.CenterLine.Line)
{
var item=this.CenterLine.Line;
this.Canvas.setLineDash(this.CenterLine.LineDash);
this.DrawLine(item.Start,item.End);
this.Canvas.setLineDash([]);
}
this.Canvas.restore();
this.DrawPoint(drawPoint); //画点
}
//xStep,yStep 移动的偏移量
this.Move=function(xStep,yStep)
{
if (this.Status!=20) return false;
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
if (this.MovePointIndex==100) //整体移动
{
for(var i=0; i<this.Point.length; ++i)
{
this.Point[i].X+=xStep;
this.Point[i].Y+=yStep;
}
}
else if (this.MovePointIndex==0 || this.MovePointIndex==1)
{
if (this.MovePointIndex<this.Point.length)
{
this.Point[this.MovePointIndex].X+=xStep;
this.Point[this.MovePointIndex].Y+=yStep;
}
}
else if (this.MovePointIndex==2) //宽度的点要计算
{
this.Point[this.MovePointIndex].X+=xStep;
this.Point[this.MovePointIndex].Y+=yStep;
var x=this.Point[1].X-this.Point[0].X;
var y=this.Point[1].Y-this.Point[0].Y;
var angle=Math.atan(Math.abs(x/y));
var yMove=this.ChannelWidth/Math.sin(angle)-yStep;
this.ChannelWidth=Math.sin(angle)*yMove;
}
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
//是否在点上
for(var i=0;i<this.Value.length; ++i)
{
var item=this.Value[i];
var pt=new Point();
if (i<2)
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.Y=this.Frame.GetYFromData(item.YValue);
}
else //第3个点使用实际坐标
{
if (i>=this.Point.length) continue;
pt.X=this.Point[i].X;
pt.Y=this.Point[i].Y;
}
this.Canvas.beginPath();
this.Canvas.arc(pt.X,pt.Y,5,0,360);
if (this.Canvas.isPointInPath(x,y)) return i;
}
//是否在线段上
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
var ptStart=item.Start;
var ptEnd=item.End;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y+5);
this.Canvas.lineTo(ptStart.X,ptStart.Y-5);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-5);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+5);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return 100;
}
return -1;
}
}
//文本
function ChartDrawPictureText()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureText';
this.Text='文本';
this.PointCount=1;
this.FontOption={ Family:'微软雅黑', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic)
//矢量图片
//this.Text="\ue606";
//this.FontOption={ Family:'iconfont', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic)
this.TextRect=null; //文字区域
this.IsInitialized=false; //是否初始化了
this.SettingMenu;
this.HQChart;
this.SetOption=function(option)
{
if (!option) return;
if (option.LineColor) this.LineColor=option.LineColor;
if (option.Text) this.Text=option.Text;
if (option.FontOption) this.FontOption=option.FontOption;
}
this.Draw=function(textFont)
{
this.TextRect=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=1) return;
this.ClipFrame();
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.GetTextFont();
this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y);
var textWidth=this.Canvas.measureText(this.Text).width;
var textHeight=this.FontOption.Size*GetDevicePixelRatio();
this.TextRect={};
this.TextRect.Left=drawPoint[0].X-textWidth/2;
this.TextRect.Top=drawPoint[0].Y-textHeight;
this.TextRect.Width=textWidth;
this.TextRect.Height=textHeight
//this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height);
this.Canvas.restore();
if (this.IsInitialized===false)
{
this.SetTextOption();
this.IsInitialized=true;
}
}
//根据设置动态生成字体
this.GetTextFont=function()
{
const defaultFont=16*GetDevicePixelRatio() +"px 微软雅黑";
if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return defaultFont;
var font='';
if (this.FontOption.Color) font+=this.FontOption.Color+' ';
if (this.FontOption.Style) font+=this.FontOption.Style+' ';
if (this.FontOption.Weight) font+=this.FontOption.Weight+' ';
if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px ';
font+=this.FontOption.Family;
return font;
}
this.SetTextOption=function()
{
JSConsole.Chart.Log('[ChartDrawPictureText::SetTextOption]');
//创建div设置窗口
if (!this.SettingMenu) this.SettingMenu=new ChartPictureTextSettingMenu(this.Frame.ChartBorder.UIElement.parentNode);
this.SettingMenu.ChartPicture=this;
this.SettingMenu.HQChart=this.HQChart;
this.SettingMenu.Position={Left:this.TextRect.Left+this.TextRect.Width,Top:this.TextRect.Top};
this.SettingMenu.DoModal();
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
if (!this.TextRect) return -1;
this.Canvas.beginPath();
this.Canvas.rect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height);
if (this.Canvas.isPointInPath(x,y)) return 100;
return -1;
}
}
//iconfont 图片
function ChartDrawPictureIconFont()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureIconFont';
this.PointCount=1;
//矢量图片
this.Text="\ue606";
this.FontOption={ Family:'iconfont', Size:24}; //Weight(bold 粗体), Style(italic)
this.TextRect=null; //文字区域
this.SettingMenu;
this.Angle=0; //旋转角度
this.SetOption=function(option)
{
if (!option) return;
if (option.LineColor) this.LineColor=option.LineColor;
if (option.FontOption && option.FontOption.Size>0) this.FontOption.Size=option.FontOption.Size;
if (IFrameSplitOperator.IsNumber(option.Angle)) this.Angle=option.Angle;
}
this.Draw=function()
{
this.TextRect=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=1) return;
var font=this.GetTextFont();
if (!font) return;
this.ClipFrame();
var isHScreen=this.Frame.IsHScreen;
var pixel=GetDevicePixelRatio();
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.font=font;
if (isHScreen)
{
this.Canvas.translate(drawPoint[0].X, drawPoint[0].Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.Text,0,0);
}
else
{
if (this.Angle!=0)
{
this.Canvas.translate(drawPoint[0].X, drawPoint[0].Y);
this.Canvas.rotate(this.Angle*(Math.PI / 180));
this.Canvas.fillText(this.Text,0,0);
}
else
{
this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y);
}
}
var textWidth=this.Canvas.measureText(this.Text).width;
this.TextRect={};
this.TextRect.Left=drawPoint[0].X-textWidth/2;
this.TextRect.Top=drawPoint[0].Y-this.FontOption.Size*pixel;
this.TextRect.Width=textWidth;
this.TextRect.Height=this.FontOption.Size*pixel;
//this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height);
this.Canvas.restore();
}
//根据设置动态生成字体
this.GetTextFont=function()
{
if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return null;
var font='';
if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px ';
font+=this.FontOption.Family;
return font;
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
if (!this.TextRect) return -1;
var offset=0;
if (this.Option && this.Option.Zoom>=1)
{
offset=this.Option.Zoom*GetDevicePixelRatio();
}
this.Canvas.beginPath();
this.Canvas.rect(this.TextRect.Left-offset,this.TextRect.Top-offset,this.TextRect.Width+offset*2,this.TextRect.Height+offset*2);
if (this.Canvas.isPointInPath(x,y)) return 100;
return -1;
}
}
//江恩角度线(Gann Fan),亦又称作甘氏线的
function ChartDrawPictureGannFan()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureGannFan';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.LinePoint=[];
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.LineDash=[5,10];
this.EnableDottedLine=false; //辅助线是否使用虚线
this.EnableArea=true; //是否绘制面积图
this.IsShowTitle=true;
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.Font) this.Font=option.Font;
if (Array.isArray(option.LineDash)) this.LineDash=option.LineDash;
if (IFrameSplitOperator.IsBool(option.EnableDottedLine)) this.EnableDottedLine=option.EnableDottedLine;
if (IFrameSplitOperator.IsBool(option.EnableArea)) this.EnableArea=option.EnableArea;
if (IFrameSplitOperator.IsBool(option.IsShowTitle)) this.IsShowTitle=option.IsShowTitle;
}
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
var quadrant=this.GetQuadrant(drawPoint[0],drawPoint[1]);
this.SetLineWidth();
if (quadrant===1 || quadrant===2 || quadrant===3 || quadrant===4)
{
this.CalculateLines(drawPoint[0],drawPoint[1],quadrant);
if (this.EnableArea) this.DrawArea();
for(var i=0; i<this.LinePoint.length; ++i)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End,item.IsDottedLine);
}
if (this.IsShowTitle)
{
for(var i=0; i<this.LinePoint.length; ++i)
{
var item =this.LinePoint[i];
if (item.Text && item.PtEnd) this.DrawTitle(item.PtEnd,item.Text);
}
}
}
else
{
this.DrawLine(drawPoint[0],drawPoint[1],false);
}
this.RestoreLineWidth();
this.Canvas.restore();
this.DrawPoint(drawPoint); //画点
}
//获取在第几象限
this.GetQuadrant=function(ptStart,ptEnd)
{
if (ptStart.X<ptEnd.X && ptStart.Y>ptEnd.Y) return 1;
else if (ptStart.X>ptEnd.X && ptStart.Y>ptEnd.Y) return 2;
else if (ptStart.X < ptEnd.X && ptStart.Y< ptEnd.Y) return 4;
else return 3;
}
//isDotline 是否是虚线
this.DrawLine=function(ptStart,ptEnd,isDottedline)
{
if (isDottedline) this.Canvas.setLineDash(this.LineDash);
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
if (isDottedline) this.Canvas.setLineDash([]);
}
this.DrawTitle=function(pt,text)
{
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
this.Canvas.fillText(text,pt.X,pt.Y);
}
this.DrawArea=function()
{
var lineStart=null,lineEnd=null;
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
if (item.Text=='1:8') lineStart=this.LinePoint[i];
else if (item.Text=='8:1') lineEnd=this.LinePoint[i];
}
if (!lineStart || !lineEnd) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y);
this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y);
this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
//计算线段
this.CalculateLines=function(ptStart,ptEnd,quadrant)
{
if (!this.Frame) return false;
var top=this.Frame.ChartBorder.GetTopEx();
var right=this.Frame.ChartBorder.GetRight();
var bottom=this.Frame.ChartBorder.GetBottom();
const SPLIT_LINE_VALUE=[0.5, 1.0/3, 0.25, 0.125, 2.0/3];
const SPLIT_LINE_X_TITLE=["1:2","1:3","1:4","1:8","2:3"];
const SPLIT_LINE_Y_TITLE=["2:1","3:1","4:1","8:1","3:2"];
var ptLineStart=new Point();
var ptLineEnd=new Point();
ptLineStart.X=ptStart.X;
ptLineStart.Y=ptStart.Y;
ptLineEnd.X=ptEnd.X;
ptLineEnd.Y=ptEnd.Y;
var lineWidth=Math.abs(ptStart.X-ptEnd.X);
var lineHeight=Math.abs(ptStart.Y-ptEnd.Y);
if (quadrant===1)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineWidth>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]};
line.PtEnd.Y=ptEnd.Y;
line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i];
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
}
}
else if (quadrant==2)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineWidth>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]};
line.PtEnd.Y=ptEnd.Y;
line.PtEnd.X=ptStart.X-lineWidth*SPLIT_LINE_VALUE[i];
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
}
}
else if (quadrant==3)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineWidth>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]};
line.PtEnd.Y=ptEnd.Y;
line.PtEnd.X=ptStart.X-lineWidth*SPLIT_LINE_VALUE[i];
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
}
}
else if (quadrant==4)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineWidth>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]};
line.PtEnd.Y=ptEnd.Y;
line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i];
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
}
}
else
{
return false;
}
return true;
}
}
//江恩角度线(Gann Fan) 通达信版本
function ChartDrawPictureGannFanV2()
{
this.newMethod=ChartDrawPictureGannFan; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureGannFanV2';
this.EnableDottedLine=true; //辅助线是否使用虚线
this.LineDash=[4,8];
this.EnableArea=false;
this.Super_CalculateLines=this.CalculateLines;
this.CalculateLines=function(ptStart,ptEnd,quadrant)
{
if (!this.Super_CalculateLines(ptStart,ptEnd,quadrant)) return false;
var border=this.Frame.ChartBorder.GetBorder();
if (quadrant==1)
{
var line={ Start:ptStart, End:{ X:border.Right, Y:ptStart.Y}, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
var line={ Start:ptStart, End:{ X:ptStart.X, Y:border.TopEx }, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
}
else if (quadrant==2)
{
var line={ Start:ptStart, End:{ X:ptStart.X, Y:border.TopEx }, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
var line={ Start:ptStart, End:{ X:border.Left, Y:ptStart.Y}, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
}
else if (quadrant==3)
{
var line={ Start:ptStart, End:{ X:border.Left, Y:ptStart.Y}, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
var line={ Start:ptStart, End:{ X:ptStart.X, Y:border.BottomEx }, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
}
else if (quadrant==4)
{
var line={ Start:ptStart, End:{ X:ptStart.X, Y:border.BottomEx }, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
var line={ Start:ptStart, End:{ X:border.Right, Y:ptStart.Y}, IsDottedLine:false, PtEnd:null, Text:null };
this.LinePoint.push(line);
}
}
}
//阻速线 (高 3等份)
function ChartDrawPictureResistanceLine()
{
this.newMethod=ChartDrawPictureGannFan; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureResistanceLine';
//计算线段
this.CalculateLines=function(ptStart,ptEnd,quadrant)
{
if (!this.Frame) return false;
var top=this.Frame.ChartBorder.GetTopEx();
var right=this.Frame.ChartBorder.GetRight();
var bottom=this.Frame.ChartBorder.GetBottom();
const SPLIT_LINE_VALUE=[1.0/3, 2.0/3];
const SPLIT_LINE_Y_TITLE=["3:1","3:2"];
var ptLineStart=new Point();
var ptLineEnd=new Point();
ptLineStart.X=ptStart.X;
ptLineStart.Y=ptStart.Y;
ptLineEnd.X=ptEnd.X;
ptLineEnd.Y=ptEnd.Y;
var lineWidth=Math.abs(ptStart.X-ptEnd.X);
var lineHeight=Math.abs(ptStart.Y-ptEnd.Y);
if (quadrant===1)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
}
}
else if (quadrant==2)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.Start;
this.LinePoint.push(line);
}
}
}
else if (quadrant==3)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
}
}
else if (quadrant==4)
{
var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd);
var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'};
this.LinePoint.push(line);
for(var i=0;i<SPLIT_LINE_VALUE.length; ++i)
{
if (lineHeight>5)
{
line={Start:ptLineStart, End:null, IsDottedLine:this.EnableDottedLine,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]};
line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i];
line.PtEnd.X=ptEnd.X;
var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd);
line.End=extendLine.End;
this.LinePoint.push(line);
}
}
}
else
{
return false;
}
return true;
}
this.DrawArea=function()
{
var lineStart=null,lineEnd=null;
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
if (item.Text=='1:1') lineStart=this.LinePoint[i];
else if (item.Text=='3:1') lineEnd=this.LinePoint[i];
}
if (!lineStart || !lineEnd) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y);
this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y);
this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
}
//阻速线2 (高 3等份)通达信版本
function ChartDrawPictureResistanceLineV2()
{
this.newMethod=ChartDrawPictureResistanceLine; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureResistanceLineV2';
this.EnableDottedLine=true; //辅助线是否使用虚线
this.LineDash=[4,8];
this.EnableArea=false;
this.IsShowTitle=false;
}
//黄金分割线
function ChartDrawPictureGoldenSection()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureGoldenSection';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.Font=14*GetDevicePixelRatio() +"px 微软雅黑";
this.GetSectionData=function()
{
const GOLDEN_SECTION_DATA= [0,0.236,0.382,0.5,0.618,0.80,1,1.236,1.382,1.5,1.618,1.8,2];
return GOLDEN_SECTION_DATA;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.CalculateLines(drawPoint[0],drawPoint[1]);
this.ClipFrame();
this.SetLineWidth();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End,item.IsDottedLine);
}
this.RestoreLineWidth();
for(var i in this.LinePoint)
{
var item =this.LinePoint[i];
if (item.Text) this.DrawTitle(item.Start,item.Text);
}
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.CalculateHSCreenLines=function(ptStart,ptEnd)
{
var sectionData=this.GetSectionData();
var left=this.Frame.ChartBorder.GetTop();
var right=this.Frame.ChartBorder.GetBottom();
var lineHeight=ptStart.X-ptEnd.X;
for(var i=0;i<sectionData.length;++i)
{
var yMove=lineHeight*sectionData[i];
var line={Start:new Point(), End:new Point()};
line.Start.X=ptStart.X-yMove;
line.Start.Y=left;
line.End.X=ptStart.X-yMove;
line.End.Y=right;
var text='';
if (i==0) text='Base '
else text=(sectionData[i]*100).toFixed(2)+'% ';
var yValue=this.Frame.GetYData(line.Start.X);
text+=yValue.toFixed(2);
line.Text=text;
this.LinePoint.push(line);
}
}
this.CalculateLines=function(ptStart,ptEnd)
{
if (this.Frame.IsHScreen)
{
this.CalculateHSCreenLines(ptStart,ptEnd);
return;
}
var sectionData=this.GetSectionData();
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var lineHeight=ptStart.Y-ptEnd.Y;
for(var i=0;i<sectionData.length;++i)
{
var yMove=lineHeight*sectionData[i];
var line={Start:new Point(), End:new Point()};
line.Start.Y=ptStart.Y-yMove;
line.Start.X=left;
line.End.Y=ptStart.Y-yMove;
line.End.X=right;
var text='';
if (i==0) text='Base '
else text=(sectionData[i]*100).toFixed(2)+'% ';
var yValue=this.Frame.GetYData(line.Start.Y);
text+=yValue.toFixed(2);
line.Text=text;
this.LinePoint.push(line);
}
}
this.DrawLine=function(ptStart,ptEnd)
{
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
}
this.DrawTitle=function(pt,text)
{
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
if (this.Frame.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(pt.X,pt.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,pt.X,pt.Y);
}
}
}
//百分比线
function ChartDrawPicturePercentage()
{
this.newMethod=ChartDrawPictureGoldenSection; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPicturePercentage';
this.GetSectionData=function()
{
const GOLDEN_SECTION_DATA= [0, 0.25, 0.333, 0.50, 1];
return GOLDEN_SECTION_DATA;
}
}
//波段线
function ChartDrawPictureWaveBand()
{
this.newMethod=ChartDrawPictureGoldenSection; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureWaveBand';
this.GetSectionData=function()
{
const GOLDEN_SECTION_DATA= [0,0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875,1];
return GOLDEN_SECTION_DATA;
}
}
//三角形
function ChartDrawPictureTriangle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureTriangle';
this.PointCount=3;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.LastPoint;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
var points=drawPoint.slice(0);
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
this.CalculateLines(points);
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.DrawArea(points);
this.DrawPoint(points); //画点
this.DrawTitle(points);
this.Canvas.restore();
}
this.DrawArea=function(points)
{
if (points.length!=3) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(points[0].X,points[0].Y);
this.Canvas.lineTo(points[1].X,points[1].Y);
this.Canvas.lineTo(points[2].X,points[2].Y);
this.Canvas.lineTo(points[0].X,points[0].Y);
this.Canvas.closePath();
this.Canvas.fill();
}
//显示角度数据
this.DrawTitle=function(points)
{
if (this.Status!=10) return; //拖拽完成以后才显示角度数据
//输出3个点的角度
/*
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
this.Canvas.fillText('∠60',points[0].X,points[0].Y);
*/
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length===2)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
}
else if (points.length===3)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
line={Start:new Point(), End:new Point()};
line.Start.Y=points[1].Y;
line.Start.X=points[1].X;
line.End.Y=points[2].Y;
line.End.X=points[2].X;
this.LinePoint.push(line);
line={Start:new Point(), End:new Point()};
line.Start.Y=points[2].Y;
line.Start.X=points[2].X;
line.End.Y=points[0].Y;
line.End.X=points[0].X;
this.LinePoint.push(line);
}
}
}
//对称角度
function ChartDrawPictureSymmetryAngle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureSymmetryAngle';
this.PointCount=2;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
//var points=drawPoint.slice(0);
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
this.CalculateLines(drawPoint);
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.DrawArea();
this.DrawPoint(drawPoint); //画点
this.DrawTitle(drawPoint);
this.Canvas.restore();
}
this.CalculateLines=function(points)
{
if (points.length!=2) return;
if (!this.Frame) return;
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[0].X;
this.LinePoint.push(line);
var xMove=points[0].X-points[1].X;
line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[0].X+xMove;
this.LinePoint.push(line);
}
this.DrawArea=function()
{
if (this.LinePoint.length!=3) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y);
this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y);
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
//显示角度数据
this.DrawTitle=function(points)
{
if (this.Status!=10) return; //拖拽完成以后才显示角度数据
//输出点的角度
/*
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
this.Canvas.fillText('∠60',points[0].X,points[0].Y);
*/
}
}
//圆
function ChartDrawPictureCircle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureCircle';
this.PointCount=2;
this.CircleData;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=2) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
var x=drawPoint[0].X-drawPoint[1].X;
var y=drawPoint[0].Y-drawPoint[1].Y;
var r=Math.sqrt(x*x+y*y);
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.strokeStyle=this.LineColor;
this.DrawLine(drawPoint[0],drawPoint[1]);
this.Canvas.beginPath();
this.Canvas.arc(drawPoint[0].X,drawPoint[0].Y,r,0,2*Math.PI);
this.Canvas.stroke();
this.Canvas.fill();
this.CircleData={X:drawPoint[0].X, Y:drawPoint[0].Y, R:r};
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y,option)
{
if (this.IsFrameMinSize()) return -1;
if (this.Status!=10) return -1;
var value=this.IsPointInXYValue(x,y,option);
if (value>=0)
return value;
if (this.CircleData && this.CircleData.R>8)
{
var triangleX=this.CircleData.X-x;
var triangleY=this.CircleData.Y-y;
var r=Math.sqrt(triangleX*triangleX+triangleY*triangleY); //计算直径
if (r<this.CircleData.R && r>this.CircleData.R-8) return 100;
}
return -1;
}
}
//四边形
function ChartDrawPictureQuadrangle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureQuadrangle';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointCount=3;
this.LastPoint;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
var points=drawPoint.slice(0);
this.CalculateLines(points);
this.ClipFrame();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.DrawArea();
this.DrawPoint(points); //画点
this.Canvas.restore();
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.DrawArea=function()
{
if (this.LinePoint.length!=4) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y);
this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y);
this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
var linePoint=this.CreateLineData(points[0],points[1]);
this.LinePoint.push(linePoint);
}
else if (points.length==3)
{
var linePoint=this.CreateLineData(points[0],points[1]);
this.LinePoint.push(linePoint);
var linePoint=this.CreateLineData(points[1],points[2]);
this.LinePoint.push(linePoint);
//计算平行线
var xMove=points[2].X-points[1].X;
var yMove=points[2].Y-points[1].Y;
var pt4=new Point(); //第4个点的坐标
pt4.X=points[0].X+xMove;
pt4.Y=points[0].Y+yMove;
var linePoint=this.CreateLineData(points[2],pt4);
this.LinePoint.push(linePoint);
var linePoint=this.CreateLineData(pt4,points[0]);
this.LinePoint.push(linePoint);
}
}
}
//斐波那契周期线
function ChartDrawPictureFibonacci()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureFibonacci';
this.PointCount=1;
this.Font=14*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint) return;
this.CalculateLines();
if (this.LinePoint.length<=0) return;
this.ClipFrame();
this.SetLineWidth();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
this.DrawTitle(item.Start,item.Title);
}
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawTitle=function(pt,text)
{
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.font=this.Font;
if (this.Frame.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(pt.X,pt.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,2,10);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,pt.X+2,pt.Y+10);
}
}
this.CalculateHSCreenLines=function()
{
var data=this.Frame.Data;
if (!data) return;
var xStart=null;
if (this.Status==10)
{
if (this.Value.length!=1) return;
xStart=this.Value[0].XValue;
}
else
{
if (this.Point.length!=1) return;
xStart=parseInt(this.Frame.GetXData(this.Point[0].Y))+data.DataOffset;
}
var top=this.Frame.ChartBorder.GetRightEx();
var bottom=this.Frame.ChartBorder.GetLeftEx();
var showCount=this.Frame.XPointCount;
const LINE_DATA=[1,2,3,5,8,13,21,34,55,89,144,233];
for(var i=0;i<LINE_DATA.length;++i)
{
var xValue=xStart+LINE_DATA[i];
var dataIndex=xValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=showCount) continue;
var x=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
var line={Start:new Point(), End:new Point(), Title:LINE_DATA[i]};
line.Start.X=top;
line.Start.Y=x;
line.End.X=bottom;
line.End.Y=x;
this.LinePoint.push(line);
}
}
this.CalculateLines=function()
{
if (this.Status<2) return;
if (!this.Frame) return;
var data=this.Frame.Data;
if (!data) return;
if (this.Frame.IsHScreen)
{
this.CalculateHSCreenLines();
return;
}
var xStart=null;
if (this.Status==10)
{
if (this.Value.length!=1) return;
xStart=this.Value[0].XValue;
}
else
{
if (this.Point.length!=1) return;
xStart=parseInt(this.Frame.GetXData(this.Point[0].X))+data.DataOffset;
}
var top=this.Frame.ChartBorder.GetTopEx();
var bottom=this.Frame.ChartBorder.GetBottom();
var showCount=this.Frame.XPointCount;
const LINE_DATA=[1,2,3,5,8,13,21,34,55,89,144,233];
for(var i=0;i<LINE_DATA.length;++i)
{
var xValue=xStart+LINE_DATA[i];
var dataIndex=xValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=showCount) continue;
var x=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
var line={Start:new Point(), End:new Point(), Title:LINE_DATA[i]};
line.Start.Y=top;
line.Start.X=x;
line.End.Y=bottom;
line.End.X=x;
this.LinePoint.push(line);
}
}
}
//线性回归
function ChartDrawLinearRegression(option)
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawLinearRegression';
this.PointCount=2;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.ChartBorder;
this.Lines=[]; //回归线 { XValue:, YValue: }
this.IsShowMaxMinLine=false; //是否显示最高 最低价通道
this.IsShowExtendLine=false; //是否显示延长线
this.ExtendLineDash=[5,5]; //延长线虚线
this.MaxPoint;
this.MinPoint;
if (option)
{
if (option.IsShowMaxMinLine==true) this.IsShowMaxMinLine=true;
if (option.IsShowExtendLine==true) this.IsShowExtendLine=true;
}
//导入
this.ImportStorageData=function(storageData)
{
if (storageData.IsShowMaxMinLine==true) this.IsShowMaxMinLine=true;
if (storageData.IsShowExtendLine==true) this.IsShowExtendLine=true;
if (storageData.Lines) this.Lines=storageData.Lines;
if (storageData.MaxPoint && storageData.MinPoint)
{
this.MaxPoint=storageData.MaxPoint;
this.MinPoint=storageData.MinPoint;
}
}
//导出
this.Super_ExportStorageData=this.ExportStorageData;
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
storageData.IsShowMaxMinLine=this.IsShowMaxMinLine;
storageData.IsShowExtendLine=this.IsShowExtendLine;
storageData.Lines=this.Lines;
if (this.IsShowMaxMinLine)
{
storageData.MaxPoint=this.MaxPoint;
storageData.MinPoint=this.MinPoint;
}
}
return storageData;
}
this.PointToValue_Backup=this.PointToValue;
this.PointToValue=function()
{
//拖拽完成 把点移动到线段头尾
this.Point[0]={X:this.Lines[0].X, Y:this.Lines[0].Y};
this.Point[1]={X:this.Lines[this.Lines.length-1].X, Y:this.Lines[this.Lines.length-1].Y};
this.PointToValue_Backup();
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true} );
if (!drawPoint || drawPoint.length!=2)
{
if (this.Status==10)
{
this.ClipFrame();
this.ChartBorder=this.Frame.ChartBorder;
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.DrawLinearLines();
this.RestoreLineWidth();
this.Canvas.restore();
}
return;
}
this.ClipFrame();
this.ChartBorder=this.Frame.ChartBorder;
//0=开始画 1=完成第1个点 2=完成第2个点 3=完成第3个点 10=完成 20=移动)
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
if (this.Status==10)
{
this.DrawLinearLines();
}
else
{
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var kPoint=this.PointToKLine([ptStart,ptEnd]);
//JSConsole.Chart.Log('[ChartDrawLinearRegression::Draw] kPoint', kPoint);
var linear=this.Calculate(kPoint);
//JSConsole.Chart.Log('[ChartDrawLinearRegression::Draw] linear', linear);
this.Lines=linear.Points;
this.MaxPoint=linear.Max;
this.MinPoint=linear.Min;
this.DrawLinearLines();
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,top);
this.Canvas.lineTo(ptStart.X,bottom);
this.Canvas.moveTo(ptEnd.X,top);
this.Canvas.lineTo(ptEnd.X,bottom);
this.Canvas.stroke();
}
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.Calculate=function(kPoint)
{
var startPoint=kPoint[0];
var endPoint=kPoint[1];
if (startPoint.XValue>endPoint.XValue)
{
startPoint=kPoint[1];
endPoint=kPoint[0];
}
var num=(endPoint.XValue-startPoint.XValue)+1;
var data=this.Frame.Data.Data;
var i=endPoint.XValue;
var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope;
var i, j,x, k;
for(j = 0, x=num; j < num && j <= i; ++j, --x)
{
Ex += x;
Ey += data[i - j].Close;
}
Ex /= num;
Ey /= num;
for(j = 0, x=num; j < num && j <= i; ++j,--x)
{
Sxy += (x-Ex)*(data[i-j].Close-Ey);
Sxx += (x-Ex)*(x-Ex);
}
Slope = Sxy / Sxx; //斜率
Const = Ey - Ex*Slope;
//value=Slope * num + Const; //Y轴值 线性回归公式
var points=[];
var max=null, min=null;
for(j = 0, k=num; j < num && j <= i; ++j,--k)
{
var xIndex=endPoint.XIndex-j;
var xValue=endPoint.XValue-j;
var x=this.Frame.GetXFromIndex(xIndex);
var yValue=Slope * k + Const;
var y=this.Frame.GetYFromData(yValue,false);
var item={ X:x, Y:y, XValue:xValue, YValue:yValue };
points.push(item);
if (max==null || max.High<data[xValue].High)
{
max={X:x,Y:y,XValue:xValue, YValue:yValue, High:data[xValue].High };
}
if (min==null || min.Low>data[xValue].Low)
{
min={X:x,Y:y,XValue:xValue, YValue:yValue, Low:data[xValue].Low };
}
}
return { Points:points, Slope:Slope, Const:Const , Max:max, Min:min };
}
this.DrawLinearLines=function()
{
if (!this.Frame) return null;
var data=this.Frame.Data;
if (!data) return null;
var showCount=this.Frame.XPointCount;
var dataOffset=data.DataOffset;
var isHScreen=this.Frame.IsHScreen;
var drawLines=[];
for(var i in this.Lines)
{
var item=this.Lines[i];
var dataIndex=item.XValue-dataOffset;
if (dataIndex<0 || dataIndex>=showCount) continue;
var pt={};
if (isHScreen) //横屏X,Y对调
{
}
else
{
pt.X=this.Frame.GetXFromIndex(dataIndex,false);
pt.Y=this.Frame.GetYFromData(item.YValue,false);
pt.YValue=item.YValue;
}
drawLines.push(pt);
}
if (drawLines.length>1)
{
for(var i in drawLines)
{
var item=drawLines[i];
if (i==0)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.X,item.Y);
}
else
{
this.Canvas.lineTo(item.X,item.Y);
if (i==drawLines.length-1) this.Canvas.stroke();
}
}
this.DrawExtendLine(drawLines);
}
//最大 最小通道
if (this.IsShowMaxMinLine && drawLines.length>1 && this.MaxPoint && this.MinPoint)
{
var highOffset=this.MaxPoint.High-this.MaxPoint.YValue;
for(var i in drawLines)
{
var item=drawLines[i];
item.Y=this.Frame.GetYFromData((item.YValue+highOffset),false);
if (i==0)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.X,item.Y);
}
else
{
this.Canvas.lineTo(item.X,item.Y);
if (i==drawLines.length-1) this.Canvas.stroke();
}
}
this.DrawExtendLine(drawLines);
var lowOffset=this.MinPoint.Low-this.MinPoint.YValue;
for(var i in drawLines)
{
var item=drawLines[i];
item.Y=this.Frame.GetYFromData((item.YValue+lowOffset),false);
if (i==0)
{
this.Canvas.beginPath();
this.Canvas.moveTo(item.X,item.Y);
}
else
{
this.Canvas.lineTo(item.X,item.Y);
if (i==drawLines.length-1) this.Canvas.stroke();
}
}
this.DrawExtendLine(drawLines);
}
}
//画延长线
this.DrawExtendLine=function(lines)
{
if (!this.IsShowExtendLine) return;
var ptStart=lines[0];
var ptEnd=lines[lines.length-1];
var aryPoint;
if (ptEnd.X>ptStart.X) aryPoint=[ptStart, ptEnd];
else aryPoint=[ptEnd, ptStart];
var ptExtend=this.CalculateExtendLineEndPoint(aryPoint);
this.Canvas.beginPath();
this.Canvas.moveTo(ptEnd.X,ptEnd.Y);
this.Canvas.lineTo(ptExtend.X,ptExtend.Y);
this.Canvas.setLineDash(this.ExtendLineDash);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
}
//尺子
function ChartDrawRuler()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawRuler';
this.PointCount=2;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.TitleColor=g_JSChartResource.ChartDrawRuler.TitleColor;
this.IsHScreen=false;
this.Draw=function()
{
this.LinePoint=[];
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.IsHScreen=this.Frame.IsHScreen;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
var kPoint=this.PointToKLine([ptStart,ptEnd]);
//JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] kPoint', kPoint);
var kDataInfo=this.Calculate(kPoint);
//JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] kDataInfo', kDataInfo);
var increase=IFrameSplitOperator.IsNumber(kDataInfo.Increase)? kDataInfo.Increase.toFixed(2)+'%': "--";
var risefall=IFrameSplitOperator.IsNumber(kDataInfo.Risefall)? kDataInfo.Risefall.toFixed(2): "--";
var title=`间距:${kDataInfo.Count} 涨跌:${risefall} 涨幅:${increase}`;
//JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] title', title);
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
//绘制信息
this.Canvas.textBaseline='bottom';
this.Canvas.textAlign='left';
this.Canvas.font=this.Font;
if (this.TitleColor)
{
this.Canvas.fillStyle=this.TitleColor;
}
else if (IFrameSplitOperator.IsNumber(kDataInfo.Increase))
{
if (kDataInfo.Increase>0) this.Canvas.fillStyle=g_JSChartResource.UpTextColor;
else if (kDataInfo.Increase<0) this.Canvas.fillStyle=g_JSChartResource.DownTextColor;
else this.Canvas.fillStyle=g_JSChartResource.UnchagneTextColor;
}
else
{
this.Canvas.fillStyle=g_JSChartResource.UnchagneTextColor;
}
var offset=3*GetDevicePixelRatio();
var xText=ptStart.X
var yText=ptStart.Y
if (this.IsHScreen)
{
this.Canvas.translate(xText+offset,yText+offset);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(title,0,0);
}
else
{
this.Canvas.fillText(title,xText+offset,yText-offset);
}
this.Canvas.restore();
}
this.Calculate=function(kPoint)
{
var startPoint=kPoint[0];
var endPoint=kPoint[1];
if (startPoint.XValue>endPoint.XValue)
{
startPoint=kPoint[1];
endPoint=kPoint[0];
}
var data=this.Frame.Data.Data;
var open, high, low, yClose, close;
var count=0;
for(var i=startPoint.XValue;i<=endPoint.XValue;++i, ++count)
{
var item=data[i];
if (count==0)
{
yClose=item.YClose;
open=item.Open;
close=item.Close;
low=item.Low;
high=item.High;
}
else
{
close=item.Close;
if (low>item.Low) low=item.Low;
if (high<item.High) high=item.High;
}
}
if (!IFrameSplitOperator.IsPlusNumber(yClose)) //前收盘无效, 取上一个交易日的收盘价
{
var index=startPoint.XValue-1;
if (index>=0 && index<data.length) yClose=data[index].Close;
}
var result={ YClose:yClose, Open:open, High:high, Low:low, Close:close, Count:count };
if (IFrameSplitOperator.IsPlusNumber(yClose))
{
result.Increase=(close-yClose)/yClose*100;
result.Risefall=(close-yClose);
}
return result;
}
}
//画图工具-标价线 支持横屏
function ChartDrawPriceLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPriceLine';
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true } );
if (!drawPoint) return;
if (drawPoint.length!=1) return;
this.IsHScreen=this.Frame.IsHScreen;
var ptStart=drawPoint[0];
var chartBorder=this.Frame.ChartBorder;
if (this.IsHScreen)
{
var left=chartBorder.GetLeftEx();
var right=chartBorder.GetRightEx();
if (ptStart.X<left || ptStart.X>right) return;
var bottom=chartBorder.GetBottom();
var ptEnd={X:ptStart.X, Y:bottom};
var price=this.Frame.GetYData(ptStart.X, false);
}
else
{
var bottom=chartBorder.GetBottomEx();
var top=chartBorder.GetTopEx();
if (ptStart.Y<top || ptStart.Y>bottom) return;
var right=chartBorder.GetRight();
var ptEnd={X:right, Y:ptStart.Y};
var price=this.Frame.GetYData(ptStart.Y, false);
}
this.ClipFrame();
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.textBaseline='bottom';
this.Canvas.textAlign='left';
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
var offset=2*GetDevicePixelRatio();
var xText=ptStart.X;
var yText=ptStart.Y;
if (this.IsHScreen)
{
this.Canvas.translate(xText+offset,yText+offset);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(price.toFixed(2),0,0);
}
else
{
this.Canvas.fillText(price.toFixed(2),xText+offset,yText-offset);
}
this.Canvas.restore();
}
}
//画图工具-标价线2 支持横屏 支持价格文字在坐标内部显示
function ChartDrawPriceLineV2()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPriceLineV2';
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.LineWidth=1;
this.IsDrawFirst=true;
this.TextColor="rgb(255,255,255)";
this.Title; //标题
this.TextPosition=[null, 0]; //[0]=左侧(没有做) [1]=右侧 0=自动 1=内部 2=外部
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.TextColor) this.TextColor=option.TextColor;
if (option.Title) this.Title=option.Title;
if (IFrameSplitOperator.IsNonEmptyArray(option.TextPosition)) this.TextPosition=option.TextPosition.slice();
}
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true } );
if (!drawPoint) return;
if (drawPoint.length!=1) return;
if (!this.IsYValueInFrame(this.Value[0].YValue)) return;
this.IsHScreen=this.Frame.IsHScreen;
var chartBorder=this.Frame.ChartBorder;
var border=this.Frame.GetBorder();
if (this.IsHScreen)
{
var left=border.LeftEx;
var right=border.RightEx;
var bottom=border.Bottom;
var top=border.Top;
var ptStart={ X:drawPoint[0].X, Y:top };
if (ptStart.X<left || ptStart.X>right) return;
var ptEnd={X:drawPoint[0].X, Y:bottom };
var price=this.Frame.GetYData(ptStart.X, false);
}
else
{
var bottom=border.BottomEx;
var top=border.TopTitle;
var left=border.Left;
var right=border.Right;
var ptStart={ X:left, Y:drawPoint[0].Y };
if (ptStart.Y<top || ptStart.Y>bottom) return;
var ptEnd={ X:right, Y:drawPoint[0].Y };
var price=this.Frame.GetYData(ptStart.Y, false);
}
//this.ClipFrame();
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(ptStart.X),ToFixedPoint(ptStart.Y));
this.Canvas.lineTo(ToFixedPoint(ptEnd.X),ToFixedPoint(ptEnd.Y));
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
var pixelTatio = GetDevicePixelRatio();
this.Canvas.font=this.Font;
var offset=2*pixelTatio;
var xText=ptEnd.X;
var yText=ptEnd.Y;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
var textHeight=this.GetFontHeight();
var text=price.toFixed(2);
var textWidth=this.Canvas.measureText(text).width+2*offset;
var centerPoint=null;
if (this.IsHScreen)
{
var position=this.TextPosition[1];
var bDrawInside=false; //在内部绘制
if (position==0) bDrawInside=chartBorder.Bottom<=10;
else if (position==1) bDrawInside=true;
else if (position==2) bDrawInside=false;
if (bDrawInside)
{
yText=yText-textWidth;
var rtBG={ Left:(xText-textHeight/2), Top:yText , Width:textHeight, Height: textWidth};
}
else //框架内部显示
{
var rtBG={ Left:(xText-textHeight/2), Top:yText , Width: textHeight, Height:textWidth };
}
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
this.Canvas.save();
this.Canvas.translate(xText,yText+1*pixelTatio);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
if (this.Title)
{
var textWidth=this.Canvas.measureText(this.Title).width+2*pixelTatio;
if (bDrawInside)
{
var rtTitle={Left:rtBG.Left, Top:rtBG.Top-textWidth-1*pixelTatio, Width:textHeight, Height:textWidth};
}
else
{
var rtTitle={ Left:rtBG.Left, Top:bottom-textWidth-1*pixelTatio, Width:textHeight, Height:textWidth };
}
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtTitle.Left, rtTitle.Top, rtTitle.Width, rtTitle.Height);
this.Canvas.save();
this.Canvas.translate(xText,rtTitle.Top+1*pixelTatio);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(this.Title,0,0);
this.Canvas.restore();
}
centerPoint={ X:ptStart.X, Y:ptStart.Y+(ptEnd.Y-ptStart.Y)/2 }; //中心点
}
else
{
var position=this.TextPosition[1];
var bDrawInside=false; //在内部绘制
if (position==0) bDrawInside=chartBorder.Right<=10;
else if (position==1) bDrawInside=true;
else if (position==2) bDrawInside=false;
if (bDrawInside)
{
var rtBG={ Left:xText-textWidth, Top:(yText-textHeight/2-1*pixelTatio) , Width:textWidth, Height: textHeight};
}
else //框架内部显示
{
var rtBG={ Left:xText, Top:(yText-textHeight/2-1*pixelTatio) , Width:textWidth, Height: textHeight};
if (rtBG.Left+rtBG.Width>border.ChartWidth) rtBG.Left=border.ChartWidth-rtBG.Width-2*pixelTatio;
}
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text, rtBG.Left+offset, yText);
if (this.Title)
{
var textWidth=this.Canvas.measureText(this.Title).width+2*pixelTatio;
if (bDrawInside)
{
var rtTitle={Left:rtBG.Left-textWidth, Top:rtBG.Top, Width:textWidth, Height:textHeight}
}
else
{
var rtTitle={ Left:right-textWidth-1*pixelTatio, Top:rtBG.Top, Width:textWidth, Height:textHeight };
if (rtBG.Left!=right) rtTitle.Left=rtBG.Left-textWidth-1*pixelTatio;
}
this.Canvas.fillStyle=this.LineColor;
this.Canvas.fillRect(rtTitle.Left, rtTitle.Top, rtTitle.Width, rtTitle.Height);
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(this.Title, rtTitle.Left+1*pixelTatio, yText);
}
centerPoint={ X:ptStart.X+(ptEnd.X-ptStart.X)/2, Y:ptStart.Y }; //中心点
}
if (centerPoint) this.DrawPoint([centerPoint]);
}
this.DrawPrice=function()
{
}
}
//画图工具-竖线 支持横屏
function ChartDrawVerticalLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawVerticalLine';
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
if (!this.Frame || !this.Frame.Data) return;
var data=this.Frame.Data;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true } );
if (!drawPoint) return;
if (drawPoint.length!=1) return;
this.IsHScreen=this.Frame.IsHScreen;
var pt=drawPoint[0];
var chartBorder=this.Frame.ChartBorder;
if (this.IsHScreen)
{
var xValue=Math.round(this.Frame.GetXData(pt.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
yLine=ToFixedPoint2(this.LineWidth,yLine);
var left=chartBorder.GetLeftEx();
var right=chartBorder.GetRightEx();
var ptStart={ X:left, Y:yLine };
var ptEnd={ X:right, Y:yLine };
}
else
{
var xValue=Math.round(this.Frame.GetXData(pt.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xLine=ToFixedPoint2(this.LineWidth,xLine);
var top=chartBorder.GetTopEx();
var bottom=chartBorder.GetBottomEx();
var ptStart={ X:xLine, Y:top };
var ptEnd={ X:xLine, Y:bottom };
}
this.ClipFrame();
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
if (this.Status==10) this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
}
//画图工具-十字线 支持横屏
function ChartDrawCrosshair()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawCrosshair';
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
if (!this.Frame || !this.Frame.Data) return;
var data=this.Frame.Data;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:false } );
if (!drawPoint) return;
if (drawPoint.length!=1) return;
this.IsHScreen=this.Frame.IsHScreen;
var pt=drawPoint[0];
var chartBorder=this.Frame.ChartBorder;
var border=this.Frame.GetBorder();
if (this.IsHScreen)
{
var xValue=Math.round(this.Frame.GetXData(pt.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
yLine=ToFixedPoint2(this.LineWidth,yLine);
var xLine=ToFixedPoint2(this.LineWidth,pt.X);
var left=border.LeftEx
var right=border.RightEx
var top=border.Top;
var bottom=border.Bottom;
var ptStart={ X:left, Y:yLine };
var ptEnd={ X:right, Y:yLine };
var ptStart2={ X:xLine, Y:top };
var ptEnd2={ X:xLine, Y:bottom };
}
else
{
var xValue=Math.round(this.Frame.GetXData(pt.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xLine=ToFixedPoint2(this.LineWidth,xLine);
var yLine=ToFixedPoint2(this.LineWidth, pt.Y);
var top=border.TopEx;
var bottom=border.BottomEx;
var left=border.Left;
var right=border.Right;
var ptStart={ X:xLine, Y:top };
var ptEnd={ X:xLine, Y:bottom };
var ptStart2={ X:left, Y:yLine };
var ptEnd2={ X:right, Y:yLine };
}
this.ClipFrame();
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.moveTo(ptStart2.X, ptStart2.Y);
this.Canvas.lineTo(ptEnd2.X,ptEnd2.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
var line2={Start:ptStart2, End:ptEnd2};
this.LinePoint.push(line);
this.LinePoint.push(line2);
if (this.Status==10) this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
}
//画图工具-监测线
function ChartDrawMonitorLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawMonitorLine';
this.PointCount=1;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.FormatLabelTextCallback=null;
this.LineColor='rgb(255,215,0)'
this.LabelConfig=
{
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
BGColor:"rgb(30,144,255)",
LineColor:"rgba(255,215,0,0.8)",
LineDash:[3,5],
Mergin:{ Left:5, Right:5, Top:5, Bottom:4 },
LineSpace:5, //行间距
TextAlign:1, //对齐方式 0=left 1=right
}
this.PointToValue_Backup=this.PointToValue;
this.PointToValue=function()
{
if (!this.PointToValue_Backup()) return false;
if (this.Frame.IsKLineFrame(false))
{
if (this.Frame.Identify===0)
{
var dataIndex=this.Value[0].XValue;
var data=this.Frame.Data;
var kItem=data.Data[dataIndex];
this.Value[0].YValue=kItem.Close; //使用收盘价
}
}
return true;
}
this.SetOption=function(option)
{
if (option.LineColor) this.LineColor=option.LineColor;
if (option.Label)
{
var item=option.Label;
var dest=this.LabelConfig
if (item.Font) dest.Font=item.Font;
if (item.BGColor) dest.BGColor=item.BGColor;
if (item.LineColor) dest.LineColor=item.LineColor;
if (item.LineDash) dest.LineDash=item.LineDash;
if (IFrameSplitOperator.IsNumber(item.LineSpace)) dest.LineSpace=item.LineSpace;
if (IFrameSplitOperator.IsNumber(item.TextAlign)) dest.TextAlign=item.TextAlign;
if (item.Mergin) CopyMarginConfig(dest.Mergin, item.Mergin);
}
if (option.FormatLabelTextCallback) this.FormatLabelTextCallback=option.FormatLabelTextCallback;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
if (!this.Frame || !this.Frame.Data) return;
var data=this.Frame.Data;
if (!IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
if (this.Point.length!=1) return;
if (this.Value.length!=1) return;
this.IsHScreen=this.Frame.IsHScreen;
if (this.IsHScreen) return;
if (this.Status==20) this.DrawMoveLine();
else if (this.Status==10) this.DrawMonitorLine(data);
}
this.DrawMoveLine=function()
{
var border=this.Frame.ChartBorder.GetBorder();
var pt=this.Point[0];
var x=ToFixedPoint(pt.X);
this.ClipFrame();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,border.TopEx);
this.Canvas.lineTo(x,border.BottomEx);
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawMonitorLine=function(data)
{
var isMinute=this.Frame.IsMinuteFrame();
var dataWidth=this.Frame.DataWidth;
var distanceWidth=this.Frame.DistanceWidth;
var xPointCount=this.Frame.XPointCount;
if (this.IsHScreen)
{
//var border=this.Frame.ChartBorder.GetHScreenBorder();
//var chartright=border.BottomEx;
//var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
}
else
{
var border=this.Frame.ChartBorder.GetBorder();
var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
var chartright=border.RightEx;
}
var ptData=this.Value[0];
this.ClipFrame();
var labelInfo=null;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var item=data.Data[i];
if (isMinute)
{
var x=this.Frame.GetXFromIndex(j);
}
else
{
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) break;
var x=left+(right-left)/2;
}
if (i==ptData.XValue) //起始
{
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,border.TopEx);
this.Canvas.lineTo(x,border.BottomEx);
this.Canvas.stroke();
var line={Start:{X:x, Y:border.TopEx}, End:{X:x, Y:border.BottomEx}};
this.LinePoint.push(line);
}
else if (i==data.Data.length-1) //结束
{
if (this.LabelConfig.LineDash) this.Canvas.setLineDash(this.LabelConfig.LineDash);
this.Canvas.strokeStyle=this.LabelConfig.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,border.TopEx);
this.Canvas.lineTo(x,border.BottomEx);
this.Canvas.stroke();
if (this.LabelConfig.LineDash) this.Canvas.setLineDash([]);
labelInfo={ Left:right, Data:data, StartIndex:ptData.XValue, AryText:[] };
}
}
this.Canvas.restore();
if (labelInfo) this.DrawLabel(labelInfo);
}
this.DrawLabel=function(labelInfo)
{
if (!this.FormatLabelTextCallback) return;
labelInfo.Config=this.LabelConfig;
this.FormatLabelTextCallback(labelInfo);
if (!IFrameSplitOperator.IsNonEmptyArray(labelInfo.AryText)) return;
if (!IFrameSplitOperator.IsNumber(labelInfo.YValue)) return;
/*
labelInfo.YValue=7.15;
labelInfo.AryText=
[
{ Name:"标题1:", Text:"6666", NameColor:"rgb(255,255,255)", TextColor:"rgb(30,10,30)" },
{ Name:"标题2:", Text:"08.00", NameColor:"rgb(255,255,255)", TextColor:"rgb(30,10,30)" },
{ Name:"标题3:", Text:"999.1", NameColor:"rgb(255,255,255)", TextColor:"rgb(30,10,30)" },
{ Name:"标题4:", Text:"320" , NameColor:"rgb(255,255,255)", TextColor:"rgb(30,10,30)"},
{ Name:"标题5:", Text:"77775.77", NameColor:"rgb(255,255,255)", TextColor:"rgb(30,10,30)" }
]
*/
this.CalculateLabelSize(labelInfo);
var y=this.Frame.GetYFromData(labelInfo.YValue,false);
var rtBG={ Left:labelInfo.Left+1, Top:y, Width:labelInfo.Width, Height:labelInfo.Height };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
this.DrawDefaultLabel(labelInfo, rtBG);
}
}
//画图工具-波浪尺
function ChartDrawWaveRuler()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawWaveRuler';
this.PointCount=3;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.LastPoint;
this.LinePoint;
this.ScaleRuler=g_JSChartResource.ChartDrawWaveRuler.ScaleRuler;
this.RulerWidth=g_JSChartResource.ChartDrawWaveRuler.RulerWidth;; //刻度尺长度
this.RulerLineWidth=g_JSChartResource.ChartDrawWaveRuler.RulerLineWidth;
this.MaxScaleRuler=g_JSChartResource.ChartDrawWaveRuler.MaxScaleRuler; //尺子最大的高度比
this.Font=g_JSChartResource.ChartDrawWaveRuler.MaxScaleRuler;
this.IsHScreen=false;
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
this.IsHScreen=this.Frame.IsHScreen;
this.CalculateLines(drawPoint);
this.ClipFrame();
this.SetLineWidth();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
//绘制波浪信息
if (drawPoint.length==3) this.DrawWaveRuler(drawPoint);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.CalculateLines=function(points)
{
if (this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
points[2]=pt;
}
if (points.length==2)
{
var linePoint=
{
Start:{X:points[0].X,Y:points[0].Y},
End:{X:points[1].X,Y:points[1].Y}
};
this.LinePoint.push(linePoint);
}
else if (points.length==3)
{
var linePoint=
{
Start:{X:points[0].X,Y:points[0].Y},
End:{X:points[1].X,Y:points[1].Y}
};
this.LinePoint.push(linePoint);
linePoint=
{
Start:{X:points[1].X,Y:points[1].Y},
End:{X:points[2].X,Y:points[2].Y}
};
this.LinePoint.push(linePoint);
}
}
this.DrawWaveRuler=function(points)
{
var ptBottom=points[1];
var ptStart=points[0];
var ptEnd=points[2];
var lineWidth=this.RulerLineWidth*GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
var rulerWidth=this.RulerWidth*GetDevicePixelRatio();//刻度线长度
if (this.IsHScreen)
{
var rulerHeight=ptStart.X-ptBottom.X;
var ptExtendBottom={ X:ptEnd.X-this.MaxScaleRuler*rulerHeight, Y:ptEnd.Y};
this.DrawLine(ptEnd,ptExtendBottom);
this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
var y=ptEnd.Y-rulerWidth/2, y2=ptEnd.Y+rulerWidth/2;
}
else
{
var rulerHeight=ptStart.Y-ptBottom.Y;
var ptExtendBottom={ X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y-this.MaxScaleRuler*rulerHeight };
this.DrawLine({X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y},ptExtendBottom);
this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
var x=ptEnd.X-rulerWidth/2, x2=ptEnd.X+rulerWidth/2;
}
var textOffset=4*GetDevicePixelRatio();
for(var i in this.ScaleRuler)
{
var item=this.ScaleRuler[i];
if (this.IsHScreen)
{
var x=ptEnd.X - item.Value*rulerHeight;
var price=this.Frame.GetYData(x, false);
this.DrawLine({X:x, Y:y}, {X:x, Y:y2});
var text=`${price.toFixed(2)} ${item.Text? item.Text: item.Value.toFixed(3)}`;
this.Canvas.save();
this.Canvas.translate(x,ptEnd.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,textOffset,0);
this.Canvas.restore();
}
else
{
var y=ptEnd.Y - item.Value*rulerHeight;
var price=this.Frame.GetYData(y, false);
this.DrawLine({X:x, Y:ToFixedPoint2(lineWidth,y)}, {X:x2, Y:ToFixedPoint2(lineWidth,y)});
var text=`${price.toFixed(2)} ${item.Text? item.Text: item.Value.toFixed(3)}`;
this.Canvas.fillText(text,x2+textOffset,y);
}
}
}
}
//画图工具-波浪尺 2个点的
function ChartDrawWaveRuler2Point()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawWaveRuler2Point';
this.PointCount=2;
this.Font=14*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.PointRate=[ 510, 517, 511.4];
this.LinePoint;
this.CPoint;
this.ScaleRuler=g_JSChartResource.ChartDrawWaveRuler2Point.ScaleRuler;
this.RulerWidth=g_JSChartResource.ChartDrawWaveRuler2Point.RulerWidth;; //刻度尺长度
this.RulerLineWidth=g_JSChartResource.ChartDrawWaveRuler2Point.RulerLineWidth;
this.MaxScaleRuler=g_JSChartResource.ChartDrawWaveRuler2Point.MaxScaleRuler; //尺子最大的高度比
this.Font=g_JSChartResource.ChartDrawWaveRuler2Point.MaxScaleRuler;
this.IsHScreen=false;
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.PointRate) this.PointRate=option.PointRate;
}
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
this.IsHScreen=this.Frame.IsHScreen;
this.CalculateLines(drawPoint);
this.ClipFrame();
this.SetLineWidth();
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
var points=[drawPoint[0],drawPoint[1],this.CPoint];
this.DrawWaveRuler(points);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.CalculateLines=function(points)
{
var firstLine=
{
Start:{ X:points[0].X,Y:points[0].Y },
End:{ X:points[1].X,Y:points[1].Y }
};
this.LinePoint.push(firstLine);
var a=points[0].Y;
var b=points[1].Y;
var width=this.PointRate[1]-this.PointRate[0];
var offset=this.PointRate[2]-this.PointRate[0];
var c=a-((a-b)*offset)/width;
this.CPoint={ X:points[1].X, Y:c };
}
this.DrawWaveRuler=function(points)
{
var ptBottom=points[1];
var ptStart=points[0];
var ptEnd=points[2];
var lineWidth=this.RulerLineWidth*GetDevicePixelRatio();
this.Canvas.lineWidth=lineWidth;
this.Canvas.textBaseline='middle';
this.Canvas.textAlign='left';
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
var rulerWidth=this.RulerWidth*GetDevicePixelRatio();//刻度线长度
if (this.IsHScreen)
{
var rulerHeight=ptStart.X-ptBottom.X;
var ptExtendBottom={ X:ptEnd.X-this.MaxScaleRuler*rulerHeight, Y:ptEnd.Y};
this.DrawLine(ptEnd,ptExtendBottom);
this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
var y=ptEnd.Y-rulerWidth/2, y2=ptEnd.Y+rulerWidth/2;
}
else
{
var rulerHeight=ptStart.Y-ptBottom.Y;
var ptExtendBottom={ X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y-this.MaxScaleRuler*rulerHeight };
this.DrawLine({X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y},ptExtendBottom);
this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
var x=ptEnd.X, x2=ptEnd.X+rulerWidth;
}
var textOffset=4*GetDevicePixelRatio();
for(var i in this.ScaleRuler)
{
var item=this.ScaleRuler[i];
if (this.IsHScreen)
{
var x=ptEnd.X - item.Value*rulerHeight;
var price=this.Frame.GetYData(x, false);
this.DrawLine({X:x, Y:y}, {X:x, Y:y2});
var text=`${price.toFixed(2)} ${item.Text? item.Text: item.Value.toFixed(3)}`;
this.Canvas.save();
this.Canvas.translate(x,ptEnd.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,textOffset,0);
this.Canvas.restore();
}
else
{
var y=ptEnd.Y - item.Value*rulerHeight;
var price=this.Frame.GetYData(y, false);
this.DrawLine({X:x, Y:ToFixedPoint2(lineWidth,y)}, {X:x2, Y:ToFixedPoint2(lineWidth,y)});
var text=`${price.toFixed(2)} ${item.Text? item.Text: item.Value.toFixed(3)}`;
this.Canvas.fillText(text,x2+textOffset,y);
}
}
}
}
//画图工具-箱型线 支持横屏
function ChartDrawBox()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawBox';
this.PointCount=2;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.AvPriceLineDash=[5*GetDevicePixelRatio(),5*GetDevicePixelRatio()];
this.KLineBorder;
this.PointToValue_Backup=this.PointToValue;
this.PointToValue=function()
{
//拖拽完成 把点移动到线段头尾
this.Point[0]={X:this.KLineBorder.Left, Y:this.KLineBorder.Top};
this.Point[1]={X:this.KLineBorder.Right, Y:this.KLineBorder.Bottom};
this.PointToValue_Backup();
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.IsHScreen=this.Frame.IsHScreen;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
var kPoint=this.PointToKLine([ptStart,ptEnd]);
JSConsole.Chart.Log('[ChartDrawBox::Draw] kPoint', kPoint);
var kDataInfo=this.Calculate(kPoint);
JSConsole.Chart.Log('[ChartDrawBox::Draw] kDataInfo', kDataInfo);
var klineBorder=this.GetKLineBorder(drawPoint, kDataInfo);
this.KLineBorder=klineBorder;
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.strokeRect(ToFixedRect(klineBorder.Left), ToFixedRect(klineBorder.Top), ToFixedRect(klineBorder.Right-klineBorder.Left), ToFixedRect(klineBorder.Bottom-klineBorder.Top));
//均价
var avPriceText;
if (kDataInfo.Amount>0 && kDataInfo.Vol>0)
{
var price=kDataInfo.Amount/kDataInfo.Vol;
avPriceText=`均价${price.toFixed(2)}`;
this.Canvas.beginPath();
if (this.IsHScreen)
{
var x=this.Frame.GetYFromData(price,false);
this.Canvas.moveTo(ToFixedPoint2(this.Canvas.lineWidth,x),klineBorder.Top);
this.Canvas.lineTo(ToFixedPoint2(this.Canvas.lineWidth,x),klineBorder.Bottom);
}
else
{
var y=this.Frame.GetYFromData(price,false);
this.Canvas.moveTo(klineBorder.Left,ToFixedPoint2(this.Canvas.lineWidth,y));
this.Canvas.lineTo(klineBorder.Right,ToFixedPoint2(this.Canvas.lineWidth,y));
}
this.Canvas.setLineDash(this.AvPriceLineDash);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
//绘制信息
this.Canvas.textBaseline='top';
this.Canvas.textAlign='left';
this.Canvas.font=this.Font;
this.Canvas.fillStyle=this.LineColor;
var textOffset=2*GetDevicePixelRatio();
var text=`K线数${kDataInfo.Count}`;
if (this.IsHScreen) this.DrawText(text,klineBorder.Right,klineBorder.Top, textOffset, textOffset);
else this.DrawText(text,klineBorder.Left,klineBorder.Top, textOffset, textOffset);
if (avPriceText)
{
if (this.IsHScreen) this.DrawText(avPriceText,x,klineBorder.Top, textOffset, textOffset); //均价
else this.DrawText(avPriceText,klineBorder.Left,y, textOffset, textOffset); //均价
}
var yClose=IFrameSplitOperator.IsNumber(kDataInfo.YClose)? kDataInfo.YClose:kDataInfo.Open;
var value=(kDataInfo.Close-yClose)/yClose*100;
text=`${value.toFixed(2)}%`;
if (this.IsHScreen) this.DrawText(text,klineBorder.Right,klineBorder.Bottom, textOffset, textOffset);
else this.DrawText(text,klineBorder.Right,klineBorder.Top, textOffset, textOffset);
value=kDataInfo.Close-yClose;
text=`${value.toFixed(2)}`;
this.Canvas.textBaseline='bottom';
if (this.IsHScreen) this.DrawText(text,klineBorder.Left,klineBorder.Bottom, textOffset, 0);
else this.DrawText(text,klineBorder.Right,klineBorder.Bottom, textOffset, 0);
this.Canvas.restore();
}
this.Calculate=function(kPoint)
{
var startPoint=kPoint[0];
var endPoint=kPoint[1];
if (startPoint.XValue>endPoint.XValue)
{
startPoint=kPoint[1];
endPoint=kPoint[0];
}
var data=this.Frame.Data.Data;
var open, high, low, yClose, close, vol=0, amount=0;
var count=0;
for(var i=startPoint.XValue;i<=endPoint.XValue;++i, ++count)
{
var item=data[i];
if (count==0)
{
yClose=item.YClose;
open=item.Open;
close=item.Close;
low=item.Low;
high=item.High;
}
else
{
close=item.Close;
if (low>item.Low) low=item.Low;
if (high<item.High) high=item.High;
}
vol+=item.Vol;
amount+=item.Amount;
}
var result={ YClose:yClose, Open:open, High:high, Low:low, Close:close, Count:count,Vol:vol, Amount:amount };
return result;
}
this.GetKLineBorder=function(drawPoint, kInfo)
{
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
var data=this.Frame.Data;
if (this.IsHScreen)
{
var xValue=Math.round(this.Frame.GetXData(ptStart.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xValue=Math.round(this.Frame.GetXData(ptEnd.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
var xHigh=this.Frame.GetYFromData(kInfo.High,false);
var xLow=this.Frame.GetYFromData(kInfo.Low,false);
var result= { Left:xLow, Top:yStart, Right:xHigh, Bottom:yEnd };
this.LinePoint.push({Start:{X:xLow, Y:yStart}, End:{X:yEnd, Y:yStart}});
this.LinePoint.push({Start:{X:xLow, Y:yEnd}, End:{X:yEnd, Y:yEnd}});
this.LinePoint.push({Start:{X:xLow, Y:yStart}, End:{X:xLow, Y:yEnd}});
this.LinePoint.push({Start:{X:xHigh, Y:yStart}, End:{X:xHigh, Y:yEnd}});
return result;
}
else
{
var xValue=Math.round(this.Frame.GetXData(ptStart.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xValue=Math.round(this.Frame.GetXData(ptEnd.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
var yHigh=this.Frame.GetYFromData(kInfo.High,false);
var yLow=this.Frame.GetYFromData(kInfo.Low,false);
var result= { Left:xStart, Top:yHigh, Right:xEnd, Bottom:yLow };
this.LinePoint.push({Start:{X:xStart, Y:yHigh}, End:{X:xEnd, Y:yHigh}});
this.LinePoint.push({Start:{X:xStart, Y:yLow}, End:{X:xEnd, Y:yLow}});
this.LinePoint.push({Start:{X:xStart, Y:yHigh}, End:{X:xStart, Y:yLow}});
this.LinePoint.push({Start:{X:xEnd, Y:yHigh}, End:{X:xEnd, Y:yLow}});
return result;
}
}
this.DrawText=function(text, x, y, xOffset, yOffset)
{
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(x,y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,xOffset,yOffset);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,x+xOffset,y+yOffset);
}
}
}
function ChartDrawTwoPointDemo()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawTwoPointDemo';
this.PointCount=2;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.IsHScreen=false;
this.PointInfo=[]; //保存点及点对应K线的信息
this.PointToValue_Backup=this.PointToValue;
this.PointToValue=function()
{
this.OnFinish();
this.PointToValue_Backup();
}
//移动或创建完成
this.OnFinish=function()
{
for(var i in this.PointInfo)
{
var item=this.PointInfo[i];
if (!item || !item.Point || !IFrameSplitOperator.IsNumber(item.Point.Y2)) continue;
this.Point[i].Y=this.PointInfo[i].Point.Y2; //点Y轴坐标调整
}
}
this.Draw=function()
{
this.LinePoint=[];
this.PointInfo=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint) return;
this.IsHScreen=this.Frame.IsHScreen;
//this.CalculateLines(drawPoint);
this.ClipFrame();
this.SetLineWidth();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1]
this.CalculatePointInfo(drawPoint);
if (this.Status==10) //绘制完成
{
this.DrawEx();
}
else //绘制中只画连线
{
for(var i=1;i<drawPoint.length;++i)
{
this.DrawLine(drawPoint[i-1],drawPoint[i]);
}
}
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
//计算点信息及K线信息
this.CalculatePointInfo=function(drawPoint)
{
if (!this.Frame || !this.Frame.Data) return;
var kPoint=this.PointToKLine(drawPoint);
//3个点
if (this.PointCount==3 && this.PointStatus==2 && this.LastPoint)
{
var pt=new Point();
pt.X=this.LastPoint.X;
pt.Y=this.LastPoint.Y;
drawPoint[2]=pt;
}
var data=this.Frame.Data;
for(var i in kPoint)
{
var item=kPoint[i];
var pt=drawPoint[i];
var kItem=data.Data[item.XValue];
var obj={ KItem: kItem, Data:item, Point:{ X:pt.X, Y:pt.Y } };
this.PointInfo.push(obj);
}
this.CalculateYPoint();
JSConsole.Chart.Log('[ChartDrawTwoPointDemo::CalculateLines] kPoint', this.PointInfo);
}
//计算需要调整的Y轴坐标
this.CalculateYPoint=function()
{
var ptStart=this.PointInfo[0];
var yStart=this.Frame.GetYFromData(ptStart.KItem.Low,false);
ptStart.Point.Y2=yStart;
var ptEnd=this.PointInfo[1];
var yEnd=this.Frame.GetYFromData(ptEnd.KItem.High,false);
ptEnd.Point.Y2=yEnd;
}
this.DrawEx=function()
{
//起始点 结束点信息
var startInfo=this.PointInfo[0];
var endInfo=this.PointInfo[1];
//K线边框信息
var chartBorder=this.Frame.ChartBorder;
var frameRight=chartBorder.GetRight(); //最右边
var ptStart={X:startInfo.Point.X, Y:startInfo.Point.Y2 };
var ptEnd={X:endInfo.Point.X, Y:endInfo.Point.Y2 };
this.DrawLine(ptStart,ptEnd);
this.LinePoint.push({Start:ptStart, End:ptEnd});
this.Canvas.setLineDash([5,5]);
//this.Canvas.lineWidth=2;
var topPrice=endInfo.KItem.YClose*0.09+endInfo.KItem.High; //结束点最高价+涨幅6% 画竖线
var y=this.Frame.GetYFromData(topPrice,false);
this.DrawLine({X:this.ToFixedPoint(ptEnd.X), Y:ptEnd.Y}, {X:this.ToFixedPoint(ptEnd.X), Y:y});
this.Canvas.textAlign="right";
this.Canvas.textBaseline = 'center';
this.Canvas.fillStyle='rgb(33,45,100)';
for(var i=3;i>0;--i)
{
var price=endInfo.KItem.YClose*(0.03*i)+endInfo.KItem.High; //%2涨幅一档画线
var y=this.Frame.GetYFromData(price,false);
y=this.ToFixedPoint(y);
//线段
this.DrawLine({X:ptEnd.X, Y:y}, {X:ptEnd.X+100, Y:y});
//文字
this.Canvas.fillText(price.toFixed(2), ptEnd.X-5, y);
}
this.Canvas.setLineDash([]);
}
//防止竖线或横线模糊调整坐标
this.ToFixedPoint=function(value,width)
{
if (!IFrameSplitOperator.IsNumber(width)) width=this.LineWidth;
return ToFixedPoint2(width, value)
}
}
function ChartDrawThreePointDemo()
{
this.newMethod=ChartDrawTwoPointDemo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawThreePointDemo';
this.PointCount=3;
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
//计算需要调整的Y轴坐标
this.CalculateYPoint=function()
{
var y;
for(var i in this.PointInfo)
{
var item=this.PointInfo[i];
if (i==0 || i==2) y=this.Frame.GetYFromData(item.KItem.Low,false);
else y=this.Frame.GetYFromData(item.KItem.High,false);
item.Point.Y2=y;
}
}
this.DrawEx=function()
{
//起始点 结束点信息
var startInfo=this.PointInfo[0];
var secondInfo=this.PointInfo[1];
var endInfo=this.PointInfo[2];
//K线边框信息
var chartBorder=this.Frame.ChartBorder;
var frameRight=chartBorder.GetRight(); //右边
var frameLeft=chartBorder.GetLeft(); //左边
var ptStart={ X:startInfo.Point.X, Y:startInfo.Point.Y2 };
var ptSecond={ X:secondInfo.Point.X, Y:secondInfo.Point.Y2};
var ptEnd={ X:endInfo.Point.X, Y:endInfo.Point.Y2 };
this.DrawLine(ptStart,ptSecond);
this.DrawLine(ptSecond,ptEnd);
this.LinePoint.push({Start:ptStart, End:ptSecond});
this.LinePoint.push({Start:ptSecond, End:ptEnd});
this.Canvas.setLineDash([5,5]);
//this.Canvas.lineWidth=2;
var topPrice=endInfo.KItem.YClose*0.09+endInfo.KItem.High; //结束点最高价+涨幅6% 画竖线
var y=this.Frame.GetYFromData(topPrice,false);
this.DrawLine({X:this.ToFixedPoint(ptEnd.X), Y:ptEnd.Y}, {X:this.ToFixedPoint(ptEnd.X), Y:y});
this.Canvas.textAlign="right";
this.Canvas.textBaseline = 'center';
this.Canvas.fillStyle='rgb(33,45,100)';
for(var i=3;i>0;--i)
{
var price=endInfo.KItem.YClose*(0.03*i)+endInfo.KItem.High; //%2涨幅一档画线
var y=this.Frame.GetYFromData(price,false);
y=this.ToFixedPoint(y);
//线段
this.DrawLine({X:ptEnd.X, Y:y}, {X:ptEnd.X+100, Y:y});
//文字
this.Canvas.fillText(price.toFixed(2), ptEnd.X-5, y);
}
this.Canvas.setLineDash([]);
}
}
//画图工具-水平线段
function ChartDrawHLineSegment()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawHLineSegment';
this.PointCount=2;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.ChartBorder;
this.PointToValue_Backup=this.PointToValue;
this.PointToValue=function()
{
//拖拽完成 把点移动到线段头尾
if (this.Frame.IsHScreen)
{
this.Point[1].X=this.Point[0].X;
}
else
{
this.Point[1].Y=this.Point[0].Y;
}
this.PointToValue_Backup();
}
this.GetXYCoordinate=function()
{
if (this.IsFrameMinSize()) return null;
var drawPoint=this.CalculateDrawPoint({ IsCheckX:false, IsCheckY:true });
return this.PointRange(drawPoint);
}
this.Draw=function()
{
if (!this.Frame) return;
this.IsHScreen=this.Frame.IsHScreen;
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true} );
if (!drawPoint || drawPoint.length!=2) return;
this.ClipFrame();
this.ChartBorder=this.Frame.ChartBorder;
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
if (this.Status==10) //0=开始画 1=完成第1个点 2=完成第2个点 3=完成第3个点 10=完成 20=移动)
{
this.DrawLine(ptStart,ptEnd,false);
}
else
{
//var kPoint=this.PointToKLine([ptStart,ptEnd]);
this.DrawVerticalLine(ptStart,ptEnd);
}
this.RestoreLineWidth();
var line={ Start:ptStart, End:ptEnd };
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawVerticalLine=function(ptStart, ptEnd)
{
var data=this.Frame.Data;
if (this.IsHScreen)
{
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var xValue=Math.round(this.Frame.GetXData(ptStart.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xValue=Math.round(this.Frame.GetXData(ptEnd.Y,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var yEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
this.Canvas.beginPath();
this.Canvas.moveTo(left,yStart);
this.Canvas.lineTo(right,yStart);
this.Canvas.moveTo(left,yEnd);
this.Canvas.lineTo(right,yEnd);
this.Canvas.stroke();
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,yStart);
this.Canvas.lineTo(ptStart.X,yEnd);
this.Canvas.stroke();
}
else
{
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var xValue=Math.round(this.Frame.GetXData(ptStart.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
xValue=Math.round(this.Frame.GetXData(ptEnd.X,false))+data.DataOffset;
if (xValue<0) xValue=0;
else if (xValue>=data.Data.length) xValue=data.Data.length-1;
var xEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
this.Canvas.beginPath();
this.Canvas.moveTo(xStart,top);
this.Canvas.lineTo(xStart,bottom);
this.Canvas.moveTo(xEnd,top);
this.Canvas.lineTo(xEnd,bottom);
this.Canvas.stroke();
this.Canvas.beginPath();
this.Canvas.moveTo(xStart,ptStart.Y);
this.Canvas.lineTo(xEnd,ptStart.Y);
this.Canvas.stroke();
}
}
}
//画图工具-volume profile fixed range
function ChartDrawVolProfile()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawVolProfile';
this.PointCount=2;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.ChartBorder;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.IsShowText=true; //是否显示成交量数据
this.VolType=0; //0=up|down bar 1=total bar
this.BarPosition=0; //柱子方向 0=左边 1=右边
this.VolFont;
this.VAVol=60; //Value area volume
this.BarWidthRate=0.3;
this.Data;
this.MaxVol;
this.MaxVolPrice;
this.DataStatus=0; //0=请求总 1=完成
this.BGColor=g_JSChartResource.ChartDrawVolProfile.BGColor;
this.BorderColor=g_JSChartResource.ChartDrawVolProfile.BorderColor;
this.VolLineColor=g_JSChartResource.ChartDrawVolProfile.VolLineColor;
this.TextConfig=
{
Color:g_JSChartResource.ChartDrawVolProfile.Text.Color,
Family:g_JSChartResource.ChartDrawVolProfile.Text.Family,
FontMaxSize:g_JSChartResource.ChartDrawVolProfile.Text.FontMaxSize,
FontMinSize:g_JSChartResource.ChartDrawVolProfile.Text.FontMinSize,
Color:g_JSChartResource.ChartDrawVolProfile.Text.Color,
}
this.BarColor=
[
g_JSChartResource.ChartDrawVolProfile.UpVolColor,
g_JSChartResource.ChartDrawVolProfile.DownVolColor,
g_JSChartResource.ChartDrawVolProfile.AreaUpColor,
g_JSChartResource.ChartDrawVolProfile.AreaDonwColor
]
this.Super_SetOption=this.SetOption; //父类函数
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.BGColor) this.BGColor=option.BGColor;
if (option.BorderColor) this.BGColor=option.BorderColor;
if (option.VolLineColor) this.BGColor=option.VolLineColor;
if (option.UpVolColor) this.BarColor[0]=option.UpVolColor;
if (option.DownVolColor) this.BarColor[1]=option.DownVolColor;
if (option.AreaUpColor) this.BarColor[2]=option.AreaUpColor;
if (option.AreaDonwColor) this.BarColor[3]=option.AreaDonwColor;
if (IFrameSplitOperator.IsNumber(option.BarWidthRate)) this.BarWidthRate=option.BarWidthRate;
if (IFrameSplitOperator.IsBool(option.IsShowText)) this.IsShowText=option.IsShowText;
if (IFrameSplitOperator.IsNumber(option.VolType)) this.VolType=option.VolType;
if (IFrameSplitOperator.IsNumber(option.BarPosition)) this.BarPosition=option.BarPosition;
if (IFrameSplitOperator.IsNumber(option.VAVol)) this.VAVol=option.VAVol;
}
}
this.OnFinish=function()
{
this.RequestVolumeProfileData();
}
this.OnMoveFinish=function()
{
this.RequestVolumeProfileData();
}
this.IsDrawMain=function() //选中绘制在动态绘图上, 没有选中绘制在背景上
{
if (!this.GetActiveDrawPicture) return true;
var active=this.GetActiveDrawPicture();
if (active.Select.Guid==this.Guid) return false;
return true;
}
this.RequestVolumeProfileData=function()
{
//请求数据
var start=this.Value[0], end=this.Value[1];
if (start.XValue>end.XValue)
{
start=this.Value[1];
end=this.Value[0];
}
var option={ Start:{ Date:start.DateTime.Date, DataIndex:start.XValue }, End:{ Date:end.DateTime.Date, DataIndex:end.XValue }, Chart:this };
if (IFrameSplitOperator.IsNumber(start.DateTime.Time)) option.Start.Time=start.DateTime.Time;
if (IFrameSplitOperator.IsNumber(end.DateTime.Time)) option.End.Time=end.DateTime.Time;
option.ValueAreaVol=this.VAVol;
this.DataStatus=0
if (this.HQChart && this.HQChart.RequestVolumeProfileData)
{
this.HQChart.RequestVolumeProfileData(option);
}
}
this.OnRecvVolumeProfileData=function(data)
{
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
var maxVol=0,vol=0;
var maxVolPrice=null;
for(var i=0, j=0;i<data.Data.length;++i)
{
var item=data.Data[i];
vol=0;
for(j=0; j<item.Vol.length;++j)
{
var volItem=item.Vol[j];
if (IFrameSplitOperator.IsNumber(volItem.Value)) vol+=volItem.Value;
}
if (maxVol<vol)
{
maxVol=vol;
maxVolPrice=item.Price;
}
}
this.MaxVolPrice=maxVolPrice;
this.MaxVol=maxVol;
if (this.MaxVolPrice<=0 || this.MaxVol<=0) return;
if (!IFrameSplitOperator.IsNumber(data.MaxPrice) || !IFrameSplitOperator.IsNumber(data.MinPrice)) return;
var yHigh=this.Frame.GetYFromData(data.MaxPrice,false);
var yLow=this.Frame.GetYFromData(data.MinPrice,false);
this.Point[0].Y=yHigh;
this.Point[1].Y=yLow;
this.PointToValue();
this.Data=data;
this.DataStatus=1;
}
this.Draw=function()
{
this.VolFont=null;
if (!this.IsDrawMain()) this.MainDraw();
if (this.IsFrameMinSize()) return;
if (this.Frame) this.ChartBorder=this.Frame.ChartBorder;
var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true} );
if (!drawPoint || drawPoint.length!=2) return;
this.ClipFrame();
this.SetLineWidth();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
//0=开始画 1=完成第1个点 2=完成第2个点 3=完成第3个点 10=完成 20=移动)
if (this.Status==10)
{
if (this.DataStatus==0) this.DrawLineBorder(ptStart,ptEnd);
}
else
{
this.DrawLineBorder(ptStart,ptEnd);
}
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.MainDraw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (this.DataStatus!=1) return;
if (this.Status!=10) return;
this.ClipFrame();
var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true} );
this.DrawVolBar();
this.Canvas.restore();
}
this.DrawLineBorder=function(ptStart, ptEnd)
{
this.Canvas.strokeStyle=this.LineColor;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X, ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.moveTo(ptStart.X,top);
this.Canvas.lineTo(ptStart.X,bottom);
this.Canvas.moveTo(ptEnd.X,top);
this.Canvas.lineTo(ptEnd.X,bottom);
this.Canvas.stroke();
}
this.DrawVolBar=function()
{
var start=this.Value[0], end=this.Value[1];
if (start.XValue>end.XValue)
{
start=this.Value[1];
end=this.Value[0];
}
var dataOffset=this.GetKDataOffset();
var cellHeight=this.GetPriceYOffset(this.Data.PriceOffset);
var left=this.Frame.GetXFromIndex(start.XValue-dataOffset,false);
var right=this.Frame.GetXFromIndex(end.XValue-dataOffset,false);
var top=this.Frame.GetYFromData(this.Data.MaxPrice)-cellHeight/2;
var bottom=this.Frame.GetYFromData(this.Data.MinPrice)+cellHeight/2;
var width=right-left;
var height=bottom-top;
var maxBarWidth=width*this.BarWidthRate;
this.Canvas.fillStyle=this.BGColor;
//JSConsole.Chart.Log('[ChartDrawVolProfile::DrawVolBar] BGColor ', this.BGColor);
this.Canvas.fillRect(left,top,width,height); //背景
if (this.MaxVolPrice>=this.Frame.HorizontalMin&& this.MaxVolPrice<=this.Frame.HorizontalMax)
{
var lineWidth=2;
var yLine=ToFixedPoint2(lineWidth,this.Frame.GetYFromData(this.MaxVolPrice,false));
this.Canvas.lineWidth=lineWidth;
this.Canvas.strokeStyle=this.VolLineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,yLine);
this.Canvas.lineTo(right,yLine);
this.Canvas.stroke();
var linePoint= { Start:{X:left,Y:yLine}, End:{X:right,Y:yLine} };
this.LinePoint.push(linePoint);
}
if (this.IsShowText)
{
this.VolFont=this.GetDynamicVolTextFont(cellHeight, maxBarWidth);
if (this.VolFont) this.Canvas.font=this.VolFont;
}
//this.Canvas.lineWidth=1;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (item.Price<this.Frame.HorizontalMin || item.Price>this.Frame.HorizontalMax) continue;
this.DrawVolBarItem(item, left, right, maxBarWidth, cellHeight);
}
}
this.DrawVolBarItem=function(item, left, right, maxBarWidth, cellHeight)
{
var barLeft=left;
var barRight=right;
var barTop=this.Frame.GetYFromData(item.Price)-cellHeight/2;
var barHeight=cellHeight-1;
if (barHeight<1) barHeight=1;
if (this.VolType==1)
{
if (!item.TotalVol) return;
if (!IFrameSplitOperator.IsNumber(item.TotalVol.Value)) return;
var barWidth=item.TotalVol.Value*maxBarWidth/this.MaxVol;
var color;
if (IFrameSplitOperator.IsNumber(item.TotalVol.ColorID)) color=this.BarColor[item.TotalVol.ColorID];
else if (item.TotalVol.Color) color=item.TotalVol.Color;
this.Canvas.fillStyle=color;
if (this.BarPosition==1)
{
this.Canvas.fillRect(barRight,ToFixedRect(barTop),-barWidth,ToFixedRect(barHeight));
}
else
{
this.Canvas.fillRect(barLeft,ToFixedRect(barTop),barWidth,ToFixedRect(barHeight));
}
if (this.IsShowText && this.VolFont)
{
var text=IFrameSplitOperator.FormatVolString(item.TotalVol.Value, this.HQChart.LanguageID);
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle=this.TextConfig.Color;
if (this.BarPosition==1)
{
this.Canvas.textAlign = 'right';
this.Canvas.fillText(text,right-5,barTop+cellHeight/2);
}
else
{
this.Canvas.textAlign = 'left';
this.Canvas.fillText(text,left+5,barTop+cellHeight/2);
}
}
}
else
{
var text="";
for(var i=0;i<item.Vol.length;++i)
{
var volItem=item.Vol[i];
if (!IFrameSplitOperator.IsNumber(volItem.Value)) continue;
var color;
if (IFrameSplitOperator.IsNumber(volItem.ColorID)) color=this.BarColor[volItem.ColorID];
else if (volItem.Color) color=volItem.Color;
if (!color) continue;
var barWidth=volItem.Value*maxBarWidth/this.MaxVol;
this.Canvas.fillStyle=color;
if (this.BarPosition==1)
{
this.Canvas.fillRect(barRight,ToFixedRect(barTop),-barWidth,ToFixedRect(barHeight));
barRight-=barWidth;
}
else
{
this.Canvas.fillRect(barLeft,ToFixedRect(barTop),barWidth,ToFixedRect(barHeight));
barLeft+=barWidth;
}
var volText=IFrameSplitOperator.FormatVolString(volItem.Value, this.HQChart.LanguageID);
if (text.length>0) text+="x";
text+=volText;
}
if (this.IsShowText && this.VolFont)
{
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle=this.TextConfig.Color;
if (this.BarPosition==1)
{
this.Canvas.textAlign = 'right';
this.Canvas.fillText(text,right-5,barTop+cellHeight/2);
}
else
{
this.Canvas.textAlign = 'left';
this.Canvas.fillText(text,left+5,barTop+cellHeight/2);
}
}
}
}
this.GetKDataOffset=function()
{
var kData=this.HQChart.ChartPaint[0].Data;
return kData.DataOffset;
}
this.GetPriceYOffset=function(value)
{
var frame=this.Frame
var y=frame.ChartBorder.GetHeightEx()*(value)/(frame.HorizontalMax-frame.HorizontalMin);
return y;
}
this.GetDynamicVolTextFont=function(cellHeight, width, fontOption)
{
var fontSize=parseInt(cellHeight)-2;
if (cellHeight<5) fontSize=parseInt(cellHeight); //高度太小了就不要上下间距了
if (fontSize>this.TextConfig.FontMaxSize) fontSize=this.TextConfig.FontMaxSize;
else if (fontSize<=0) fontSize=1;
if (fontSize<this.TextConfig.FontMinSize) return null;
var font=this.FormatFontString(fontSize, this.TextConfig.Family, fontOption);
return font;
}
this.FormatFontString=function(fontSize, family, option)
{
var font;
if (!option)
{
font=`${fontSize}px ${family}`;
}
else
{
if (option.Weight) font=`${option.Weight} ${fontSize}px ${family}`;
}
return font;
}
}
//画图工具 tradingview
function ChartDrawNote()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawNote';
this.PointCount=1;
//矢量图片
this.Text=g_JSChartResource.ChartDrawNote.Text;
this.FontOption={ Family:g_JSChartResource.ChartDrawNote.FontOption.Family, Size:g_JSChartResource.ChartDrawNote.FontOption.Size }; //Weight(bold 粗体), Style(italic)
this.AryNoteText=[ {Text:"输入内容 ......"}];
/*
this.AryNoteText=
[
{Text:" 北京时间6月5日,U20世界杯1/4决赛全部结束,韩国创造历史,将在半决赛对阵意大利,另一场半决赛则是以色列对阵乌拉圭", } ,
{Text:"", },
{Text:" 韩国是上届U20世界杯亚军,今年他们经过加时赛1-0力克淘汰阿根廷的尼日利亚,历史上第三次进入四强,亚洲球队最多,也是第一支连续两届晋级四强的球队。", }
];
*/
this.NoteFontOption=
{
Family:g_JSChartResource.ChartDrawNote.NoteFontOption.Family,
Size:g_JSChartResource.ChartDrawNote.NoteFontOption.Size,
Weight:g_JSChartResource.ChartDrawNote.NoteFontOption.Weight,
Style:g_JSChartResource.ChartDrawNote.NoteFontOption.Style
}
this.NoteWidth=g_JSChartResource.ChartDrawNote.NoteWidth;
this.NoteMargin=
{
Left:g_JSChartResource.ChartDrawNote.NoteMargin.Left,
Top:g_JSChartResource.ChartDrawNote.NoteMargin.Top,
Bottom:g_JSChartResource.ChartDrawNote.NoteMargin.Bottom,
Right:g_JSChartResource.ChartDrawNote.NoteMargin.Right
};
this.NoteBGColor=g_JSChartResource.ChartDrawNote.NoteBGColor;
this.NoteTextColor=g_JSChartResource.ChartDrawNote.NoteTextColor;
this.NoteBorderColor=g_JSChartResource.ChartDrawNote.NoteBorderColor;
this.LineSpace=g_JSChartResource.ChartDrawNote.LineSpace; //行间距
this.ArrowSize=g_JSChartResource.ChartDrawNote.ArrowSize;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=false;
//内部变量
this.PtButtom;
this.PtTop;
this.TextRect=null; //文字区域
this.PtCenter;
this.SetOption_Backup=this.SetOption;
this.SetOption=function(option)
{
this.SetOption_Backup(option);
if (!option) return;
if (option.Text) this.Text=option.Text;
if (option.FontOption) this.SetFont(this.FontOption, option.FontOption);
if (option.NoteFontOption) this.SetFont(this.NoteFontOption, option.NoteFontOption);
if (IFrameSplitOperator.IsNumber(option.NoteWidth)) this.NoteWidth=option.NoteWidth;
if (option.NoteMargin)
{
var item=option.NoteMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.NoteMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Top)) this.NoteMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.NoteMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Right)) this.NoteMargin.Right=item.Right;
}
if (option.NoteBGColor) this.NoteBGColor=option.NoteBGColor;
if (option.NoteTextColor) this.NoteTextColor=option.NoteTextColor;
if (option.NoteBorderColor) this.NoteBorderColor=option.NoteBorderColor;
if (IFrameSplitOperator.IsNumber(option.LineSpace)) this.LineSpace=option.LineSpace;
if (IFrameSplitOperator.IsNumber(option.ArrowSize)) this.ArrowSize=option.ArrowSize;
if (IFrameSplitOperator.IsNonEmptyArray(option.AryNoteText)) this.AryNoteText=this.CloneArrayText(option.AryNoteText);
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
storageData.Value=[];
if (this.Value && this.Value[0])
{
var item=this.Value[0];
storageData.Value.push({ XValue:item.XValue, YValue:item.YValue, DateTime:item.DateTime });
}
storageData.NoteFont=this.NoteFont;
storageData.NoteWidth=this.NoteWidth;
storageData.NoteBGColor=this.NoteBGColor;
storageData.NoteTextColor=this.NoteTextColor;
storageData.NoteBorderColor=this.NoteBorderColor;
storageData.LineSpace=this.LineSpace;
storageData.ArrowSize=this.ArrowSize;
storageData.NoteMargin={ Left:this.NoteMargin.Left, Top:this.NoteMargin.Right, Bottom:this.NoteMargin.Bottom, Right:this.NoteMargin.Right };
storageData.AryNoteText=this.CloneArrayText(this.AryNoteText);
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.NoteFont) this.NoteFont=storageData.NoteFont;
if (IFrameSplitOperator.IsNumber(storageData.NoteWidth)) this.NoteWidth=storageData.NoteWidth;
if (storageData.NoteMargin)
{
var item=storageData.NoteMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.NoteMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Top)) this.NoteMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.NoteMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Right)) this.NoteMargin.Right=item.Right;
}
if (storageData.NoteBGColor) this.NoteBGColor=storageData.NoteBGColor;
if (storageData.NoteTextColor) this.NoteTextColor=storageData.NoteTextColor;
this.NoteBorderColor=storageData.NoteBorderColor;
if (IFrameSplitOperator.IsNumber(storageData.LineSpace)) this.LineSpace=storageData.LineSpace;
if (IFrameSplitOperator.IsNumber(storageData.ArrowSize)) this.ArrowSize=storageData.ArrowSize;
this.AryNoteText=this.CloneArrayText(storageData.AryNoteText);
}
this.Draw=function()
{
this.PtButtom=null;
this.PtTop=null;
this.TextRect=null;
this.PtCenter=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=1) return;
var font=this.GetTextFont();
if (!font) return;
this.ClipFrame();
var isHScreen=this.Frame.IsHScreen;
var pixel=GetDevicePixelRatio();
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.font=font;
if (isHScreen)
{
this.Canvas.translate(drawPoint[0].X, drawPoint[0].Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.Text,0,0);
this.PtButtom={ X:drawPoint[0].X, Y:drawPoint[0].Y+this.FontOption.Size*pixel/2+2 };
this.PtTop={ X:drawPoint[0].X, Y:drawPoint[0].Y-this.FontOption.Size*pixel/2-2};
this.PtCenter=drawPoint[0];
var ptSelected={X:drawPoint[0].X-this.FontOption.Size*pixel/2-2, Y:drawPoint[0].Y};
}
else
{
this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y);
this.PtButtom={ X:drawPoint[0].X, Y:drawPoint[0].Y+this.FontOption.Size*pixel/2+2 };
this.PtTop={ X:drawPoint[0].X, Y:drawPoint[0].Y-this.FontOption.Size*pixel/2-2 };
var ptSelected={X:this.PtButtom.X, Y:this.PtButtom.Y};
}
var textWidth=this.Canvas.measureText(this.Text).width;
this.TextRect={};
this.TextRect.Left=drawPoint[0].X-textWidth/2;
this.TextRect.Top=drawPoint[0].Y-(this.FontOption.Size*pixel)/2;
this.TextRect.Width=textWidth;
this.TextRect.Height=this.FontOption.Size*pixel;
if (this.IsShowNoteText())
this.DrawText();
//this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height);
this.Canvas.restore();
this.DrawPoint([ptSelected]); //画点
}
this.DrawText=function()
{
this.Canvas.font=this.GetFontString(this.NoteFontOption);
var height=0;
var lineHeight=this.Canvas.measureText("擎").width;
var border=this.Frame.GetBorder();
var pixel=GetDevicePixelRatio();
var isHScreen=this.Frame.IsHScreen;
var width=this.NoteWidth;
var aryText=[];
if (IFrameSplitOperator.IsNonEmptyArray(this.AryNoteText))
{
for(var i=0; i<this.AryNoteText.length; ++i)
{
var item=this.AryNoteText[i];
if (!item) continue;
if (height>0) height+=this.LineSpace;
if (item.Text)
{
var value=this.GetMultiLineText(item.Text, width);
if (value && IFrameSplitOperator.IsNonEmptyArray(value.AryText))
{
for(var j=0; j<value.AryText.length; ++j)
{
if (j>0) height+=this.LineSpace;
var textItem=value.AryText[j];
aryText.push(textItem);
height+=lineHeight;
}
}
}
else
{
aryText.push({Text:""});
height+=lineHeight;
}
}
}
else
{
height=lineHeight;
}
var rtBG={ Width:width+this.NoteMargin.Left+this.NoteMargin.Right, Height:height+this.NoteMargin.Top+this.NoteMargin.Bottom, ArrowType:0 };
if (isHScreen)
{
rtBG.Left=this.PtTop.X-rtBG.Width/2-this.PtCenter.X;
rtBG.Top=this.PtTop.Y-rtBG.Height-this.ArrowSize-this.PtCenter.Y;
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Arrow={ X:this.PtTop.X-this.PtCenter.X, Y:this.PtTop.Y-this.PtCenter.Y}; //Type 0=向下箭头 1=向上箭头
if (this.PtCenter.X+height+this.FontOption.Size*pixel/2+2+this.ArrowSize>border.RightEx)
{
rtBG.Top=this.PtButtom.Y+this.ArrowSize+this.PointRadius*pixel-this.PtCenter.Y;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Arrow.X=this.PtButtom.X-this.PtCenter.X;
rtBG.Arrow.Y=this.PtButtom.Y-this.PtCenter.Y;
rtBG.ArrowType=1;
}
}
else
{
rtBG.Left=this.PtTop.X-rtBG.Width/2;
rtBG.Top=this.PtTop.Y-rtBG.Height-this.ArrowSize;
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Arrow={ X:this.PtTop.X, Y:this.PtTop.Y}; //Type 0=向下箭头 1=向上箭头
if (rtBG.Left<border.Left)
{
rtBG.Left=border.Left;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else if (rtBG.Right>border.Right)
{
rtBG.Right=border.Right;
rtBG.Left=rtBG.Right-rtBG.Width;
}
if (rtBG.Top<border.TopEx)
{
rtBG.Top=this.PtButtom.Y+this.ArrowSize+this.PointRadius*pixel;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Arrow.X=this.PtButtom.X;
rtBG.Arrow.Y=this.PtButtom.Y;
rtBG.ArrowType=1;
}
}
this.DrawNoteBG(rtBG);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.fillStyle=this.NoteTextColor;
var xText=rtBG.Left+this.NoteMargin.Left;
var yText=rtBG.Top+this.NoteMargin.Top;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
if (!item) continue;
if (item.Text)
{
this.Canvas.fillText(item.Text,xText,yText);
yText+=lineHeight;
}
else
{
yText+=lineHeight;
}
yText+=this.LineSpace;
}
}
this.DrawNoteBG=function(rtBG)
{
this.Canvas.fillStyle=this.NoteBGColor;
if (rtBG.ArrowType==0 || rtBG.ArrowType==1)
{
var path=new Path2D();
if (rtBG.ArrowType==0)
{
path.moveTo(rtBG.Left, rtBG.Bottom);
path.lineTo(rtBG.Left, rtBG.Top);
path.lineTo(rtBG.Right, rtBG.Top);
path.lineTo(rtBG.Right,rtBG.Bottom);
var x=rtBG.Arrow.X+this.ArrowSize*0.6;
path.lineTo(x,rtBG.Bottom);
path.lineTo(rtBG.Arrow.X, rtBG.Arrow.Y);
var x=rtBG.Arrow.X-this.ArrowSize*0.6;
path.lineTo(x,rtBG.Bottom);
}
else
{
path.moveTo(rtBG.Left, rtBG.Top);
path.lineTo(rtBG.Left, rtBG.Bottom);
path.lineTo(rtBG.Right, rtBG.Bottom);
path.lineTo(rtBG.Right, rtBG.Top);
var x=rtBG.Arrow.X+this.ArrowSize*0.6;
path.lineTo(x,rtBG.Top);
path.lineTo(rtBG.Arrow.X, rtBG.Arrow.Y);
var x=rtBG.Arrow.X-this.ArrowSize*0.6;
path.lineTo(x,rtBG.Top);
}
path.closePath();
this.Canvas.fill(path);
if (this.NoteBorderColor)
{
this.Canvas.strokeStyle=this.NoteBorderColor;
this.Canvas.stroke(path);
}
}
else
{
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
}
this.IsShowNoteText=function()
{
if (this.GetActiveDrawPicture)
{
var active=this.GetActiveDrawPicture();
if (active.Move.Guid!=this.Guid && active.Select.Guid!=this.Guid && active.MoveOn.Guid!=this.Guid)
return false;
//if (active.Select.Guid!=this.Guid && active.MoveOn.Guid==this.Guid)
// return true;
return true;
}
return false;
}
//根据设置动态生成字体
this.GetTextFont=function()
{
if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return null;
var font='';
if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px ';
font+=this.FontOption.Family;
return font;
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
var data=this.Frame.Data;
if (!data) return -1;
if (!this.TextRect) return -1;
var offset=0;
if (this.Option && this.Option.Zoom>=1)
{
offset=this.Option.Zoom*GetDevicePixelRatio();
}
var rect={ Left:this.TextRect.Left-offset, Top:this.TextRect.Top-offset, Width:this.TextRect.Width+offset*2, Height:this.TextRect.Height+offset*2 };
rect.Right=rect.Left+rect.Width;
rect.Bottom=rect.Top+rect.Height;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
return 100;
return -1;
}
this.GetCursorType=function(ptIndex)
{
if (ptIndex==100) return "pointer";
return null;
}
}
function ChartDrawAnchoredText()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawAnchoredText';
this.PointCount=1;
this.AryText=[ {Text:"输入内容"} ];
this.TextColor=g_JSChartResource.ChartDrawAnchoredText.TextColor;
this.FontOption=
{
Family:g_JSChartResource.ChartDrawAnchoredText.FontOption.Family,
Size:g_JSChartResource.ChartDrawAnchoredText.FontOption.Size,
Weight:g_JSChartResource.ChartDrawAnchoredText.FontOption.Weight,
Style:g_JSChartResource.ChartDrawAnchoredText.FontOption.Style
};
this.TextMaxWidth=g_JSChartResource.ChartDrawAnchoredText.TextMaxWidth; //文本最大宽度
this.LineSpace=g_JSChartResource.ChartDrawAnchoredText.LineSpace;
this.BGColor=g_JSChartResource.ChartDrawAnchoredText.BGColor;
this.BorderColor=g_JSChartResource.ChartDrawAnchoredText.BorderColor;
this.TextMargin=
{
Left:g_JSChartResource.ChartDrawAnchoredText.TextMargin.Left,
Top:g_JSChartResource.ChartDrawAnchoredText.TextMargin.Top,
Bottom:g_JSChartResource.ChartDrawAnchoredText.TextMargin.Bottom,
Right:g_JSChartResource.ChartDrawAnchoredText.TextMargin.Right
};
//内部变量
this.TextRect;
this.SetOption=function(option)
{
if (!option) return;
if (option.TextColor) this.TextColor=option.TextColor;
if (option.Text) this.Text=option.Text;
if (option.FontOption) this.SetFont(this.FontOption, option.FontOption);
if (IFrameSplitOperator.IsNumber(option.TextMaxWidth)) this.TextMaxWidth=option.TextMaxWidth;
if (IFrameSplitOperator.IsNonEmptyArray(option.AryText)) this.AryText=this.CloneArrayText(option.AryText);
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
var item=this.Value[0];
storageData.Value=[ { XValue:item.XValue, YValue:item.YValue } ];
storageData.FontOption={};
this.SetFont(storageData.FontOption, this.FontOption);
storageData.BGColor=this.BGColor;
storageData.TextColor=this.TextColor;
storageData.BorderColor=this.BorderColor;
storageData.LineSpace=this.LineSpace;
storageData.TextMaxWidth=this.TextMaxWidth;
storageData.TextMargin={ Left:this.TextMargin.Left, Top:this.TextMargin.Right, Bottom:this.TextMargin.Bottom, Right:this.TextMargin.Right };
storageData.AryText= this.CloneArrayText(this.AryText);
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.TextMargin)
{
var item=storageData.TextMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.TextMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Top)) this.TextMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.TextMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Right)) this.TextMargin.Right=item.Right;
}
if (storageData.TextColor) this.TextColor=storageData.TextColor;
this.BGColor=storageData.BGColor;
this.BorderColor=storageData.BorderColor;
this.TextMaxWidth=storageData.TextMaxWidth;
if (IFrameSplitOperator.IsNumber(storageData.LineSpace)) this.LineSpace=storageData.LineSpace;
this.AryText = this.CloneArrayText(storageData.AryText);
}
this.Draw=function()
{
this.TextRect=null;
if (this.Status<2) return;
if(this.Point.length!=1 || !this.Frame) return;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint();
if (!drawPoint || drawPoint.length!=1) return;
this.ClipFrame();
this.DrawMultiLineText(drawPoint[0]);
this.Canvas.restore();
}
this.ValueToPoint=function()
{
if (!this.Frame) return false;
var item=this.Value[0];
var pt=this.XYValueToPoint(item.XValue, item.YValue);
this.Point=[pt];
}
this.PointToValue=function()
{
if (!this.Frame) return false;
var border=this.Frame.GetBorder();
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
var left=border.LeftEx;
var top=border.Top;
var width=border.RightEx-left;
var height=border.Bottom-top;
var pt=this.Point[0];
var yValue=(pt.X-left)/width;
var xValue=(pt.Y-top)/height;
this.Value[0]={ XValue:xValue, YValue:yValue };
}
else
{
var left=border.Left;
var top=border.TopEx;
var width=border.Right-left;
var height=border.BottomEx-top;
var pt=this.Point[0];
var xValue=(pt.X-left)/width;
var yValue=(pt.Y-top)/height;
this.Value[0]={ XValue:xValue, YValue:yValue };
}
}
this.XYValueToPoint=function(xValue, yValue)
{
if (!this.Frame) return null;
var isHScreen=this.Frame.IsHScreen;
var border=this.Frame.GetBorder();
if (isHScreen)
{
var left=border.LeftEx;
var top=border.Top;
var width=border.RightEx-left;
var height=border.Bottom-top;
var x=(yValue*width)+left;
var y=(xValue*height)+top;
return {X:x, Y:y};
}
else
{
var left=border.Left;
var top=border.TopEx;
var width=border.Right-left;
var height=border.BottomEx-top;
var x=(xValue*width)+left;
var y=(yValue*height)+top;
return {X:x, Y:y};
}
}
this.CalculateDrawPoint=function(option)
{
if (this.Status<2) return null;
if(this.Point.length!=1 || !this.Frame) return null;
var drawPoint=[];
if (this.Status==10)
{
var item=this.Value[0];
var pt=this.XYValueToPoint(item.XValue, item.YValue);
drawPoint.push(pt);
}
else
{
drawPoint=this.Point;
}
return drawPoint;
}
this.DrawMultiLineText=function(pt)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryText)) return;
var height=0;
this.Canvas.font=this.GetFontString(this.FontOption);
var lineHeight=this.Canvas.measureText("擎").width;
var border=this.Frame.GetBorder();
var pixel=GetDevicePixelRatio();
var isHScreen=this.Frame.IsHScreen;
var ptBottom={X:pt.X, Y:pt.Y};
if (isHScreen)
{
this.Canvas.translate(ptBottom.X, ptBottom.Y);
this.Canvas.rotate(90 * Math.PI / 180);
ptBottom.X=0;
ptBottom.Y=0;
}
var aryText=[];
var maxTextWidth=0;
for(var i=0; i<this.AryText.length; ++i) //计算输出高度和宽度
{
var item=this.AryText[i];
if (!item) continue;
if (height>0) height+=this.LineSpace;
if (this.TextMaxWidth>50 && item.Text) //限制宽度
{
var value=this.GetMultiLineText(item.Text, this.TextMaxWidth);
if (value && IFrameSplitOperator.IsNonEmptyArray(value.AryText))
{
for(var j=0; j<value.AryText.length; ++j)
{
if (j>0) height+=this.LineSpace;
var textItem=value.AryText[j];
aryText.push(textItem);
height+=lineHeight;
}
}
}
else
{
if (item.Text)
{
var textWidth=this.Canvas.measureText(item.Text).width+2;
if (maxTextWidth<textWidth) maxTextWidth=textWidth;
}
aryText.push({ Text:item.Text });
height+=lineHeight;
}
}
if (this.TextMaxWidth>50) maxTextWidth=this.TextMaxWidth;
var rtBG=
{
Left:ptBottom.X, Bottom:ptBottom.Y,
Height:height+this.TextMargin.Top+this.TextMargin.Bottom,
Width:maxTextWidth+this.TextMargin.Left+this.TextMargin.Right
};
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
this.DrawBG(rtBG);
this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
var xText=rtBG.Left+this.TextMargin.Left;
var yText=rtBG.Top+this.TextMargin.Top;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
if (!item) continue;
if (item.Text)
{
this.Canvas.fillText(item.Text,xText,yText);
yText+=lineHeight;
}
else
{
yText+=lineHeight;
}
yText+=this.LineSpace;
}
if (isHScreen)
{
rtBG.Left=pt.X;
rtBG.Top=pt.Y;
rtBG.Width=height+this.TextMargin.Top+this.TextMargin.Bottom;
rtBG.Height=maxTextWidth+this.TextMargin.Left+this.TextMargin.Right;
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
}
this.TextRect=rtBG;
var ptSelected={ X:rtBG.Left+rtBG.Width/2, Y:rtBG.Bottom };
this.DrawPoint([ptSelected]); //画点
}
this.DrawBG=function(rtBG)
{
if (!this.BGColor && !this.BorderColor) return;
var path=new Path2D();
path.rect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill(path);
}
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.stroke(path);
}
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
if (!this.TextRect) return -1;
var rect=this.TextRect;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
return 100;
return -1;
}
this.GetCursorType=function(ptIndex)
{
if (ptIndex==100) return "pointer";
return null;
}
}
function ChartDrawPriceLabel()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPriceLabel';
this.PointCount=1;
this.OnlyMoveXIndex=true;
this.TextColor=g_JSChartResource.ChartDrawPriceLabel.TextColor;
this.FontOption=
{
Family:g_JSChartResource.ChartDrawPriceLabel.FontOption.Family,
Size:g_JSChartResource.ChartDrawPriceLabel.FontOption.Size,
Weight:g_JSChartResource.ChartDrawPriceLabel.FontOption.Weight,
Style:g_JSChartResource.ChartDrawPriceLabel.FontOption.Style
};
this.BGColor=g_JSChartResource.ChartDrawPriceLabel.BGColor;
this.BorderColor=g_JSChartResource.ChartDrawPriceLabel.BorderColor;
this.LabelOffset={ X:10, Y:20 };
this.TextMargin=
{
Left:g_JSChartResource.ChartDrawPriceLabel.TextMargin.Left,
Top:g_JSChartResource.ChartDrawPriceLabel.TextMargin.Top,
Bottom:g_JSChartResource.ChartDrawPriceLabel.TextMargin.Bottom,
Right:g_JSChartResource.ChartDrawPriceLabel.TextMargin.Right
};
//内部变量
this.TextRect;
this.SetOption=function(option)
{
if (!option) return;
if (option.TextColor) this.TextColor=option.TextColor;
if (option.BGColor) this.BGColor=option.BGColor;
if (option.BorderColor) this.BorderColor=option.BorderColor;
if (option.FontOption) this.SetFont(this.FontOption, option.FontOption);
if (option.LabelOffset)
{
var item=option.LabelOffset;
if (IFrameSplitOperator.IsNumber(item.X)) this.LabelOffset.X=item.X;
if (IFrameSplitOperator.IsNumber(item.Y)) this.LabelOffset.Y=item.Y;
}
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
var item=this.Value[0];
storageData.Value=[ { XValue:item.XValue, YValue:item.YValue } ];
storageData.BGColor=this.BGColor;
storageData.TextColor=this.TextColor;
storageData.BorderColor=this.BorderColor;
storageData.TextMargin={ Left:this.TextMargin.Left, Top:this.TextMargin.Right, Bottom:this.TextMargin.Bottom, Right:this.TextMargin.Right };
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.TextMargin)
{
var item=storageData.TextMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.TextMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Top)) this.TextMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.TextMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Right)) this.TextMargin.Right=item.Right;
}
if (storageData.TextColor) this.TextColor=storageData.TextColor;
this.BGColor=storageData.BGColor;
this.BorderColor=storageData.BorderColor;
}
this.Draw=function()
{
this.TextRect=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=1) return;
var pt=drawPoint[0];
this.ClipFrame();
this.DrawPriceLabel(pt);
this.Canvas.restore();
this.DrawPoint([pt]); //画点
}
this.DrawPriceLabel=function(pt)
{
var font=this.GetFontString(this.FontOption);
if (!font) return;
var isHScreen=this.Frame.IsHScreen;
var pixelRatio=GetDevicePixelRatio();
var ptBottom, price;
var yOffset=0;
if (isHScreen)
{
this.Canvas.translate(pt.X, pt.Y);
this.Canvas.rotate(90 * Math.PI / 180);
ptBottom={ X:0, Y:0 };
price=this.Frame.GetYData(pt.X, false);
yOffset=1;
}
else
{
ptBottom={ X:pt.X, Y:pt.Y };
price=this.Frame.GetYData(pt.Y, false);
}
var floatPrecision=2;
if (this.Symbol && this.Frame.Identify==0)
floatPrecision=GetfloatPrecision(this.Symbol);
var text=price.toFixed(floatPrecision);
this.Canvas.font=font;
var left=ptBottom.X+this.LabelOffset.X;
var bottom=ptBottom.Y-this.LabelOffset.Y;
var textHeight=this.Canvas.measureText("擎").width;
var textWidth=this.Canvas.measureText(text).width;
var rtBG={ Left:left, Bottom:bottom, Width:textWidth+this.TextMargin.Left+this.TextMargin.Right, Height:textHeight+this.TextMargin.Top+this.TextMargin.Bottom };
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
this.DrawBG(rtBG, ptBottom);
var xText=rtBG.Left+rtBG.Width/2;
var yText=rtBG.Top+rtBG.Height/2;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,xText,yText+yOffset);
if (isHScreen)
{
this.TextRect=
{
Left:pt.X+this.LabelOffset.Y, Top:pt.Y+this.LabelOffset.X,
Width:textHeight+this.TextMargin.Top+this.TextMargin.Bottom,
Height:textWidth+this.TextMargin.Left+this.TextMargin.Right
}
this.TextRect.Right=this.TextRect.Left+this.TextRect.Width;
this.TextRect.Bottom=this.TextRect.Top+this.TextRect.Height;
}
else
{
this.TextRect=rtBG;
}
}
this.DrawBG=function(rtBG, pt)
{
var pixelRatio=GetDevicePixelRatio();
var path=new Path2D();
path.moveTo(rtBG.Left, rtBG.Bottom);
path.lineTo(rtBG.Left, rtBG.Top);
path.lineTo(rtBG.Right, rtBG.Top);
path.lineTo(rtBG.Right,rtBG.Bottom);
var x=rtBG.Left+15*pixelRatio;
path.lineTo(x,rtBG.Bottom);
path.lineTo(pt.X, pt.Y);
x=rtBG.Left+5*pixelRatio;
path.lineTo(x,rtBG.Bottom);
path.closePath();
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill(path);
}
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.stroke(path);
}
//绘制一个点
if (this.BGColor)
{
this.Canvas.beginPath();
this.Canvas.arc(pt.X,pt.Y,2*pixelRatio,0,360,false);
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill();
}
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
if (!this.TextRect) return -1;
var rect=this.TextRect;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
return 100;
return -1;
}
this.GetCursorType=function(ptIndex)
{
if (ptIndex==100) return "pointer";
return null;
}
}
function ChartDrawPriceNote()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPriceNote';
this.PointCount=2;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.FontOption=
{
Family:g_JSChartResource.ChartDrawPriceNote.FontOption.Family,
Size:g_JSChartResource.ChartDrawPriceNote.FontOption.Size,
Weight:g_JSChartResource.ChartDrawPriceNote.FontOption.Weight,
Style:g_JSChartResource.ChartDrawPriceNote.FontOption.Style
};
this.TextMargin=
{
Left:g_JSChartResource.ChartDrawPriceNote.TextMargin.Left,
Top:g_JSChartResource.ChartDrawPriceNote.TextMargin.Top,
Bottom:g_JSChartResource.ChartDrawPriceNote.TextMargin.Bottom,
Right:g_JSChartResource.ChartDrawPriceNote.TextMargin.Right
};
this.BGColor=g_JSChartResource.ChartDrawPriceNote.BGColor;
this.BorderColor=g_JSChartResource.ChartDrawPriceNote.BorderColor;
this.TextColor=g_JSChartResource.ChartDrawPriceNote.TextColor;
this.BorderRoundRadius=3;
//内部变量
this.TextRect;
this.SetOption=function(option)
{
if (!option) return;
if (option.TextColor) this.TextColor=option.TextColor;
if (option.BGColor) this.BGColor=option.BGColor;
if (option.BorderColor) this.BorderColor=option.BorderColor;
if (option.FontOption) this.SetFont(this.FontOption, option.FontOption);
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
storageData.Value=[];
for(var i=0;i<this.Value.length;++i)
{
var item=this.Value[i];
storageData.Value.push( { XValue:item.XValue, YValue:item.YValue } );
}
storageData.BGColor=this.BGColor;
storageData.TextColor=this.TextColor;
storageData.BorderColor=this.BorderColor;
storageData.TextMargin={ Left:this.TextMargin.Left, Top:this.TextMargin.Right, Bottom:this.TextMargin.Bottom, Right:this.TextMargin.Right };
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.TextMargin)
{
var item=storageData.TextMargin;
if (IFrameSplitOperator.IsNumber(item.Left)) this.TextMargin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Top)) this.TextMargin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.TextMargin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Right)) this.TextMargin.Right=item.Right;
}
if (storageData.TextColor) this.TextColor=storageData.TextColor;
this.BGColor=storageData.BGColor;
this.BorderColor=storageData.BorderColor;
}
this.Draw=function()
{
this.LinePoint=[];
this.TextRect=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.LineWidth=1;
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
this.DrawPriceLabel(ptStart, ptEnd);
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawPriceLabel=function(ptStart, ptEnd)
{
var font=this.GetFontString(this.FontOption);
if (!font) return;
var floatPrecision=2;
if (this.Symbol && this.Frame.Identify==0) floatPrecision=GetfloatPrecision(this.Symbol);
var pixelRatio=GetDevicePixelRatio();
var ptPrice={ X:ptEnd.X, Y:ptEnd.Y };
var price=this.Frame.GetYData(ptStart.Y, false);
var text=price.toFixed(floatPrecision);
var textHeight=this.Canvas.measureText("擎").width;
var textWidth=this.Canvas.measureText(text).width;
var angle=this.CalculateAngle(ptStart.X, ptStart.Y, ptEnd.X, ptEnd.Y);
if ((angle>=0 && angle<=45) || (angle>=315 && angle<=360))
{
var left=ptPrice.X;
var bottom=ptPrice.Y;
var rtBG={ Left:left, Bottom:bottom, Width:textWidth+this.TextMargin.Left+this.TextMargin.Right, Height:textHeight+this.TextMargin.Top+this.TextMargin.Bottom };
rtBG.Bottom=bottom+(rtBG.Height/2);
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else if (angle>45 && angle<=135)
{
var left=ptPrice.X;
var bottom=ptPrice.Y;
var rtBG={ Left:left, Bottom:bottom, Width:textWidth+this.TextMargin.Left+this.TextMargin.Right, Height:textHeight+this.TextMargin.Top+this.TextMargin.Bottom };
rtBG.Left=left-(rtBG.Width/2);
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=rtBG.Left+rtBG.Width;
}
else if (angle>=135 && angle<=225)
{
var left=ptPrice.X;
var bottom=ptPrice.Y;
var rtBG={ Width:textWidth+this.TextMargin.Left+this.TextMargin.Right, Height:textHeight+this.TextMargin.Top+this.TextMargin.Bottom };
rtBG.Bottom=bottom+(rtBG.Height/2);
rtBG.Top=rtBG.Bottom-rtBG.Height;
rtBG.Right=left;
rtBG.Left=rtBG.Right-rtBG.Width;
}
else if (angle>=225 && angle<=315)
{
var left=ptPrice.X;
var top=ptPrice.Y;
var rtBG={ Width:textWidth+this.TextMargin.Left+this.TextMargin.Right, Height:textHeight+this.TextMargin.Top+this.TextMargin.Bottom };
rtBG.Top=top;
rtBG.Bottom=rtBG.Top+rtBG.Height;
rtBG.Left=left-(rtBG.Width/2);
rtBG.Right=rtBG.Left-rtBG.Width;
}
else
return;
this.DrawBG(rtBG);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
var xText=rtBG.Left+this.TextMargin.Left;
var yText=rtBG.Top+rtBG.Height/2;
var yOffset=0;
this.Canvas.fillText(text,xText,yText+yOffset);
//绘制一个点
if (this.BGColor)
{
this.Canvas.beginPath();
this.Canvas.arc(ptStart.X,ptStart.Y,2*pixelRatio,0,360,false);
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill();
}
this.TextRect=rtBG;
}
this.DrawBG=function(rtBG)
{
if (!rtBG) return;
var pixelRatio=GetDevicePixelRatio();
var roundRadius=this.BorderRoundRadius*pixelRatio;
var path=new Path2D();
path.roundRect(ToFixedPoint(rtBG.Left), ToFixedPoint(rtBG.Top), ToFixedRect(rtBG.Width), ToFixedRect(rtBG.Height), [roundRadius]);
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fill(path);
}
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.stroke(path);
}
}
this.IsPointIn=function(x,y)
{
if (!this.Frame || this.Status!=10) return -1;
if (!this.TextRect) return -1;
var rect=this.TextRect;
if (x>rect.Left && x<rect.Right && y>rect.Top && y<rect.Bottom)
return 1;
return this.IsPointIn_XYValue_Line(x,y);
}
}
/////////////////////////////////////////////////////////////////////////////
// 0=中心点 1=起始点(决定半径长度) 2=结束点(任意位置)
//
function ChartDrawFibWedge()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawFibWedge';
this.PointCount=3;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LastPoint;
this.AreaConfig=
{
AryData:
[
{ Value: 0.236, Color:"rgb(242,52,69)", Enable:true },
{ Value: 0.382, Color:"rgb(255,152,0)",Enable:true },
{ Value: 0.5, Color:"rgb(76,175,80)", Enable:true },
{ Value: 0.618, Color:"rgb(8,153,129)", Enable:true },
{ Value: 0.786, Color:"rgb(0,188,212)" ,Enable:true },
{ Value: 1, Color:"rgb(120,123,134)", Enable:true },
{ Value: 1.618, Color:"rgb(41,98,255)",Enable:false },
{ Value: 2.618, Color:"rgb(242,54,69)",Enable:false },
],
Opacity:0.3
}
//内部变量
this.TextAngle;
this.Radius; //半径
//计算斜边
this.CalculateHypotenuse=function(pt1, pt2)
{
var a=pt1.X-pt2.X;
var b=pt1.Y-pt2.Y;
var c=Math.sqrt(a*a+b*b);
return c;
}
//吸附X轴和Y轴K线价格
this.MagnetXY=function(aryPoint)
{
var option= { IsFixedX:this.OnlyMoveXIndex };
//磁吸功能
if (this.Option && this.Option.Magnet && this.Option.Magnet.Enable && this.IsSupportMagnet && this.Frame.Identify==0)
{
var pointIndex=-1;
if (this.Status==2) pointIndex=1; //创建第2个点
if (IFrameSplitOperator.IsNumber(this.MovePointIndex)) pointIndex=this.MovePointIndex;
if (pointIndex>=0)
{
option.Magnet=
{
Enable:true,
PointIndex:pointIndex,
Distance:this.Option.Magnet.Distance,
Type:this.Option.Magnet.Type
}
}
}
this.AdjustPoint(aryPoint,option)
}
this.CalculateAllPoint=function(ptStart, pt2, ptEnd)
{
var drawPoint=[];
drawPoint.push({ X:ptStart.X, Y:ptStart.Y });
drawPoint.push({ X:pt2.X, Y:pt2.Y });
this.MagnetXY(drawPoint);
drawPoint.push({ X:ptEnd.X, Y:ptEnd.Y });
var radius=this.CalculateHypotenuse(drawPoint[0], drawPoint[1]); //求半径
var a=drawPoint[0].X-drawPoint[2].X;
var b=drawPoint[0].Y-drawPoint[2].Y;
var c=Math.sqrt(a*a+b*b);
var a2=a*radius/c;
var b2=b*radius/c;
drawPoint[2].X=drawPoint[0].X-a2;
drawPoint[2].Y=drawPoint[0].Y-b2;
return drawPoint;
}
//数值转成坐标
this.ValueToPoint_V2=function(aryValue)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryValue)) return null;
if (!this.Frame) return null;
var data=this.Frame.Data;
if (!data) return null;
var isHScreen=this.Frame.IsHScreen;
var aryPoint=[];
for(var i=0; i<aryValue.length; ++i)
{
var item=aryValue[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset, false);
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
aryPoint[i]=pt;
}
return aryPoint;
}
this.CalculateDrawPoint=function(option)
{
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
var drawPoint=[];
if (this.Status==2) //完成第2个点
{
if (this.PointStatus==2 && this.LastPoint) //第3个点
{
drawPoint=this.CalculateAllPoint(this.Point[0], this.Point[1], this.LastPoint);
}
else
{
for(var i=0;i<this.Point.length && i<2;++i)
{
var item=this.Point[i];
drawPoint.push({ X:item.X, Y:item.Y });
}
this.MagnetXY(drawPoint);
}
}
else if (this.Status==10)
{
var data=this.Frame.Data;
if (!data) return null;
var showCount=this.Frame.XPointCount;
var invaildX=0; //超出范围的x点个数
var isHScreen=this.Frame.IsHScreen;
for(var i=0; i<this.Value.length; ++i)
{
var item=this.Value[i];
var dataIndex=item.XValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=showCount) ++invaildX;
var pt=new Point();
if (isHScreen) //横屏X,Y对调
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.Y=this.Frame.GetYFromData(item.YValue,false);
}
drawPoint.push(pt);
}
}
else if (this.Status==20)
{
drawPoint=this.CalculateAllPoint(this.Point[0], this.Point[1], this.Point[2]);
}
return drawPoint;
}
this.Draw=function()
{
this.LinePoint=[];
this.TextAngle=null;
this.Radius=null;
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint({IsCheckX:false, IsCheckY:false});
if (!IFrameSplitOperator.IsNonEmptyArray(drawPoint)) return;
var points=drawPoint.slice(0);
this.CalculateLines(points);
this.ClipFrame();
this.DrawArea(points);
this.DrawLines(this.LinePoint);
this.DrawPoint(points); //画点
this.DrawTitle(points);
this.Canvas.restore();
}
this.DrawArea=function(aryPoint)
{
if (aryPoint.length!=3) return;
if (!this.AreaConfig || !IFrameSplitOperator.IsNonEmptyArray(this.AreaConfig.AryData)) return;
var ptCenter=aryPoint[0];
var radius=this.CalculateHypotenuse(ptCenter, aryPoint[1]); //求半径
var startAngle=this.CalculateAngle(ptCenter.X,ptCenter.Y,aryPoint[1].X,aryPoint[1].Y);
var endAngle=this.CalculateAngle(ptCenter.X,ptCenter.Y,aryPoint[2].X,aryPoint[2].Y);
var sectorAngle=startAngle-endAngle;
if (sectorAngle<0) sectorAngle+=360;
if (sectorAngle>180)
{
var temp=startAngle;
startAngle=endAngle;
endAngle=temp;
}
var centerAngle=startAngle-(startAngle-endAngle)/2;
if (startAngle-endAngle<0) centerAngle-=180;
var preValue=null;
for(var i=0;i<this.AreaConfig.AryData.length;++i)
{
var item=this.AreaConfig.AryData[i];
if (!item.Enable) continue;
var value=radius*item.Value; //半径
var lineColor=item.Color;
var areaColor=IChartDrawPicture.ColorToRGBA(lineColor, this.AreaConfig.Opacity);
var path=new Path2D();
if (IFrameSplitOperator.IsNumber(preValue))
{
path.arc(ptCenter.X,ptCenter.Y,preValue,(Math.PI / 180)*(360-startAngle),(Math.PI / 180)*(360-endAngle));
path.arc(ptCenter.X,ptCenter.Y,value,(Math.PI / 180)*(360-endAngle), (Math.PI / 180)*(360-startAngle),true);
}
else
{
path.moveTo(ptCenter.X,ptCenter.Y);
path.arc(ptCenter.X,ptCenter.Y,value,(Math.PI / 180)*(360-startAngle),(Math.PI / 180)*(360-endAngle));
}
this.Canvas.fillStyle=areaColor;
this.Canvas.fill(path);
preValue=value;
}
for(var i=0;i<this.AreaConfig.AryData.length;++i)
{
var item=this.AreaConfig.AryData[i];
if (!item.Enable) continue;
var value=radius*item.Value; //半径
var lineColor=item.Color;
var path=new Path2D();
path.arc(ptCenter.X,ptCenter.Y,value,(Math.PI / 180)*(360-startAngle),(Math.PI / 180)*(360-endAngle));
this.Canvas.strokeStyle = lineColor;
this.Canvas.stroke(path);
}
this.Radius=radius;
this.TextAngle=centerAngle;
}
//显示角度数据
this.DrawTitle=function(aryPoint)
{
if (aryPoint.length!=3) return;
if (!this.AreaConfig || !IFrameSplitOperator.IsNonEmptyArray(this.AreaConfig.AryData)) return;
var ptCenter=aryPoint[0];
var radian =(Math.PI/180)*(360-this.TextAngle);
this.Canvas.font=this.Font;
for(var i=0;i<this.AreaConfig.AryData.length;++i)
{
var item=this.AreaConfig.AryData[i];
if (!item.Enable) continue;
var value=this.Radius*item.Value; //半径
var lineColor=item.Color;
var text=`${item.Value}`;
var y=Math.sin(radian)*value+ptCenter.Y
var x=Math.cos(radian)*value+ptCenter.X;
this.Canvas.fillStyle=lineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
this.Canvas.fillText(text,x+2,y+2);
}
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
this.DrawLines=function(aryLine)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryLine)) return;
for(var i=0; i<aryLine.length; ++i)
{
var item=aryLine[i];
this.DrawLine(item.Start,item.End);
}
}
this.CalculateLines=function(points)
{
if (points.length===2)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
}
else if (points.length===3)
{
var line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[1].Y;
line.End.X=points[1].X;
this.LinePoint.push(line);
line={Start:new Point(), End:new Point()};
line.Start.Y=points[0].Y;
line.Start.X=points[0].X;
line.End.Y=points[2].Y;
line.End.X=points[2].X;
this.LinePoint.push(line);
}
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y,option)
{
if (this.Status!=10) return -1;
var value=this.IsPointInXYValue(x,y,this.AryPoint,option);
if (value>=0) return value;
value=this.IsPointInLine(x,y,option);
if (value>=0) return 100;
return -1;
}
this.IsPointInDots=function(x, y, aryPoint, option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return -1;
if (!this.Frame) return -1;
var data=this.Frame.Data;
if (!data) return -1;
if (!this.Value) return -1;
var radius=5;
if (option && IFrameSplitOperator.IsNumber(option.Zoom)) radius+=option.Zoom;
else if (this.Option && IFrameSplitOperator.IsNumber(this.Option.Zoom)) radius+=this.Option.Zoom;
var isHScreen=this.Frame.IsHScreen;
radius*=GetDevicePixelRatio();
for(var i=0;i<aryPoint.length; ++i) //是否在点上
{
var pt=aryPoint[i];
var path=new Path2D();
path.arc(pt.X,pt.Y,radius,0,360);
if (this.Canvas.isPointInPath(path,x,y)) return i;
}
return -1;
}
this.GetCursorType=function(ptIndex)
{
if (ptIndex==2) return "ns-resize";
return null;
}
this.PointToValue=function()
{
if (!this.Frame) return false;
var item=this.Point[2];
var ptLast={X:item.X, Y:item.Y};
if (!this.PointToValue_Default()) return false;
//计算第3个点的位置
var aryValue=[this.Value[0], this.Value[1]];
var aryPoint=this.ValueToPoint_V2(aryValue);
var radius=this.CalculateHypotenuse(aryPoint[0], aryPoint[1]); //求半径
var a=aryPoint[0].X-ptLast.X;
var b=aryPoint[0].Y-ptLast.Y;
var c=Math.sqrt(a*a+b*b);
var a2=a*radius/c;
var b2=b*radius/c;
this.Point[2].X=aryPoint[0].X-a2;
this.Point[2].Y=aryPoint[0].Y-b2;
var aryValue=this.PointToValue_V2([this.Point[2]], {Type:1});
if (!aryValue) return false;
this.Value[2]=aryValue[0];
return true;
}
this.PointToValue_V2=function(aryPoint,option)
{
if (!this.Frame) return null;
if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
{
return this.PointToValue_Minute_V2(aryPoint, option);
}
else
{
return this.PointToValue_KLine_V2(aryPoint, option);
}
}
this.PointToValue_KLine_V2=function(aryPoint, option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return null;
if (!this.Frame) return null;
var data=this.Frame.Data;
if (!data) return null;
var aryValue=[]
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i=0;i<aryPoint.length;++i)
{
var item=aryPoint[i];
var xValue=this.Frame.GetXData(item.Y,false)+data.DataOffset;
var yValue=this.Frame.GetYData(item.X,false);
var valueItem={ XValue:xValue, YValue:yValue, Type:1 };
aryValue[i]=valueItem;
}
}
else
{
for(var i=0; i<aryPoint.length; ++i)
{
var item=aryPoint[i];
var xValue=this.Frame.GetXData(item.X,false)+data.DataOffset;
var yValue=this.Frame.GetYData(item.Y,false);
var valueItem={ XValue:xValue, YValue:yValue, Type:1 };
aryValue[i]=valueItem;
}
}
return aryValue;
}
}
//////////////////////////////////////////////////////////////////////////////
// 斐波那契回测
//
function ChartFibRetracement()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartFibRetracement';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LineDash=[6,3];
this.LineWidth=1;
this.EnableBGColor=true;
this.ExtendLine={ Left:false, Right: false }; //延长线
this.AreaConfig=
{
AryData:
[
{ Value: 0, Color:"rgb(128,128,128)", Enable:true },
{ Value: 0.236, Color:"rgb(242,52,69)", Enable:true },
{ Value: 0.382, Color:"rgb(255,152,0)",Enable:true },
{ Value: 0.5, Color:"rgb(76,175,80)", Enable:true },
{ Value: 0.618, Color:"rgb(8,153,129)", Enable:true },
{ Value: 0.786, Color:"rgb(0,188,212)" ,Enable:true },
{ Value: 1, Color:"rgb(120,123,134)", Enable:true },
{ Value: 1.618, Color:"rgb(41,98,255)",Enable:true },
{ Value: 2.618, Color:"rgb(242,54,69)",Enable:false },
],
Opacity:0.3
}
this.SetOption=function(option)
{
if (!option) return;
if (option.Font) this.Font=option.Font;
if (option.LineWidth) this.LineWidth=option.LineWidth;
if (option.LineDash) this.LineDash=option.LineDash;
if (IFrameSplitOperator.IsBool(option.EnableBGColor)) this.EnableBGColor=option.EnableBGColor;
if (option.ExtendLine)
{
var item=option.ExtendLine;
if (IFrameSplitOperator.IsBool(item.Left)) this.ExtendLine.Left=item.Left;
if (IFrameSplitOperator.IsBool(item.Right)) this.ExtendLine.Left=item.Right;
}
if (option.AreaConfig) this.AreaConfig=option.AreaConfig;
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
storageData.Value=[];
for(var i=0;i<this.Value.length && i<this.PointCount;++i)
{
var item=this.Value[i];
storageData.Value.push( { XValue:item.XValue, YValue:item.YValue } );
}
storageData.Font=this.Font;
storageData.EnableBGColor=this.EnableBGColor;
storageData.LineDash=this.LineDash;
storageData.ExtendLine={ Left:this.ExtendLine.Left, Right:this.ExtendLine.Right };
storageData.AreaConfig=CloneData(this.AreaConfig);
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.Font) this.Font=storageData.Font;
if (storageData.LineDash) this.LineDash=storageData.LineDash;
if (IFrameSplitOperator.IsBool(storageData.EnableBGColor)) this.EnableBGColor=storageData.EnableBGColor;
if (storageData.ExtendLine) this.ExtendLine=storageData.ExtendLine;
if (storageData.AreaConfig) this.AreaConfig=storageData.AreaConfig;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var bCheckXY=true;
if (this.ExtendLine.Left || this.ExtendLine.Right) bCheckXY=false;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:bCheckXY, IsCheckY:bCheckXY} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.setLineDash(this.LineDash);
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
this.DrawBlock(ptStart, ptEnd);
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.GetArrayAreaConfig=function()
{
var aryArea=[];
for(var i=0;i<this.AreaConfig.AryData.length;++i)
{
var item=this.AreaConfig.AryData[i];
if (item.Enable) aryArea.push(item);
}
aryArea.sort((left,right)=>{ return right.Value-left.Value; })
return aryArea;
}
this.DrawBlock=function(ptStart, ptEnd)
{
var yTop=Math.min(ptStart.Y, ptEnd.Y);
var yBottom=Math.max(ptStart.Y, ptEnd.Y);
var xLeft=Math.min(ptStart.X, ptEnd.X);
var xRight=Math.max(ptStart.X, ptEnd.X);
var height=yBottom-yTop;
//var baseValue=Math.min(this.Value[0].YValue, this.Value[1].YValue);
//var diffValue=Math.abs(this.Value[0].YValue-this.Value[1].YValue); //差值
if (this.ExtendLine.Right) xRight=this.Frame.ChartBorder.GetRight();
if (this.ExtendLine.Left) xLeft=this.Frame.ChartBorder.GetLeft();
var aryArea=this.GetArrayAreaConfig();
var yPre=null; //上一个点
var clrArea=null;
this.Canvas.font=this.Font;
if (this.ExtendLine.Left) this.Canvas.textAlign="left";
else this.Canvas.textAlign="right";
this.Canvas.textBaseline="bottom";
for(var i=0;i<aryArea.length;++i)
{
var item=aryArea[i];
var y=yBottom-height*item.Value;
//var yValue=baseValue+diffValue*item.Value;
yValue=this.Frame.GetYData(y,false);
y=ToFixedPoint(y);
if (this.EnableBGColor && IFrameSplitOperator.IsNumber(yPre))
{
var rtBG={ Left:xLeft, Right:xRight, Top:yPre, Bottom:y };
rtBG.Width=rtBG.Right-rtBG.Left;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=clrArea;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
this.Canvas.strokeStyle=item.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(xLeft,y);
this.Canvas.lineTo(xRight,y);
this.Canvas.stroke();
var line={ Start:{X:xLeft, Y:y}, End:{X:xRight, Y:y} };
this.LinePoint.push(line);
//文字
var text=`${item.Value} (${yValue.toFixed(2)})`;
this.Canvas.fillStyle=item.Color;
if (this.ExtendLine.Left)
this.Canvas.fillText(text,xLeft+2,y-2);
else
this.Canvas.fillText(text,xLeft-2,y-2);
yPre=y;
clrArea=IChartDrawPicture.ColorToRGBA(item.Color, this.AreaConfig.Opacity);
}
}
}
function ChartFibSpeedResistanceFan()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartFibSpeedResistanceFan';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LineWidth=1;
this.EnableBGColor=true;
this.AreaConfig=
{
AryYData:
[
{ Value: 0, Color:"rgb(128,128,128)", Enable:true },
{ Value: 0.25, Color:"rgb(242,52,69)", Enable:true },
{ Value: 0.382, Color:"rgb(255,152,0)",Enable:true },
{ Value: 0.5, Color:"rgb(76,175,80)", Enable:true },
{ Value: 0.618, Color:"rgb(8,153,129)", Enable:true },
{ Value: 0.75, Color:"rgb(0,188,212)" ,Enable:true },
{ Value: 1, Color:"rgb(120,123,134)", Enable:true },
],
AryXData:
[
{ Value: 0, Color:"rgb(128,128,128)", Enable:true },
{ Value: 0.25, Color:"rgb(242,52,69)", Enable:true },
{ Value: 0.382, Color:"rgb(255,152,0)",Enable:true },
{ Value: 0.5, Color:"rgb(76,175,80)", Enable:true },
{ Value: 0.618, Color:"rgb(8,153,129)", Enable:true },
{ Value: 0.75, Color:"rgb(0,188,212)" ,Enable:true },
{ Value: 1, Color:"rgb(120,123,134)", Enable:true },
],
Opacity:0.3
}
this.SetOption=function(option)
{
if (!option) return;
if (option.Font) this.Font=option.Font;
if (option.LineWidth) this.LineWidth=option.LineWidth;
if (IFrameSplitOperator.IsBool(option.EnableBGColor)) this.EnableBGColor=option.EnableBGColor;
if (option.AreaConfig) this.AreaConfig=option.AreaConfig;
}
//导出成存储格式
this.ExportStorageData=function()
{
var storageData=this.ExportBaseData();
storageData.Value=[];
for(var i=0;i<this.Value.length && i<this.PointCount;++i)
{
var item=this.Value[i];
storageData.Value.push( { XValue:item.XValue, YValue:item.YValue } );
}
storageData.Font=this.Font;
storageData.EnableBGColor=this.EnableBGColor;
storageData.AreaConfig=CloneData(this.AreaConfig);
return storageData;
}
this.ImportStorageData=function(storageData)
{
if (storageData.Font) this.Font=storageData.Font;
if (IFrameSplitOperator.IsBool(storageData.EnableBGColor)) this.EnableBGColor=storageData.EnableBGColor;
if (storageData.AreaConfig) this.AreaConfig=storageData.AreaConfig;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var bCheckXY=false;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:bCheckXY, IsCheckY:bCheckXY} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.DrawBlock(ptEnd, ptStart);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
//获取在第几象限
this.GetQuadrant=function(ptStart,ptEnd)
{
if (ptStart.X<ptEnd.X && ptStart.Y>ptEnd.Y) return 1;
else if (ptStart.X>ptEnd.X && ptStart.Y>ptEnd.Y) return 2;
else if (ptStart.X<ptEnd.X && ptStart.Y< ptEnd.Y) return 4;
else return 3;
}
this.DrawBlock=function(ptStart, ptEnd)
{
var center=ptEnd;
var xDiff=ptEnd.X-ptStart.X;
var yDiff=ptEnd.Y-ptStart.Y;
var quadrant=this.GetQuadrant(center,ptStart); //象限
var aryYData=this.GetArrayAreaConfig(this.AreaConfig.AryYData);
var ptPre=null; //上一个点
var clrArea=null;
this.Canvas.font=this.Font;
var border=this.Frame.GetBorder();
var ptLeftTop={ X:border.Left, Y:border.TopEx };
var ptRightTop={X:border.Right, Y:border.TopEx };
var ptLeftBottom={ X:border.Left, Y:border.BottomEx };
var ptRightBottom={ X:border.Right, Y:border.BottomEx };
var textOffset=4;
if (quadrant==1 || quadrant==4)
{
this.Canvas.textAlign="right";
textOffset=-4;
}
else
{
this.Canvas.textAlign="left";
textOffset=4;
}
this.Canvas.textBaseline="middle";
for(var i=0;i<aryYData.length;++i)
{
var item=aryYData[i];
var y=item.Value*yDiff+ptStart.Y;
var pt=this.CalculateExtendLineEndPoint([center, {X:ptStart.X, Y:y}]);
if (ptPre)
{
this.Canvas.beginPath();
this.Canvas.moveTo(center.X,center.Y);
this.Canvas.lineTo(ptPre.X,ptPre.Y);
if (quadrant==1)
{
if (ptPre.X>=ptRightTop.X && pt.X<ptRightTop.X)
{
this.Canvas.lineTo(ptRightTop.X,ptRightTop.Y);
}
}
else if (quadrant==2)
{
if (ptPre.X<=ptLeftTop.X && pt.X>ptLeftTop.X)
{
this.Canvas.lineTo(ptLeftTop.X,ptLeftTop.Y);
}
}
else if (quadrant==3)
{
if (ptPre.X<=ptLeftBottom.X && pt.X>ptLeftBottom.X)
{
this.Canvas.lineTo(ptLeftBottom.X,ptLeftBottom.Y);
}
}
else if (quadrant==4)
{
if (ptPre.X>=ptRightBottom.X && pt.X<ptRightBottom.X)
{
this.Canvas.lineTo(ptRightBottom.X,ptRightBottom.Y);
}
}
this.Canvas.lineTo(pt.X,pt.Y);
this.Canvas.closePath();
this.Canvas.fillStyle=clrArea;
this.Canvas.fill();
}
this.Canvas.strokeStyle=item.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(center.X,center.Y);
this.Canvas.lineTo(pt.X,pt.Y);
this.Canvas.stroke();
this.LinePoint.push({Start:center, End:pt});
if (item.Value!=1)
{
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(center.X,y);
this.Canvas.lineTo(ptStart.X,y);
this.Canvas.stroke();
}
ptPre=pt;
clrArea=IChartDrawPicture.ColorToRGBA(item.Color, this.AreaConfig.Opacity);
//文字
var text=`${item.Value}`;
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(text,center.X+textOffset,y);
}
var aryXData=this.GetArrayAreaConfig(this.AreaConfig.AryXData);
var ptPre=null;
this.Canvas.textAlign="center";
if (quadrant==3 || quadrant==4)
{
this.Canvas.textBaseline="bottom";
textOffset=-5;
}
else
{
this.Canvas.textBaseline="top";
textOffset=5;
}
for(var i=0;i<aryXData.length;++i)
{
var item=aryXData[i];
var x=item.Value*xDiff+ptStart.X;
var pt=this.CalculateExtendLineEndPoint([center, {X:x, Y:ptStart.Y}]);
if (ptPre) //面积
{
this.Canvas.beginPath();
this.Canvas.moveTo(center.X,center.Y);
this.Canvas.lineTo(ptPre.X,ptPre.Y);
if (quadrant==1)
{
if (ptPre.X<ptRightTop.X && pt.X>=ptRightTop.X)
{
this.Canvas.lineTo(ptRightTop.X,ptRightTop.Y);
}
}
else if (quadrant==2)
{
if (ptPre.X>ptLeftTop.X && pt.X<=ptLeftTop.X)
{
this.Canvas.lineTo(ptLeftTop.X,ptLeftTop.Y);
}
}
else if (quadrant==3)
{
if (ptPre.X>ptLeftBottom.X && pt.X<=ptLeftBottom.X)
{
this.Canvas.lineTo(ptLeftBottom.X,ptLeftBottom.Y);
}
}
else if (quadrant==4)
{
if (ptPre.X<ptRightBottom.X && pt.X>=ptRightBottom.X)
{
this.Canvas.lineTo(ptRightBottom.X,ptRightBottom.Y);
}
}
this.Canvas.lineTo(pt.X,pt.Y);
this.Canvas.closePath();
this.Canvas.fillStyle=clrArea;
this.Canvas.fill();
}
this.Canvas.strokeStyle=item.Color;
this.Canvas.beginPath();
this.Canvas.moveTo(center.X,center.Y);
this.Canvas.lineTo(pt.X,pt.Y);
this.Canvas.stroke();
this.LinePoint.push({Start:center, End:pt});
if (item.Value!=1)
{
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,center.Y);
this.Canvas.lineTo(x,ptStart.Y);
this.Canvas.stroke();
}
ptPre=pt;
clrArea=IChartDrawPicture.ColorToRGBA(item.Color, this.AreaConfig.Opacity);
//文字
var text=`${item.Value}`;
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(text,x,center.Y+textOffset);
}
}
this.GetArrayAreaConfig=function(aryData)
{
var aryArea=[];
for(var i=0;i<aryData.length;++i)
{
var item=aryData[i];
if (item.Enable) aryArea.push(item);
}
aryArea.sort((left,right)=>{ return right.Value-left.Value; })
return aryArea;
}
}
function ChartPriceRange()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartPriceRange';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.TextColor=this.LineColor;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LineWidth=1;
this.EnableBGColor=true;
this.BGColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.15);
this.ExtendLine={ Left:false, Right: false }; //延长线
this.Label={ TextColor:"rgb(0,0,0)", BGColor:"rgb(211,211,211)", EnableBGColor:true, LeftMargin:5, RightMargin:5 };
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var bCheckXY=true;
if (this.ExtendLine.Left || this.ExtendLine.Right) bCheckXY=false;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:bCheckXY, IsCheckY:bCheckXY} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.DrawRange(ptStart,ptEnd);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawRange=function(ptStart, ptEnd)
{
var yTop=Math.min(ptStart.Y, ptEnd.Y);
var yBottom=Math.max(ptStart.Y, ptEnd.Y);
var xLeft=Math.min(ptStart.X, ptEnd.X);
var xRight=Math.max(ptStart.X, ptEnd.X);
var height=yBottom-yTop;
var xCenter=ptStart.X+(ptEnd.X-ptStart.X)/2;
if (this.ExtendLine.Right) xRight=this.Frame.ChartBorder.GetRight();
if (this.ExtendLine.Left) xLeft=this.Frame.ChartBorder.GetLeft();
if (this.EnableBGColor)
{
var rtBG={ Left:xLeft, Top:yTop, Right:xRight, Bottom:yBottom };
rtBG.Width=rtBG.Right-rtBG.Left;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(xLeft,ToFixedPoint(yTop));
this.Canvas.lineTo(xRight,ToFixedPoint(yTop));
this.Canvas.moveTo(xLeft,ToFixedPoint(yBottom));
this.Canvas.lineTo(xRight,ToFixedPoint(yBottom));
this.Canvas.moveTo(ToFixedPoint(xCenter),ToFixedPoint(yTop));
this.Canvas.lineTo(ToFixedPoint(xCenter),ToFixedPoint(yBottom));
this.Canvas.stroke();
this.LinePoint.push({ Start:{X:xLeft, Y:yTop}, End:{X:xRight, Y:yTop} });
this.LinePoint.push({ Start:{X:xLeft, Y:yBottom}, End:{X:xRight, Y:yBottom} });
this.LinePoint.push({ Start:{X:xCenter, Y:yTop}, End:{X:xCenter, Y:yBottom} });
this.DrawArrow({X:ToFixedPoint(xCenter), Y:ptStart.Y}, {X:ToFixedPoint(xCenter), Y:ptEnd.Y});
var bottom=this.Frame.ChartBorder.GetBottomEx();
var top=this.Frame.ChartBorder.GetTopEx();
//文字输出
var startValue=this.Frame.GetYData(ptStart.Y,false);
var endValue=this.Frame.GetYData(ptEnd.Y,false);
var diffValue=endValue-startValue;
var rate=(diffValue/startValue)*100;
var text=`${diffValue.toFixed(2)} (${rate.toFixed(2)}%)`;
this.Canvas.font=this.Font;
var textHeight=this.GetFontHeight();
var textWidth=this.Canvas.measureText(text).width+4+(this.Label.LeftMargin+this.Label.RightMargin);
var rtTextBG={ Left:xCenter-textWidth/2, Width:textWidth, Height:textHeight+2 };
if (diffValue>0) rtTextBG.Top=ptEnd.Y-rtTextBG.Height-4;
else rtTextBG.Top=ptEnd.Y+4;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
if (diffValue>0)
{
if (rtTextBG.Top<=top)
{
rtTextBG.Top=top;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
}
}
else
{
if (rtTextBG.Bottom>=bottom)
{
rtTextBG.Bottom=bottom;
rtTextBG.Top=rtTextBG.Bottom-rtTextBG.Height;
}
}
if (this.Label.EnableBGColor)
{
var path=new Path2D();
path.roundRect(ToFixedPoint(rtTextBG.Left), ToFixedPoint(rtTextBG.Top), ToFixedRect(rtTextBG.Width), ToFixedRect(rtTextBG.Height), [3]);
this.Canvas.fillStyle=this.Label.BGColor;
this.Canvas.fill(path);
}
this.Canvas.fillStyle=this.Label.TextColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.fillText(text,rtTextBG.Left+2+this.Label.LeftMargin,rtTextBG.Bottom-2);
}
}
function ChartDateRange()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDateRange';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.TextColor=this.LineColor;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LineWidth=1;
this.EnableBGColor=true;
this.BGColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.15);
this.ExtendLine={ Top:false, Bottom: false }; //延长线
this.Label={ TextColor:"rgb(0,0,0)", BGColor:"rgb(211,211,211)", EnableBGColor:true, LeftMargin:5, RightMargin:5 };
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var bCheckXY=true;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:bCheckXY, IsCheckY:bCheckXY} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.DrawRange(ptStart,ptEnd);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawRange=function(ptStart, ptEnd)
{
var yTop=Math.min(ptStart.Y, ptEnd.Y);
var yBottom=Math.max(ptStart.Y, ptEnd.Y);
var xLeft=Math.min(ptStart.X, ptEnd.X);
var xRight=Math.max(ptStart.X, ptEnd.X);
var height=yBottom-yTop;
var width=xRight-xLeft;
var yCenter=ptStart.Y+(ptEnd.Y-ptStart.Y)/2;
var xCenter=ptStart.X+(ptEnd.X-ptStart.X)/2;
if (this.ExtendLine.Top) yTop=this.Frame.ChartBorder.GetTopEx();
if (this.ExtendLine.Bottom) yBottom=this.Frame.ChartBorder.GetBottomEx();
if (this.EnableBGColor)
{
var rtBG={ Left:xLeft, Top:yTop, Right:xRight, Bottom:yBottom };
rtBG.Width=rtBG.Right-rtBG.Left;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xLeft),yTop);
this.Canvas.lineTo(ToFixedPoint(xLeft),yBottom);
this.Canvas.moveTo(ToFixedPoint(xRight),yTop);
this.Canvas.lineTo(ToFixedPoint(xRight),yBottom);
this.Canvas.moveTo(ToFixedPoint(xLeft),ToFixedPoint(yCenter));
this.Canvas.lineTo(ToFixedPoint(xRight),ToFixedPoint(yCenter));
this.Canvas.stroke();
this.LinePoint.push({ Start:{X:xLeft, Y:yTop}, End:{X:xLeft, Y:yBottom} });
this.LinePoint.push({ Start:{X:xRight, Y:yTop}, End:{X:xRight, Y:yBottom} });
this.LinePoint.push({ Start:{X:xLeft, Y:yCenter}, End:{X:xRight, Y:yCenter} });
this.DrawArrow({X:ptStart.X, Y:ToFixedPoint(yCenter)}, {X:ptEnd.X, Y:ToFixedPoint(yCenter)});
//文字输出
var bottom=this.Frame.ChartBorder.GetBottomEx();
var top=this.Frame.ChartBorder.GetTopEx();
var startIndex=this.Frame.GetXData(ptStart.X,false);
var endIndex=this.Frame.GetXData(ptEnd.X,false);
var startValue=this.Frame.GetYData(ptStart.Y,false);
var endValue=this.Frame.GetYData(ptEnd.Y,false);
var diffValue=endValue-startValue;
var barCount=endIndex-startIndex+1;
var text=`${barCount} bars`;
this.Canvas.font=this.Font;
var textHeight=this.GetFontHeight();
var textWidth=this.Canvas.measureText(text).width+4+(this.Label.LeftMargin+this.Label.RightMargin);
var rtTextBG={ Left:xCenter-textWidth/2, Top:ptEnd.Y+4, Width:textWidth, Height:textHeight+2 };
if (diffValue>0) rtTextBG.Top=ptEnd.Y-rtTextBG.Height-4;
else rtTextBG.Top=ptEnd.Y+4;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
if (diffValue>0)
{
if (rtTextBG.Top<=top)
{
rtTextBG.Top=top;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
}
}
else
{
if (rtTextBG.Bottom>=bottom)
{
rtTextBG.Bottom=bottom;
rtTextBG.Top=rtTextBG.Bottom-rtTextBG.Height;
}
}
if (this.Label.EnableBGColor)
{
var path=new Path2D();
path.roundRect(ToFixedPoint(rtTextBG.Left), ToFixedPoint(rtTextBG.Top), ToFixedRect(rtTextBG.Width), ToFixedRect(rtTextBG.Height), [3]);
this.Canvas.fillStyle=this.Label.BGColor;
this.Canvas.fill(path);
}
this.Canvas.fillStyle=this.Label.TextColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.fillText(text,rtTextBG.Left+2+this.Label.LeftMargin,rtTextBG.Bottom-2);
}
}
function ChartDatePriceRange()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDatePriceRange';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.TextColor=this.LineColor;
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.PointToValue_Default=this.PointToValue;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LineWidth=1;
this.EnableBGColor=true;
this.BGColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.15);
this.ExtendLine={ Top:false, Bottom: false }; //延长线
this.Label={ TextColor:"rgb(0,0,0)", BGColor:"rgb(211,211,211)", EnableBGColor:true, LeftMargin:5, RightMargin:5 };
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var bCheckXY=true;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:bCheckXY, IsCheckY:bCheckXY} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.DrawRange(ptStart,ptEnd);
this.RestoreLineWidth();
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
this.DrawRange=function(ptStart, ptEnd)
{
var yTop=Math.min(ptStart.Y, ptEnd.Y);
var yBottom=Math.max(ptStart.Y, ptEnd.Y);
var xLeft=Math.min(ptStart.X, ptEnd.X);
var xRight=Math.max(ptStart.X, ptEnd.X);
var height=yBottom-yTop;
var width=xRight-xLeft;
var yCenter=ptStart.Y+(ptEnd.Y-ptStart.Y)/2;
var xCenter=ptStart.X+(ptEnd.X-ptStart.X)/2;
if (this.ExtendLine.Top) yTop=this.Frame.ChartBorder.GetTopEx();
if (this.ExtendLine.Bottom) yBottom=this.Frame.ChartBorder.GetBottomEx();
if (this.EnableBGColor)
{
var rtBG={ Left:xLeft, Top:yTop, Right:xRight, Bottom:yBottom };
rtBG.Width=rtBG.Right-rtBG.Left;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);
}
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(xLeft),yTop);
this.Canvas.lineTo(ToFixedPoint(xLeft),yBottom);
this.Canvas.moveTo(ToFixedPoint(xRight),yTop);
this.Canvas.lineTo(ToFixedPoint(xRight),yBottom);
this.Canvas.moveTo(ToFixedPoint(xLeft),ToFixedPoint(yCenter));
this.Canvas.lineTo(ToFixedPoint(xRight),ToFixedPoint(yCenter));
this.Canvas.moveTo(ToFixedPoint(xCenter),ToFixedPoint(yTop));
this.Canvas.lineTo(ToFixedPoint(xCenter),ToFixedPoint(yBottom));
this.Canvas.stroke();
this.LinePoint.push({ Start:{X:xLeft, Y:yTop}, End:{X:xLeft, Y:yBottom} });
this.LinePoint.push({ Start:{X:xRight, Y:yTop}, End:{X:xRight, Y:yBottom} });
this.LinePoint.push({ Start:{X:xLeft, Y:yCenter}, End:{X:xRight, Y:yCenter} });
this.DrawArrow({X:ptStart.X, Y:ToFixedPoint(yCenter)}, {X:ptEnd.X, Y:ToFixedPoint(yCenter)});
this.DrawArrow({X:ToFixedPoint(xCenter), Y:ptStart.Y}, {X:ToFixedPoint(xCenter), Y:ptEnd.Y});
//文字输出
var bottom=this.Frame.ChartBorder.GetBottomEx();
var top=this.Frame.ChartBorder.GetTopEx();
var startIndex=this.Frame.GetXData(ptStart.X,false);
var endIndex=this.Frame.GetXData(ptEnd.X,false);
var barCount=endIndex-startIndex+1;
var startValue=this.Frame.GetYData(ptStart.Y,false);
var endValue=this.Frame.GetYData(ptEnd.Y,false);
var diffValue=endValue-startValue;
var rate=(diffValue/startValue)*100;
var aryText=
[
`${diffValue.toFixed(2)} (${rate.toFixed(2)}%)`,
`${barCount} bars`
];
this.Canvas.font=this.Font;
var textHeight=this.GetFontHeight();
var textWidth=0;
for(var i=0;i<aryText.length;++i)
{
var text=aryText[i];
var value=this.Canvas.measureText(text).width;
if (textWidth<value) textWidth=value;
}
textWidth+=(this.Label.LeftMargin+this.Label.RightMargin);
var rtTextBG={ Left:xCenter-textWidth/2, Top:ptEnd.Y+4, Width:textWidth, Height:aryText.length*textHeight+2 };
if (diffValue>0) rtTextBG.Top=ptEnd.Y-rtTextBG.Height-4;
else rtTextBG.Top=ptEnd.Y+4;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
if (diffValue>0)
{
if (rtTextBG.Top<=top)
{
rtTextBG.Top=top;
rtTextBG.Bottom=rtTextBG.Top+rtTextBG.Height;
}
}
else
{
if (rtTextBG.Bottom>=bottom)
{
rtTextBG.Bottom=bottom;
rtTextBG.Top=rtTextBG.Bottom-rtTextBG.Height;
}
}
if (this.Label.EnableBGColor)
{
var path=new Path2D();
path.roundRect(ToFixedPoint(rtTextBG.Left), ToFixedPoint(rtTextBG.Top), ToFixedRect(rtTextBG.Width), ToFixedRect(rtTextBG.Height), [3]);
this.Canvas.fillStyle=this.Label.BGColor;
this.Canvas.fill(path);
}
this.Canvas.fillStyle=this.Label.TextColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var yText=rtTextBG.Bottom-2;
for(var i=0;i<aryText.length;++i)
{
var text=aryText[i];
this.Canvas.fillText(text,rtTextBG.Left+2+this.Label.LeftMargin,yText);
yText-=textHeight;
}
}
}
//线段信息统计
function ChartInfoLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartInfoLine';
this.PointCount=2;
this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.GetXYCoordinate=this.GetXYCoordinate_default;
this.IsShowYCoordinate=false;
this.CopyData=this.CopyData_default;
this.OnlyMoveXIndex=true;
this.IsSupportMagnet=true;
this.LabelConfig=
{
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
BGColor:"rgba(135, 206 ,250,0.95)",
Mergin:{ Left:10, Right:10, Top:10, Bottom:8 },
LineSpace:5, //行间距
TextAlign:1, //对齐方式 0=left 1=right
}
this.FormatLabelTextCallback=null;
this.SetOption=function(option)
{
if (option.LineColor) this.LineColor=option.LineColor;
if (option.PointColor) this.PointColor=option.PointColor
if (option.Label)
{
var item=option.Label;
var dest=this.LabelConfig
if (item.Font) dest.Font=item.Font;
if (item.BGColor) dest.BGColor=item.BGColor;
if (IFrameSplitOperator.IsNumber(item.LineSpace)) dest.LineSpace=item.LineSpace;
if (IFrameSplitOperator.IsNumber(item.TextAlign)) dest.TextAlign=item.TextAlign;
if (item.Mergin) CopyMarginConfig(dest.Mergin, item.Mergin);
}
if (option.FormatLabelTextCallback) this.FormatLabelTextCallback=option.FormatLabelTextCallback;
}
this.Draw=function()
{
this.LinePoint=[];
if (this.IsFrameMinSize()) return;
if (!this.IsShow) return;
var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:false} );
if (!drawPoint) return;
if (drawPoint.length!=2) return;
this.ClipFrame();
var ptStart=drawPoint[0];
var ptEnd=drawPoint[1];
this.SetLineWidth();
this.Canvas.strokeStyle=this.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ptStart.X,ptStart.Y);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y);
this.Canvas.stroke();
this.RestoreLineWidth();
var line={Start:ptStart, End:ptEnd};
this.LinePoint.push(line);
this.DrawPoint(drawPoint); //画点
var labelInfo={ };
labelInfo.Config=this.LabelConfig;
labelInfo.PtStart=ptStart;
labelInfo.PtEnd=ptEnd;
this.Canvas.restore();
this.DrawLabel(labelInfo);
}
this.DrawLabel=function(labelInfo)
{
if (!this.FormatLabelTextCallback) return;
labelInfo.AryPoint=this.Point;
if (this.Status!=10)
{
labelInfo.AryValue=this.PointToKLine(this.Point);
}
else
{
labelInfo.AryValue=this.Value;
}
labelInfo.Data=this.Frame.Data; //数据
this.FormatLabelTextCallback(labelInfo);
if (!IFrameSplitOperator.IsNonEmptyArray(labelInfo.AryText)) return;
this.CalculateLabelSize(labelInfo);
var ptStart=labelInfo.PtStart;
var ptEnd=labelInfo.PtEnd;
if (ptStart.X>ptEnd.X)
{
ptStart=labelInfo.PtEnd;
ptEnd=labelInfo.PtStart;
}
var config=labelInfo.Config;
var xCenter=labelInfo.PtStart.X+(labelInfo.PtEnd.X-labelInfo.PtStart.X)/2;
var yCenter=labelInfo.PtStart.Y+(labelInfo.PtEnd.Y-labelInfo.PtStart.Y)/2;
if (ptStart.Y<ptEnd.Y)
{
var rtBG={ Left:xCenter, Bottom:yCenter, Width:labelInfo.Width, Height:labelInfo.Height };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Top=rtBG.Bottom-rtBG.Height;
}
else
{
var rtBG={ Left:xCenter, Top:yCenter, Width:labelInfo.Width, Height:labelInfo.Height };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
}
this.DrawDefaultLabel(labelInfo, rtBG);
}
}
function ChartBarsPattern()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartBarsPattern';
this.PointCount=2;
this.KData=null; //K线数据 []
this.Draw=function()
{
}
}
function ChartDrawStorage()
{
this.DrawData=new Map(); //画图工具数据 key=symbol-Period, value=Map() Key:Guid, Value:{Guid, Symbol, Period, ClassName, Value}
this.StorageKey;
this.GetEventCallback; //事件回调
this.Load=function(key) //从本地读取画图工具
{
if (!key) return;
this.StorageKey=key;
var cacheValue = localStorage[this.StorageKey];
JSConsole.Chart.Log(`[ChartDrawStorage::Load] Load to localStorage, key=${this.StorageKey}, cache=${cacheValue}`);
if (!cacheValue) return;
if (typeof(cacheValue) != "string") return;
var saveData=JSON.parse(cacheValue);
for(var i in saveData)
{
var item=saveData[i];
var drawMap=new Map();
for(var j in item.Value)
{
var drawItem=item.Value[j];
drawMap.set(drawItem.Key, drawItem.Value);
}
this.DrawData.set(item.Key,drawMap);
}
}
this.Save=function() //把数据保存到本地
{
if (!this.StorageKey) return;
var saveData=[];
for(var stock of this.DrawData)
{
var key=stock[0];
var value=stock[1];
var itemData={ Key:key, Value:[]};
for(var drawItem of value)
{
if (drawItem[1] && drawItem[1].EnableSave===false) continue;
itemData.Value.push({Key:drawItem[0], Value:drawItem[1]});
}
if (IFrameSplitOperator.IsNonEmptyArray(itemData.Value))
saveData.push(itemData);
}
JSConsole.Chart.Log(`[ChartDrawStorage::Save] save to localStorage, key=${this.StorageKey}`);
var strData=JSON.stringify(saveData);
localStorage[this.StorageKey]=strData;
}
this.GetItemKey=function(obj) //生成每个画图工具的key
{
var strKey=`${obj.Symbol}-${obj.Period}`;
return strKey;
}
this.SaveDrawData=function(drawPicture) //保存一个画图工具
{
var strKey=this.GetItemKey(drawPicture);
var data=drawPicture.ExportStorageData();
if (!data) return;
if (this.DrawData.has(strKey)) //更新
{
JSConsole.Chart.Log('[ChartDrawStorage::SaveDrawData] Upate: key, drawPicture, data', strKey, drawPicture,data);
this.DrawData.get(strKey).set(data.Guid, data);
}
else //新增
{
JSConsole.Chart.Log('[ChartDrawStorage::SaveDrawData] Insert: key, drawPicture, data', strKey, drawPicture,data);
var newData=new Map();
newData.set(data.Guid, data);
this.DrawData.set(strKey,newData);
}
JSConsole.Chart.Log('[ChartDrawStorage::SaveDrawData] All draw data: ', this.DrawData);
this.Save();
}
this.DeleteDrawData=function(drawPicture) //删除一个画图工具
{
var strKey=this.GetItemKey(drawPicture);
if (!this.DrawData.has(strKey)) return;
var mapDraw=this.DrawData.get(strKey);
if (!mapDraw.has(drawPicture.Guid)) return;
mapDraw.delete(drawPicture.Guid);
this.Save();
}
this.Clear=function()
{
this.DrawData=new Map();
this.Save();
}
this.GetDrawData=function(obj) //获取已有的画图工具数据{Symbol: , Period:, }
{
var data=[];
var strKey=this.GetItemKey(obj);
if (!this.DrawData.has(strKey)) return data;
var stockData=this.DrawData.get(strKey);
for(var item of stockData)
{
data.push(item[1]);
}
return data;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 数据分割
// [0]=Start起始 [1]=End结束 [2]=FixInterval修正的间隔 [3]=Increase
//
function SplitData()
{
this.Data=[
[0.000001, 0.000002, 0.000001, 0.0000001],
[0.000002, 0.000004, 0.000002, 0.0000002],
[0.000004, 0.000005, 0.000004, 0.0000001],
[0.000005, 0.00001, 0.000005, 0.0000005],
[0.00001, 0.00002, 0.00001, 0.000001],
[0.00002, 0.00004, 0.00002, 0.000002],
[0.00004, 0.00005, 0.00004, 0.000001],
[0.00005, 0.0001, 0.00005, 0.000005],
[0.0001, 0.0002, 0.0001, 0.00001],
[0.0002, 0.0004, 0.0002, 0.00002],
[0.0004, 0.0005, 0.0004, 0.00001],
[0.0005, 0.001, 0.0005, 0.00005],
[0.001, 0.002, 0.001, 0.0001],
[0.002, 0.004, 0.002, 0.0002],
[0.004, 0.005, 0.004, 0.0001],
[0.005, 0.01, 0.005, 0.0005],
[0.01, 0.02, 0.01, 0.001],
[0.02, 0.04, 0.02, 0.002],
[0.04, 0.05, 0.04, 0.001],
[0.05, 0.1, 0.05, 0.005],
[0.1, 0.2, 0.1, 0.01],
[0.2, 0.4, 0.2, 0.02],
[0.4, 0.5, 0.4, 0.01],
[0.5, 1, 0.5, 0.05],
[1, 2, 0.5, 0.05],
[2, 4, 0.5, 0.05],
[4, 5, 0.5, 0.05],
[5, 10, 0.5, 0.05],
[10, 20, 10, 2],
[20, 40, 20, 5],
[40, 50, 40, 2],
[50, 100, 50, 10],
[100, 200, 100, 10],
[200, 400, 200, 20],
[400, 500, 400, 10],
[500, 1000, 500, 50],
[1000, 2000, 1000, 50],
[2000, 4000, 2000, 50],
[4000, 5000, 4000, 50],
[5000, 10000, 5000, 100],
[10000, 20000, 10000, 1000],
[20000, 40000, 10000, 1000],
[40000, 50000, 10000, 1000],
[50000, 100000, 10000, 1000],
[100000, 200000, 100000, 10000],
[200000, 400000, 100000, 10000],
[400000, 500000, 100000, 10000],
[500000, 1000000, 100000, 10000],
[1000000, 2000000, 1000000, 100000],
[2000000, 4000000, 1000000, 100000],
[4000000, 5000000, 1000000, 100000],
[5000000, 10000000, 1000000, 100000],
[10000000, 20000000, 10000000, 1000000],
[20000000, 40000000, 10000000, 1000000],
[40000000, 50000000, 10000000, 1000000],
[50000000, 100000000, 10000000, 1000000],
[100000000, 200000000, 100000000, 10000000],
[200000000, 400000000, 100000000, 10000000],
[400000000, 500000000, 100000000, 10000000],
[500000000, 1000000000, 100000000, 10000000],
[1000000000, 2000000000, 1000000000, 100000000],
[2000000000, 4000000000, 1000000000, 100000000],
[4000000000, 5000000000, 1000000000, 100000000],
[5000000000, 10000000000, 1000000000, 100000000]
];
this.Find=function(interval)
{
for(var i in this.Data)
{
var item =this.Data[i];
if (interval>item[0] && interval<=item[1])
{
var result={};
result.FixInterval=item[2];
result.Increase=item[3];
return result;
}
}
return null;
}
}
function PriceSplitData()
{
this.newMethod=SplitData; //派生
this.newMethod();
delete this.newMethod;
this.Data=[
[0.000001, 0.000002, 0.000001, 0.0000001],
[0.000002, 0.000004, 0.000002, 0.0000002],
[0.000004, 0.000005, 0.000004, 0.0000001],
[0.000005, 0.00001, 0.000005, 0.0000005],
[0.00001, 0.00002, 0.00001, 0.000001],
[0.00002, 0.00004, 0.00002, 0.000002],
[0.00004, 0.00005, 0.00004, 0.000001],
[0.00005, 0.0001, 0.00005, 0.000005],
[0.0001, 0.0002, 0.0001, 0.00001],
[0.0002, 0.0004, 0.0002, 0.00002],
[0.0004, 0.0005, 0.0004, 0.00001],
[0.0005, 0.001, 0.0005, 0.00005],
[0.001, 0.002, 0.001, 0.0001],
[0.002, 0.004, 0.002, 0.0001],
[0.004, 0.005, 0.004, 0.0001],
[0.005, 0.01, 0.005, 0.0005],
[0.01, 0.02, 0.01, 0.001],
[0.02, 0.04, 0.02, 0.001],
[0.04, 0.05, 0.04, 0.001],
[0.05, 0.1, 0.05, 0.001],
[0.1, 0.2, 0.1, 0.01],
[0.2, 0.4, 0.2, 0.01],
[0.4, 0.5, 0.2, 0.01],
[0.5, 0.8, 0.2, 0.01],
[0.8, 1, 0.5, 0.01],
[1, 2, 0.5, 0.05],
[2, 4, 0.5, 0.05],
[4, 5, 0.5, 0.05],
[5, 10, 0.5, 0.05],
[10, 12, 10, 2],
[20, 40, 20, 5],
[40, 50, 40, 2],
[50, 100, 50, 10],
[100, 200, 100, 10],
[200, 400, 200, 20],
[400, 500, 400, 10],
[500, 1000, 500, 50],
[1000, 2000, 1000, 50],
[2000, 4000, 2000, 50],
[4000, 5000, 4000, 50],
[5000, 10000, 5000, 100],
[10000, 20000, 10000, 1000],
[20000, 40000, 20000, 2000],
[40000, 50000, 40000, 1000],
[50000, 100000, 50000, 5000],
[100000, 200000, 100000, 10000],
[200000, 400000, 200000, 20000],
[400000, 500000, 400000, 10000],
[500000, 1000000, 500000, 50000],
[1000000, 2000000, 1000000, 100000],
[2000000, 4000000, 2000000, 200000],
[4000000, 5000000, 4000000, 100000],
[5000000, 10000000, 5000000, 500000],
[10000000, 20000000, 10000000, 1000000],
[20000000, 40000000, 20000000, 2000000],
[40000000, 50000000, 40000000, 1000000],
[50000000, 100000000, 50000000, 5000000],
[100000000, 200000000, 100000000, 10000000],
[200000000, 400000000, 200000000, 20000000],
[400000000, 500000000, 400000000, 10000000],
[500000000, 1000000000, 500000000, 50000000],
[1000000000, 2000000000, 1000000000, 100000000],
[2000000000, 4000000000, 2000000000, 200000000],
[4000000000, 5000000000, 4000000000, 100000000],
[5000000000, 10000000000, 5000000000, 500000000]
];
}
/////////////////////////////////////////////////////////////////////////////
// 全局配置颜色
//
//
function JSChartResource()
{
this.IsDOMFrameTitle=false; //外部DOM指标标题栏
this.IsDOMFrameToolbar=false;
//全局K线窗口按钮配置
this.KLineToolbar=
{
ModifyIndex:true, //修改参数
ChangeIndex:true, //切换指标
CloseIndex:true, //关闭窗口
OverlayIndex:false, //叠加指标
MaxMinWindow:true, //最大最小化窗口
TitleWindow:true, //标题模式
ExportData:false, //数据导出
IsShowOverlayToolbar:true, //是否显示叠加坐标工具栏按钮
IsShowOverlayFrame:true, //是否显示右侧叠加坐标
}
//全局分时图窗口按钮配置
this.MinuteToolbar=
{
ModifyIndex:true, //修改参数
ChangeIndex:true, //切换指标
CloseIndex:true, //关闭窗口
OverlayIndex:true, //叠加指标
MaxMinWindow:true, //最大最小化窗口
TitleWindow:true, //标题模式
ExportData:false, //数据导出
}
this.TooltipBGColor="rgb(255, 255, 255)"; //背景色
this.TooltipAlpha=0.92; //透明度
this.PopMinuteChart=
{
BGColor:"rgba(250,250,250,0.95)",
BorderColor:"rgb(0,0,0)",
}
this.SelectRectBGColor="rgba(1,130,212,0.06)"; //背景色
// this.SelectRectAlpha=0.06; //透明度
this.UpBarColor="rgb(238,21,21)"; //上涨柱子颜色
this.DownBarColor="rgb(25,158,0)"; //下跌柱子颜色
this.UnchagneBarColor="rgb(0,0,0)"; //平盘柱子颜色
this.EmptyBarBGColor="rgb(255,255,255)"; //空心柱子背景色
this.HighLowBarColor='rgb(41,98,255)'; //high low bar 颜色
this.HighLowText={ FontName:"arial", MaxSize:30, MinSize:4, Color:"rgb(41,98,255)", MaxText:"9999.9" };
this.SplashScreen=
{
BGColor:"rgba(112,128,144,0.5)",
Title:"下载数据中......",
TextColor:"rgb(43,54,69)",
Font:14*GetDevicePixelRatio() +'px 微软雅黑'
}
this.HLCArea=
{
HighLineColor:'rgb(242,54,69)',
LowLineColor:"rgb(8,153,129)",
CloseLineColor:"rgb(224,227,227)",
LineWidth:2*GetDevicePixelRatio(),
UpAreaColor:"rgba(253,214,218, 0.5)",
DownAreaColor:"rgba(205,235,230, 0.5)",
};
this.Minute={};
this.Minute.VolBarColor=null; //分时图成交量柱子颜色 默认不用, 设置了柱子就不是红绿了
this.Minute.VolTitleColor="rgb(105,105,105)";
this.Minute.PriceColor="rgb(50,171,205)"; //分时图价格线颜色
this.Minute.PriceLineWidth=1*GetDevicePixelRatio(); //价格线宽度
this.Minute.AreaPriceColor='rgba(50,171,205,0.1)'; //价格的面积图
this.Minute.AvPriceColor="rgb(238,127,9)"; //分时图均价线颜色
this.Minute.PositionColor='rgb(218,165,32)'; //持仓量线段颜色
this.Minute.FrameSplitTextColor=null; //刻度文字颜色 (缺省使用 this.FrameSplitTextColor)
this.Minute.Before=
{
BGColor:'rgba(240,240,240,0.7)', //分钟 集合竞价背景
LineColor:"rgb(50,171,205)", //集合竞价线段颜色
VolColor:["rgb(192,192,0)"], //成交量其他的颜色 colorID=3 开始
AvPriceColor:'rgb(190,190,190)', //均线
Point:{ Color:"rgb(65,105,225)", Radius:2*GetDevicePixelRatio() },
CloseIcon:
{
Family:'iconfont',
Text:"\ue60c",
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Size:12*GetDevicePixelRatio()
} //关闭按钮
};
this.Minute.After=
{
BGColor:'rgba(240,240,240,0.7)', //分钟 集合竞价背景
LineColor:"rgb(50,171,205)", //集合竞价线段颜色
VolColor:["rgb(192,192,0)"], //成交量其他的颜色 colorID=3 开始
AvPriceColor:'rgb(190,190,190)', //均线
Point:{ Color:"rgb(65,105,225)", Radius:2*GetDevicePixelRatio() },
};
this.Minute.NightDay=
{
NightBGColor:"rgba(0,0,0,0.2)",
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
Day: { Color:"rgb(0,0,0)", BGColor:"rgb(179,179,179)", BorderColor:"rgb(179,179,179)", Margin:{ Left:5, Top:2, Bottom:2, Right:5 } },
Night: { Color:"rgb(0,0,0)", BGColor:"rgb(179,179,179)", BorderColor:"rgb(179,179,179)", Margin:{ Left:5, Top:2, Bottom:2, Right:5 } },
}
this.DefaultTextColor="rgb(43,54,69)"; //图形中默认的字体颜色
this.DefaultTextFont=14*GetDevicePixelRatio() +'px 微软雅黑'; //图形中默认的字体
this.TitleFont=13*GetDevicePixelRatio() +'px 微软雅黑'; //指标显示,tooltip显示字体
this.IndexTitleBGColor='rgb(250,250,250)'; //指标名字背景色
this.IndexTitleBorderColor='rgb(180,180,180)'; //指标名字边框颜色
this.IndexTitleBorderMoveOnColor='rgb(0,0,0)'; //指标名字边框颜色(鼠标在上面)
this.IndexTitleBorderStyle=1, //0=直角边框 1=圆角边框
this.IndexTitleColor="rgb(43,54,69)"; //指标名字颜色
this.IndexTitleSelectedColor="rgb(65,105,225)";
this.OverlayIndexTitleBGColor='rgba(255,255,255,0.7)';
this.IndexTitleMerginLeft=1; //指标输出左边间距
this.IndexTitle=
{
UpDownArrow: //数值涨跌箭头
{
UpColor:"rgb(238,21,21)", //上涨
DownColor:"rgb(25,158,0)", //下跌
UnchangeColor:"rgb(0,0,0)" //不变
},
ArrowType:0,
EnableIndexArrow:true, //指标数值是否带上涨下跌箭头
NameArrow:{ Color:"rgb(43,54,69)", Space:2, Symbol:'▼' },
}
this.Title={
TradeIndexColor:'rgb(105,105,105)', //交易指标颜色
ColorIndexColor:'rgb(112,128,144)', //五彩K线颜色
VolColor:"rgb(43,54,69)", //标题成交量
AmountColor:"rgb(43,54,69)", //成交金额
DateTimeColor:"rgb(43,54,69)", //时间,日期
SettingColor:"rgb(43,54,69)", //周期,复权
NameColor:"rgb(43,54,69)" , //股票名称
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(43,54,69)" //持仓
};
this.UpTextColor="rgb(238,21,21)"; //上涨文字颜色
this.DownTextColor="rgb(25,158,0)"; //下跌文字颜色
this.UnchagneTextColor="rgb(0,0,0)"; //平盘文字颜色
this.CloseLineColor='rgb(0,191,255)'; //收盘价线颜色
this.CloseLineAreaColor=['rgba(0,191,255,0.8)','rgba(0,191,255,0.2)']; //收盘价面积图颜色
this.CloseLineWidth=2; //收盘价面积|收盘价|叠加的收盘价线段宽度
this.FrameBorderPen="rgb(225,236,242)"; //边框颜色
this.MultiDayBorderPen='rgb(225,236,242)'; //多日分时图集合竞价分割线
this.FrameSplitPen="rgb(225,236,242)"; //刻度分割线
this.FrameDotSplitPen='rgb(105,105,105)'; //分割虚线
this.FrameYLineDash= null; //[5*GetDevicePixelRatio(), 5*GetDevicePixelRatio()]; //Y轴线段虚线点间距,填null 就是实线
this.FrameXLineDash= null; //[5*GetDevicePixelRatio(), 5*GetDevicePixelRatio()]; //X轴线段虚线点间距,填null 就是实线
this.FrameSplitTextColor="rgb(117,125,129)"; //刻度文字颜色
this.FrameSplitTextFont=14*GetDevicePixelRatio() +"px 微软雅黑"; //坐标刻度文字字体
this.FrameTitleBGColor="rgb(246,251,253)"; //标题栏背景色
this.SelFrameBorderColor='rgb(130, 130, 130)';
this.Frame={
XBottomOffset:2*GetDevicePixelRatio(), //X轴文字向下偏移
YTopOffset:2*GetDevicePixelRatio(), //Y轴顶部文字向下偏移
YTextPadding:[2,2],
EnableRemoveZero:true, //移除小数点后面的0
StringFormat:0
};
this.ToolbarButtonStyle=0;
this.FrameLogo=
{
TextColor:'rgb(178,34,34)',
Font:"bold "+ 16*GetDevicePixelRatio() +"px 微软雅黑",
Text:"", //不要修改声明, 任何修改声明产生的任何法律责任由修改者自行独立承担,与HQChart插件作者无关。
BGColor:"rgba(230,230,230, 0.5)",
};
//百分比坐标文字颜色
this.Frame.PercentageText= {
PriceColor:'rgb(117,125,129)',
PercentageColor:"rgb(117,125,129)",
SplitColor:"rgb(117,125,129)",
Font:14*GetDevicePixelRatio() +"px 微软雅黑"
};
//对数坐标
this.FrameLogarithmic= {
OpenPriceFont: "bold "+14*GetDevicePixelRatio() +"px 微软雅黑", //开盘价刻度文字字体
MinInterval: 45*GetDevicePixelRatio() //刻度最小间距
};
//等比坐标
this.FrameSplitIncrease= {
Increase:0.1 //涨幅
};
//等分坐标
this.FrameSplitAverage= {
Count:4 //分割个数
};
//黄金分割坐标
this.FrameGoldenSection=
{
Golden:[0, 0.191, 0.382, 0.5, 0.618, 0.809, 1]
};
//Y轴最新价格刻度颜色
this.FrameLatestPrice =
{
TextColor:'rgb(255,255,255)', //最新价格文字颜色
UpBarColor:"rgb(238,21,21)", //上涨
DownBarColor:"rgb(25,158,0)", //下跌
UnchagneBarColor:"rgb(0,0,0)", //平盘
BGAlpha:0.6,
EmptyBGColor:"rgb(255,255,255)", //空心背景色
OverlayTextColor:"rgb(255,255,255)", //叠加股票的文字颜色
};
this.FrameMargin=4; //左右一共的边距
this.FrameLeftMargin=2;
this.FrameRightMargin=2;
this.DragSubFrameBorder= {
TopBorderHeight:6*GetDevicePixelRatio(), //拖拽边框高度
MinFrameHeight:50*GetDevicePixelRatio() //指标窗口最小高度
},
//叠加指标框架
this.OverlayFrame={
BolderPen:'rgb(190,190,190)', //指标边框线
TitleColor:'rgb(105,105,105)', //指标名字颜色
TitleFont:11*GetDevicePixelRatio() +'px arial', //指标名字字体
};
this.CorssCursorBGColor="rgb(43,54,69)"; //十字光标背景
this.CorssCursorTextColor="rgb(255,255,255)"; //十字光文字颜色
this.CorssCursorTextFont=14*GetDevicePixelRatio() +"px 微软雅黑";
this.CorssCursorHPenColor="rgb(130,130,130)"; //十字光标线段颜色(水平)
this.CorssCursorVPenColor="rgb(130,130,130)"; //十字光标线段颜色(垂直)
this.CorssCursorXRangeBGColor="rgba(100,149,237,0.3)"; //十字光标X轴访问背景色
this.CorssCursor=
{
RightButton :
{
BGColor:'rgb(43,54,69)',
PenColor:'rgb(255,255,255)',
Icon: { Text:'\ue6a3', Color:'rgb(255,255,255)', Family:"iconfont", Size:18 }
},
RightMargin: { Left:2, Right:2, Top:5, Bottom:3 }
};
this.LockBGColor = "rgb(220, 220, 220)"; //指标锁区域颜色
this.LockTextColor = "rgb(210, 34, 34)"; //指标锁提示信息文字颜色
this.Domain="http://127.0.0.1:8080"; //API域名
this.CacheDomain="http://127.0.0.1:8087"; //缓存域名
this.PyIndexDomain='http://127.0.0.1:8088'; //py指标计算域名
//K线配置
this.KLine=
{
MaxMin: {Font:12*GetDevicePixelRatio() +'px 微软雅黑',Color:'rgb(43,54,69)', RightArrow:"→", LeftArrow:"←", HighYOffset:0, LowYOffset:0}, //K线最大最小值显示
Info: //信息地雷
{
Investor:
{
ApiUrl:'/API/NewsInteract', //互动易
IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本
},
Announcement: //公告
{
ApiUrl:'/API/ReportList',
IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' }, //SVG 文本
IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' }, //SVG 文本 //季报
},
Pforecast: //业绩预告
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本
},
Research: //调研
{
ApiUrl:'/API/InvestorRelationsList',
IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本
},
BlockTrading: //大宗交易
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本
},
TradeDetail: //龙虎榜
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' } //SVG 文本
},
//扩展图标库
IconLibrary:
{
Family:'iconfont',
Icon:
[
{ Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' },
{ Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' },
{ Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' },
{ Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' }
]
},
},
NumIcon:
{
Color:'rgb(251,80,80)',Family:'iconfont',
Text:[ '\ue649',
'\ue63b','\ue640','\ue63d','\ue63f','\ue645','\ue641','\ue647','\ue648','\ue646','\ue636',
'\ue635','\ue637','\ue638','\ue639','\ue63a','\ue63c','\ue63e','\ue642','\ue644','\ue643'
]
},
TradeIcon: //交易指标 图标
{
Family:'iconfont',
Buy: { Color:'rgb(255,15,4)', Text:'\ue683', HScreenText:'\ue682'},
Sell: { Color:'rgb(64,122,22)', Text:'\ue681',HScreenText:'\ue680'},
}
};
this.VirtualKLine=
{
Color:'rgb(100,100,100)',
LineDash:[2,2]
};
this.PriceGapStyple=
{
Line:{ Color:"rgb(186,186,186)" },
Text:{ Color:"rgb(105,105,105)", Font:`${12*GetDevicePixelRatio()}px 微软雅黑`}
};
//订单流配置
this.OrderFlow=
{
UpColor:{BG:'rgb(223,191,180)', Border:"rgb(196,84,86)" }, //阳线
DownColor:{ BG:"rgb(176,212,184)", Border:'rgb(66,94,74)' }, //阴线
UnchagneColor: {BG:"rgb(216,221,177)", Border:"rgb(209,172,129)"}, //平盘
Text:{ Color: "rgb(92,96,89)" , Family:'Arial', FontMaxSize:18, MaxValue:"8888" }, //文字(风格 2,3共用)
Line:{ UpDownColor: "rgb(0,0,0)", MiddleColor:"rgb(211,211,211)" }, //最大, 最低,中间 竖线
AlwaysShowOrderText:true, //总是显示订单流文字
POCGBColor:"rgba(178,34,34,0.8)",
AskBarColor:'rgb(14,209,69)',
BidBarColor:'rgb(236,28,36)'
};
this.OrderFlow_Style2=
{
BarWidth:10,
UpColor:'rgb(241,55,63)',
DownColor:"rgb(75,105,150)",
UnchagneColor:"rgb(79,79,79)"
};
this.OrderFlow_Style3=
{
BarWidth:20,
UpColor:'rgb(241,55,63)',
DownColor:"rgb(75,105,150)",
UnchagneColor:"rgb(79,79,79)"
};
this.OrderFlow_Style4=
{
KBarWidth:5,
UpColor:'rgb(241,55,63)',
DownColor:"rgb(75,105,150)",
UnchagneColor:"rgb(79,79,79)",
VolBarSpace:1,
LeftMargin:1,
RightMargin:1
};
this.OrderFlow_Style5=
{
AskBarColor:"rgb(176,22,22)", //左
BidBarColor:"rgb(98,126,176)", //右
LeftMargin:3,
RightMargin:2,
};
this.Index={};
//指标线段颜色
this.Index.LineColor=
[
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
];
this.OverlaySymbol={ Random:0 }; //Random 颜色的随机数
this.OverlaySymbol.Color= //叠加股票颜色
[
"rgb(38,198,218)",
"rgb(103,58,183)",
"rgb(0,191,165)",
"rgb(130,177,255)",
];
//历史数据api
this.Index.StockHistoryDayApiUrl="http://127.0.0.1:8080/API/StockHistoryDay";
//市场多空
this.Index.MarketLongShortApiUrl="http://127.0.0.1:8080/API/FactorTiming";
//市场关注度
this.Index.MarketAttentionApiUrl="http://127.0.0.1:8080/API/MarketAttention";
//行业,指数热度
this.Index.MarketHeatApiUrl="http://127.0.0.1:8080/API/MarketHeat";
//自定义指数热度
this.Index.CustomIndexHeatApiUrl="http://127.0.0.1:8080/API/QuadrantCalculate";
//指标不支持信息
this.Index.NotSupport={Font:`${14*GetDevicePixelRatio()}px 微软雅黑`, TextColor:"rgb(52,52,52)"};
//按钮
this.Buttons=
{
CloseOverlayIndex:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue60c",
Size:12*GetDevicePixelRatio(),
MerginLeft:3
},
CloseWindow:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue60c",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
ChangeIndex:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue656",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
OverlayIndex:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue655",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
ModifyIndexParam:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue604",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
//最大化, 最小化
MaxMinWindow:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue6a5",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
//指标标题窗口模式
TitleWindow:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue6a6",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
//指标标题窗口模式
ExportData:
{
Color:"rgb(0,0,0)",
MoveOnColor:'rgb(30,144,255)',
Family:"iconfont",
Text:"\ue6a9",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
Tooltip:
{
Font:13*GetDevicePixelRatio() +"px 微软雅黑",
Color:'rgb(71,71,71)',
ColorBG:'rgb(255,255,255)',
ColorBorder:'rgb(0,0,0)',
BorderRadius:2,
Mergin:{ Left:4, Right:4, Top:2, Bottom:3 },
}
}
//画图工具
this.DrawPicture=
{
LineColor:
[
"rgb(41,98,255)"
],
PointColor:
[
"rgb(41,98,255)", //选中颜色
"rgb(89,135,255)", //moveon颜色
"rgb(255,255,255)" //空心点背景色
],
XYCoordinate:
{
BGColor:'rgba(203,216,255,0.5)', //区间段背景色
TextBGColor:"rgb(52,101,255)", //文字背景色
TextColor:"rgb(255,255,255)", //文字颜色
Font:14*GetDevicePixelRatio() +"px 微软雅黑" //文字字体
},
PointType:2, // 0=圆点 1=方框 2=空心圆
IsShowPoint:false //是否始终显示点
};
this.ChartOX=
{
Family:'iconfont',
Up:{Color:'rgb(178,34,34)', Text:"\ue697" },
Down:{Color:"rgb(0,206,209)", Text:"\ue68c" },
SquareLineColor:'rgb(119,136,153)'
};
this.KLineTrain = {
Font:'bold 14px arial',
LastDataIcon: {Color:'rgb(0,0,205)',Text:'⬇'},
BuyIcon: {Color:'rgb(0,205,102 )',Text:'B'},
SellIcon: {Color:'rgb(255,127,36 )',Text:'S'},
IconFont:
{
Family:'iconfont',
Buy:{ Text:'\ue64a', HScreenText:'\ue68a' ,Color:'rgb(255,140,0)' },
Sell:{ Text:'\ue64b', HScreenText:'\ue68a' ,Color:'rgb(6,79,18)' },
Last:{ Text:'\ue681', HScreenText:'\ue68a' ,Color:'rgb(55,0,255)' },
}
};
this.ChartKLineTable=
{
TextFont:{ Family:'Arial' , FontMaxSize:25 },
ItemMergin:{ Left:5, Right:5, Top:4, Bottom:2 },
};
//手机端tooltip
this.TooltipPaint = {
BGColor:'rgba(250,250,250,0.8)', //背景色
BorderColor:'rgb(120,120,120)', //边框颜色
TitleColor:'rgb(79, 79, 79)', //标题颜色
TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑', //字体
DateTimeColor:'rgb(105 105 105)',
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(79, 79, 79)", //成交金额
};
this.PCTooltipPaint =
{
BGColor:'rgba(250,250,250)', //背景色
BorderColor:'rgb(120,120,120)', //边框颜色
TitleColor:'rgb(60,60,60)', //标题颜色
TitleFont:12*GetDevicePixelRatio() +'px 微软雅黑', //字体
DateTimeColor:'rgb(60,60,60)',
VolColor:"rgb(60,60,60)", //标题成交量
AmountColor:"rgb(60,60,60)", //成交金额
PositionColor:"rgb(60,60,60)", //持仓量
};
this.PCTooltip= {
LineHeight:25 //单行高度
};
this.DialogTooltip=
{
BGColor:'rgb(250,250,250)', //背景色
BorderColor:'rgb(20,20,20)', //边框颜色
TitleColor:'rgb(250,250,250)', //标题颜色
TitleBGColor:"rgb(200, 66, 69)", //标题背景颜色
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(79, 79, 79)", //成交金额
DateTimeColor:'rgb(60,60,60)',
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)", //持仓
TextColor:"rgb(0,0,0)", //数值名称
ValueColor:"rgb(0,0,0)", //数值
};
this.FloatTooltip=
{
BGColor:'rgb(250,250,250)', //背景色
BorderColor:'rgb(20,20,20)', //边框颜色
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(79, 79, 79)", //成交金额
DateTimeColor:'rgb(60,60,60)',
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)", //持仓
TextColor:"rgb(0,0,0)", //数值名称
ValueColor:"rgb(0,0,0)", //数值
};
//区间统计
this.DialogSelectRect=
{
BGColor:'rgb(250,250,250)', //背景色
BorderColor:'rgb(20,20,20)', //边框颜色
TitleColor:'rgb(0,0,0)', //对话框标题颜色
TextColor:"rgb(0,0,0)", //数值名称
ValueColor:"rgb(0,0,0)", //数值
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(79, 79, 79)", //成交金额
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)" //持仓
};
//键盘精灵
this.DialogPopKeyboard=
{
BGColor:'rgb(250,250,250)', //背景色
BorderColor:'rgb(20,20,20)', //边框颜色
TitleColor:'rgb(0,0,0)', //对话框标题颜色
TitleBGColor:"rgb(200, 66, 69)", //标题背景颜色
Input:
{
BGColor:"rgb(250,250,250)",
TextColor:"rgb(0,0,0)",
}
};
//指标搜索
this.DialogSearchIndex=
{
BGColor:'rgb(250,250,250)', //背景色
BorderColor:'rgb(20,20,20)', //边框颜色
TitleColor:'rgb(250,250,250)', //标题颜色
TitleBGColor:"rgb(200, 66, 69)", //标题背景颜色
IndexNameColor:"rgb(0,0,0)", //数值名称
GroupNameColor:"rgb(0,0,0)",
InputTextColor:"rgb(0,0,0)"
};
//弹幕
this.Barrage= {
Font:16*GetDevicePixelRatio() +'px 微软雅黑', //字体
Height:20,
Color:'RGB(109,109,109)'
}
//走势图 信息地雷
this.MinuteInfo={
TextColor: 'rgb(84,143,255)',
Font: 14*GetDevicePixelRatio() +'px 微软雅黑',
PointColor:'rgb(38,113,254)',
LineColor:'rgb(120,167,255)',
TextBGColor:'rgba(255,255,255,0.8)',
PointRadius:4*GetDevicePixelRatio(), //圆点半径
}
//画图工具-尺子
this.ChartDrawRuler=
{
TitleColor:null, //K线信息标题颜色, (可选,不填使用涨跌颜色)
}
//画图工具-波浪尺
this.ChartDrawWaveRuler=
{
RulerWidth:10, //刻度尺长度
RulerLineWidth:1, //刻度线粗细
MaxScaleRuler:2, //尺子最大的高度比
Font:14*GetDevicePixelRatio() +"px 微软雅黑",
ScaleRuler:
[
{Value:0, Text:"0.0%"}, { Value:0.382, Text:"38.2%" }, { Value:0.618, Text:"61.8%" } ,{ Value:1, Text:"100%"},
{ Value:1.618, Text:"161.8%" }, { Value:2.0, Text:"200%" }
]
}
this.ChartDrawWaveRuler2Point=
{
RulerWidth:20, //刻度尺长度
RulerLineWidth:1, //刻度线粗细
MaxScaleRuler:2, //尺子最大的高度比
Font:14*GetDevicePixelRatio() +"px 微软雅黑",
ScaleRuler:
[
{Value:0, Text:"base"}, { Value:0.618, Text:"61.8%" } ,{ Value:1, Text:"100%"},
{ Value:1.618, Text:"161.8%" }
]
}
this.ChartDrawVolProfile=
{
BGColor:"rgba(244,250,254,0.8)",
BorderColor:"rgba(255,255,255)",
VolLineColor:"rgb(232,5,9)",
UpVolColor:"rgba(103,179,238, 0.24)",
DownVolColor:"rgba(237,208,105,0.24)",
AreaUpColor:"rgb(103,179,238,0.7)",
AreaDonwColor:"rgba(237,208,105,0.7)",
Text:{ Color: "rgb(0,0,0)" , Family:'Arial', FontMaxSize:18, FontMinSize:6 }, //文字
}
this.ChartVolProfileVisibleRange=
{
VolLineColor:"rgb(232,5,9)",
VolLineFont:14*GetDevicePixelRatio() +"px 微软雅黑",
VolLineTextColor:'rgb(255,255,255)',
UpVolColor:"rgba(103,179,238, 0.24)",
DownVolColor:"rgba(237,208,105,0.24)",
AreaUpColor:"rgb(103,179,238,0.7)",
AreaDonwColor:"rgba(237,208,105,0.7)",
Text:{ Color: "rgb(0,0,0)" , Family:'Arial', FontMaxSize:18, FontMinSize:6 }, //文字
VAHLineColor:'rgb(0,0,255)',
VAHTextColor:"rgb(255,255,255)",
VALLineColor:"rgb(0,0,255)",
VALTextColor:"rgb(255,255,255)",
VAFont:14*GetDevicePixelRatio() +"px 微软雅黑",
}
this.ChartDrawNote=
{
Text:"\ue6aa",
FontOption:{ Family:'iconfont', Size:32 },
NoteFontOption:{ Family:'微软雅黑', Size:12, Weight:null, Style:null }, //Weight(bold 粗体), Style(italic)
NoteWidth:200,
NoteMargin:{ Left:5, Top:5, Bottom:5, Right:5 },
NoteBGColor:'rgba(104,114,255,0.7)',
NoteTextColor:"rgb(240,240,240)",
NoteBorderColor:"rgb(220,220,220)",
LineSpace:3, //行间距
ArrowSize:10
}
this.ChartDrawAnchoredText=
{
TextMargin:{ Left:5, Top:5, Bottom:5, Right:5 },
BGColor:'rgba(104,114,255,0.7)',
BorderColor:"rgb(220,220,220)",
TextColor:'rgb(0,0,0)',
FontOption:{ Family:'微软雅黑', Size:12, Weight:null, Style:null }, //Weight(bold 粗体), Style(italic)
LineSpace:2, //行间距
TextMaxWidth:-1
}
this.ChartDrawPriceLabel=
{
TextMargin:{ Left:10, Top:5, Bottom:5, Right:10 },
BGColor:'rgba(104,114,255,0.7)',
BorderColor:"rgb(220,220,220)",
TextColor:'rgb(0,0,0)',
FontOption:{ Family:'微软雅黑', Size:14, Weight:null, Style:null }, //Weight(bold 粗体), Style(italic)
}
this.ChartDrawPriceNote=
{
TextMargin:{ Left:10, Top:5, Bottom:5, Right:10 },
BGColor:'rgba(104,114,255,0.7)',
BorderColor:"rgb(220,220,220)",
TextColor:'rgb(0,0,0)',
FontOption:{ Family:'微软雅黑', Size:14, Weight:null, Style:null }, //Weight(bold 粗体), Style(italic)
}
//多图标指标ChartMultiSVGIcon -> MULTI_SVGICON
//单图标指标ChartSingleText -> DRAWICON
this.DRAWICON=
{
Icon:
{
MaxSize:24, //图标最大
MinSize:12, //图标最小
YOffset:0,
Zoom:
{
Type:1, //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
Value:1
}
},
Text:
{
MaxSize:50, //字体最大
MinSize:12, //字体最小
YOffset:0,
Zoom:
{
Type:1, //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
Value:1
},
FontName:'Arial' //字体
}
}
this.DRAWTEXT=
{
MaxSize:30, //字体最大
MinSize:20, //字体最小
YOffset:0,
Zoom:
{
Type:1, //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
Value:1
},
FontName:'微软雅黑' //字体
}
this.DRAWNUMBER=
{
MaxSize:30, //字体最大
MinSize:20, //字体最小
YOffset:0,
Zoom:
{
Type:1, //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
Value:1
},
FontName:'微软雅黑' //字体
}
this.DRAWABOVE=
{
YOffset:0 //y坐标向上偏移
}
this.DRAWTEXT_FIX={ Font:14*GetDevicePixelRatio() +'px 微软雅黑' }
this.DRAWNUMBER_FIX={ Font:14*GetDevicePixelRatio() +'px 微软雅黑' }
//虚线配置
this.DOTLINE=
{
LineDash:[3,5] //虚线配置
}
this.DRAWSL=
{
PixelWidth:15 //1个像素点宽度
}
this.CIRCLEDOT=
{
Radius:1.3*GetDevicePixelRatio()
}
this.TIPICON=
{
Family:'iconfont',
TextFont:`${GetDevicePixelRatio()}px 微软雅黑`,
Size:10*GetDevicePixelRatio(),
Color:"rgb(255,165,0)"
}
this.POINTDOT=
{
Radius:2*GetDevicePixelRatio()
}
this.DepthMapPaint=
{
LineColor:"rgba(255,185,15)",
AreaColor:["rgba(255,185,15,0.8)","rgba(255,185,15,0.4)"],
TextColor:"rgba(255,255,255)",
TextBGColor:'rgb(43,54,69)'
}
this.KLineYAxisBGPaint=
{
Font:12*GetDevicePixelRatio() +'px 微软雅黑',
LineColor:"rgb(117,125,129)",
DiffValutTextColor:"rgb(117,125,129)",
DiffValueBGColor:"rgb(251,140,1)"
}
//筹码分布图
this.StockChip=
{
InfoColor:'rgb(0,0,0)', //文字颜色
DayInfoColor:'rgb(255,255,255)', //周期颜色内文字颜色
DefaultButton:
{
Color:"rgb(128,128,128)",
MoveOnColor:'rgb(30,144,255)',
SelectedColor:"rgb(255,0,0)",
Family:"iconfont",
Text:"\ue621",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
LongButton:
{
Color:"rgb(128,128,128)",
MoveOnColor:'rgb(30,144,255)',
SelectedColor:"rgb(255,128,0)",
Family:"iconfont",
Text:"\ue617",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
RecentButton:
{
Color:"rgb(128,128,128)",
MoveOnColor:'rgb(30,144,255)',
SelectedColor:"rgb(0,0,204)",
Family:"iconfont",
Text:"\ue617",
Size:13*GetDevicePixelRatio(),
MerginLeft:4
},
}
//深度图
this.DepthChart=
{
BidColor: { Line:"rgb(82,176,123)", Area:"rgba(82,176,123,0.8)"}, //卖
AskColor: { Line:"rgb(207,76,89)", Area:"rgba(207,76,89, 0.8)"}, //买
LineWidth:4
}
this.DepthCorss=
{
BidColor: { Line:"rgb(82,176,123)" }, //卖
AskColor: { Line:"rgb(207,76,89)" }, //买
LineWidth:2, //线段宽度
LineDash:[3,3],
Tooltip:
{
BGColor:'rgba(236,240,245, 0.8)', TextColor:"rgb(130,140,151)",
Border:{ Top:5, Left:20, Right:20, Bottom:5, ItemSpace:5 },
Font:14*GetDevicePixelRatio() +"px 微软雅黑",
}
}
//区间选择
this.RectSelect=
{
LineColor:"rgb(64,64,64)", //竖线
LineWidth:1*GetDevicePixelRatio(),
LineDotted:[3,3],
AreaColor:"rgba(234,234,234,0.5)", //面积
SubAreaColor:"rgba(105,105,105,0.5)",
RangeTextColor:"rgb(248,248,255)",
RangeTextFont:14*GetDevicePixelRatio() +"px 微软雅黑",
RangeTextBGColor:'rgb(43,54,69)',
RangeTextSubColor:"rgb(255,255,255)",
RangeTextSubFont:12*GetDevicePixelRatio() +"px 微软雅黑",
RangeTextSubBGColor:'rgb(54,54,54)',
Mark:{ Family:'iconfont', Text:'\ue695' , Color:'rgb(250,0,0)', Size:15*GetDevicePixelRatio(), Position:{ Index:0, Top:"TopEx" } }
}
//选中图形
this.SelectedChart=
{
LineWidth:1,
LineColor:'rgb(55,100,100)',
Radius:4,
MinSpace:200, //点和点间最小间距
BGColor:"rgb(255,255,255)"
}
//鼠标区间选中
this.RectDrag=
{
LineColor:"rgb(0,0,0)", //竖线
LineWidth:1*GetDevicePixelRatio(),
BGColor:"rgba(128,128,128,0.2)", //面积
}
this.DragMovePaint=
{
TextColor:"rgb(0,0,0)",
Font:14*GetDevicePixelRatio() +"px 微软雅黑"
}
this.SessionBreaksPaint=
{
BGColor:[null, "rgb(245,246,246)"],
SplitLine:{ Color:'rgb(73,133,231)', Width:1*GetDevicePixelRatio(), Dash:[5*GetDevicePixelRatio(),5*GetDevicePixelRatio()] }
}
//成交明细
this.DealList=
{
BorderColor:'rgb(192,192,192)', //边框线
Header:
{
Color:"RGB(60,60,60)",
Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
Font:{ Size:12, Name:"微软雅黑" }
},
Row:
{
Mergin:{ Top:2, Bottom:2 },
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 }
},
FieldColor:
{
Vol:"rgb(90,90,90)", //成交量
Time:"rgb(60,60,60)", //时间
Deal:"rgb(90,90,90)", //成交笔数
Index:"rgb(60,60,60)", //序号
BarTitle:'rgb(60,60,60)', //柱子文字
Text:"rgb(60,60,60)", //默认文本
Bar:
[
"rgb(255,0,0)", "rgb(34,139,34)", "rgb(119,136,153)","rgb(75,0,130)",
"rgb(65,105,225)","rgb(255,215,0)", 'rgb(255,0,255)', "rgb(128,128,0)"
] //柱子颜色
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchagneTextColor:"rgb(0,0,0)" //平盘文字颜色
},
//报价列表
this.Report=
{
BorderColor:'rgb(192,192,192)', //边框线
SelectedColor:"rgb(180,240,240)", //选中行
Header:
{
Color:"rgb(60,60,60)", //表头文字颜色
SortColor:"rgb(255,0,0)", //排序箭头颜色
Mergin:{ Left:5, Right:5, Top:4, Bottom:4 }, //表头四周间距
Font:{ Size:12, Name:"微软雅黑" }, //表头字体
},
//排序图标
SortIcon:
{
Size:12, Family:"iconfont",
Arrow:[null, "\ue6b2", "\ue6b1"],
Color:[null, "rgb(255,0,0)", "rgb(255,0,0)"],
Margin:{ Left:0, Bottom:6 }
},
Item:
{
Mergin:{ Top:2, Bottom:4,Left:5, Right:5 }, //单元格四周间距
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 },//单元格字体
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" },
},
//固定行
FixedItem:
{
Font:{ Size:15, Name:"微软雅黑"},
},
LimitBorder:
{
Color:"rgb(180,180,180)",
Mergin:{ Top:1, Bottom:1,Left:0, Right:0 },
},
NameSymbolV2:
{
Name:{ Size:14, Name:"微软雅黑", Color: "rgb(60,60,60)"},
Symbol:{ Size:10, Name:"微软雅黑", Color: "rgb(105 105 105)"},
},
//涨停 跌停背景色
LimitColor:
{
UpColor:"rgb(255,0,0)",
DownColor:"rgb(0,128,0)",
TextColor:"rgb(250,250,250)",
},
FieldColor:
{
Index:"rgb(60,60,60)", //序号
Symbol:"rgb(60,60,60)",
Name:"rgb(60,60,60)",
Vol:"rgb(90,90,90)", //成交量
Amount:"rgb(90,90,90)", //成交金额
Text:"rgb(60,60,60)", //默认文本
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchagneTextColor:"rgb(90,90,90)", //平盘文字颜色
CloseLine:
{
CloseColor:"rgb(30,144,255)",
YCloseColor:"rgba(105,105,105,0.5)", //昨收线
AreaColor:'rgba(0,191,255,0.2)',
},
KLine:
{
UpColor:"rgb(255,0,0)",
DownColor:"rgb(0,128,0)",
UnchagneColor:'rgb(90,90,90)',
DataWidth:16,
DistanceWidth:3
},
Tab:
{
Font:{ Size:12, Name:"微软雅黑" },
ScrollBarWidth:100,
ButtonColor:"rgb(252,252,252)",
BarColor:"rgb(180,180,180)",
BorderColor:'rgb(180,180,180)',
Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
TabTitleColor:'rgb(60,60,60)',
TabSelectedTitleColor:'rgb(255,255,255)',
TabSelectedBGColor:"rgb(234,85,4)",
TabMoveOnTitleColor:"rgb(234,85,4)",
TabBGColor:"rgb(220,220,220)"
},
PageInfo:
{
Font:{ Size:15, Name:"微软雅黑"},
TextColor:"rgb(0,0,0)",
BGColor:"rgba(180,180,180,0.5)",
Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
},
DragRow:
{
Color:"rgba(190,190,190,0.8)",
TextColor:'rgba(0,0, 0, 0.8)',
MoveRowColor:'rgb(240,128,128)',
SrcRowColor:'rgb(180,240,240)',
},
VScrollbar:
{
ScrollBarHeight:60,
ButtonColor:"rgba(252,252,252,0.8)",
BarColor:"rgba(168,168,168,0.9)",
BorderColor:'rgba(180,180,180,0.9)',
BGColor:"rgba(234,239,248,0.9)",
BarWidth:{ Size:12 }
},
CheckBox:
{
Family:"iconfont", Size:15,
Checked:{ Color:"rgb(69,147,238)", Symbol:"\ue6b3", DisableColor:"rgb(230,230,230)", MouseOnColor:"rgb(69,147,238)" },
Unchecked:{ Color:"rgb(120,120,120)", Symbol:"\ue6b4", DisableColor:"rgb(230,230,230)", MouseOnColor:"rgb(69,147,238)" },
Margin:{ Left:5, Right:5, Bottom:2, Top:4 },
},
Link:
{
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
TextColor:"rgb(30,144,255)",
Disable:{ TextColor:"rgb(211,211,211)" },
MouseOn:{ TextColor:"rgb(30,144,255)" },
},
ProgressBar:
{
BGColor:"rgb(229,231,238)",
BarColor:"rgb(26,125,255)",
Margin:{ Left:2, Right:2, Bottom:2, Top:2 },
BarMargin:{ Left:2, Right:2, Bottom:2, Top:2 },
TextColor:"rgb(0,0,0)",
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
TextMargin:{ Left:40, Right:2, Bottom:2, Top:2},
Disable:{ BGColor:"rgb(229,231,238)", BarColor:"rgb(131,131,131)", TextColor:"rgb(159,161,159)"}
},
Button:
{
BGColor:"rgb(61,134,180)",
TextColor:"rgb(255,255,255)",
BorderColor:"rgb(200,200,200)",
Disable:{ BGColor:"rgb(105,105,105)", TextColor:"rgb(169,169,169)"},
MouseOn:{ BGColor:"rgb(57,125,169)", TextColor:"rgb(230,230,230)" },
Margin:{ Left:5, Right:5, Bottom:2, Top:2 },
TextMargin:{ Bottom:2 },
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`
}
},
//报价列表
this.TReport=
{
BorderColor:'rgb(192,192,192)', //边框线
SelectedColor:"rgb(3,89,245)", //选中行
Header:
{
Color:"rgb(60,60,60)", //表头文字颜色
SortColor:"rgb(255,0,0)", //排序箭头颜色
Mergin:{ Left:5, Right:5, Top:4, Bottom:2}, //表头四周间距
Font:{ Size:14, Name:"微软雅黑" } //表头字体
},
Item:
{
Mergin:{ Top:2, Bottom:0,Left:5, Right:5 }, //单元格四周间距
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 },//单元格字体
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" }
},
//固定行
FixedItem:
{
Font:{ Size:15, Name:"微软雅黑"},
},
CenterItem:
{
TextColor:"rgb(60,60,83)",
BaseTextColor:"rgb(60,60,83)",
BGColor:"rgb(180,180,180)"
},
FieldColor:
{
Index:"rgb(60,60,60)", //序号
Symbol:"rgb(60,60,60)",
Name:"rgb(60,60,60)",
Vol:"rgb(90,90,90)", //成交量
Position:"rgb(90,90,90)", //持仓量
Amount:"rgb(90,90,90)", //成交金额
Text:"rgb(60,60,60)", //默认文本
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchangeTextColor:"rgb(90,90,90)", //平盘文字颜色
UpBGColor:"rgb(255,220,220)",
DownBGColor:"rgb(190,220,190)",
MarkBorder:
{
MaxPositionColor:"rgb(192,192,192)"
},
},
//键盘精灵
this.Keyboard=
{
BorderColor:'rgb(192,192,192)', //边框线
SelectedColor:"rgb(180,240,240)", //选中行
TextColor:"rgb(0,0,0)",
Item:
{
Mergin:{ Top:2, Bottom:0,Left:1, Right:1 }, //单元格四周间距
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:0, Right:0, Bottom:2 },//单元格字体
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" }
},
VScrollbar:
{
ScrollBarHeight:50,
ButtonColor:"rgba(252,252,252,0.8)",
BarColor:"rgba(168,168,168,0.9)",
BorderColor:'rgba(180,180,180,0.9)',
BGColor:"rgba(234,239,248,0.9)",
BarWidth:{ Size:8 }
},
},
//滚动条
this.ScrollBar=
{
BorderColor:'rgb(192,192,192)',
XSplitTextFont:`${12*GetDevicePixelRatio()}px 微软雅黑`,
XSplitTextColor:"rgb(0,0,0)",
XSplitLineColor:"rgba(0,0,0,0.8)",
BGChart:
{
Color:"rgb(135,206,250)",
LineWidth:1,
AreaColor:"rgba(135,206,250,0.5)",
},
Slider:
{
DateFont:`${14*GetDevicePixelRatio()}px 微软雅黑`,
DateColor:'rgb(0,0,0)',
BarColor:"rgb(207,207,207)",
BarAreaColor:"rgba(232,232,232,0.65)",
BarWidth:10,
BarPadding:15, //上下留白
MinCenterWidth:15
}
},
this.FrameButtomToolbar=
{
BGColor:"rgb(235,235,235)",
BorderColor:"rgb(204,204,204)",
Button:
{
Font:{ Family:"微软雅黑", Size:12*GetDevicePixelRatio() },
TitleColor: { Selected:"rgb(255,255,255)", Default:"rgb(125,125,125)", MoveOn:"rgb(234,85,4)" },
BGColor: { Selected:"rgb(234,85,4)", Default:"rgb(235,235,235)", MoveOn:"rgb(242,242,242)" },
BorderColor:"rgb(204,204,204)",
Mergin: { Left:5*GetDevicePixelRatio(), Right:5*GetDevicePixelRatio(), Top:4*GetDevicePixelRatio(), Bottom:2*GetDevicePixelRatio() },
SVG:{ Family:"iconfont", Size:12*GetDevicePixelRatio(), MerginLeft:4*GetDevicePixelRatio() }
}
}
//自定义风格
this.SetStyle=function(style)
{
var T_SetButtonStyle=function(item, dest)
{
if (!item) return;
if (item.Color) dest.Color=item.Color;
if (item.MoveOnColor) dest.MoveOnColor=item.MoveOnColor;
if (item.SelectedColor) dest.SelectedColor=item.SelectedColor;
if (item.Family) dest.Family=item.Family;
if (item.Text) dest.Text=item.Text;
if (IFrameSplitOperator.IsNumber(item.Size)) dest.Size=item.Size;
if (IFrameSplitOperator.IsNumber(item.MerginLeft)) dest.MerginLeft=item.MerginLeft;
}
if (style.TooltipBGColor) this.TooltipBGColor = style.TooltipBGColor;
if (style.TooltipAlpha) this.TooltipAlpha = style.TooltipAlpha;
if (style.SelectRectBGColor) this.SelectRectBGColor = style.SelectRectBGColor;
if (style.UpBarColor) this.UpBarColor = style.UpBarColor;
if (style.DownBarColor) this.DownBarColor = style.DownBarColor;
if (style.UnchagneBarColor) this.UnchagneBarColor = style.UnchagneBarColor;
if (style.EmptyBarBGColor) this.EmptyBarBGColor=style.EmptyBarBGColor;
if (style.HighLowBarColor) this.HighLowBarColor=style.HighLowBarColor;
if (style.HighLowText)
{
var dest=this.HighLowText;
var item=style.HighLowText;
if (item.FontName) dest.FontName=item.FontName;
if (item.Color) dest.Color=item.Color;
if (item.MaxText) dest.MaxText=item.MaxText;
if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) dest.MaxSize=item.MaxSize;
if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) dest.MinSize=item.MinSize;
}
if (style.SplashScreen)
{
var item=style.SplashScreen;
if (item.BGColor) this.SplashScreen.BGColor=item.BGColor;
if (item.Title) this.SplashScreen.Title=item.Title;
if (item.TextColor) this.SplashScreen.TextColor=item.TextColor;
if (item.Font) this.SplashScreen.Font=item.Font;
}
if (style.HLCArea)
{
var item=style.HLCArea;
if (item.HighLineColor) this.HLCArea.HighLineColor=item.HighLineColor;
if (item.LowLineColor) this.HLCArea.LowLineColor=item.LowLineColor;
if (item.CloseLineColor) this.HLCArea.CloseLineColor=item.CloseLineColor;
if (item.UpAreaColor) this.HLCArea.UpAreaColor=item.UpAreaColor;
if (item.DownAreaColor) this.HLCArea.DownAreaColor=item.DownAreaColor;
if (IFrameSplitOperator.IsNumber(item.LineWidth)) this.HLCArea.LineWidth=item.LineWidth;
}
if (style.Minute)
{
if (style.Minute.VolBarColor) this.Minute.VolBarColor = style.Minute.VolBarColor;
if (style.Minute.VolTitleColor) this.Minute.VolTitleColor = style.Minute.VolTitleColor;
if (style.Minute.PriceColor) this.Minute.PriceColor = style.Minute.PriceColor;
if (IFrameSplitOperator.IsNumber(style.Minute.PriceLineWidth)) this.Minute.PriceLineWidth=style.Minute.PriceLineWidth;
if (style.Minute.AvPriceColor) this.Minute.AvPriceColor = style.Minute.AvPriceColor;
if (style.Minute.AreaPriceColor) this.Minute.AreaPriceColor = style.Minute.AreaPriceColor;
if (style.Minute.PositionColor) this.Minute.PositionColor = style.Minute.PositionColor;
if (style.Minute.FrameSplitTextColor) this.Minute.FrameSplitTextColor = style.Minute.FrameSplitTextColor;
if (style.Minute.Before)
{
var item=style.Minute.Before;
if (item.BGColor) this.Minute.Before.BGColor=item.BGColor;
if (item.LineColor) this.Minute.Before.LineColor=item.LineColor;
if (item.VolColor) this.Minute.Before.VolColor=item.VolColor;
if (item.AvPriceColor) this.Minute.Before.AvPriceColor=item.AvPriceColor;
if (item.CloseIcon) T_SetButtonStyle(item.CloseIcon, this.Minute.Before.CloseIcon);
if (item.Point)
{
if (item.Point.Color) this.Minute.Before.Point.Color=item.Point.Color;
if (item.Point.Radius) this.Minute.Before.Point.Radius=item.Point.Radius;
}
}
if (style.Minute.After)
{
var item=style.Minute.After;
if (item.BGColor) this.Minute.After.BGColor=item.BGColor;
if (item.LineColor) this.Minute.After.LineColor=item.LineColor;
if (item.VolColor) this.Minute.After.VolColor=item.VolColor;
if (item.AvPriceColor) this.Minute.After.AvPriceColor=item.AvPriceColor;
if (item.Point)
{
if (item.Point.Color) this.Minute.After.Point.Color=item.Point.Color;
if (item.Point.Radius) this.Minute.After.Point.Radius=item.Point.Radius;
}
}
if (style.Minute.NightDay)
{
var item=style.Minute.NightDay;
if (item.NightBGColor) this.Minute.NightDay.NightBGColor=item.NightBGColor;
if (item.Font) this.Minute.NightDay.Font=item.Font;
if (item.Day)
{
var subItem=item.Day;
if (subItem.Color) this.Minute.NightDay.Day.Color=subItem.Color;
if (subItem.BGColor) this.Minute.NightDay.Day.BGColor=subItem.BGColor;
if (subItem.BorderColor) this.Minute.NightDay.Day.BorderColor=subItem.BorderColor;
CopyMarginConfig(this.Minute.NightDay.Day.Margin,subItem.Margin);
}
if (item.Night)
{
var subItem=item.Night;
if (subItem.Color) this.Minute.NightDay.Night.Color=subItem.Color;
if (subItem.BGColor) this.Minute.NightDay.Night.BGColor=subItem.BGColor;
if (subItem.BorderColor) this.Minute.NightDay.Night.BorderColor=subItem.BorderColor;
CopyMarginConfig(this.Minute.NightDay.Night.Margin,subItem.Margin);
}
}
}
if (style.PopMinuteChart)
{
var item=style.PopMinuteChart;
if (item.BGColor) this.PopMinuteChart.BGColor=item.BGColor;
if (item.BorderColor) this.PopMinuteChart.BorderColor=item.BorderColor;
}
if (style.DefaultTextColor) this.DefaultTextColor = style.DefaultTextColor;
if (style.DefaultTextFont) this.DefaultTextFont = style.DefaultTextFont;
if (style.TitleFont) this.TitleFont = style.TitleFont;
if (style.IndexTitleBGColor) this.IndexTitleBGColor=style.IndexTitleBGColor;
if (style.IndexTitleBorderColor) this.IndexTitleBorderColor=style.IndexTitleBorderColor;
if (style.IndexTitleBorderMoveOnColor) this.IndexTitleBorderMoveOnColor=style.IndexTitleBorderMoveOnColor;
if (IFrameSplitOperator.IsNumber(style.IndexTitleBorderStyle)) this.IndexTitleBorderStyle=style.IndexTitleBorderStyle;
if (style.IndexTitleColor) this.IndexTitleColor=style.IndexTitleColor;
if (style.IndexTitleSelectedColor) this.IndexTitleSelectedColor=style.IndexTitleSelectedColor;
if (style.OverlayIndexTitleBGColor) this.OverlayIndexTitleBGColor=style.OverlayIndexTitleBGColor;
if (style.UpTextColor) this.UpTextColor = style.UpTextColor;
if (style.DownTextColor) this.DownTextColor = style.DownTextColor;
if (style.UnchagneTextColor) this.UnchagneTextColor = style.UnchagneTextColor;
if (style.CloseLineColor) this.CloseLineColor = style.CloseLineColor;
if (style.CloseLineAreaColor) this.CloseLineAreaColor = style.CloseLineAreaColor;
if (style.CloseLineWidth) this.CloseLineWidth=style.CloseLineWidth;
if (style.FrameBorderPen) this.FrameBorderPen = style.FrameBorderPen;
if (style.MultiDayBorderPen) this.MultiDayBorderPen = style.MultiDayBorderPen;
if (style.FrameSplitPen) this.FrameSplitPen = style.FrameSplitPen;
if (style.FrameDotSplitPen) this.FrameDotSplitPen = style.FrameDotSplitPen;
if (style.FrameSplitTextColor) this.FrameSplitTextColor = style.FrameSplitTextColor;
if (style.FrameSplitTextFont) this.FrameSplitTextFont = style.FrameSplitTextFont;
if (style.FrameTitleBGColor) this.FrameTitleBGColor = style.FrameTitleBGColor;
if (style.SelFrameBorderColor) this.SelFrameBorderColor=style.SelFrameBorderColor;
if (IFrameSplitOperator.IsNumber(style.IndexTitleMerginLeft)) this.IndexTitleMerginLeft = style.IndexTitleMerginLeft;
if (style.IndexTitle)
{
var item=style.IndexTitle;
if (item.UpDownArrow)
{
var subItem=item.UpDownArrow;
if (subItem.UpColor) this.IndexTitle.UpDownArrow.UpColor = subItem.UpColor;
if (subItem.DownColor) this.IndexTitle.UpDownArrow.DownColor = subItem.DownColor;
if (subItem.UnchangeColor) this.IndexTitle.UpDownArrow.UnchangeColor = subItem.UnchangeColor;
}
if (IFrameSplitOperator.IsNumber(item.ArrowType)) this.IndexTitle.ArrowType=item.ArrowType;
if (IFrameSplitOperator.IsBool(item.EnableIndexArrow)) this.IndexTitle.EnableIndexArrow=item.EnableIndexArrow;
if (item.NameArrow)
{
var subItem=item.NameArrow;
if (subItem.Color) this.IndexTitle.NameArrow.Color = subItem.Color;
if (subItem.Symbol) this.IndexTitle.NameArrow.Symbol = subItem.Symbol;
if (IFrameSplitOperator.IsNumber(subItem.Space)) this.IndexTitle.NameArrow.Space = subItem.Space;
}
}
if (style.Frame)
{
if (style.Frame.XBottomOffset) this.Frame.XBottomOffset=style.Frame.XBottomOffset;
if (style.Frame.YTopOffset) this.Frame.YTopOffset=style.Frame.YTopOffset;
if (style.Frame.PercentageText)
{
var item=style.Frame.PercentageText;
if (item.PriceColor) this.Frame.PercentageText.PriceColor=item.PriceColor;
if (item.PercentageColor) this.Frame.PercentageText.PercentageColor=item.PercentageColor;
if (item.SplitColor) this.Frame.PercentageText.SplitColor=item.SplitColor;
if (item.Font) this.Frame.PercentageText.Font=item.Font;
}
}
if (IFrameSplitOperator.IsNumber(style.ToolbarButtonStyle)) this.ToolbarButtonStyle=style.ToolbarButtonStyle;
if (IFrameSplitOperator.IsBool(style.IsDOMFrameTitle)) this.IsDOMFrameTitle=style.IsDOMFrameTitle;
if (style.FrameLatestPrice)
{
var item=style.FrameLatestPrice;
if (style.FrameLatestPrice.TextColor) this.FrameLatestPrice.TextColor = style.FrameLatestPrice.TextColor;
if (style.FrameLatestPrice.UpBarColor) this.FrameLatestPrice.UpBarColor = style.FrameLatestPrice.UpBarColor;
if (style.FrameLatestPrice.DownBarColor) this.FrameLatestPrice.DownBarColor = style.FrameLatestPrice.DownBarColor;
if (style.FrameLatestPrice.UnchagneBarColor) this.FrameLatestPrice.UnchagneBarColor = style.FrameLatestPrice.UnchagneBarColor;
if (style.FrameLatestPrice.BGAlpha) this.FrameLatestPrice.BGAlpha = style.FrameLatestPrice.BGAlpha;
if (style.FrameLatestPrice.OverlayTextColor) this.FrameLatestPrice.OverlayTextColor = style.FrameLatestPrice.OverlayTextColor;
if (item.EmptyBGColor) this.FrameLatestPrice.EmptyBGColor = item.EmptyBGColor;
}
if (style.OverlayFrame)
{
var item=style.OverlayFrame;
if (style.OverlayFrame.BolderPen) this.OverlayFrame.BolderPen = style.OverlayFrame.BolderPen;
if (style.OverlayFrame.TitleColor) this.OverlayFrame.TitleColor = style.OverlayFrame.TitleColor;
if (style.OverlayFrame.TitleFont) this.OverlayFrame.TitleFont = style.OverlayFrame.TitleFont;
}
if (style.CorssCursorBGColor) this.CorssCursorBGColor = style.CorssCursorBGColor;
if (style.CorssCursorTextColor) this.CorssCursorTextColor = style.CorssCursorTextColor;
if (style.CorssCursorTextFont) this.CorssCursorTextFont = style.CorssCursorTextFont;
if (style.CorssCursorVPenColor) this.CorssCursorVPenColor = style.CorssCursorVPenColor;
if (style.CorssCursorHPenColor) this.CorssCursorHPenColor = style.CorssCursorHPenColor;
if (style.CorssCursorBorderColor) this.CorssCursorBorderColor=style.CorssCursorBorderColor;
if (style.CorssCursorXRangeBGColor) this.CorssCursorXRangeBGColor=style.CorssCursorXRangeBGColor;
if (style.CorssCursor && style.CorssCursor.RightButton)
{
var item=style.CorssCursor.RightButton;
if (item.BGColor) this.CorssCursor.RightButton.BGColor=item.BGColor;
if (item.PenColor) this.CorssCursor.RightButton.PenColor=item.PenColor;
if (item.Icon) this.CorssCursor.RightButton.Icon=item.Icon;
}
if (style.KLine) this.KLine = style.KLine;
if (style.VirtualKLine)
{
var item=style.VirtualKLine;
if (item.Color) this.VirtualKLine.Color=item.Color;
if (item.LineDash) this.VirtualKLine.LineDash=item.LineDash;
}
if (style.PriceGapStyple)
{
var item=style.PriceGapStyple;
if (item.Line && item.Line.Color) this.PriceGapStyple.Line.Color=item.Line.Color;
if (item.Text)
{
if (item.Text.Color) this.PriceGapStyple.Text.Color=item.Text.Color;
if (item.Text.Font) this.PriceGapStyple.Text.Font=item.Text.Font;
}
}
if (style.Index)
{
if (style.Index.LineColor) this.Index.LineColor = style.Index.LineColor;
if (style.Index.NotSupport) this.Index.NotSupport = style.Index.NotSupport;
}
if (style.ColorArray) this.ColorArray = style.ColorArray;
if (style.DrawPicture)
{
var item=style.DrawPicture;
if (item.LineColor) this.DrawPicture.LineColor = item.LineColor;
if (item.PointColor) this.DrawPicture.PointColor = item.PointColor;
if (item.XYCoordinate) this.DrawPicture.XYCoordinate=item.XYCoordinate;
if (IFrameSplitOperator.IsNumber(item.PointType)) this.DrawPicture.PointType=item.PointType;
if (IFrameSplitOperator.IsBool(item.IsShowPoint)) this.DrawPicture.IsShowPoint=item.IsShowPoint;
}
if (style.TooltipPaint)
{
if (style.TooltipPaint.BGColor) this.TooltipPaint.BGColor=style.TooltipPaint.BGColor;
if (style.TooltipPaint.BorderColor) this.TooltipPaint.BorderColor=style.TooltipPaint.BorderColor;
if (style.TooltipPaint.TitleColor) this.TooltipPaint.TitleColor=style.TooltipPaint.TitleColor;
if (style.TooltipPaint.TitleFont) this.TooltipPaint.TitleFont=style.TooltipPaint.TitleFont;
if (style.TooltipPaint.DateTimeColor) this.TooltipPaint.DateTimeColor=style.TooltipPaint.DateTimeColor;
if (style.TooltipPaint.VolColor) this.TooltipPaint.VolColor=style.TooltipPaint.VolColor;
if (style.TooltipPaint.AmountColor) this.TooltipPaint.AmountColor=style.TooltipPaint.AmountColor;
}
if (style.PCTooltipPaint)
{
var item=style.PCTooltipPaint;
if (item.BGColor) this.PCTooltipPaint.BGColor=item.BGColor;
if (item.BorderColor) this.PCTooltipPaint.BorderColor=item.BorderColor;
if (item.TitleColor) this.PCTooltipPaint.TitleColor=item.TitleColor;
if (item.TitleFont) this.PCTooltipPaint.TitleFont=item.TitleFont;
if (item.DateTimeColor) this.PCTooltipPaint.DateTimeColor=item.DateTimeColor;
if (item.VolColor) this.PCTooltipPaint.VolColor=item.VolColor;
if (item.AmountColor) this.PCTooltipPaint.AmountColor=item.AmountColor;
if (item.PositionColor) this.PCTooltipPaint.PositionColor=item.PositionColor;
}
if (style.DialogTooltip)
{
var item=style.DialogTooltip;
if (item.BGColor) this.DialogTooltip.BGColor=item.BGColor;
if (item.BorderColor) this.DialogTooltip.BorderColor=item.BorderColor;
if (item.TitleColor) this.DialogTooltip.TitleColor=item.TitleColor;
if (item.TitleBGColor) this.DialogTooltip.TitleBGColor=item.TitleBGColor;
if (item.DateTimeColor) this.DialogTooltip.DateTimeColor=item.DateTimeColor;
if (item.VolColor) this.DialogTooltip.VolColor=item.VolColor;
if (item.AmountColor) this.DialogTooltip.AmountColor=item.AmountColor;
if (item.TurnoverRateColor) this.DialogTooltip.TurnoverRateColor=item.TurnoverRateColor;
if (item.PositionColor) this.DialogTooltip.PositionColor=item.PositionColor;
if (item.TextColor) this.DialogTooltip.TextColor=item.TextColor;
if (item.ValueColor) this.DialogTooltip.ValueColor=item.ValueColor;
}
if (style.FloatTooltip)
{
var item=style.FloatTooltip;
if (item.BGColor) this.FloatTooltip.BGColor=item.BGColor;
if (item.BorderColor) this.FloatTooltip.BorderColor=item.BorderColor;
if (item.DateTimeColor) this.FloatTooltip.DateTimeColor=item.DateTimeColor;
if (item.VolColor) this.FloatTooltip.VolColor=item.VolColor;
if (item.AmountColor) this.FloatTooltip.AmountColor=item.AmountColor;
if (item.TurnoverRateColor) this.FloatTooltip.TurnoverRateColor=item.TurnoverRateColor;
if (item.PositionColor) this.FloatTooltip.PositionColor=item.PositionColor;
if (item.TextColor) this.FloatTooltip.TextColor=item.TextColor;
if (item.ValueColor) this.FloatTooltip.ValueColor=item.ValueColor;
}
if (style.DialogSelectRect)
{
var item=style.DialogSelectRect;
if (item.BGColor) this.DialogSelectRect.BGColor=item.BGColor;
if (item.BorderColor) this.DialogSelectRect.BorderColor=item.BorderColor;
if (item.TitleColor) this.DialogSelectRect.TitleColor=item.TitleColor;
if (item.TextColor) this.DialogSelectRect.TextColor=item.TextColor;
if (item.ValueColor) this.DialogSelectRect.ValueColor=item.ValueColor;
if (item.VolColor) this.DialogSelectRect.VolColor=item.VolColor;
if (item.AmountColor) this.DialogSelectRect.AmountColor=item.AmountColor;
if (item.TurnoverRateColor) this.DialogSelectRect.TurnoverRateColor=item.TurnoverRateColor;
if (item.PositionColor) this.DialogSelectRect.PositionColor=item.PositionColor;
}
if (style.DialogPopKeyboard)
{
var item=style.DialogPopKeyboard;
if (item.BGColor) this.DialogPopKeyboard.BGColor=item.BGColor;
if (item.BorderColor) this.DialogPopKeyboard.BorderColor=item.BorderColor;
if (item.TitleColor) this.DialogPopKeyboard.TitleColor=item.TitleColor;
if (item.TitleBGColor) this.DialogTooltip.TitleBGColor=item.TitleBGColor;
if (item.Input)
{
var subItem=item.Input;
if (subItem.BGColor) this.DialogPopKeyboard.Input.BGColor=subItem.BGColor;
if (subItem.TextColor) this.DialogPopKeyboard.Input.TextColor=subItem.TextColor;
}
}
if (style.DialogSearchIndex)
{
var item=style.DialogSearchIndex;
if (item.BGColor) this.DialogSearchIndex.BGColor=item.BGColor;
if (item.BorderColor) this.DialogSearchIndex.BorderColor=item.BorderColor;
if (item.TitleColor) this.DialogSearchIndex.TitleColor=item.TitleColor;
if (item.TitleBGColor) this.DialogSearchIndex.TitleBGColor=item.TitleBGColor;
if (item.IndexNameColor) this.DialogSearchIndex.IndexNameColor=item.IndexNameColor;
if (item.GroupNameColor) this.DialogSearchIndex.GroupNameColor=item.GroupNameColor;
if (item.InputTextColor) this.DialogSearchIndex.InputTextColor=item.InputTextColor;
}
if (style.MinuteInfo)
{
var item=style.MinuteInfo;
if (style.MinuteInfo.TextColor) this.MinuteInfo.TextColor=style.MinuteInfo.TextColor;
if (style.MinuteInfo.Font) this.MinuteInfo.Font=style.MinuteInfo.Font;
if (style.MinuteInfo.PointColor) this.MinuteInfo.PointColor=style.MinuteInfo.PointColor;
if (style.MinuteInfo.LineColor) this.MinuteInfo.LineColor=style.MinuteInfo.LineColor;
if (style.MinuteInfo.TextBGColor) this.MinuteInfo.TextBGColor=style.MinuteInfo.TextBGColor;
if (IFrameSplitOperator.IsNumber(item.PointRadius)) this.MinuteInfo.PointRadius=item.PointRadius;
}
if (style.Title)
{
if (style.Title.TradeIndexColor) this.Title.TradeIndexColor=style.Title.TradeIndexColor;
if (style.Title.ColorIndexColor) this.Title.ColorIndexColor=style.Title.ColorIndexColor;
if (style.Title.VolColor) this.Title.VolColor=style.Title.VolColor;
if (style.Title.AmountColor) this.Title.AmountColor=style.Title.AmountColor;
if (style.Title.DateTimeColor) this.Title.DateTimeColor=style.Title.DateTimeColor;
if (style.Title.NameColor) this.Title.NameColor=style.Title.NameColor;
if (style.Title.SettingColor) this.Title.SettingColor=style.Title.SettingColor;
if (style.Title.TurnoverRateColor) this.Title.TurnoverRateColor=style.Title.TurnoverRateColor;
if (style.Title.PositionColor) this.Title.PositionColor=style.Title.PositionColor;
}
if (style.DRAWICON)
{
if (style.DRAWICON.Icon)
{
var item=style.DRAWICON.Icon;
if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.Icon.MaxSize=item.MaxSize;
if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.Icon.MinSize=item.MinSize;
if (item.Zoom) this.DRAWICON.Icon.Zoom=item.Zoom;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWICON.Icon.YOffset=item.YOffset;
}
if (style.DRAWICON.Text)
{
var item=style.DRAWICON.Text;
if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.Text.MaxSize=item.MaxSize;
if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.Text.MinSize=item.MinSize;
if (item.Zoom) this.DRAWICON.Text.Zoom=item.Zoom;
if (item.FontName) this.DRAWICON.Text.FontName=item.FontName;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWICON.Text.YOffset=item.YOffset;
}
}
if (style.DRAWTEXT)
{
var item=style.DRAWTEXT;
if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.MaxSize=item.MaxSize;
if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.MinSize=item.MinSize;
if (item.Zoom) this.DRAWTEXT.Zoom=item.Zoom;
if (item.FontName) this.DRAWTEXT.FontName=item.FontName;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWTEXT.YOffset=item.YOffset;
}
if (style.DRAWTEXT_FIX)
{
var item=style.DRAWTEXT_FIX;
if (item.Font) this.DRAWTEXT_FIX.Font=item.Font;
}
if (style.DRAWNUMBER_FIX)
{
var item=style.DRAWNUMBER_FIX;
if (item.Font) this.DRAWNUMBER_FIX.Font=item.Font;
}
if (style.DRAWNUMBER)
{
var item=style.DRAWNUMBER;
if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWNUMBER.MaxSize=item.MaxSize;
if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWNUMBER.MinSize=item.MinSize;
if (item.Zoom) this.DRAWNUMBER.Zoom=item.Zoom;
if (item.FontName) this.DRAWNUMBER.FontName=item.FontName;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWNUMBER.YOffset=item.YOffset;
}
if (style.DRAWABOVE)
{
var item=style.DRAWABOVE;
if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWABOVE.YOffset=item.YOffset;
}
if (style.DOTLINE) this.DOTLINE=style.DOTLINE;
if (style.DRAWSL) this.DOTLINE=style.DRAWSL;
if (style.DragSubFrameBorder) this.DragSubFrameBorder=style.DragSubFrameBorder;
if (style.DepthMapPaint)
{
var item=style.DepthMapPaint;
if (item.LineColor) this.DepthMapPaint.LineColor=item.LineColor;
if (item.AreaColor) this.DepthMapPaint.AreaColor=item.AreaColor;
if (item.TextColor) this.DepthMapPaint.TextColor=item.TextColor;
if (item.TextBGColor) this.DepthMapPaint.TextBGColor=item.TextBGColor;
}
if (style.KLineYAxisBGPaint)
{
var item=style.KLineYAxisBGPaint;
if (item.Font) this.KLineYAxisBGPaint.Font=item.Font;
if (item.LineColor) this.KLineYAxisBGPaint.LineColor=item.LineColor;
if (item.DiffValutTextColor) this.KLineYAxisBGPaint.DiffValutTextColor=item.DiffValutTextColor;
if (item.DiffValueBGColor) this.KLineYAxisBGPaint.DiffValueBGColor=item.DiffValueBGColor;
}
if (style.StockChip)
{
var item=style.StockChip;
if (item.InfoColor) this.StockChip.InfoColor=item.InfoColor;
if (item.DayInfoColor) this.StockChip.DayInfoColor=item.DayInfoColor;
if (item.DefaultButton) T_SetButtonStyle(item.DefaultButton, this.StockChip.DefaultButton);
if (item.LongButton) T_SetButtonStyle(item.LongButton, this.StockChip.LongButton);
if (item.RecentButton) T_SetButtonStyle(item.RecentButton, this.StockChip.RecentButton);
}
if (style.DepthChart)
{
var item=style.DepthChart;
if (item.BidColor)
{
if (item.BidColor.Line) this.DepthChart.BidColor.Line=item.BidColor.Line;
if (item.BidColor.Area) this.DepthChart.BidColor.Area=item.BidColor.Area;
}
if (item.AskColor)
{
if (item.AskColor.Line) this.DepthChart.AskColor.Line=item.AskColor.Line;
if (item.AskColor.Area) this.DepthChart.AskColor.Area=item.AskColor.Area;
}
if (item.LineWidth) this.DepthChart.LineWidth=item.LineWidth;
}
if (style.DepthCorss)
{
var item=style.DepthCorss;
if (item.BidColor)
{
if (item.BidColor.Line) this.DepthCorss.BidColor.Line=item.BidColor.Line;
}
if (item.AskColor)
{
if (item.AskColor.Line) this.DepthCorss.AskColor.Line=item.AskColor.Line;
}
if (item.LineWidth) this.DepthCorss.LineWidth=item.LineWidth;
if (item.LineDash) this.DepthCorss.LineDash=item.LineDash;
if (item.Tooltip)
{
var tooltip=item.Tooltip;
if (tooltip.BGColor) this.DepthCorss.Tooltip.BGColor=tooltip.BGColor;
if (tooltip.TextColor) this.DepthCorss.Tooltip.TextColor=tooltip.TextColor;
if (tooltip.Font) this.DepthCorss.Tooltip.Font=tooltip.Font;
if (tooltip.LineHeight) this.DepthCorss.Tooltip.LineHeight=tooltip.LineHeight;
var border=tooltip.Border;
if (IFrameSplitOperator.IsNumber(border.Top)) this.DepthCorss.Tooltip.Border.Top=border.Top;
if (IFrameSplitOperator.IsNumber(border.Bottom)) this.DepthCorss.Tooltip.Border.Bottom=border.Bottom;
if (IFrameSplitOperator.IsNumber(border.Left)) this.DepthCorss.Tooltip.Border.Left=border.Left;
if (IFrameSplitOperator.IsNumber(border.Right)) this.DepthCorss.Tooltip.Border.Right=border.Right;
if (IFrameSplitOperator.IsNumber(border.ItemSpace)) this.DepthCorss.Tooltip.Border.ItemSpace=border.ItemSpace;
}
}
if (style.CIRCLEDOT)
{
var item=style.CIRCLEDOT;
if (IFrameSplitOperator.IsNumber(item.Radius)) this.CIRCLEDOT.Radius=item.Radius;
}
if (style.POINTDOT)
{
var item=style.POINTDOT;
if (IFrameSplitOperator.IsNumber(item.Radius)) this.POINTDOT.Radius=item.Radius;
}
if (style.RectSelect)
{
var item=style.RectSelect;
if (item.LineColor) this.RectSelect.LineColor=item.LineColor;
if (item.LineWidth>0) this.RectSelect.LineWidth=item.LineWidth;
if (item.LineDotted) this.RectSelect.LineDotted=item.LineDotted;
if (item.AreaColor) this.RectSelect.AreaColor=item.AreaColor;
if (item.SubAreaColor) this.RectSelect.SubAreaColor=item.SubAreaColor;
if (item.RangeTextColor) this.RectSelect.RangeTextColor=item.RangeTextColor;
if (item.RangeTextFont) this.RectSelect.RangeTextFont=item.RangeTextFont;
if (item.RangeTextBGColor) this.RectSelect.RangeTextBGColor=item.RangeTextBGColor;
if (item.RangeTextSubColor) this.RectSelect.RangeTextSubColor=item.RangeTextSubColor;
if (item.RangeTextSubFont) this.RectSelect.RangeTextSubFont=item.RangeTextSubFont;
if (item.RangeTextSubBGColor) this.RectSelect.RangeTextSubBGColor=item.RangeTextSubBGColor;
if (item.Mark)
{
var subItem=item.Mark;
if (subItem.Family) this.RectSelect.Mark.Family=subItem.Family;
if (subItem.Text) this.RectSelect.Mark.Text=subItem.Text;
if (subItem.Color) this.RectSelect.Mark.Color=subItem.Color;
if (IFrameSplitOperator.IsNumber(subItem.Size)) this.RectSelect.Mark.Size=subItem.Size;
if (subItem.Position)
{
if (subItem.Position.Top) this.RectSelect.Mark.Position.Top=subItem.Position.Top;
if (IFrameSplitOperator.IsNumber(subItem.Position.Index)) this.RectSelect.Mark.Position.Index=subItem.Position.Index;
}
}
}
if (style.RectDrag)
{
var item=style.RectDrag;
var dest=this.RectDrag;
if (item.LineColor) dest.LineColor=item.LineColor;
if (IFrameSplitOperator.IsPlusNumber(item.LineWidth)) dest.LineWidth=item.LineWidth;
if (item.BGColor) dest.BGColor=item.BGColor;
}
if (style.OrderFlow)
{
item=style.OrderFlow;
if (item.UpColor) this.OrderFlow.UpColor=item.UpColor;
if (item.DownColor) this.OrderFlow.DownColor=item.DownColor;
if (item.UnchagneColor) this.OrderFlow.UnchagneColor=item.UnchagneColor;
if (item.Text) this.OrderFlow.Text=item.Text;
if (item.Line) this.OrderFlow.Line=item.Line;
}
if (style.OrderFlow_Style2)
{
item=style.OrderFlow_Style2;
if (item.UpColor) this.OrderFlow_Style2.UpColor=item.UpColor;
if (item.DownColor) this.OrderFlow_Style2.DownColor=item.DownColor;
if (item.UnchagneColor) this.OrderFlow_Style2.UnchagneColor=item.UnchagneColor;
if (IFrameSplitOperator.IsNumber(item.BarWidth)) this.OrderFlow_Style2.BarWidth=item.BarWidth;
}
if (style.ChartOX)
{
var item=style.ChartOX;
if (item.Family) this.ChartOX.Family=item.Family;
if (item.Up) this.ChartOX.Up=item.Up;
if (item.Down) this.ChartOX.Down=item.Down;
if (item.SquareLineColor) this.ChartOX.SquareLineColor=item.SquareLineColor;
}
if (style.DealList)
{
var item=style.DealList;
if (item.BorderColor) this.DealList.BorderColor=item.BorderColor;
if (item.UpTextColor) this.DealList.UpTextColor=item.UpTextColor;
if (item.DownTextColor) this.DealList.DownTextColor=item.DownTextColor;
if (item.UnchagneTextColor) this.DealList.UnchagneTextColor=item.UnchagneTextColor;
if (item.CloseLineColor) this.DealList.CloseLineColor=item.CloseLineColor;
if (item.Header)
{
var header=item.Header;
if (header.Color) this.DealList.Header.Color=header.Color;
if (header.Mergin)
{
var mergin=header.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.DealList.Header.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.DealList.Header.Mergin.Left=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.DealList.Header.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.DealList.Header.Mergin.Bottom=mergin.Bottom;
}
if (header.Font)
{
var font=header.Font;
if (font.Name) this.DealList.Header.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.DealList.Header.Font.Size=font.Size;
}
}
if (item.Row)
{
var row=item.Row;
if (row.Mergin)
{
var mergin=row.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.DealList.Row.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.DealList.Row.Mergin.Bottom=mergin.Bottom;
}
if (row.Font)
{
var font=row.Font;
if (font.Name) this.DealList.Row.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.DealList.Row.Font.Size=font.Size;
}
if (row.BarMergin)
{
var mergin=row.BarMergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.DealList.Row.BarMergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.DealList.Row.BarMergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.DealList.Row.BarMergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.DealList.Row.BarMergin.Bottom=mergin.Bottom;
}
}
if (item.FieldColor)
{
var filed=item.FieldColor;
if (filed.Vol) this.DealList.FieldColor.Vol=filed.Vol;
if (filed.Time) this.DealList.FieldColor.Time=filed.Time;
if (filed.Deal) this.DealList.FieldColor.Deal=filed.Deal;
if (filed.Index) this.DealList.FieldColor.Index=filed.Index;
if (filed.BarTitle) this.DealList.FieldColor.BarTitle=filed.BarTitle;
if (filed.Text) this.DealList.FieldColor.Text=filed.Text;
if (IFrameSplitOperator.IsNonEmptyArray(filed.Bar))
{
for(var i=0;i<filed.Bar.length;++i)
this.DealList.FieldColor.Bar[i]=filed.Bar[i];
}
}
}
if (style.Report) this.SetReportStyle(style.Report);
if (style.TReport) this.SetTReportStyle(style.TReport);
if (style.SelectedChart)
{
var item=style.SelectedChart;
if (IFrameSplitOperator.IsNumber(item.LineWidth)) this.SelectedChart.LineWidth=item.LineWidth;
if (IFrameSplitOperator.IsNumber(item.Radius)) this.SelectedChart.Radius=item.Radius;
if (IFrameSplitOperator.IsNumber(item.MinSpace)) this.SelectedChart.MinSpace=item.MinSpace;
if (item.LineColor) this.SelectedChart.LineColor=item.LineColor;
if (item.LineColor) this.SelectedChart.BGColor=item.BGColor;
}
if (style.DragMovePaint)
{
var item=style.DragMovePaint;
if (item.TextColor) this.DragMovePaint.TextColor=item.TextColor;
if (item.Font) this.DragMovePaint.Font=item.Font;
}
if (style.SessionBreaksPaint)
{
var item=style.SessionBreaksPaint;
if (IFrameSplitOperator.IsNonEmptyArray(item.BGColor)) this.SessionBreaksPaint.BGColor=item.BGColor.slice();
if (item.SplitLine)
{
var subItem=item.SplitLine;
if (subItem.Color) this.SessionBreaksPaint.SplitLine.Color=subItem.Color;
if (IFrameSplitOperator.IsNumber(subItem.Width)) this.SessionBreaksPaint.SplitLine.Width=subItem.Width;
this.SessionBreaksPaint.SplitLine.Dash=subItem.Dash;
}
}
if (IFrameSplitOperator.IsNumber(style.ToolbarButtonStyle)) this.ToolbarButtonStyle=style.ToolbarButtonStyle;
if (style.Buttons)
{
var buttons=style.Buttons;
T_SetButtonStyle(buttons.CloseOverlayIndex, this.Buttons.CloseOverlayIndex);
T_SetButtonStyle(buttons.CloseWindow, this.Buttons.CloseWindow);
T_SetButtonStyle(buttons.ChangeIndex, this.Buttons.ChangeIndex);
T_SetButtonStyle(buttons.OverlayIndex, this.Buttons.OverlayIndex);
T_SetButtonStyle(buttons.ModifyIndexParam, this.Buttons.ModifyIndexParam);
T_SetButtonStyle(buttons.MaxMinWindow, this.Buttons.MaxMinWindow);
T_SetButtonStyle(buttons.TitleWindow, this.Buttons.TitleWindow);
T_SetButtonStyle(buttons.ExportData, this.Buttons.ExportData);
if (buttons.Tooltip)
{
var item=buttons.Tooltip;
var src=this.Buttons.Tooltip;
if (item.Font) src.Font=item.Font;
if (item.Color) src.Color=item.Color;
if (item.ColorBG) src.ColorBG=item.ColorBG;
if (item.ColorBorder) src.ColorBorder=item.ColorBorder;
if (item.BorderRadius) src.BorderRadius=item.BorderRadius;
if (item.Margin)
{
if (IFrameSplitOperator.IsNumber(item.Margin.Left)) src.Margin.Left=item.Margin.Left;
if (IFrameSplitOperator.IsNumber(item.Margin.Top)) src.Margin.Top=item.Margin.Top;
if (IFrameSplitOperator.IsNumber(item.Margin.Bottom)) src.Margin.Bottom=item.Margin.Bottom;
if (IFrameSplitOperator.IsNumber(item.Margin.Right)) src.Margin.Right=item.Margin.Right;
}
}
}
if (style.ChartDrawVolProfile)
{
var item=style.ChartDrawVolProfile;
if (item.UpVolColor) this.ChartDrawVolProfile.UpVolColor=item.UpVolColor;
if (item.DownVolColor) this.ChartDrawVolProfile.DownVolColor=item.DownVolColor;
if (item.AreaUpColor) this.ChartDrawVolProfile.AreaUpColor=item.AreaUpColor;
if (item.AreaDonwColor) this.ChartDrawVolProfile.AreaDonwColor=item.AreaDonwColor;
if (item.BGColor) this.ChartDrawVolProfile.BGColor=item.BGColor;
if (item.BorderColor) this.ChartDrawVolProfile.BorderColor=item.BorderColor;
if (item.VolLineColor) this.ChartDrawVolProfile.VolLineColor=item.VolLineColor;
if (item.Text)
{
if (item.Text.Color) this.ChartDrawVolProfile.Text.Color=item.Text.Color;
if (item.Text.Family) this.ChartDrawVolProfile.Text.Family=item.Text.Family;
if (IFrameSplitOperator.IsNumber(item.Text.FontMaxSize)) this.ChartDrawVolProfile.Text.FontMaxSize=item.Text.FontMaxSize;
if (IFrameSplitOperator.IsNumber(item.Text.FontMinSize)) this.ChartDrawVolProfile.Text.FontMinSize=item.Text.FontMinSize;
}
}
if (style.DisableLogo===true)
{
if (this.FrameLogo) this.FrameLogo.Text=null;
}
if (style.ScrollBar)
{
var item=style.ScrollBar;
if (item.BorderColor) this.ScrollBar.BorderColor=item.BorderColor;
if (item.XSplitTextFont) this.ScrollBar.XSplitTextFont=item.XSplitTextFont;
if (item.XSplitTextColor) this.ScrollBar.XSplitTextColor=item.XSplitTextColor;
if (item.XSplitLineColor) this.ScrollBar.XSplitLineColor=item.XSplitLineColor;
if (item.Slider)
{
var subItem=item.Slider;
if (subItem.DateFont) this.ScrollBar.Slider.DateFont=subItem.DateFont;
if (subItem.DateColor) this.ScrollBar.Slider.DateColor=subItem.DateColor;
if (subItem.BarColor) this.ScrollBar.Slider.BarColor=subItem.BarColor;
if (subItem.BarAreaColor) this.ScrollBar.Slider.BarAreaColor=subItem.BarAreaColor;
if (IFrameSplitOperator.IsNumber(subItem.BarWidth)) this.ScrollBar.Slider.BarWidth=subItem.BarWidth;
if (IFrameSplitOperator.IsNumber(subItem.BarPadding)) this.ScrollBar.Slider.BarPadding=subItem.BarPadding;
if (IFrameSplitOperator.IsNumber(subItem.MinCenterWidth)) this.ScrollBar.Slider.MinCenterWidth=subItem.MinCenterWidth;
}
if (item.BGChart)
{
var subItem=item.BGChart;
if (subItem.Color) this.ScrollBar.BGChart.Color=subItem.Color;
if (subItem.AreaColor) this.ScrollBar.BGChart.AreaColor=subItem.AreaColor;
if (IFrameSplitOperator.IsPlusNumber(subItem.LineWidth)) this.ScrollBar.BGChart.LineWidth=subItem.LineWidth;
}
}
if (style.FrameButtomToolbar)
this.SetFrameButtomToolbar(style.FrameButtomToolbar);
if (style.Keyboard) this.SetKeyboardStyle(style.Keyboard);
}
this.SetKeyboardStyle=function(style)
{
var item=style;
var dest=this.Keyboard;
if (item.BorderColor) dest.BorderColor=item.BorderColor;
if (item.SelectedColor) dest.SelectedColor=item.SelectedColor;
if (item.TextColor) dest.TextColor=item.TextColor;
if (item.Item)
{
var row=item.Item;
if (row.Mergin)
{
var mergin=row.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) dest.Item.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) dest.Item.Mergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) dest.Item.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) dest.Item.Mergin.Bottom=mergin.Bottom;
}
if (row.Font)
{
var font=row.Font;
if (font.Name) dest.Item.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.Font.Size=font.Size;
}
if (row.BarMergin)
{
var mergin=row.BarMergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) dest.Item.BarMergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Top)) dest.Item.BarMergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Right)) dest.Item.BarMergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) dest.Item.BarMergin.Bottom=mergin.Bottom;
}
if (row.NameFont)
{
var font=row.NameFont;
if (font.Name) dest.Item.NameFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.NameFont.Size=font.Size;
}
if (row.SymbolFont)
{
var font=row.SymbolFont;
if (font.Name) dest.Item.SymbolFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.SymbolFont.Size=font.Size;
}
}
if (item.VScrollbar)
{
var scroll=item.VScrollbar;
if (IFrameSplitOperator.IsNumber(scroll.ScrollBarHeight)) dest.VScrollbar.ScrollBarHeight=scroll.ScrollBarHeight;
if (scroll.ButtonColor) dest.VScrollbar.ButtonColor=scroll.ButtonColor;
if (scroll.BarColor) dest.VScrollbar.BarColor=scroll.BarColor;
if (scroll.BorderColor) dest.VScrollbar.BorderColor=scroll.BorderColor;
if (scroll.BGColor) dest.VScrollbar.BGColor=scroll.BGColor;
if (scroll.BarWidth)
{
var subItem=scroll.BarWidth;
if (IFrameSplitOperator.IsNumber(subItem.Size)) dest.VScrollbar.BarWidth.Size=subItem.Size;
}
}
}
this.SetReportStyle=function(style)
{
var item=style;
var dest=this.Report;
if (item.BorderColor) this.Report.BorderColor=item.BorderColor;
if (item.UpTextColor) this.Report.UpTextColor=item.UpTextColor;
if (item.DownTextColor) this.Report.DownTextColor=item.DownTextColor;
if (item.UnchagneTextColor) this.Report.UnchagneTextColor=item.UnchagneTextColor;
if (item.BorderColor) this.Report.SelectedColor=item.SelectedColor;
if (item.CloseLine)
{
var closeLine=item.CloseLine;
if (closeLine.CloseColor) this.Report.CloseLine.CloseColor=closeLine.CloseColor;
if (closeLine.YCloseColor) this.Report.CloseLine.YCloseColor=closeLine.YCloseColor;
if (closeLine.AreaColor) this.Report.CloseLine.AreaColor=closeLine.AreaColor;
}
if (item.KLine)
{
var kline=item.KLine;
if (kline.UpColor) this.Report.KLine.UpColor=kline.UpColor;
if (kline.DownColor) this.Report.KLine.DownColor=kline.DownColor;
if (kline.UnchagneColor) this.Report.KLine.UnchagneColor=kline.UnchagneColor;
if (IFrameSplitOperator.IsNumber(kline.DataWidth)) this.Report.KLine.DataWidth=kline.DataWidth;
if (IFrameSplitOperator.IsNumber(kline.DistanceWidth)) this.Report.KLine.DistanceWidth=kline.DistanceWidth;
}
if (item.Header)
{
var header=item.Header;
if (header.Color) this.Report.Header.Color=header.Color;
if (header.Mergin)
{
var mergin=header.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.Report.Header.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.Report.Header.Mergin.Left=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.Report.Header.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.Report.Header.Mergin.Bottom=mergin.Bottom;
}
if (header.Font)
{
var font=header.Font;
if (font.Name) this.Report.Header.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.Header.Font.Size=font.Size;
}
}
if (item.Item)
{
var row=item.Item;
if (row.Mergin)
{
var mergin=row.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.Report.Item.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.Report.Item.Mergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.Report.Item.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.Report.Item.Mergin.Bottom=mergin.Bottom;
}
if (row.Font)
{
var font=row.Font;
if (font.Name) this.Report.Item.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.Item.Font.Size=font.Size;
}
if (row.BarMergin)
{
var mergin=row.BarMergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.Report.Item.BarMergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.Report.Item.BarMergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.Report.Item.BarMergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.Report.Item.BarMergin.Bottom=mergin.Bottom;
}
if (row.NameFont)
{
var font=row.NameFont;
if (font.Name) this.Report.Item.NameFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.Item.NameFont.Size=font.Size;
}
if (row.SymbolFont)
{
var font=row.SymbolFont;
if (font.Name) this.Report.Item.SymbolFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.Item.SymbolFont.Size=font.Size;
}
}
if (item.FixedItem)
{
var row=item.FixedItem;
if (row.Font)
{
var font=row.Font;
if (font.Name) this.Report.FixedItem.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.FixedItem.Font.Size=font.Size;
}
}
if (item.LimitBorder)
{
var limit=item.LimitBorder;
if (limit.Color) this.Report.LimitBorder.Color=limit.Color;
if (limit.Mergin)
{
var mergin=limit.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.Report.LimitBorder.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.Report.LimitBorder.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.Report.LimitBorder.Mergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.Report.LimitBorder.Mergin.Bottom=mergin.Bottom;
}
}
if (item.LimitColor)
{
var limit=item.LimitColor;
if (limit.UpColor) this.Report.LimitColor.UpColor=limit.UpColor;
if (limit.DownColor) this.Report.LimitColor.DownColor=limit.DownColor;
if (limit.TextColor) this.Report.LimitColor.UpColor=limit.TextColor;
}
if (item.FieldColor)
{
var filed=item.FieldColor;
if (filed.Name) this.Report.FieldColor.Name=filed.Name;
if (filed.Symbol) this.Report.FieldColor.Symbol=filed.Symbol;
if (filed.Vol) this.Report.FieldColor.Vol=filed.Vol;
if (filed.Amount) this.Report.FieldColor.Amount=filed.Amount;
if (filed.Index) this.Report.FieldColor.Index=filed.Index;
if (filed.BarTitle) this.Report.FieldColor.BarTitle=filed.BarTitle;
if (filed.Text) this.Report.FieldColor.Text=filed.Text;
if (IFrameSplitOperator.IsNonEmptyArray(filed.Bar))
{
for(var i=0;i<filed.Bar.length;++i)
this.Report.FieldColor.Bar[i]=filed.Bar[i];
}
}
if (item.NameSymbolV2)
{
var nameSymbol=item.NameSymbolV2;
if (nameSymbol.Name)
{
var subItem=nameSymbol.Name;
if (IFrameSplitOperator.IsNumber(subItem.Size)) this.Report.NameSymbolV2.Name.Size=subItem.Size;
if (subItem.Name) this.Report.NameSymbolV2.Name.Name=subItem.Name;
if (subItem.Color) this.Report.NameSymbolV2.Name.Color=subItem.Color;
}
if (nameSymbol.Symbol)
{
var subItem=nameSymbol.Symbol;
if (IFrameSplitOperator.IsNumber(subItem.Size)) this.Report.NameSymbolV2.Symbol.Size=subItem.Size;
if (subItem.Name) this.Report.NameSymbolV2.Symbol.Name=subItem.Name;
if (subItem.Color) this.Report.NameSymbolV2.Symbol.Color=subItem.Color;
}
}
if (item.Tab)
{
var tab=item.Tab;
if (tab.Font)
{
var font=tab.Font;
if (font.Name) this.Report.Tab.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.Tab.Font.Size=font.Size;
}
if (IFrameSplitOperator.IsNumber(tab.ScrollBarWidth)) this.Report.Tab.ScrollBarWidth=tab.ScrollBarWidth;
if (tab.ButtonColor) this.Report.Tab.ButtonColor=tab.ButtonColor;
if (tab.BarColor) this.Report.Tab.BarColor=tab.BarColor;
if (tab.BorderColor) this.Report.Tab.BorderColor=tab.BorderColor;
if (tab.TabTitleColor) this.Report.Tab.TabTitleColor=tab.TabTitleColor;
if (tab.TabSelectedTitleColor) this.Report.Tab.TabSelectedTitleColor=tab.TabSelectedTitleColor;
if (tab.TabSelectedBGColor) this.Report.Tab.TabSelectedBGColor=tab.TabSelectedBGColor;
if (tab.TabMoveOnTitleColor) this.Report.Tab.TabMoveOnTitleColor=tab.TabMoveOnTitleColor;
if (tab.TabBGColor) this.Report.Tab.TabBGColor=tab.TabBGColor;
}
if (item.PageInfo)
{
var pageinfo=item.PageInfo;
if (pageinfo.Font)
{
var font=pageinfo.Font;
if (font.Name) this.Report.PageInfo.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) this.Report.PageInfo.Font.Size=font.Size;
}
if (pageinfo.TextColor) this.Report.PageInfo.TextColor=pageinfo.TextColor;
if (pageinfo.BGColor) this.Report.PageInfo.BGColor=pageinfo.BGColor;
if (pageinfo.Mergin)
{
var mergin=pageinfo.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) this.Report.PageInfo.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Top)) this.Report.PageInfo.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Right)) this.Report.PageInfo.Mergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) this.Report.PageInfo.Mergin.Bottom=mergin.Bottom;
}
}
if (item.DragRow)
{
var dragRow=item.DragRow;
if (dragRow.Color) this.Report.DragRow.Color=dragRow.Color;
if (dragRow.TextColor) this.Report.DragRow.TextColor=dragRow.TextColor;
if (dragRow.MoveRowColor) this.Report.DragRow.MoveRowColor=dragRow.MoveRowColor;
if (dragRow.SrcRowColor) this.Report.DragRow.SrcRowColor=dragRow.SrcRowColor;
}
if (item.VScrollbar)
{
var subItem=item.VScrollbar;
if (IFrameSplitOperator.IsNumber(subItem.ScrollBarHeight)) dest.VScrollbar.ScrollBarHeight=subItem.ScrollBarHeight;
if (subItem.ButtonColor) dest.VScrollbar.ButtonColor=subItem.ButtonColor;
if (subItem.BarColor) dest.VScrollbar.BarColor=subItem.BarColor;
if (subItem.BorderColor) dest.VScrollbar.BorderColor=subItem.BorderColor;
if (subItem.BGColor) dest.VScrollbar.BGColor=subItem.BGColor;
}
if (item.CheckBox)
{
var subItem=item.CheckBox;
if (subItem.Family) dest.CheckBox.Family=subItem.Family;
if (IFrameSplitOperator.IsNumber(subItem.Size)) dest.CheckBox.Size=subItem.Size;
if (subItem.Checked)
{
var child=subItem.Checked;
if (child.Color) dest.CheckBox.Checked.Color=child.Color;
if (child.Symbol) dest.CheckBox.Checked.Symbol=child.Symbol;
if (child.DisableColor) dest.CheckBox.Checked.DisableColor=child.DisableColor;
}
if (subItem.Unchecked)
{
var child=subItem.Unchecked;
if (child.Color) dest.CheckBox.Unchecked.Color=child.Color;
if (child.Symbol) dest.CheckBox.Unchecked.Symbol=child.Symbol;
if (child.DisableColor) dest.CheckBox.Unchecked.DisableColor=child.DisableColor;
}
CopyMarginConfig(dest.CheckBox.Margin, subItem.Margin);
}
if (item.Link)
{
var subItem=item.Link;
if (subItem.Font) dest.Link.Font=subItem.Font;
if (subItem.TextColor) dest.Link.TextColor=subItem.TextColor;
if (subItem.Disable && subItem.Disable.TextColor) dest.Link.Disable.TextColor=subItem.Disable.TextColor;
if (subItem.MouseOn && subItem.MouseOn.TextColor) dest.Link.MouseOn.TextColor=subItem.MouseOn.TextColor;
}
if (item.ProgressBar)
{
var subItem=item.ProgressBar;
if (subItem.BGColor) dest.ProgressBar.BGColor=subItem.BGColor;
if (subItem.BarColor) dest.ProgressBar.BarColor=subItem.BarColor;
if (subItem.TextColor) dest.ProgressBar.TextColor=subItem.TextColor;
if (subItem.Font) dest.ProgressBar.Font=subItem.Font;
if (subItem.Disable)
{
if (subItem.Disable.BGColor) dest.ProgressBar.Disable.BGColor=subItem.Disable.BGColor;
if (subItem.Disable.BarColor) dest.ProgressBar.Disable.BarColor=subItem.Disable.BarColor;
if (subItem.Disable.TextColor) dest.ProgressBar.Disable.TextColor=subItem.Disable.TextColor;
}
CopyMarginConfig(dest.ProgressBar.Margin, subItem.Margin);
CopyMarginConfig(dest.ProgressBar.BarMargin, subItem.BarMargin);
CopyMarginConfig(dest.ProgressBar.TextMargin, subItem.TextMargin);
}
if (item.Buttom)
{
var subItem=item.Buttom;
if (subItem.BGColor) dest.Buttom.BGColor=subItem.BGColor;
if (subItem.TextColor) dest.Buttom.TextColor=subItem.TextColor;
if (subItem.BorderColor) dest.Buttom.BorderColor=subItem.BorderColor;
if (subItem.Font) dest.Buttom.Font=subItem.Font;
if (subItem.Disable)
{
if (subItem.Disable.BGColor) dest.Buttom.Disable.BGColor=subItem.Disable.BGColor;
if (subItem.Disable.TextColor) dest.Buttom.Disable.TextColor=subItem.Disable.TextColor;
}
if (subItem.MouseOn)
{
if (subItem.MouseOn.BGColor) dest.Buttom.MouseOn.BGColor=subItem.MouseOn.BGColor;
if (subItem.MouseOn.TextColor) dest.Buttom.MouseOn.TextColor=subItem.MouseOn.TextColor;
}
CopyMarginConfig(dest.Buttom.Margin, subItem.Margin);
CopyMarginConfig(dest.Buttom.TextMargin, subItem.TextMargin);
}
}
this.SetTReportStyle=function(style)
{
var item=style;
var dest=this.TReport;
if (item.BorderColor) dest.BorderColor=item.BorderColor;
if (item.UpTextColor) dest.UpTextColor=item.UpTextColor;
if (item.DownTextColor) dest.DownTextColor=item.DownTextColor;
if (item.UnchangeTextColor) dest.UnchangeTextColor=item.UnchangeTextColor;
if (item.BorderColor) dest.SelectedColor=item.SelectedColor;
if (item.UpBGColor) dest.UpBGColor=item.UpBGColor;
if (item.DownBGColor) dest.DownBGColor=item.DownBGColor;
if (item.Header)
{
var header=item.Header;
if (header.Color) dest.Header.Color=header.Color;
if (header.SortColor) dest.Header.SortColor=header.SortColor;
if (header.Mergin)
{
var mergin=header.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) dest.Header.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) dest.Header.Mergin.Left=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) dest.Header.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) dest.Header.Mergin.Bottom=mergin.Bottom;
}
if (header.Font)
{
var font=header.Font;
if (font.Name) dest.Header.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Header.Font.Size=font.Size;
}
}
if (item.CenterItem)
{
var cell=item.CenterItem;
if (cell.TextColor) dest.CenterItem.TextColor=cell.TextColor;
if (cell.BaseTextColor) dest.CenterItem.BaseTextColor=cell.BaseTextColor;
if (cell.BGColor) dest.CenterItem.BGColor=cell.BGColor;
}
if (item.Item)
{
var row=item.Item;
if (row.Mergin)
{
var mergin=row.Mergin;
if (IFrameSplitOperator.IsNumber(mergin.Left)) dest.Item.Mergin.Left=mergin.Left;
if (IFrameSplitOperator.IsNumber(mergin.Right)) dest.Item.Mergin.Right=mergin.Right;
if (IFrameSplitOperator.IsNumber(mergin.Top)) dest.Item.Mergin.Top=mergin.Top;
if (IFrameSplitOperator.IsNumber(mergin.Bottom)) dest.Item.Mergin.Bottom=mergin.Bottom;
}
if (row.Font)
{
var font=row.Font;
if (font.Name) dest.Item.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.Font.Size=font.Size;
}
if (row.NameFont)
{
var font=row.NameFont;
if (font.Name) dest.Item.NameFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.NameFont.Size=font.Size;
}
if (row.SymbolFont)
{
var font=row.SymbolFont;
if (font.Name) dest.Item.SymbolFont.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.Item.SymbolFont.Size=font.Size;
}
}
if (item.FieldColor)
{
var filed=item.FieldColor;
if (filed.Name) dest.FieldColor.Name=filed.Name;
if (filed.Symbol) dest.FieldColor.Symbol=filed.Symbol;
if (filed.Vol) dest.FieldColor.Vol=filed.Vol;
if (filed.Amount) dest.FieldColor.Amount=filed.Amount;
if (filed.Index) dest.FieldColor.Index=filed.Index;
if (filed.Text) dest.FieldColor.Text=filed.Text;
if (filed.Position) dest.FieldColor.Position=filed.Position;
}
if (item.MarkBorder)
{
var subIem=item.MarkBorder;
if (subIem.MaxPositionColor) dest.MarkBorder.MaxPositionColor=subIem.MaxPositionColor;
}
if (item.FixedItem)
{
var subIem=item.FixedItem;
if (subIem.Font)
{
var font=subIem.Font;
if (font.Name) dest.FixedItem.Font.Name=font.Name;
if (IFrameSplitOperator.IsNumber(font.Size)) dest.FixedItem.Font.Size=font.Size;
}
}
}
this.SetFrameButtomToolbar=function(style)
{
var dest=this.FrameButtomToolbar;
if (style.BGColor) dest.BGColor=style.BGColor;
if (style.BorderColor) dest.BorderColor=style.BorderColor;
if (style.Button)
{
var button=style.Button;
if (button.BorderColor) dest.Button.BorderColor=button.BorderColor;
if (button.Font)
{
var item=button.Font;
var destItem=this.FrameButtomToolbar.Button.Font;
if (item.Family) destItem.Family=item.Family;
if (IFrameSplitOperator.IsNumber(item.Size)) destItem.Size=item.Size;
}
if (button.TitleColor)
{
var item=button.TitleColor;
var destItem=this.FrameButtomToolbar.Button.TitleColor;
if (item.Selected) destItem.Selected=item.Selected;
if (item.Default) destItem.Default=item.Default;
if (item.MoveOn) destItem.MoveOn=item.MoveOn;
}
if (button.BGColor)
{
var item=button.BGColor;
var destItem=this.FrameButtomToolbar.Button.BGColor;
if (item.Selected) destItem.Selected=item.Selected;
if (item.Default) destItem.Default=item.Default;
if (item.MoveOn) destItem.MoveOn=item.MoveOn;
}
if (button.Mergin)
{
var item=button.Mergin;
var destItem=this.FrameButtomToolbar.Button.Mergin;
if (IFrameSplitOperator.IsNumber(item.Left)) destItem.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Right)) destItem.Left=item.Right;
if (IFrameSplitOperator.IsNumber(item.Top)) destItem.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) destItem.Bottom=item.Bottom;
}
if (button.SVG)
{
var item=button.SVG;
var destItem=this.FrameButtomToolbar.Button.SVG;
if (IFrameSplitOperator.IsNumber(item.Size)) destItem.Size=item.Size;
if (IFrameSplitOperator.IsNumber(item.MerginLeft)) destItem.MerginLeft=item.MerginLeft;
if (item.Family) destItem.Family=item.Family;
}
}
}
}
var g_JSChartResource=new JSChartResource();
/////////////////////////////////////////////////////////////////////////////////
//
//
//
var JSCHART_LANGUAGE_ID=
{
LANGUAGE_CHINESE_ID:0, //简体中文 CN
LANGUAGE_ENGLISH_ID:1, //英文 EN
LANGUAGE_TRADITIONAL_CHINESE_ID:2, //繁体中文 TC
};
function JSChartLocalization()
{
this.TextResource=new Map([
//内部tooltip
['Tooltip-Open', {CN:'开:', EN:'O:', TC:'開'}],
['Tooltip-High', {CN:'高:', EN:'H:', TC:'高'}],
['Tooltip-Low', {CN:'低:', EN:'L:', TC:'低'}],
['Tooltip-Close', {CN:'收:', EN:'C:', TC:'收'}],
['Tooltip-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
['Tooltip-Vol', {CN:'量:', EN:'V:', TC:'量'}],
['Tooltip-Amount', {CN:'额:', EN:'A:', TC:'額'}],
['Tooltip-AvPrice', {CN:'均:', EN:'AP:', TC:'均'}],
['Tooltip-Price', {CN:'价:', EN:'P:', TC:'價'}],
['Tooltip-Exchange', {CN:'换:', EN:'E:', TC:'換'}],
['Tooltip-Position',{CN:'持:', EN:'P:', TC:'持'}],
['DivTooltip-Open', {CN:'开盘:', EN:'Open:', TC:'開盤'}],
['DivTooltip-High', {CN:'最高:', EN:'High:', TC:'最高'}],
['DivTooltip-Low', {CN:'最低:', EN:'Low:', TC:'最低'}],
['DivTooltip-Close', {CN:'收盘:', EN:'Close:', TC:'收盤'}],
['DivTooltip-Increase', {CN:'涨幅:', EN:'Increase:', TC:'漲幅'}],
['DivTooltip-Vol', {CN:'数量:', EN:'Volume:', TC:'數量'}],
['DivTooltip-Amount', {CN:'金额:', EN:'Amount:', TC:'金額'}],
['DivTooltip-Exchange', {CN:'换手:', EN:'Exchange:', TC:'換手'}],
['DivTooltip-Position', {CN:'持仓:', EN:'Position:', TC:'持倉'}],
['DivTooltip-Price', {CN:'价格:', EN:'Price:', TC:'價格'}],
['DialogTooltip-Date', {CN:'日期', EN:'Date', TC:'日期'}],
['DialogTooltip-Time', {CN:'时间', EN:'Time', TC:'時間'}],
['DialogTooltip-Open', {CN:'开盘价', EN:'Open', TC:'開盤價'}],
['DialogTooltip-High', {CN:'最高价', EN:'High', TC:'最高價'}],
['DialogTooltip-Low', {CN:'最低价', EN:'Low', TC:'最低價'}],
['DialogTooltip-Close', {CN:'收盘价', EN:'Close', TC:'收盤價'}],
['DialogTooltip-Increase', {CN:'涨幅', EN:'Increase', TC:'漲幅'}],
['DialogTooltip-Risefall', {CN:'涨跌', EN:'Risefall', TC:'漲跌'}],
['DialogTooltip-Vol', {CN:'成交量', EN:'Volume', TC:'數量'}],
['DialogTooltip-Amount', {CN:'成交额', EN:'Amount', TC:'金額'}],
['DialogTooltip-Exchange', {CN:'换手率', EN:'Exchange', TC:'換手'}],
['DialogTooltip-Position', {CN:'持仓量', EN:'Position', TC:'持倉'}],
['DialogTooltip-Price', {CN:'价格', EN:'Price', TC:'價格'}],
['DialogTooltip-AvPrice', {CN:'均价', EN:'AVPrice:', TC:'均價'}],
['DialogTooltip-FClose', {CN:"结算价", EN:'Settlement', TC:'結算價'}],
['DialogTooltip-Amplitude', {CN:'振幅', EN:'amplitude', TC:'振幅'}],
['DialogTooltip-AC-Price', {CN:'匹配价', EN:'Price', TC:'匹配價'}],
['DialogTooltip-AC-AvPrice', {CN:'匹配均价', EN:'AVPrice', TC:'匹配均價'}],
['DialogTooltip-AC-Increase', {CN:'竞价涨幅', EN:'Increase', TC:'競價漲幅'}],
['DialogTooltip-AC-Vol', {CN:'匹配量', EN:'Vol', TC:'匹配量'}],
['DialogTooltip-Value', {CN:'数值', EN:'Value', TC:'数值'}],
['FloatTooltip-Date', {CN:'日期', EN:'Date', TC:'日期'}],
['FloatTooltip-Time', {CN:'时间', EN:'Time', TC:'時間'}],
['FloatTooltip-Open', {CN:'开盘价', EN:'Open', TC:'開盤價'}],
['FloatTooltip-High', {CN:'最高价', EN:'High', TC:'最高價'}],
['FloatTooltip-Low', {CN:'最低价', EN:'Low', TC:'最低價'}],
['FloatTooltip-Close', {CN:'收盘价', EN:'Close', TC:'收盤價'}],
['FloatTooltip-YClose', {CN:'昨收价', EN:'YClose', TC:'昨收價'}],
['FloatTooltip-Increase', {CN:'涨幅', EN:'Increase', TC:'漲幅'}],
['FloatTooltip-Risefall', {CN:'涨跌', EN:'Risefall', TC:'漲跌'}],
['FloatTooltip-Vol', {CN:'成交量', EN:'Volume', TC:'數量'}],
['FloatTooltip-Amount', {CN:'成交额', EN:'Amount', TC:'金額'}],
['FloatTooltip-Exchange', {CN:'换手率', EN:'Exchange', TC:'換手'}],
['FloatTooltip-Position', {CN:'持仓量', EN:'Position', TC:'持倉'}],
['FloatTooltip-Price', {CN:'价格', EN:'Price', TC:'價格'}],
['FloatTooltip-AvPrice', {CN:'均价', EN:'AVPrice:', TC:'均價'}],
['FloatTooltip-FClose', {CN:"结算价", EN:'Settlement', TC:'結算價'}],
['FloatTooltip-YSettlePrice', {CN:"昨结算", EN:'YSettlement', TC:'昨結算'}],
['FloatTooltip-Amplitude', {CN:'振幅', EN:'amplitude', TC:'振幅'}],
['DialogSelectRect-StartPrice', {CN:'起始价:', EN:'Start Price:', TC:'起始價'}],
['DialogSelectRect-EndPrice', {CN:'最终价:', EN:"End Price:", TC:'最终價'}],
['DialogSelectRect-High', {CN:'最高价:', EN:'High:', TC:'最高價'}],
['DialogSelectRect-Low', {CN:'最低价:', EN:"Low:", TC:'最低價'}],
['DialogSelectRect-Increase', {CN:'区间涨幅:', EN:'Increase', TC:'漲幅'}],
['DialogSelectRect-Amplitude', {CN:'区间振幅:', EN:'amplitude', TC:'振幅'}],
['DialogSelectRect-Vol', {CN:'成交量:', EN:'Volume', TC:'數量'}],
['DialogSelectRect-Amount', {CN:'成交额:', EN:'Amount', TC:'金額'}],
['DialogSelectRect-Up', {CN:'阳线:', EN:'Up', TC:'阳线'}],
['DialogSelectRect-Down', {CN:'阴线:', EN:'Down', TC:'阴线'}],
['DialogSelectRect-Unchanged', {CN:'平线:', EN:'Unchanged', TC:'平线'}],
['DialogSelectRect-DataCount', {CN:'数据个数:', EN:'Data Count:', TC:'数据个数'}],
//走势图PC tooltip
['PCTooltip-Date', {CN:'日期', EN:'Date', TC:"日期"}],
['PCTooltip-Time', {CN:'时间', EN:'Time', TC:"時間"}],
['PCTooltip-Price', {CN:'价格', EN:'Price:', TC:'價格'}],
['PCTooltip-AvPrice', {CN:'均价', EN:'AVPrice:', TC:'均價'}],
['PCTooltip-Increase', {CN:'涨幅', EN:'Increase:', TC:'漲幅'}],
['PCTooltip-Vol', {CN:'成交量', EN:'Volume:', TC:'成交量'}],
['PCTooltip-Amount', {CN:'成交额', EN:'Amount:', TC:'成交額'}],
["PCTooltip-Position",{CN:'持仓量', EN:'Position:', TC:'持倉'}],
['PCTooltip-AC-Price', {CN:'匹配价:', EN:'Price:', TC:'匹配價'}],
['PCTooltip-AC-Increase', {CN:'竞价涨幅:', EN:'Increase:', TC:'競價漲幅'}],
['PCTooltip-AC-Vol', {CN:'匹配量:', EN:'V:', TC:'匹配量'}],
['PCTooltip-AC-NotMatchVol', {CN:'未匹配量:', EN:'NV:', TC:'未匹配量'}],
//K线动态标题
['KTitle-Open', {CN:'开:', EN:'O:', TC:'開'}],
['KTitle-High', {CN:'高:', EN:'H:', TC:'高'}],
['KTitle-Low', {CN:'低:', EN:'L:', TC:'低'}],
['KTitle-Close', {CN:'收:', EN:'C:', TC:'收'}],
['KTitle-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
['KTitle-Vol', {CN:'量:', EN:'V:', TC:'量'}],
['KTitle-Amount', {CN:'额:', EN:'A:', TC:'額'}],
['KTitle-Exchange', {CN:'换:', EN:'E:', TC:'換'}],
['KTitle-Position', {CN:'持:', EN:'P:', TC:'持'}],
['KTitle-Price', {CN:'价:', EN:'Price:', TC:'價'}],
//走势图动态标题
['MTitle-AC-Price', {CN:'匹配价:', EN:'C:', TC:'匹配價'}],
['MTitle-AC-AvPrice', {CN:'匹配均价:', EN:'C:', TC:'匹配均價'}],
['MTitle-AC-Increase', {CN:'竞价涨幅:', EN:'I:', TC:'競價漲幅'}],
['MTitle-AC-Vol', {CN:'匹配量:', EN:'V:', TC:'匹配量'}],
['MTitle-AC-NotMatchVol', {CN:'未匹配量:', EN:'NV:', TC:'未匹配量'}],
['MTitle-AC-Amount', {CN:'匹配量金额:', EN:'A:', TC:'匹配量金额'}],
['MTitle-AC-NotMatchAmount', {CN:'未匹配量金额:', EN:'NA:', TC:'未匹配量金额'}],
//走势图标题
['MTitle-Close', {CN:'价:', EN:'C:', TC:'價'}],
['MTitle-AvPrice', {CN:'均:', EN:'AC:', TC:'均'}],
['MTitle-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
['MTitle-Vol', {CN:'量:', EN:'V:', TC:'量'}],
['MTitle-Amount', {CN:'额:', EN:'A:', TC:'額'}],
['MTitle-Position', {CN:'持:', EN:'P:', TC:'持'}],
["MTitle-UpdateTime", {CN:"更新:", EN:"Update:", TC:"更新:"}],
//周期
['日线', {CN:'日线', EN:'1D', TC:'日綫'}],
['周线', {CN:'周线', EN:'1W', TC:'周綫'}],
['双周', {CN:'双周', EN:"2W", TC:'雙周'}],
['月线', {CN:'月线', EN:'1M', TC:'月綫'}],
["半年", {CN:'半年', EN:'HY', TC:'半年'}],
['年线', {CN:'年线', EN:'1Y', TC:'年綫'}],
['1分', {CN:'1分', EN:'1Min', TC:'1分'}],
['5分', {CN:'5分', EN:'5Min', TC:'5分'}],
['15分', {CN:'15分', EN:'15Min', TC:'15分'}],
['30分', {CN:'30分', EN:'30Min', TC:'30分'}],
['60分', {CN:'60分', EN:'60Min', TC:'60分'}],
['季线', {CN:'季线', EN:'1Q', TC:'季綫'}],
['分笔', {CN:'分笔', EN:'Tick', TC:'分筆'}],
['2小时', {CN:'2小时', EN:'2H', TC:'2小時'}],
['4小时', {CN:'4小时', EN:'4H', TC:'4小時'}],
//复权
['不复权', {CN:'不复权', EN:'No Right', TC:'不復權'}],
['前复权', {CN:'前复权', EN:'Pro Right', TC:'前復權'}],
['后复权', {CN:'后复权', EN:'Post Right', TC:'后復權'}],
//week
['日', {CN:'日', EN:'Sun.', TC:'日'}],
['一', {CN:'一', EN:'Mon.', TC:'壹'}],
['二', {CN:'二', EN:'Tues.', TC:'貳'}],
['三', {CN:'三', EN:'Wed.', TC:'叁'}],
['四', {CN:'四', EN:'Thur.', TC:'肆'}],
['五', {CN:'五', EN:'Fri.', TC:'伍'}],
['六', {CN:'六', EN:'Sat.', TC:'陸'}],
['1月', {CN:'1月', EN:'Jan', TC:'1月'}],
['2月', {CN:'2月', EN:'Feb', TC:'2月'}],
['3月', {CN:'3月', EN:'Mar', TC:'3月'}],
['4月', {CN:'4月', EN:'Apr', TC:'4月'}],
['5月', {CN:'5月', EN:'May', TC:'5月'}],
['6月', {CN:'6月', EN:'Jun', TC:'6月'}],
['7月', {CN:'7月', EN:'Jul', TC:'7月'}],
['8月', {CN:'8月', EN:'Aug', TC:'8月'}],
['9月', {CN:'9月', EN:'Sept', TC:'9月'}],
['10月', {CN:'10月', EN:'Oct', TC:'10月'}],
['11月', {CN:'11月', EN:'Nov', TC:'11月'}],
['12月', {CN:'12月', EN:'Dec', TC:'12月'}],
['自定义分钟', {CN:'分', EN:'Min', TC:'分'}],
['自定义日线', {CN:'日', EN:'D', TC:'日'}],
['自定义秒', {CN:'秒', EN:'S', TC:'秒'}],
['自定义毫秒', {CN:'毫秒', EN:'MS', TC:'毫秒'}],
["MVol-Vol", {CN:"成交量", EN:"Volume", TC:'成交量'} ],
["MVol-Position", {CN:"持仓量", EN:"Position", TC:'持倉量'} ],
//深度图
["Depth-Price", {CN:"委托价", EN:"Price", TC:'委托價'}],
["Depth-Sum", {CN:"累计", EN:"Sum", TC:'累計'}],
//工具栏提示信息
["Toolbar-"+JSCHART_BUTTON_ID.MODIFY_INDEX_PARAM, {CN:"调整指标参数", EN:"Change indicator parameters", TC:"调整指标参数"}],
["Toolbar-"+JSCHART_BUTTON_ID.CHANGE_INDEX, {CN:"选择指标", EN:"Change indicator", TC:"切换指标"}],
["Toolbar-"+JSCHART_BUTTON_ID.CLOSE_INDEX_WINDOW, {CN:"关闭窗口", EN:"Delete window", TC:"关闭指标窗口"}],
["Toolbar-"+JSCHART_BUTTON_ID.OVERLAY_INDEX, {CN:"叠加指标", EN:"Overlay indicator", TC:"叠加指标"}],
["Toolbar-"+JSCHART_BUTTON_ID.MODIFY_OVERLAY_INDEX_PARAM, {CN:"调整叠加指标参数", EN:"Change overlay indicator parameters", TC:"调整叠加指标参数"}],
["Toolbar-"+JSCHART_BUTTON_ID.MAX_MIN_WINDOW, {CN:"最大化", EN:"Maximize", TC:"最大化"}],
["Toolbar-"+JSCHART_BUTTON_ID.TITLE_WINDOW, {CN:"折叠窗口", EN:"Collapse window", TC:"折叠窗口"}],
["Toolbar-"+JSCHART_BUTTON_ID.EXPORT_DATA, {CN:"数据导出", EN:"Export data", TC:"数据导出"}],
["Toolbar-"+JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID, {CN:"关闭集合竞价", EN:"Close call auction", TC:"关闭集合竞价"}],
["Toolbar-"+JSCHART_BUTTON_ID.CLOSE_OVERLAY_INDEX, {CN:"关闭叠加指标", EN:"Delte overlay indicator", TC:"关闭叠加指标"}],
["Toolbar-"+JSCHART_BUTTON_ID.CHIP_RECENT, {CN:"近期成本分布", EN:"Recent chip", TC:"近期成本分布"}],
["Toolbar-"+JSCHART_BUTTON_ID.CHIP_LONG, {CN:"远期成本分布", EN:"Long chip", TC:"远期成本分布"}],
["Toolbar-"+JSCHART_BUTTON_ID.CHIP_DEFULT, {CN:"默认筹码分布", EN:"Default chip", TC:"默认筹码分布"}],
["Toolbar-"+JSCHART_BUTTON_ID.DRAW_PICTURE_DELETE, {CN:"删除", EN:"Delete", TC:"删除"}],
["Toolbar-"+JSCHART_BUTTON_ID.DRAW_PICTURE_SETTING, {CN:"设置", EN:"Setting", TC:"设置"}],
//日盘|夜盘
["日盘",{CN:'日盘', EN:'Day', TC:'日盤'}],
["夜盘",{CN:'夜盘', EN:'Night', TC:'夜盤'} ]
]);
this.GetText=function(key,language)
{
var item=this.TextResource.get(key);
if (!item) return '';
switch(language)
{
case JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID:
return item.CN;
case JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID:
return item.EN;
case JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID:
return item.TC;
default:
return item.CN;
}
}
this.SetTextResource=function(key,value)
{
this.TextResource.set(key,value)
}
this.GetLanguageID=function(languageName)
{
var languageID=null;
switch(languageName)
{
case 'EN':
languageID=JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID;
break;
case 'CN':
languageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
break;
case "TC":
languageID=JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID;
break;
default:
break;
}
return languageID;
}
this.GetLanguageName=function(id)
{
switch(id)
{
case JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID:
return "EN";
case JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID:
return "CN";
case JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID:
return "TC"
default:
return null;
}
}
};
var g_JSChartLocalization=new JSChartLocalization();
/*
指标列表 指标信息都在这里,不够后面再加字段
*/
function JSIndexMap()
{
}
JSIndexMap.Get=function(id)
{
var indexMap=new Map(
[
['CJL', { IsMainIndex:false, Create:function(){ return new JSIndex_CJL(); } } ], //期货指标
["OX", { IsMainIndex:false, Create:function() { return new JSIndex_OX(); } } ],
["可视范围成交量分布图", { IsMainIndex:true, Create:function(option) { return new VolProfileVisibleRangeIndex(option); } } ],
]
);
return indexMap.get(id);
}
// 定制K线计算
function KLineCustomCalulate()
{
this.DataMap=new Map(
[
["RenkoCalculate", { Create:function() { return new RenkoCalculate(); } }],
["HeikinAshiCalculate", { Create:function() { return new HeikinAshiCalculate(); } }],
["LineBreakCalcuate", { Create:function() { return new LineBreakCalcuate(); } }],
["KagiCalculate", { Create:function(){ return new KagiCalculate(); } }]
]
);
this.Create=function(name)
{
if (!this.DataMap.has(name)) return null;
var item=this.DataMap.get(name);
return item.Create();
}
}
var g_KLineCustomCalulate=new KLineCustomCalulate();
///////////////////////////////////////////////////////////////////
// renko candle
//
function RenkoCalculate()
{
this.BrickSize=0.05; //固定大小
this.SourceData;
this.LastData;
this.ATR={ Count:14, BrickSize:0.05 }; //使用ATR计算砖块大小
this.BrickSizeType=1; //0=固定 1=ATR动态计算
this.Symbol;
this.FloatPrecision=2; //品种小数位数
this.ClassName="RenkoCalculate";
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsNumber(option.BrickSize)) this.BrickSize=option.BrickSize;
if (IFrameSplitOperator.IsNumber(option.BrickSizeType)) this.BrickSizeType=option.BrickSizeType;
if (option.ATR)
{
var item=option.ATR;
if (IFrameSplitOperator.IsNumber(item.Count)) this.ATR.Count=item.Count;
}
}
this.CalculateByClose=function(sourceData) //使用收盘价计算
{
var bindData=new ChartData();
bindData.Data=[]
bindData.Right=sourceData.Right;
bindData.Period=sourceData.Period;
bindData.DataType=sourceData.DataType;
bindData.Symbol=sourceData.symbol;
if (!IFrameSplitOperator.IsNonEmptyArray(sourceData.Data)) return bindData;
var brickSize=this.BrickSize;
if (this.BrickSizeType==1) brickSize=this.ATR.BrickSize;
var kItem=sourceData.Data[0];
this.LastData=HistoryData.Copy(kItem);
for(var i=1; i<sourceData.Data.length; )
{
var kItem=sourceData.Data[i];
var movementFromClose=kItem.Close - this.LastData.Close;
var movementFromOpen=kItem.Close - this.LastData.Open;
if (Math.abs(movementFromClose)>= brickSize && Math.abs(movementFromOpen)>=brickSize)
{
var vol=0;
if (movementFromClose>0 || movementFromOpen>0)
{
var yClose=this.LastData.Close;
var open=Math.max(this.LastData.Close,this.LastData.Open);
var close=open+brickSize;
var high=close;
var low=open;
vol=kItem.Vol;
}
else
{
var yClose=this.LastData.Close;
var open=Math.min(this.LastData.Close,this.LastData.Open);
var close=open-brickSize;
var high=open;
var low=close;
vol=kItem.Vol;
}
var item=new HistoryData();
item.Date=kItem.Date;
item.Time=kItem.Time;
item.YClose=yClose;
item.Open=open;
item.High=high;
item.Low=low;
item.Close=close;
item.Vol=this.LastData.Vol+vol;
bindData.Data.push(item);
this.LastData.YClose=item.YClose;
this.LastData.Open = item.Open;
this.LastData.High = item.High;
this.LastData.Low = item.Low;
this.LastData.Close = item.Close;
this.LastData.Date=item.Date;
this.LastData.Time=item.Time;
this.LastData.Vol=0;
}
else
{
this.LastData.Vol+=kItem.Vol; //量需要累加
++i;
}
}
return bindData;
}
this.RecvHistoryData=function(sourceData, option) //历史日线数据
{
this.Symbol=option.Symbol;
this.SourceData=sourceData;
this.FloatPrecision=GetfloatPrecision(this.Symbol);
if (this.BrickSizeType==1) this.CalculateATR();
return this.CalculateByClose(sourceData);
}
this.Clear=function()
{
this.SourceData=null;
this.LastData=null;
this.Symbol=null;
}
//获取配置信息
this.GetTitle=function()
{
if (this.BrickSizeType==1)
{
var text=`Renko [ATR(${this.ATR.Count}), ${this.ATR.BrickSize}]`;
}
else
{
var text=`Renko [Traditional, ${this.BrickSize}]`;
}
return text;
}
//通过ATR计算砖块大小
//真实范围 = MAX(最高价 (1) – 最低价 (1);最高价 (1) – 收盘价 (2);收盘价 (2) – 最低价 (1))
this.CalculateATR=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data)) return;
var kData=this.SourceData.Data;
var count=kData.length;
var aryData=[];
for(var i=count-1, j=0; i>=0 && j<this.ATR.Count; --i, ++j)
{
var item=kData[i];
var value=Math.max(item.High-item.Low, item.High-item.Close, item.Close-item.Low);
aryData.push(value);
}
//使用MA计算,也可以使用SMA计算
var total=0;
for(var i=0; i<aryData.length; ++i)
{
total+=aryData[i];
}
var brickSize=total/aryData.length;
var value=brickSize.toFixed(this.FloatPrecision);
this.ATR.BrickSize=parseFloat(value);
}
}
/////////////////////////////////////////////////////////////////////////
//kagi candle
//
function KagiCalculate()
{
this.newMethod=RenkoCalculate; //派生
this.newMethod();
delete this.newMethod;
this.ClassName="KagiCalculate";
this.BrickSizeType=0;
this.BrickSize=0.5; //固定大小
this.RecvHistoryData=function(sourceData, option) //历史日线数据
{
this.Symbol=option.Symbol;
this.SourceData=sourceData;
this.FloatPrecision=GetfloatPrecision(this.Symbol);
if (this.BrickSizeType==1) this.CalculateATR();
return this.CalculateByClose(sourceData);
}
this.CalculateByClose=function(sourceData)
{
var bindData=new ChartData();
bindData.Data=[]
bindData.Right=sourceData.Right;
bindData.Period=sourceData.Period;
bindData.DataType=sourceData.DataType;
bindData.Symbol=sourceData.symbol;
if (!IFrameSplitOperator.IsNonEmptyArray(sourceData.Data)) return bindData;
var brickSize=this.BrickSize;
if (this.BrickSizeType==1) brickSize=this.ATR.BrickSize;
var kItem=sourceData.Data[0];
var kagiItem=HistoryData.Copy(kItem);
kagiItem.High=kagiItem.Low=kItem.Close;
kagiItem.StartItem=kItem;
kagiItem.Direction=0; //1 上 2=下
var T_MergeKData=function(dest, src)
{
dest.Vol+=src.Vol;
dest.Amount+=src.Amount;
}
var index=1;
for( ;index<sourceData.Data.length;++index) //确定好方向
{
var kItem=sourceData.Data[index];
if (kItem.Close>kagiItem.Close)
{
kagiItem.Direction=1;
kagiItem.Close=kItem.Close;
kagiItem.EndItem=kItem;
kagiItem.High=kItem.Close;
break;
}
else if (kItem.Close<kagiItem.Close)
{
kagiItem.Direction=2;
kagiItem.Close=kItem.Close;
kagiItem.EndItem=kItem;
kagiItem.Low=kItem.Close;
break;
}
}
var changeItem=null;
for(++index; index<sourceData.Data.length;++index )
{
var kItem=sourceData.Data[index];
if (kagiItem.Direction==1) //上
{
if (kItem.Close>=kagiItem.High)
{
kagiItem.Close=kItem.Close;
kagiItem.High=kItem.Close;
kagiItem.EndItem=kItem;
changeItem=null;
}
else
{
if (!changeItem)
{
changeItem=HistoryData.Copy(kItem);
changeItem.High=changeItem.Low=kItem.Close;
}
else
{
changeItem.Close=kItem.Close;
if (changeItem.Low>kItem.Close) changeItem.Low=kItem.Close;
}
if (Math.abs(changeItem.Low-kagiItem.High)>brickSize) //达到变盘点
{
bindData.Data.push(kagiItem);
var newItem=HistoryData.Copy(kItem);
newItem.High=kagiItem.High;
newItem.Low=kItem.Close;
newItem.Direction=2; //1 上 2=下
newItem.StartItem=kItem;
kagiItem=newItem;
changeItem=null;
}
}
}
else if (kagiItem.Direction==2) //下
{
if (kItem.Close<=kagiItem.Low)
{
kagiItem.Close=kItem.Close;
kagiItem.Low=kItem.Close;
kagiItem.EndItem=kItem;
}
else
{
if (!changeItem)
{
changeItem=HistoryData.Copy(kItem);
changeItem.High=changeItem.Low=kItem.Close;
}
else
{
changeItem.Close=kItem.Close;
if (changeItem.High<kItem.Close) changeItem.High=kItem.Close;
}
if (Math.abs(changeItem.High-kagiItem.Low)>brickSize) //达到变盘点
{
bindData.Data.push(kagiItem);
var newItem=HistoryData.Copy(kItem);
newItem.High=kItem.Close;
newItem.Low=kagiItem.Low;
newItem.Direction=1; //1 上 2=下
newItem.StartItem=kItem;
kagiItem=newItem;
changeItem=null;
}
}
}
}
return bindData;
}
//获取配置信息
this.GetTitle=function()
{
if (this.BrickSizeType==1)
{
var text=`Kagi [ATR(${this.ATR.Count}), ${this.ATR.BrickSize}]`;
}
else
{
var text=`Kagi [Traditional]`;
}
return text;
}
}
//////////////////////////////////////////////////////////////////
// HeikinAshi
//
function HeikinAshiCalculate()
{
this.SourceData;
this.Symbol;
this.FloatPrecision=2; //品种小数位数
this.ClassName="HeikinAshiCalculate";
this.Clear=function()
{
this.SourceData=null;
this.LastData=null;
this.Symbol=null;
}
this.RecvHistoryData=function(sourceData, option) //历史日线数据
{
this.Symbol=option.Symbol;
this.SourceData=sourceData;
this.FloatPrecision=GetfloatPrecision(this.Symbol);
return this.Calculate(sourceData);
}
this.GetTitle=function()
{
return "Heikin Ashi";
}
this.Calculate=function(sourceData)
{
var bindData=new ChartData();
bindData.Data=[]
bindData.Right=sourceData.Right;
bindData.Period=sourceData.Period;
bindData.DataType=sourceData.DataType;
bindData.Symbol=sourceData.symbol;
if (!IFrameSplitOperator.IsNonEmptyArray(sourceData.Data)) return bindData;
var lastKItem=null;
var yClose=null;
for(var i=0;i<sourceData.Data.length;++i)
{
var kItem=sourceData.Data[i];
var newItem=HistoryData.Copy(kItem);
if (!lastKItem)
{
newItem.Open=(kItem.Close+kItem.Open)/2;
newItem.Close=(kItem.Close+kItem.Open+kItem.High+kItem.Low)/4;
yClose=newItem.Close;
}
else
{
newItem.Close=(kItem.Close+kItem.Open+kItem.High+kItem.Low)/4;
newItem.Open=(lastKItem.Close+lastKItem.Open)/2;
newItem.YClose=yClose;
newItem.High=Math.max(newItem.Close, newItem.Open, kItem.High);
newItem.Low=Math.min(newItem.Close, newItem.Open, kItem.Low);
yClose=newItem.Close;
}
lastKItem=kItem;
bindData.Data.push(newItem);
}
return bindData;
}
}
//////////////////////////////////////////////////////////////////
// line break
//
function LineBreakCalcuate()
{
this.SourceData;
this.Symbol;
this.FloatPrecision=2; //品种小数位数
this.LineCount=3;
this.ClassName="LineBreakCalcuate";
this.Clear=function()
{
this.SourceData=null;
this.LastData=null;
this.Symbol=null;
}
this.GetTitle=function()
{
return `Line Break [${this.LineCount}]`;
}
this.RecvHistoryData=function(sourceData, option) //历史日线数据
{
this.Symbol=option.Symbol;
this.SourceData=sourceData;
this.FloatPrecision=GetfloatPrecision(this.Symbol);
return this.CalculateByClose(sourceData);
}
//计算前N个周期的最大最小值
this.CalculatePreviousKLine=function(preKLine)
{
for(var i=0;i<preKLine.Data.length;++i)
{
var item=preKLine.Data[i];
if (i==0)
{
preKLine.High=item.High;
preKLine.Low=item.Low;
}
else
{
if (preKLine.High<item.High) preKLine.High=item.High;
if (preKLine.Low<item.Low) preKLine.Low=item.Low;
}
preKLine.Date=item.Date;
preKLine.Time=item.Time;
preKLine.Vol+=item.Vol;
preKLine.Amount+=item.Amount;
}
}
//使用收盘价计算
/*
If the close of the daily bar is higher than the high of the previous white line, draw a new white line with the open equal to the previous line’s high, and the close equal to the close of the current daily bar.
If the close of the daily bar is lower than the low of the last three lines, draw a new red line with the open equal to the previous line’s low and the close equal to the close of the current daily bar.
If neither of the above two conditions are met, no new line is produced.
*/
this.CalculateByClose=function(sourceData)
{
var bindData=new ChartData();
bindData.Data=[]
bindData.Right=sourceData.Right;
bindData.Period=sourceData.Period;
bindData.DataType=sourceData.DataType;
bindData.Symbol=sourceData.symbol;
if (!IFrameSplitOperator.IsNonEmptyArray(sourceData.Data)) return bindData;
var index=0;
var preItem={ High:null, Low:null, Date:null, Time:null, Direction:0 };
for(; index<sourceData.Data.length && index<this.LineCount ;++index)
{
var kItem=sourceData.Data[index];
if (i==0)
{
preItem.High=kItem.High;
preItem.Low=kItem.Low;
}
else
{
if (preItem.High<kItem.High) preItem.High=kItem.High;
if (preItem.Low>kItem.Low) preItem.Low=kItem.Low;
}
preItem.Date=kItem.Date;
preItem.Time=kItem.Time;
preItem.Vol+=kItem.Vol;
preItem.Amount+=kItem.Amount;
}
for(var i=index;i<sourceData.Data.length;++i)
{
var kItem=sourceData.Data[i];
if (kItem.Close>preItem.High) //阳线
{
var item=new HistoryData();
item.YClose=preItem.Low;
if (preItem) item.Open=preItem.High;
else item.Open=preItem.High;
item.Close=kItem.Close;
item.Low=Math.min(item.Open,item.Close);
item.High=Math.max(item.Open,item.Close);
item.Date=kItem.Date;
item.Time=kItem.Time;
item.Vol=kItem.Vol;
item.Amount=kItem.Amount;
item.Direction=1; //阳线
bindData.Data.push(item);
//if (preItem && preItem.Direction==1) preItem.Close=preItem.High;
//else if (preItem && preItem.Direction==2) preItem.Close=preItem.Low;
preItem=item;
}
else if (kItem.Close<preItem.Low) //阴线
{
var item=new HistoryData();
item.YClose=preItem.High;
if (preItem) item.Open=preItem.Low;
else item.Open=preItem.Low;
item.Close=kItem.Close;
item.Low=Math.min(item.Open,item.Close);
item.High=Math.max(item.Open,item.Close);
item.Date=kItem.Date;
item.Time=kItem.Time;
item.Vol=kItem.Vol;
item.Amount=kItem.Amount;
item.Direction=2; //阴线
bindData.Data.push(item);
//if (preItem && preItem.Direction==1) preItem.Close=preItem.High;
//else if (preItem && preItem.Direction==2) preItem.Close=preItem.Low;
preItem=item;
}
else
{
if (preItem)
{
if (preItem.Direction==1)
{
//if (preItem.High<kItem.High) preItem.High=kItem.High;
}
else if (preItem.Direction==2)
{
//if (preItem.Low>kItem.Low) preItem.Low=kItem.Low;
}
preItem.Vol+=kItem.Vol;
preItem.Amount+=kItem.Amount;
}
}
}
return bindData;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
// K线图 控件
// this.ChartPaint[0] K线画法 这个不要修改
//
//
function KLineChartContainer(uielement,OffscreenElement, cacheElement)
{
var _self =this;
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement,OffscreenElement,cacheElement);
delete this.newMethod;
this.ClassName='KLineChartContainer';
this.WindowIndex=new Array();
this.ColorIndex; //五彩K线
this.TradeIndex; //交易指标/专家系统
this.Symbol;
this.Name;
this.Period=0; //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 9=季线 10=分笔线 11=120分钟 12=240分钟
this.IsApiPeriod=false; //使用API计算周期
this.Right=0; //复权 0 不复权 1 前复权 2 后复权
this.RightFormula=0 //复权公式 0=简单复权, 1=复权因子复权
this.SourceData; //原始的历史数据
this.MaxRequestDataCount=3000; //数据个数
this.MaxRequestMinuteDayCount=5; //分钟数据请求的天数
this.PageSize=200; //每页数据个数
this.KLineDrawType=0;
this.ScriptErrorCallback; //脚本执行错误回调
this.FlowCapitalReady=false; //流通股本是否下载完成
this.EnableFlowCapital={}; //强制现在流通股 { BIT:数据货币true/false, }
this.EnableZoomUpDown=null; //是否手势/键盘/鼠标允许缩放{ Touch:true/false, Mouse:true/false, Keyboard:true/false, Wheel:true/false }
this.ChartDrawStorage=new ChartDrawStorage();
this.ChartDrawStorageCache=null; //首次需要创建的画图工具数据
this.RightSpaceCount=0; //右侧空白个数
this.SourceDataLimit=new Map(); //每个周期缓存数据最大个数 key=周期 value=最大个数
this.CtrlMoveStep=5; //Ctrl+(Left/Right) 移动数据个数
this.CustomShow=null; //首先显示的K线的起始日期 { Date:日期, Time:时间, PageSize:, Callback:}
this.ZoomType=0; //缩放模式 0=最右边固定缩放, 1=十字光标两边缩放
this.IsZoomLockRight=false;
this.KLineSize=null; //{ DataWidth:, }
//this.EnableYDrag={ Left:false, Right:true };
this.Page= {
Day:{ Enable:false, Index:0, Finish:false }, //日线
Minute:{ Enable:false, Index:0, Finish:false } //分钟
}; //分页下载 Enable:是否分页下载 Index:已下载到第几页 Finish:是否所有分页完成
this.DragDownload= {
Day:{ Enable:false, IsEnd:false, Status:0 }, //日线数据拖拽下载 Status: 0空闲 1 下载中
Minute: { Enable:false, IsEnd:false, Status:0 }, //分钟/秒数据拖拽下载
Tick: { Enable:false, IsEnd:false, Status:0 } //分笔
};
this.ZoomDownload=
{
Day:{ Enable:false, IsEnd:false, Status:0 }, //日线数据缩放下载 Status: 0空闲 1 下载中
Minute: { Enable:false, IsEnd:false, Status:0 }, //分钟/秒数据缩放下载
Tick: { Enable:false, IsEnd:false, Status:0 } //分笔
}
//自动更新设置
this.IsAutoUpdate=false; //是否自动更新行情数据
this.AutoUpdateFrequency=30000; //30秒更新一次数据
this.AutoUpdateTimer; //自动更新定时器
//this.KLineApiUrl="http://opensource.zealink.com/API/KLine2"; //历史K线api地址
this.KLineApiUrl=g_JSChartResource.Domain+"/API/KLine2"; //历史K线api地址
this.MinuteKLineApiUrl=g_JSChartResource.Domain+'/API/KLine3'; //历史分钟数据
this.DragMinuteKLineApiUrl=g_JSChartResource.Domain+'/API/KLine4'; //拖动1分钟K数据下载
this.DragKLineApiUrl=g_JSChartResource.Domain+'/API/KLine5'; //拖动日K数据下载
this.ZoomMinuteKLineApiUrl=g_JSChartResource.Domain+'/API/KLine4'; //拖动1分钟K数据下载
this.ZoomKLineApiUrl=g_JSChartResource.Domain+'/API/KLine5'; //拖动日K数据下载
this.RealtimeApiUrl=g_JSChartResource.Domain+"/API/Stock"; //实时行情api地址
this.KLineMatchUrl=g_JSChartResource.Domain+"/API/KLineMatch"; //形态匹配
this.StockHistoryDayApiUrl= g_JSChartResource.Domain+'/API/StockHistoryDay'; //股票历史数据
this.TickApiUrl=g_JSChartResource.Domain+'/API/StockDetail'; //当天分笔数据
this.PopMinuteChart=null; //双击历史K线 弹出分钟走势图
this.BeforeBindMainData=null; //function(funcName) 在BindMainData() 调用前回调用
this.AfterBindMainData=null; //function(funcName) 在BindMainData() 调用前后调用
this.KLineCalculate=null; //K线定制指标计算
this.KLineCalcOption=new Map(); //K线定制指标配置
this.ScrollBar=null; //横向滚动条
this.IsAutoSyncDataOffset=true; //增量更新时,是否移动当前屏数据
this.GetKLineCalulate=function()
{
var kLineDrawType=this.GetKLineDrawType();
var className;
if (kLineDrawType==10) className="RenkoCalculate";
else if (kLineDrawType==11) className="HeikinAshiCalculate";
else if (kLineDrawType==12) className="LineBreakCalcuate";
else if (kLineDrawType==16) className="KagiCalculate";
else return null;
if (!this.KLineCalculate || this.KLineCalculate.ClassName!=className)
{
this.KLineCalculate=g_KLineCustomCalulate.Create(className);
if (this.KLineCalculate.SetOption && this.KLineCalcOption.has(className))
{
var option=this.KLineCalcOption.get(className);
this.KLineCalculate.SetOption(option);
}
}
return this.KLineCalculate;
}
this.SetKLineCalcOption=function(className, option)
{
this.KLineCalcOption.set(className, option);
if (this.KLineCalculate && this.KLineCalculate.ClassName==className && this.KLineCalculate.SetOption)
{
this.KLineCalculate.SetOption(option);
}
}
this.ClearKLineCaluate=function()
{
if (!this.KLineCalculate) return;
if (!this.KLineCalculate.Clear) return;
this.KLineCalculate.Clear();
}
this.ResetDragDownload=function()
{
this.DragDownload.Day.Status=0;
this.DragDownload.Day.IsEnd=false;
this.DragDownload.Minute.Status=0;
this.DragDownload.Minute.IsEnd=false;
this.DragDownload.Tick.Status=0;
this.DragDownload.Tick.IsEnd=false;
}
this.ResetZoomDownload=function()
{
this.ZoomDownload.Day.Status=0;
this.ZoomDownload.Day.IsEnd=false;
this.ZoomDownload.Minute.Status=0;
this.ZoomDownload.Minute.IsEnd=false;
this.ZoomDownload.Tick.Status=0;
this.ZoomDownload.Tick.IsEnd=false;
}
this.ResetPage=function() //重置分页下载
{
this.Page.Day.Finish=false;
this.Page.Day.Index=0;
this.Page.Minute.Finish=false;
this.Page.Minute.Index=0;
}
this.AddCustomKLine=function(kline, option)
{
var klineChart=this.ChartPaint[0];
if (!klineChart) return;
if (!kline) return;
if (!klineChart.CustomKLine) klineChart.CustomKLine=new Map();
if (Array.isArray(kline))
{
for(var i=0;i<kline.length;++i)
{
var item=kline[i];
klineChart.CustomKLine.set(item.Key, item.Data);
}
}
else if (kline)
{
klineChart.CustomKLine.set(kline.Key, kline.Data);
}
if (option && option.Draw==true) this.Draw();
}
this.ClearCustomKLine=function(option)
{
var klineChart=this.ChartPaint[0];
if (!klineChart) return;
klineChart.ClearCustomKLine();
if (option && option.Draw==true) this.Draw();
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
this.AutoUpdateEvent(false,'KLineChartContainer::StopAutoUpdate');
if (!this.IsAutoUpdate) return;
this.IsAutoUpdate=false;
}
//沙盘操作 { ID: 1=开始, Data:绑定K线数据(可选)
// ID: 2=更新数据, Data:绑定K线数据
// ID: 3=结束, IsAutoUpdate:是否启动自动更新(可选) }
this.SandTableOperator=function(obj)
{
switch(obj.ID)
{
case 1:
this.StopAutoUpdate();
if (obj.Data) this.ManualUpdateKData(obj);
break;
case 2:
this.ManualUpdateKData(obj);
break;
case 3:
if (obj.IsAutoUpdate) this.IsAutoUpdate=obj.IsAutoUpdate;
this.ChangeSymbol(this.Symbol);
break;
}
}
//外部手动更新K线数据, 内部不计算周期和复权
this.ManualUpdateKData=function(obj)
{
var kData=obj.Data;
var lastDataCount=kData.length;
var bindData=new ChartData();
bindData.Data=kData;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.Symbol=this.Symbol;
this.UpdateMainData(bindData,lastDataCount);//更新主图数据
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//更新当前屏K线索引
if (IFrameSplitOperator.IsNumber(obj.DataOffset) && obj.DataOffset>=0)
{
var data=null;
if (this.Frame.Data)
data=this.Frame.Data;
else
data=this.Frame.SubFrame[0].Frame.Data;
if (data) data.DataOffset=obj.DataOffset;
}
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(1); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw(); //刷新画图
this.SendManualKLineUpdateEvent(bindData);
}
//获取k线数据
this.GetKDataInfo=function()
{
if (!this.ChartPaint[0]) return null;
var chartKLine=this.ChartPaint[0];
var obj={};
if (chartKLine.Data && chartKLine.Data.Data)
obj.Data=chartKLine.Data.CloneData("HistoryData");
obj.ShowRange=chartKLine.ShowRange;
obj.Period=this.Period;
obj.RightSpaceCount=this.RightSpaceCount;
return obj;
}
this.ChartOperator=function(obj) //图形控制函数 {ID:JSCHART_OPERATOR_ID, ...参数 }
{
var id=obj.ID;
if (id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT || id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT ) //左右移动 { Step:移动数据个数 }
{
var isLeft=(id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT ? true:false);
var step=1;
if (obj.Step>0) step=obj.Step;
var oneStepWidth=this.GetMoveOneStepWidth();
if(this.DataMove(step*oneStepWidth,isLeft)) //每次移动一个数据
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
else
{
if (id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT && this.DragDownloadData)
this.DragDownloadData();
}
}
else if (id===JSCHART_OPERATOR_ID.OP_ZOOM_IN || id===JSCHART_OPERATOR_ID.OP_ZOOM_OUT) //缩放
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (id===JSCHART_OPERATOR_ID.OP_ZOOM_IN)
{
if (!this.Frame.ZoomUp(cursorIndex)) return;
}
else
{
if (!this.Frame.ZoomDown(cursorIndex)) return;
}
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
this.Draw();
}
else if (id===JSCHART_OPERATOR_ID.OP_GOTO_HOME)
{
var hisData=this.ChartOperator_Temp_GetHistroyData();;
if (!hisData) return; //数据还没有到达
var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
showCount-=this.RightSpaceCount;
var index=hisData.Data.length-showCount;
hisData.DataOffset=index;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO_HOME, dataOffset=${hisData.DataOffset} CursorIndex=${this.CursorIndex} PageSize=${showCount}`);
this.ChartOperator_Temp_Update();
}
else if (id===JSCHART_OPERATOR_ID.OP_GOTO_END)
{
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
hisData.DataOffset=0;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO_END `);
this.ChartOperator_Temp_Update();
}
else if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_IN || id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_OUT) //{ Step:增加/减少数量 } 左边增加/减少显示个数
{
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
var dataCount=hisData.Data.length;
var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
var dataOffset=hisData.DataOffset;
if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_IN) //增加
{
if (IFrameSplitOperator.IsNumber(obj.Step))
{
if (showCount>=dataCount) return;
var step=obj.Step;
if (step>dataOffset) step=dataOffset;
if (showCount+step>dataCount) step=dataCount-showCount;
if (step<=0) return;
showCount+=step;
hisData.DataOffset-=step;
}
}
else if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_OUT) //减少
{
var pageSize = this.GetMaxMinPageSize();
var minShowCount=pageSize.Min;
if (IFrameSplitOperator.IsNumber(obj.Step))
{
if (showCount<minShowCount) return;
var step=obj.Step;
if (showCount-step<minShowCount) step=showCount-minShowCount;
if (step<=0) return;
showCount-=step;
hisData.DataOffset+=step;
}
}
for(var i in this.Frame.SubFrame) //设置一屏显示的数据个数
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=showCount;
}
if (hisData.DataOffset<0) hisData.DataOffset=0;
this.ChartOperator_Temp_Update();
}
else if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_IN || id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_OUT) //{ Step:增加/减少数量 , ShowCount:显示个数 } 右边增加/减少显示个数
{
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
var dataCount=hisData.Data.length;
var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
var dataOffset=hisData.DataOffset;
if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_IN) //增加
{
if (IFrameSplitOperator.IsNumber(obj.Step))
{
if (showCount>=dataCount) return;
var endPos=dataOffset+showCount;
var rightCount=dataCount-endPos;
if (rightCount<=0) return;
var step=obj.Step;
if (step>rightCount) step=rightCount;
if (step<=0) return;
showCount+=step;
}
}
else if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_OUT) //减少
{
var pageSize = this.GetMaxMinPageSize();
var minShowCount=pageSize.Min;
if (IFrameSplitOperator.IsNumber(obj.Step))
{
if (showCount<minShowCount) return;
var step=obj.Step;
if (step>showCount) step=showCount;
if (showCount-step<minShowCount) step=showCount-minShowCount;
if (step<=0) return;
showCount-=step;
}
}
for(var i in this.Frame.SubFrame) //设置一屏显示的数据个数
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=showCount;
}
if (hisData.DataOffset<0) hisData.DataOffset=0;
this.ChartOperator_Temp_Update();
}
else if (id==JSCHART_OPERATOR_ID.OP_SET_SELECTRECT) //区间选择 {Start:{ Date:, Time:}, End:{ Date:, Time }, SubClient:{ Start:{ Date: }, End:{Date: }},}
{
if (!this.ChartPaint[0]) return false;
if (!this.ChartPaint[0].Data) return false;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return false;
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (!ChartData.IsDayPeriod(this.Period,true)) return false; //TODO:暂时只支持日线的
var firstPoint, secondPoint, subFirstPoint, subSecondPoint;
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (item.Date==obj.Start.Date)
{
firstPoint={ KItem:item, DataIndex:i };
}
if (item.Date==obj.End.Date)
{
secondPoint={ KItem:item, DataIndex:i };
}
if (obj.SubClient && obj.SubClient.Start && item.Date==obj.SubClient.Start.Date)
{
subFirstPoint={ KItem:item, DataIndex:i };
}
if (obj.SubClient && obj.SubClient.End && item.Date==obj.SubClient.End.Date)
{
subSecondPoint={ KItem:item, DataIndex:i };
}
if (firstPoint && secondPoint)
break;
}
if (!firstPoint || !secondPoint)
{
JSConsole.Chart.Warn("[KLineChartContainer::ChartOperator][OP_SET_SELECTRECT] can't find date. firstPoint, secondPoint, obj", firstPoint, secondPoint, obj);
return false;
}
paint.SetPoint(firstPoint.KItem, {Index:0, DataIndex:firstPoint.DataIndex });
paint.SetPoint(secondPoint.KItem, {Index:1, DataIndex:secondPoint.DataIndex });
if (subFirstPoint && subSecondPoint)
{
paint.SetPoint(subFirstPoint.KItem, {Index:3, DataIndex:subFirstPoint.DataIndex });
paint.SetPoint(subSecondPoint.KItem, {Index:4, DataIndex:subSecondPoint.DataIndex });
}
if (IFrameSplitOperator.IsBool(obj.PreventClose)) paint.PreventClose=obj.PreventClose;
//当前屏的K线范围, 如果区间不在当前屏移动K线
var bMoveKLine=false; //是否需要移动K线
var drawKRange=this.ChartPaint[0].DrawKRange;
if (drawKRange)
{
//左边
if ( (drawKRange.Start>=firstPoint.DataIndex && drawKRange.Start>=secondPoint.DataIndex) ||
(drawKRange.End<=firstPoint.DataIndex && drawKRange.End<=secondPoint.DataIndex) )
{
var offset=firstPoint.DataIndex;;
var dataCount=hisData.Data.length;
var showCount=this.ChartPaint[0].ShowRange.ShowCount; //显示个数
if (offset+showCount>dataCount) offset=dataCount-showCount;
if (offset<0) offset=0;
hisData.DataOffset=offset;
bMoveKLine=true;
}
}
if (bMoveKLine)
{
this.ChartOperator_Temp_Update();
}
else
{
this.Draw();
}
return true;
}
else if (id==JSCHART_OPERATOR_ID.OP_SET_SUB_SELECTRECT) // {Start:{ Date:, Time:}, End:{ Date:, Time }
{
if (!this.ChartPaint[0]) return false;
if (!this.ChartPaint[0].Data) return false;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return false;
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (!ChartData.IsDayPeriod(this.Period,true)) return false; //TODO:暂时只支持日线的
var firstPoint, secondPoint, subFirstPoint, subSecondPoint;
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (item.Date==obj.Start.Date)
{
firstPoint={ KItem:item, DataIndex:i };
}
if (item.Date==obj.End.Date)
{
secondPoint={ KItem:item, DataIndex:i };
}
if (firstPoint && secondPoint)
break;
}
if (!firstPoint || !secondPoint)
{
JSConsole.Chart.Warn("[KLineChartContainer::ChartOperator][OP_SET_SUB_SELECTRECT] can't find date. firstPoint, secondPoint, obj", firstPoint, secondPoint, obj);
return false;
}
paint.SetPoint(firstPoint.KItem, {Index:3, DataIndex:firstPoint.DataIndex });
paint.SetPoint(secondPoint.KItem, {Index:4, DataIndex:secondPoint.DataIndex });
this.Draw();
return true;
}
else if (id==JSCHART_OPERATOR_ID.OP_SCROOLBAR_SLIDER_CHANGED)
{
var hisData=this.ChartOperator_Temp_GetHistroyData();;
if (!hisData) return; //数据还没有到达
if (obj.Type==0) //滑块移动
{
hisData.DataOffset=obj.Start.Index;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
this.ChartOperator_Temp_Update();
}
else if (obj.Type==1 || obj.Type==2) //左,右
{
var startIndex=obj.Start.Index;
var showCount=(obj.End.Index-obj.Start.Index)+1;
var start=hisData.Data[obj.Start.Index];
var end=hisData.Data[obj.End.Index];
//设置X轴显示数据个数
this.Frame.SetXShowCount(showCount);
hisData.DataOffset=obj.Start.Index;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
this.ChartOperator_Temp_Update();
}
}
else if (id==JSCHART_OPERATOR_ID.OP_GOTO) //{ Date:日期, Time:, PageSize:可选 }
{
if (!IFrameSplitOperator.IsNumber(obj.Date)) return;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
var index=this.ChartOperator_GetIndex_ByDateTime(hisData, obj, this.Period, 0);
if (index===null)
{
JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO can't find date=${obj.Date} time=${obj.Time}`);
return;
}
var oldXPointCount=this.Frame.SubFrame[0].Frame.XPointCount;
var xPointCount=oldXPointCount;
if (obj.PageSize>0) //调整一屏显示的个数
{
xPointCount=obj.PageSize;
}
if (xPointCount!=oldXPointCount)
{
//设置X轴显示数据个数
this.Frame.SetXShowCount(xPointCount);
}
hisData.DataOffset=index;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
this.ChartOperator_Temp_Update();
}
else if (id==JSCHART_OPERATOR_ID.OP_GOTO_BY_DATAINDEX) //{PageSize:可选, DataIndex:起始位置数据索引}
{
if (!IFrameSplitOperator.IsNumber(obj.DataIndex)) return;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
if (obj.DataIndex<0 || obj.DataIndex>=hisData.Data.length)
{
JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO_BY_DATAINDEX obj.DataIndex=${obj.DataIndex} error.}`);
return;
}
var oldXPointCount=this.Frame.SubFrame[0].Frame.XPointCount;
var xPointCount=oldXPointCount;
if (obj.PageSize>0) xPointCount=obj.PageSize; //调整一屏显示的个数
if (xPointCount!=oldXPointCount) this.Frame.SetXShowCount(xPointCount); //设置X轴显示数据个数
hisData.DataOffset=obj.DataIndex;
this.CursorIndex=0;
this.LastPoint.X=null;
this.LastPoint.Y=null;
this.ChartOperator_Temp_Update();
}
else if (id==JSCHART_OPERATOR_ID.OP_CORSSCURSOR_GOTO) //移动十字光标{ Date:, Time }
{
if (!IFrameSplitOperator.IsNumber(obj.Date)) return;
var bTime=IFrameSplitOperator.IsNumber(obj.Time);
var pageInfo=this.GetChartStatus();
if (!pageInfo) return;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return; //数据还没有到达
var start=hisData.DataOffset;
var findIndex=-1, findItem=null, dataIndex=-1;
for(var i=start, j=0; i<hisData.Data.length && j<pageInfo.KLine.PageSize; ++i, ++j)
{
var item=hisData.Data[i];
if (bTime)
{
if (item.Date==obj.Date && item.Time==obj.Time)
{
findItem=item;
findIndex=j;
dataIndex=i;
break;
}
}
else
{
if (item.Date==obj.Date)
{
findItem=item;
findIndex=j;
dataIndex=i;
break;
}
}
}
if (findIndex<0)
{
return;
}
if (!this.Frame || !this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return false;
var frame=this.Frame.SubFrame[0].Frame;
var x=frame.GetXFromIndex(findIndex);
var y=frame.GetYFromData(item.Close);
//保存最后一次鼠标移动信息
var MoveStatus={ X:x, Y:y, IsInClient: this.IsMouseOnClient(x,y) };
this.LastMouseStatus.OnMouseMove=MoveStatus;
this.LastMouseStatus.MoveOnPoint={X:x, Y:y}; //鼠标移动的位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MOUSE_MOVE);
var titleChart=this.TitlePaint[0];
if (event && titleChart) titleChart.OnMouseMoveEvent=event;
var pixelTatio = GetDevicePixelRatio();
var e={};
e.clientX=(x/pixelTatio)+this.UIElement.getBoundingClientRect().left;
e.clientY=(y/pixelTatio)+this.UIElement.getBoundingClientRect().top;
this.MoveOnPoint={X:x, Y:y};
this.OnMouseMove(x,y,e);
this.LastMouseStatus.MoveOnPoint=null;
if (titleChart) titleChart.OnMouseMoveEvent=null;
}
}
//内部函数
this.ChartOperator_Temp_GetHistroyData=function()
{
var hisData=null;
if (!this.Frame.Data) hisData=this.Frame.Data;
else hisData=this.Frame.SubFrame[0].Frame.Data;
if (!hisData) return null; //数据还没有到达
return hisData;
}
this.ChartOperator_Temp_Update=function()
{
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.ResetFrameXSplit();
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
}
//定位K线的索引
//searchType 0模糊匹配 1=精确匹配
this.ChartOperator_GetIndex_ByDateTime=function(hisData, dateTime, period, searchType)
{
if (!hisData) return null; //数据还没有到达
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return null;
if (!IFrameSplitOperator.IsPlusNumber(dateTime.Date) || dateTime.Date<19810101) return null;
if (ChartData.IsDayPeriod(period, true))
{
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (searchType==1)
{
if (item.Date==dateTime.Date) return i;
}
else
{
if (item.Date>=dateTime.Date) return i;
}
}
return null;
}
if (ChartData.IsMinutePeriod(period,true) || ChartData.IsMilliSecondPeriod(period))
{
var findTime=null;
if (IFrameSplitOperator.IsNumber(dateTime.Time)) findTime=dateTime.Time;
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (searchType==1) //精确匹配
{
if (findTime==null) return null;
if (item.Date==dateTime.Date && item.Time==findTime) return i;
}
else
{
if (findTime==null) //只有日期
{
if (item.Date>=dateTime.Date) return i;
}
else
{
if (item.Date>dateTime.Date || (item.Date==dateTime.Date && item.Time>=findTime)) return i;
}
}
}
return null;
}
return null;
}
this.OnWheel=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer::OnWheel]',e);
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
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);
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
var enableZoomUpDown=true; //是否允许缩放
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Wheel===false) enableZoomUpDown=false;
if (this.SourceData && this.SourceData.Data)
{
if (isInClient && wheelValue<0 && enableZoomUpDown) //缩小
{
var cursorIndex={ ZoomType:this.ZoomType, IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (e.ctrlKey) cursorIndex.ZoomType=1; //ctrl+滚轴 十字中心缩放
if (this.Frame.ZoomDown(cursorIndex, { ZoomDownloadDataCallback:(requestData)=>{ this.ZoomDownloadData(requestData) } } ))
{
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true)
{
}
else
{
this.Draw();
}
this.OnKLinePageChange("wheel");
}
}
else if (isInClient && wheelValue>0 && enableZoomUpDown) //放大
{
var cursorIndex={ ZoomType:this.ZoomType, IsLockRight:this.IsZoomLockRight };
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (e.ctrlKey) cursorIndex.ZoomType=1; //ctrl+滚轴 十字中心缩放
if (this.Frame.ZoomUp(cursorIndex))
{
JSConsole.Chart.Log("[KLineChartContainer::OnWheel] cursorIndex ",cursorIndex)
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.ResetFrameXSplit();
this.Draw();
this.OnKLinePageChange("wheel");
}
}
}
if (!isInClient)
{
if (!this.OnWheel_ZoomUpDownFrameY(e,x,y)) return;
}
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
//通过滚轴缩放Y轴
this.OnWheel_ZoomUpDownFrameY=function(e, x, y)
{
if (!this.EnableYDrag.Wheel) return false;
var dragY=this.TryYDrag(x,y);
if (!dragY) return false;
if ((dragY.Left && !dragY.IsOverlay) || dragY.Right)
{
}
else
{
return false;
}
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
var yMove=this.EnableYDrag.WheelYMove;
if (wheelValue>0) yMove*=-1;
dragY.Position=0; //只能两边缩放
if (!this.Frame.OnZoomUpDownFrameY(dragY, yMove)) return false;
this.Frame.SetSizeChage(true);
this.Draw();
return true;
}
//创建
//windowCount 窗口个数
this.Create=function(windowCount, option)
{
this.UIElement.JSChartContainer=this;
//创建十字光标
this.ChartCorssCursor=new ChartCorssCursor();
this.ChartCorssCursor.Canvas=this.Canvas;
this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
this.ChartCorssCursor.StringFormatX.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
this.ChartCorssCursor.StringFormatY.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
this.ChartCorssCursor.StringFormatY.ExtendChartPaint=this.ExtendChartPaint;
this.ChartCorssCursor.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.OnChangeStatusCallback=(data, obj)=>{ this.OnChangeCorssCursorStatus(data,obj); }
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.HQChart=this;
//创建框架容器
this.Frame=new HQTradeFrame();
this.Frame.ChartBorder=new ChartBorder();
this.Frame.ChartBorder.UIElement=this.UIElement;
this.Frame.ChartBorder.Top=30;
this.Frame.ChartBorder.Left=5;
this.Frame.ChartBorder.Bottom=20;
this.Frame.Canvas=this.Canvas;
this.Frame.GetExtendChartRightWidth=()=> { return this.GetExtendChartRightWidth() }
this.Frame.GetExtendChartByClassName=(name)=> { return this.GetExtendChartByClassName(name); }
this.Frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
this.CreateChildWindow(windowCount);
this.CreateMainKLine();
this.CreateExtendChart("RectSelectPaint", option? option.SelectRect:null); //区间统计
if (this.EnableIndexChartDrag) this.CreateExtendChart("DragMovePaint");
this.CreateDragSelectRect(option? option.DragSelectRect:null);
//子窗口动态标题
for(var i in this.Frame.SubFrame)
{
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
this.TitlePaint.push(titlePaint);
}
this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame;
this.ChartCorssCursor.StringFormatY.Frame=this.Frame;
var bRegisterKeydown=true;
var bRegisterWheel=true;
if (option && option.Listener)
{
var item=option.Listener;
if (item.KeyDown===false)
{
bRegisterKeydown=false;
JSConsole.Chart.Log('[KLineChartContainer::Create] not register keydown event.');
}
if (item.Wheel===false)
{
bRegisterWheel=false;
JSConsole.Chart.Log('[KLineChartContainer::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.InitalPopMinuteChart(option);
}
this.InitalPopMinuteChart=function(option)
{
if (!option || !option.KLine) return false;
var item=option.KLine;
if (item.KLineDoubleClick===true)
{
this.PopMinuteChart=new JSPopMinuteChart();
this.PopMinuteChart.Inital(this);
return true;
}
return false;
}
this.DestroyPopMinuteChart=function()
{
if (!this.PopMinuteChart) return;
this.PopMinuteChart.Destroy();
this.PopMinuteChart=null;
}
this.ShowMinuteChartDialog=function(data, x,y)
{
if (!this.PopMinuteChart) return;
if (!data.Tooltip || !data.Chart) return;
var pixelRatio=GetDevicePixelRatio();
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
x+=(rtClient.left+rtScroll.Left);
y+=(rtClient.top+rtScroll.Top);
var date=data.Tooltip.Data.Date;
var symbol=data.Chart.Symbol;
this.PopMinuteChart.Show({ Date:date, Symbol:symbol, Data:data.Tooltip.Data }, x/pixelRatio,y/pixelRatio);
}
this.OnCustomKeyDown=function(keyID, e) //自定义键盘事件
{
if (keyID==37 && e.ctrlKey) //Ctrl+Left
{
this.MoveCorssCursorLeft(this.CtrlMoveStep);
return true;
}
else if (keyID==39 && e.ctrlKey) //Ctrl+Right
{
this.MoveCorssCursorRight(this.CtrlMoveStep);
return true;
}
else
{
return false;
}
}
this.MoveCorssCursorLeft=function(step)
{
var data=null;
if (this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return;
if (data.DataOffset<=0 && this.CursorIndex<=0) //数据到头了
{
if (this.DragDownloadData) this.DragDownloadData();
return;
}
if (this.CursorIndex-step<0) //当前屏到头了
{
data.DataOffset-=step;
if (data.DataOffset<0)
{
data.DataOffset=0;
this.CursorIndex=0;
}
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
return;
}
this.CursorIndex-=step;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
this.ShowTooltipByKeyDown();
}
this.MoveCorssCursorRight=function(step)
{
var data=null;
if (this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return;
var xPointcount=0; //当前屏显示个数
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (this.CursorIndex+data.DataOffset+1>=data.Data.length) return; //最右边了
var bMoveEnd=false; //最后一个
if (this.CursorIndex+step+data.DataOffset+1>data.Data.length) //数据不够步长
{
step=data.Data.length-1-data.DataOffset-this.CursorIndex;
bMoveEnd=true;
}
if (this.CursorIndex+step>=xPointcount) //当前屏最右边了
{
var lMoveStep=(this.CursorIndex+step)-(xPointcount-1);
data.DataOffset+=lMoveStep;
if (bMoveEnd) this.CursorIndex=xPointcount-1;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("keydown");
return;
}
this.CursorIndex+=step;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
this.ShowTooltipByKeyDown();
}
//获取K线图实例
this.GetKLineChart=function()
{
if (!this.ChartPaint[0]) return null;
return this.ChartPaint[0];
}
//创建子窗口
this.CreateChildWindow=function(windowCount)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_FRAME);
for(var i=0;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=g_ChartFrameFactory.Create("KLineFrame", { ID:i });
frame.Canvas=this.Canvas;
frame.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); };
frame.ChartBorder=border;
frame.Identify=i; //窗口序号
frame.RightSpaceCount=this.RightSpaceCount; //右边
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.GlobalOption=this.GlobalOption;
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
frame.HorizontalMax=20;
frame.HorizontalMin=10;
if (i==0)
{
frame.YSplitOperator=new FrameSplitKLinePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
frame.YSplitOperator.FrameSplitData2=this.FrameSplitData.get('double');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.YSplitOperator.GetKLineChartCallback=()=> { return this.GetKLineChart(); }
frame.YSplitOperator.HQChart=this;
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
border.BottomSpace=15*pixelTatio; //主图上下留空间
border.TopSpace=15*pixelTatio;
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.YSplitOperator.GetKLineChartCallback=()=> { return this.GetKLineChart(); }
frame.YSplitOperator.HQChart=this;
//frame.IsLocked = true;
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.LanguageID=this.LanguageID;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
}
this.CreateSubFrameItem=function(id)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frameClassName="KLineFrame";
if (this.ClassName=="KLineChartHScreenContainer") frameClassName="KLineHScreenFrame";
var frame=g_ChartFrameFactory.Create(frameClassName, { ID:id });
frame.Canvas=this.Canvas;
frame.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); };
frame.ChartBorder=border;
frame.Identify=id; //窗口序号
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.GlobalOption=this.GlobalOption;
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
frame.HorizontalMax=20;
frame.HorizontalMin=10;
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.YSplitOperator.GetKLineChartCallback=()=> { return this.GetKLineChart(); };
frame.YSplitOperator.HQChart=this;
frame.XSplitOperator.Symbol=this.Symbol;
frame.XSplitOperator.Period=this.Period;
//K线数据绑定
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
frame.Data=this.ChartPaint[0].Data;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
subFrame.Height=10;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_FRAME);
if (event && event.Callback)
{
var sendData={ SubFrame:subFrame, WindowIndex:id };
event.Callback(event, sendData, this);
}
return subFrame;
}
//创建主图K线画法
this.CreateMainKLine=function()
{
var kline=g_ChartPaintFactory.Create("ChartKLine");
kline.Canvas=this.Canvas;
kline.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
kline.ChartFrame=this.Frame.SubFrame[0].Frame;
kline.Name="Main-KLine";
kline.DrawType=this.KLineDrawType;
kline.Identify="Main-KLine";
kline.GetEventCallback=(id)=>{ return this.GetEventCallback(id); };
this.ChartPaint[0]=kline;
this.TitlePaint[0]=new DynamicKLineTitlePainting();
this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].Canvas=this.Canvas;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.TitlePaint[0].LanguageID=this.LanguageID;
this.TitlePaint[0].HQChart=this;
this.TitlePaint[0].GetEventCallback=(id)=>{ return this.GetEventCallback(id); };
}
//绑定主图K线数据
this.BindMainData=function(hisData, showCount, chartOperator)
{
var isShowAll=false; //全部显示
if (chartOperator && chartOperator.IsShowAll===true) isShowAll=true;
this.ChartPaint[0].Data=hisData;
this.ChartPaint[0].Symbol=this.Symbol;
if (this.KLineSize)
{
if (!IFrameSplitOperator.IsNumber(this.KLineSize.DataWidth))
{
showCount=this.Frame.SubFrame[0].Frame.XPointCount-this.RightSpaceCount;
}
else
{
var obj=this.Frame.SetDataWidth(this.KLineSize.DataWidth);
showCount=obj.XPointCount-this.RightSpaceCount;
this.KLineSize.DataWidth=null;
}
}
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item =this.Frame.SubFrame[i].Frame;
if (isShowAll) item.XPointCount=hisData.Data.length+this.RightSpaceCount;
else item.XPointCount=showCount+this.RightSpaceCount;
item.Data=this.ChartPaint[0].Data;
item.XSplitOperator.Symbol=this.Symbol;
item.XSplitOperator.Period=this.Period;
}
this.TitlePaint[0].Data=this.ChartPaint[0].Data; //动态标题
this.TitlePaint[0].Symbol=this.Symbol;
this.TitlePaint[0].Name=this.Name;
this.TitlePaint[0].Period=this.Period;
this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标
this.Frame.Data=this.ChartPaint[0].Data;
for(var i=0; i<this.OverlayChartPaint.length; ++i) //K线叠加 主图股票数据绑定到叠加上
{
var item=this.OverlayChartPaint[i];
item.MainData=this.ChartPaint[0].Data;
}
if (isShowAll)
{
var dataOffset=0;
this.CursorIndex=0;
}
else
{
var dataOffset=hisData.Data.length-showCount;
if (dataOffset<0) dataOffset=0;
this.ChartPaint[0].Data.DataOffset=dataOffset;
this.CursorIndex=showCount;
if (this.CursorIndex+dataOffset>=hisData.Data.length) this.CursorIndex=hisData.Data.length-1-dataOffset;
if (this.CursorIndex<0) this.CursorIndex=0; //不一定对啊
}
this.ChartPaint[0].Period=this.Period;
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
if (this.CustomShow) //定制显示 1次有效
{
this.SetCustomShow(this.CustomShow,hisData);
this.CustomShow=null;
}
}
this.ShowAllKLine=function()
{
var chart=this.ChartPaint[0];
if (!chart) return false;
var kData=chart.Data;
if (!kData || !IFrameSplitOperator.IsNonEmptyArray(kData.Data)) return false;
var xCount=kData.Data.length+this.RightSpaceCount;
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=xCount;
}
kData.DataOffset=0;
this.CursorIndex=0;
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.UpdatePointByCursorIndex(2); //取消十字光标
this.Draw();
}
this.UpdateMainData=function(hisData, lastDataCount)
{
var frameHisdata=null;
if (!this.Frame.Data) frameHisdata=this.Frame.Data;
else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata=this.Frame.SubFrame[0].Frame.Data;
if (!frameHisdata) return;
var xPointCount=this.Frame.SubFrame[0].Frame.XPointCount; //当前一屏能显示的数据个数
var newDataCount=0;
if (IFrameSplitOperator.IsNumber(lastDataCount))
{
if (lastDataCount>0 && hisData.Data.length>lastDataCount)
{
newDataCount=hisData.Data.length-lastDataCount;
JSConsole.Chart.Log(`[KLineChartContainer::UpdateMainData] [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}], [Pagesize=${xPointCount}]`);
}
else if (lastDataCount==0 && hisData.Data.length>xPointCount) //历史数据为空,当前收到数据大于一屏的数据,显示最新数据
{
newDataCount=hisData.Data.length-xPointCount;
JSConsole.Chart.Log(`[KLineChartContainer::UpdateMainData] history data is empty. [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}], [Pagesize=${xPointCount}]`);
}
}
this.ChartPaint[0].Data=hisData;
this.ChartPaint[0].Symbol=this.Symbol;
if (hisData.Data.length>xPointCount) //不满一屏的, 不需要调整索引
this.ChartPaint[0].Data.DataOffset=frameHisdata.DataOffset+newDataCount; //加上数据增加的个数
for(var i in this.Frame.SubFrame)
{
var item =this.Frame.SubFrame[i].Frame;
item.Data=this.ChartPaint[0].Data;
if (i==0) //更新Y轴K线数据
{
item.YSplitOperator.Symbol=this.Symbol;
item.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
item.YSplitOperator.Period=this.Period; //周期
}
}
this.TitlePaint[0].Data=this.ChartPaint[0].Data; //动态标题
this.TitlePaint[0].Symbol=this.Symbol;
this.TitlePaint[0].Name=this.Name;
this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标
this.Frame.Data=this.ChartPaint[0].Data;
for(var i in this.OverlayChartPaint) //主图股票数据绑定到叠加股票上
{
var item=this.OverlayChartPaint[i];
item.MainData=this.ChartPaint[0].Data;
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
}
this.SetCustomShow=function(customShow,hisData)
{
if (customShow.Callback) //预留给外部回调,可以定制移动
{
customShow.Callback(chart, hisData)
return;
}
var index=this.ChartOperator_GetIndex_ByDateTime(hisData,customShow, this.Period, 0);
if (index===null)
{
JSConsole.Chart.Log("[KLineChartContainer::SetCustomShow] Can't find index by customShow=",customShow);
return;
}
if (IFrameSplitOperator.IsPlusNumber(customShow.PageSize)) //调整一屏显示个数 否则使用默认的
{
var showCount=customShow.PageSize;
for(var i=0;i<this.Frame.SubFrame.length; ++i)
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=showCount;
}
}
this.ChartPaint[0].Data.DataOffset=index;
this.CursorIndex=0;
}
this.OnDragSelectRectMouseUp=function(e)
{
var paint=this.GetRectSelectPaint();
if (!paint) return;
var selectData=paint.GetSelectRectData();
if (!selectData) return;
var pixelTatio = GetDevicePixelRatio();
var corssCursor=this.ChartCorssCursor; //十字光标
var x=corssCursor.LastPoint.X/pixelTatio;
var y=corssCursor.LastPoint.Y/pixelTatio;
var isShowMenu=true;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT_MOUSEUP);
if (event)
{
var data=
{
X:x,
Y:y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
IsShowMenu:false,
};
event.Callback(event,data,this);
isShowMenu=data.IsShowMenu;
}
if (this.IsShowSelectRectDialog()) //区间统计
{
var data=
{
Chart:this,X:x,Y:y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
e.data=data;
this.DrawSelectRectDialog(e);
}
else if (isShowMenu)
{
var data=
{
Chart:this,
X:x,
Y:y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
e.data=data;
this.PopupSelectRectMenuV2(data, e);
}
}
this.OnDragSubSelectRectMouseUp=function(e)
{
var paint=this.GetRectSelectPaint();
if (!paint) return;
var selectData=paint.GetSelectRectData();
if (!selectData) return;
var pixelTatio = GetDevicePixelRatio();
var corssCursor=this.ChartCorssCursor; //十字光标
var x=corssCursor.LastPoint.X/pixelTatio;
var y=corssCursor.LastPoint.Y/pixelTatio;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SUB_SELECT_RECT_MOUSEUP);
if (event)
{
var subRectData={ Start:paint.SubClient.FirstPoint, End: paint.SubClient.SecondPoint };
var data=
{
X:x,
Y:y,
SubSelectData:subRectData, //子区域数据
RectSelectPaint:paint, //区间选择背景
};
event.Callback(event,data,this);
}
}
this.ShowSelectData=function(selectData)
{
this.HideSelectRect();
JSConsole.Chart.Log('[KLineChartContainer::ShowSelectData] selectData', selectData);
var dataOffset=selectData.Start;
var showCount=(selectData.End-selectData.Start)+1;
JSConsole.Chart.Log(`[KLineChartContainer::ShowSelectData] DataOffset=${dataOffset}, ShowCount=${showCount}`);
for(var i in this.Frame.SubFrame)
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=showCount;
}
this.ChartPaint[0].Data.DataOffset=dataOffset;
this.CursorIndex=0;
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
}
this.OnMarkRectSelect=function(e)
{
var corssCursor=this.ChartCorssCursor; //十字光标
if (!corssCursor || corssCursor.Status==0) return;
if (!IFrameSplitOperator.IsNumber(corssCursor.CursorIndex)) return;
if (!this.ChartPaint[0] || !this.ChartPaint[0].Data) return;
var paint=this.GetRectSelectPaint();
if (!paint) return;
var cursorIndex=corssCursor.CursorIndex;
JSConsole.Chart.Log("[KLineChartContainer::OnMarkRectSelect] dataIndex", cursorIndex);
var kData=this.ChartPaint[0].Data;
cursorIndex=parseInt(cursorIndex.toFixed(0));
var index=cursorIndex+kData.DataOffset;
if (index>=kData.Data.length) index=kData.Data.length-1;
var item = kData.Data[index];
JSConsole.Chart.Log("[KLineChartContainer::OnMarkRectSelect] item", item);
if (!this.SetRectSelectData(item, index)) return;
var pointCount=paint.GetPointCount();
var pixelTatio = GetDevicePixelRatio();
if (pointCount==1) //第1个位置
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT_FIRST);
if (event && event.Callback)
{
var data=
{
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
Item:item,
Index:index,
RectSelectPaint:paint, //区间选择背景
e:e,
};
event.Callback(event,data,this);
}
}
else if (pointCount==2)
{
var selectData=paint.GetSelectRectData();
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT);
var isShowMenu=true;
if (event && event.Callback)
{
var data=
{
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
IsShowMenu:true,
e:e,
};
event.Callback(event,data,this);
isShowMenu=data.IsShowMenu;
}
if (isShowMenu)
{
var data=
{
Chart:this,
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
e.data=data
this.PopupSelectRectMenuV2(data, e);
}
}
this.Draw();
}
//创建指定窗口指标
this.CreateWindowIndex=function(windowIndex)
{
this.WindowIndex[windowIndex].Create(this,windowIndex);
}
this.BindIndexData=function(windowIndex, hisData, option)
{
if (!this.WindowIndex[windowIndex]) return;
var item=this.WindowIndex[windowIndex];
if (typeof(item.RequestData)=="function") //数据需要另外下载的.
{
item.RequestData(this,windowIndex,hisData, option);
return;
}
if (typeof(item.ExecuteScript)=='function')
{
if (option && option.CheckRunCount)
if (item.IsExcessRunCount()) return;
item.ExecuteScript(this,windowIndex,hisData);
return;
}
item.BindData(this,windowIndex,hisData);
}
//叠加指标 option={ CheckRunCount:执行次数检测 ,SyncExecute:同步|异步检测 }
this.BindOverlayIndexData=function(overlayItem, windowIndex, hisData, option)
{
if (!overlayItem.Script) return;
if (typeof(overlayItem.Script.RequestData)=='function')
{
overlayItem.Script.RequestData(this,windowIndex,hisData);
return;
}
if (typeof(overlayItem.Script.ExecuteScript)=='function')
{
if (option)
{
if (option.CheckRunCount) //检测执行次数
{
if (overlayItem.Script.IsExcessRunCount())
return;
}
if (IFrameSplitOperator.IsBool(option.SyncExecute)) //异步|同步
{
if (overlayItem.Script.IsSync!=option.SyncExecute)
return;
}
}
overlayItem.Script.ExecuteScript(this,windowIndex,hisData);
return;
}
overlayItem.Script.BindData(this,windowIndex,hisData);
}
//执行指示(专家指示 五彩K线)
this.BindInstructionIndexData=function(hisData)
{
if (this.ColorIndex && typeof(this.ColorIndex.ExecuteScript)=='function') //五彩K线
{
this.ColorIndex.ExecuteScript(this,0,hisData);
}
if (this.TradeIndex && typeof(this.TradeIndex.ExecuteScript)=='function') //交易指标
{
this.TradeIndex.ExecuteScript(this,0,hisData);
}
}
//获取子窗口的所有画法
this.GetChartPaint=function(windowIndex)
{
var paint=new Array();
for(var i in this.ChartPaint)
{
if (i==0) continue; //第1个K线数据除外
var item=this.ChartPaint[i];
if (item.ChartFrame==this.Frame.SubFrame[windowIndex].Frame)
paint.push(item);
}
return paint;
}
this.AutoUpdateEvent=function(bStart, explain) //自定更新事件, 是给websocket使用
{
var eventID=bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE:JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE;
if (!this.mapEvent.has(eventID)) return;
var self=this;
var event=this.mapEvent.get(eventID);
var data={ Stock:{ Symbol:this.Symbol, Name:this.Name, Right:this.Right, Period:this.Period }, Explain: explain };
if (bStart)
{
data.Callback=function(data) //数据到达更新回调
{
if (ChartData.IsDayPeriod(self.Period,true)) self.RecvRealtimeData(data);
else if (ChartData.IsMinutePeriod(self.Period,true)) self.RecvMinuteRealtimeData(data);
else if (ChartData.IsSecondPeriod(self.Period)) self.RecvMinuteRealtimeData(data);
else if (ChartData.IsMilliSecondPeriod(self.Period)) self.RecvMinuteRealtimeData(data);
}
}
event.Callback(event,data,this);
}
this.SendKLineUpdateEvent=function(bindData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.RECV_KLINE_UPDATE_DATA);
if (event && event.Callback)
{
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
return true;
}
return false;
}
this.SendManualKLineUpdateEvent=function(bindData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.RECV_KLINE_MANUAL_UPDATE_DATA);
if (event && event.Callback)
{
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
return true;
}
return false;
}
this.GetKLineDrawType=function()
{
return this.KLineDrawType;
}
this.RequestHistoryData=function()
{
var self=this;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.FlowCapitalReady=false;
this.ResetPage(); //重置分页
this.ResetDragDownload();
this.ResetZoomDownload();
this.Draw();
if (this.NetworkFilter)
{
var kLineDrawType=this.GetKLineDrawType();
var obj=
{
Name:'KLineChartContainer::RequestHistoryData', //类名::
Explain:'日K数据',
Request:{ Url:self.KLineApiUrl, Type:'POST' ,
Data:
{
symbol:self.Symbol, count:self.MaxRequestDataCount,
field: ["name","symbol","yclose","open","price","high","low","vol"],
period:this.Period, right:this.Right, klineDrawType:kLineDrawType
} },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
{
self.RequestHistoryPageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::RequestHistoryData');
self.AutoUpdate();
}
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.KLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
{
self.RequestHistoryPageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::RequestHistoryData');
self.AutoUpdate();
}
}
});
}
this.BindAllOverlayIndexData=function(hisData, option)
{
if (!this.Frame || !this.Frame.SubFrame) return;
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,hisData,option)
}
}
}
this.RecvHistoryData=function(data)
{
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[KLineChartContainer::RecvHistoryData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=0; //0=日线数据 1=分钟数据
sourceData.Symbol=data.symbol;
this.SourceData=sourceData;
if (this.BeforeBindMainData) this.BeforeBindMainData("RecvHistoryData");
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=0;
bindData.Symbol=data.symbol;
if (bindData.Right>0 && !this.IsApiPeriod) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula } );
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:"RecvHistoryData" });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.Symbol=data.symbol;
this.Name=data.name;
this.BindMainData(bindData,this.PageSize);
if (this.AfterBindMainData) this.AfterBindMainData("RecvHistoryData");
this.Frame.SetSizeChage(true);
var firstSubFrame;
if (this.Frame.SubFrame[0]) firstSubFrame=this.Frame.SubFrame[0].Frame;
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
}
var page=this.Page.Day;
if (page.Enable==false || (page.Enable==true && page.Finish==true)) //分页下载 这些数据迁移到分页下载完以后下载
{
this.ReqeustKLineInfoData({ FunctionName:"RecvHistoryData" }); //请求信息地雷
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) page.Index=1; //第一页下载完成
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i) //执行指标
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.UpdatePointByCursorIndex(2); //取消十字光标
this.Draw();
this.BindAllOverlayIndexData(bindData,{ SyncExecute:false } ); //异步模式叠加指标
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.RequestHistoryPageData=function() //请求分页
{
var self=this;
if (this.NetworkFilter)
{
var firstItem=this.SourceData.Data[0]; //最新的一条数据
var obj=
{
Name:'KLineChartContainer::RequestHistoryPageData', //类名::
Explain:'日K数据分页',
Request:{ Url:'none', Type:'POST' ,
Data: { symbol:self.Symbol, index:self.Page.Day.Index, field: ["name","symbol","yclose","open","price","high","low","vol"], firstDate:firstItem.Date, first:{ date: firstItem.Date } } },
Page:self.Page.Day,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvHistoryPageData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
self.RequestHistoryPageData(); //继续下载
else
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//模拟异步请求
setTimeout(function()
{
var page=self.Page.Day;
page.Finish=true;
var data= //测试数据
{
data:
[
[ 20150218, 12.54, 12.5, 12.74, 11.95, 12.27, 117632441, 1459671045 ],
[ 20150219, 12.27, 12.1, 12.23, 11.9, 12.23, 95889423, 1157078548 ],
[ 20150220, 12.23, 12.17, 12.17, 11.9, 12.05, 67763439, 815652761]
],
symbol:self.Symbol,
name:self.Name
};
self.RecvHistoryPageData(data);
if (page.Enable==true && page.Finish==false)
self.RequestHistoryPageData();
else
self.AutoUpdate();
},500)
}
this.RecvHistoryPageData=function(data)
{
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[KLineChartContainer::RecvHistoryPageData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
for(var i in aryDayData) //数据往前插
{
var item=aryDayData[i];
this.SourceData.Data.splice(i,0,item);
}
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
if (bindData.Right>0 && bindData.Period<=3) //复权(日线数据才复权)
{
var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
var page=this.Page.Day;
++page.Index;
if (page.Enable==true && page.Finish==true) //分页下载 这些数据迁移到分页下载完以后下载
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.RequestHistoryMinuteData=function()
{
var self=this;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.FlowCapitalReady=false;
this.ResetPage(); //重置分页
this.ResetDragDownload();
this.ResetZoomDownload();
this.Draw();
if (this.NetworkFilter)
{
var kLineDrawType=this.GetKLineDrawType();
var obj=
{
Name:'KLineChartContainer::ReqeustHistoryMinuteData', //类名::
Explain:'1分钟K线数据',
Request:{ Url:self.MinuteKLineApiUrl, Type:'POST',
Data:
{
symbol:self.Symbol, count:self.MaxRequestMinuteDayCount,
field: ["name","symbol", "yclose","open","price","high","low","vol"],
period:this.Period, right:this.Right, klineDrawType:kLineDrawType
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvMinuteHistoryData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
{
self.ReqeustHistoryMinutePageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::ReqeustHistoryMinuteData');
self.AutoUpdate();
}
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol", "yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvMinuteHistoryData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
{
self.ReqeustHistoryMinutePageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::ReqeustHistoryMinuteData');
self.AutoUpdate();
}
}
});
}
//支持老版本
this.ReqeustHistoryMinuteData=this.RequestHistoryMinuteData;
this.RecvMinuteHistoryData=function(data)
{
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[KLineChartContainer::RecvMinuteHistoryData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=1; //0=日线数据 1=分钟数据
sourceData.Symbol=data.symbol;
this.SourceData=sourceData;
if (this.BeforeBindMainData) this.BeforeBindMainData("RecvMinuteHistoryData");
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=1;
bindData.Symbol=data.symbol;
if (bindData.Right>0 && !this.IsApiPeriod && this.RightFormula>=1) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula } );
bindData.Data=rightData;
}
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:"RecvMinuteHistoryData" });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.Symbol=data.symbol;
this.Name=data.name;
var chartOperator=null; //额外的图形控制
if (data && data.ChartOperator)
{
var item=data.ChartOperator;
chartOperator={ };
if (item.IsShowAll===true) chartOperator.IsShowAll=true; //全部显示
}
this.BindMainData(bindData,this.PageSize,chartOperator);
if (this.AfterBindMainData) this.AfterBindMainData("RecvMinuteHistoryData");
this.Frame.SetSizeChage(true);
var firstSubFrame;
if (this.Frame.SubFrame[0]) firstSubFrame=this.Frame.SubFrame[0].Frame;
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
}
for(var i in this.OverlayChartPaint) //分钟数据不支持叠加 清空
{
var item=this.OverlayChartPaint[i];
item.Data=null;
//item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
}
var page=this.Page.Minute;
if (page.Enable==false || (page.Enable==true && page.Finish==true) )
{
this.ReqeustKLineInfoData({ FunctionName:"RecvMinuteHistoryData" }); //请求信息地雷
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryMinuteData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) ++page.Index;
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i) //执行指标
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(2); //切换周期了取消十字光标
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
//叠加指标
this.BindAllOverlayIndexData(bindData, { SyncExecute:false } ); //异步模式叠加指标
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.ReqeustHistoryMinutePageData=function()
{
var self=this;
if (this.NetworkFilter)
{
var firstItem=this.SourceData.Data[0]; //最新的一条数据
var obj=
{
Name:'KLineChartContainer::RecvHistoryMinutePageData', //类名::
Explain:'1分钟K线数据分页',
Request:{ Url:'none', Type:'POST' ,
Data: { symbol:self.Symbol, index:self.Page.Minute.Index, field: ["name","symbol","yclose","open","price","high","low","vol"], firstDate:firstItem.Date, first:{ date: firstItem.Date, time:firstItem.Time } } },
Page:self.Page.Minute,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvHistoryMinutePageData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
self.ReqeustHistoryMinutePageData(); //继续下载
else
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//模拟异步请求
setTimeout(function()
{
var page=self.Page.Minute;
page.Finish=true;
var data= //测试数据
{
data:
[
[ 20190906,14.58,14.71,14.71,14.71,14.71,1096425,16128411,925],
[ 20190906,14.71,14.73,14.74,14.71,14.71,2154859,31731820,930],
[ 20190906,14.71,14.71,14.71,14.68,14.69,1427516,20989208,931],
[ 20190906,14.69,14.69,14.71,14.68,14.7, 1680503,24694143,932],
[ 20190906,14.7,14.69,14.7,14.65,14.65,1315900,19310964,933],
[ 20190906,14.65,14.66,14.69,14.65,14.68,702955,10313842,934],
[ 20190906,14.68,14.7,14.71,14.67, 14.67,1735266,25495875,935],
[ 20190906,14.67,14.68,14.7,14.67,14.67,739000,10845398,936],
[ 20190906,14.67,14.67,14.68,14.67,14.68,389800,5721266,937],
[ 20190906,14.68,14.68,14.7,14.68,14.69,648477,9527859,938],
[ 20190906,14.69,14.7,14.71,14.69,14.7,1128400,16589794,939],
[ 20190906,14.7,14.7,14.71,14.69,14.71,714858,10509708,940],
[ 20190906,14.71,14.71,14.71,14.69,14.69,401500,5900477,941],
[ 20190906,14.69,14.69,14.71,14.69,14.69,1165684,17131034,942],
[ 20190906,14.69, 14.69,14.7,14.67,14.67,498516, 7321024,943],
[ 20190906,14.67,14.68,14.68,14.67,14.67,350126,5139012,944],
[ 20190906,14.67,14.67,14.69,14.67,14.69,561600,8246789,945]
],
//symbol:'600000.sh',
//name:'浦发行情'
};
self.RecvHistoryMinutePageData(data);
if (page.Enable==true && page.Finish==false)
self.ReqeustHistoryMinutePageData();
else
self.AutoUpdate();
},500)
}
this.RecvHistoryMinutePageData=function(data)
{
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[KLineChartContainer::RecvHistoryMinutePageData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
for(var i in aryDayData) //数据往前插
{
var item=aryDayData[i];
this.SourceData.Data.splice(i,0,item);
}
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,false)) //复权(日线数据才复权)
{
var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
var page=this.Page.Minute;
if (page.Enable==false || (page.Enable==true && page.Finish==true) )
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) ++page.Index;
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
//请求实时行情数据
this.RequestRealtimeData=function()
{
var self=this;
var arySymbol=[self.Symbol];
for(var i in this.OverlayChartPaint) //叠加的股票更新
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue;
arySymbol.push(item.Symbol);
}
if (this.NetworkFilter)
{
var kLineDrawType=this.GetKLineDrawType();
var dateRange=null;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (hisData) dateRange=hisData.GetDateRange();
var obj=
{
Name:'KLineChartContainer::RequestRealtimeData', //类名::函数名
Explain:'当天最新日线数据',
Request:
{
Url:self.RealtimeApiUrl,
Data:
{
symbol: arySymbol,
field:["name","symbol","yclose","open","price","high","low","vol","amount","date","time"],
period:this.Period, right:this.Right, klineDrawType:kLineDrawType,
dateRange:dateRange
},
Type:'POST'
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvRealtimeData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time"],
"symbol": arySymbol,
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvRealtimeData(data);
self.AutoUpdate();
}
});
}
this.RecvRealtimeData=function(data)
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
var realtimeData=KLineChartContainer.JsonDataToRealtimeData(data,this.Symbol);
if (!realtimeData) return;
var item=this.SourceData.Data[this.SourceData.Data.length-1]; //最新的一条数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
if (this.SourceData.Data.length==0) //第1条数据
{
var newItem =new HistoryData();
HistoryData.CopyTo(newItem,realtimeData);
this.SourceData.Data.push(newItem);
}
else if (item.Date==realtimeData.Date) //实时行情数据更新
{
JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] update kline by realtime data',realtimeData);
HistoryData.CopyTo(item,realtimeData);
}
else if (item.Date<realtimeData.Date) //新增加数据
{
JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] insert kline by realtime data',realtimeData);
var newItem =new HistoryData();
HistoryData.CopyTo(newItem,realtimeData);
if (!IFrameSplitOperator.IsNumber(newItem.YClose) && this.SourceData.Data.length>0)
newItem.YClose=this.SourceData.Data[this.SourceData.Data.length-1].YClose;
this.SourceData.Data.push(newItem);
}
else
{
var bFind=false;
var aryKData=this.SourceData.Data;
for(var i=aryKData.length-1;i>=0; --i)
{
var kItem=aryKData[i];
if (kItem.Date==realtimeData.Date)
{
HistoryData.CopyTo(kItem,realtimeData);
bFind=true;
break;
}
}
if (!bFind) return;
}
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,true) && MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && !this.IsApiPeriod) //复权(A股日线数据才复权)
{
var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (!this.IsApiPeriod)
{
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:"RecvRealtimeData" });
bindData=newBindData;
this.FlowCapitalReady=true;
}
this.UpdateMainData(bindData,lastDataCount);//更新主图数据
this.UpdateOverlayRealtimeData(data); //更新叠加股票数据
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData, { CheckRunCount:true });
}
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true, SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(1); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
this.UpdateDOMTooltip(0, bindData);
this.UpdateHQFloatTooltip(bindData);
//叠加指标计算
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true,SyncExecute:false }); //异步模式叠加指标
if (this.mapEvent.has(JSCHART_EVENT_ID.ON_RECV_REALTIME_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.ON_RECV_REALTIME_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.UpdateOverlayRealtimeData=function(data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint)) return;
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue;
var realtimeData=KLineChartContainer.JsonDataToRealtimeData(data,item.Symbol); //获取叠加股票的最新数据
if (!realtimeData) continue;
var sourceData=item.SourceData; //叠加股票的所有数据
var latestData=sourceData.Data[sourceData.Data.length-1]; //最新的一条数据
if (latestData.Date==realtimeData.Date) //实时行情数据更新
{
JSConsole.Chart.Log('[KLineChartContainer::UpdateOverlayRealtimeData] update kline by minute data',realtimeData);
latestData.Close=realtimeData.Close;
latestData.High=realtimeData.High;
latestData.Low=realtimeData.Low;
latestData.Vol=realtimeData.Vol;
latestData.Amount=realtimeData.Amount;
}
else if (latestData.Date<realtimeData.Date) //新增加数据
{
JSConsole.Chart.Log('[KLineChartContainer::UpdateOverlayRealtimeData] insert kline by minute data',realtimeData);
var newItem =new HistoryData();
newItem.YClose=realtimeData.YClose;
newItem.Open=realtimeData.Open;
newItem.Close=realtimeData.Close;
newItem.High=realtimeData.High;
newItem.Low=realtimeData.Low;
newItem.Vol=realtimeData.Vol;
newItem.Amount=realtimeData.Amount;
newItem.Date=realtimeData.Date;
sourceData.Data.push(newItem);
}
else
{
continue;
}
var bindData=new ChartData();
bindData.Data=sourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol) && !this.IsApiPeriod) //复权数据 ,A股才有有复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
}
}
this.RequestMinuteRealtimeData=function()
{
var self=this;
var arySymbol=[self.Symbol];
for(var i in this.OverlayChartPaint) //叠加的股票更新
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue;
arySymbol.push(item.Symbol);
}
if (this.NetworkFilter)
{
var kLineDrawType=this.GetKLineDrawType();
var dateRange=null;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (hisData) dateRange=hisData.GetDateRange();
var obj=
{
Name:'KLineChartContainer::RequestMinuteRealtimeData', //类名::
Explain:'当天1分钟K线数据',
Request:
{
Url:self.RealtimeApiUrl,
Data:
{
symbol: arySymbol,
field:["name","symbol","price","yclose","minutecount","minute","date","time"],
period:this.Period, right:this.Right, klineDrawType:kLineDrawType,
dateRange:dateRange
},
Type:'POST'
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvMinuteRealtimeData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.RealtimeApiUrl,
data:
{
"field": ["name","symbol","price","yclose","minutecount","minute","date","time"],
"symbol": arySymbol,
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvMinuteRealtimeData(data);
self.AutoUpdate();
}
});
}
this.SetSourceDatatLimit=function(aryLimit)
{
this.SourceDataLimit=new Map();
for(var i in aryLimit)
{
var item=aryLimit[i];
this.SourceDataLimit.set(item.Period, item.MaxCount); //每个周期缓存数据最大个数 key=周期 value=最大个数
JSConsole.Chart.Log(`[KLineChartContainer::SetSourceDatatLimit] Period=${item.Period}, MaxCount=${item.MaxCount}`);
}
}
this.ReduceSourceData=function()
{
if (!this.SourceDataLimit) return;
if (!this.SourceDataLimit.has(this.Period)) return;
var limitCount=this.SourceDataLimit.get(this.Period);
var frameHisdata=null;
if (!this.Frame.Data) frameHisdata=this.Frame.Data;
else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata=this.Frame.SubFrame[0].Frame.Data;
if (!frameHisdata) return;
if (limitCount<50) return;
var dataOffset=frameHisdata.DataOffset;
var removeCount=0;
while(this.SourceData.Data.length>limitCount)
{
this.SourceData.Data.shift();
--dataOffset;
++removeCount;
}
if (removeCount>0)
{
if (dataOffset<0) dataOffset=0;
frameHisdata.DataOffset=dataOffset;
JSConsole.Chart.Log(`[KLineChartContainer::ReduceSourceData] remove data ${removeCount}, dataOffset=${dataOffset}`);
}
}
this.RecvMinuteRealtimeDataV2=function(data) //新版本的
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[KLineChartContainer::RecvMinuteRealtimeDataV2] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryMinuteData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
if (!aryMinuteData || aryMinuteData.length<=0) return;
if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
if (!this.SourceData) return;
if (!this.SourceData.MergeMinuteData(aryMinuteData)) return;
JSConsole.Chart.Log(`[KLineChartContainer::RecvMinuteRealtimeDataV2] update kline by 1 minute data [${lastDataCount}->${this.SourceData.Data.length}], IsAutoSyncDataOffset=${this.IsAutoSyncDataOffset}`);
if (this.IsAutoSyncDataOffset===false) lastDataCount=null; //维持当前的屏位置
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (bindData.Right>0 && !this.IsApiPeriod && this.RightFormula>=1) //复权 复权系数
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if ((ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) && !this.IsApiPeriod) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:"RecvMinuteRealtimeDataV2" });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
this.UpdateOverlayMinuteRealtimeData(data); //更新叠加股票数据
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true, SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(1); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
this.UpdateDOMTooltip(0, bindData);
this.UpdateHQFloatTooltip(bindData);
//更新叠加指标
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true,SyncExecute:false }); //异步模式叠加指标
if (this.mapEvent.has(JSCHART_EVENT_ID.ON_RECV_REALTIME_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.ON_RECV_REALTIME_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.RecvMinuteRealtimeData=function(data)
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
if (data.ver==2.0)
{
this.RecvMinuteRealtimeDataV2(data);
return;
}
var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeData(data, this.Symbol);
if (!realtimeData) return;
if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
var lastSourceDataCount=this.SourceData.Data.length;
if (!this.SourceData.MergeMinuteData(realtimeData)) return;
JSConsole.Chart.Log(`[KLineChartContainer::RecvMinuteRealtimeData] update kline by 1 minute data [${lastSourceDataCount}->${this.SourceData.Data.length}]`);
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (bindData.Right>0 && !this.IsApiPeriod && this.RightFormula>=1) //复权 复权系数
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if ( (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) && !this.IsApiPeriod) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:"RecvMinuteRealtimeData" });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
this.UpdateOverlayMinuteRealtimeData(data); //更新叠加股票数据
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true, SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(1); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
//更新叠加指标
this.BindAllOverlayIndexData(bindData, { CheckRunCount:true, SyncExecute:false }); //异步模式叠加指标
}
//更新当天的全量分钟数据
this.UpdateOverlayMinuteRealtimeData=function(data)
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue;
if (data.ver==2.0)
var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeDataV2(data,item.Symbol); //获取叠加股票的最新数据
else
var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeData(data,item.Symbol); //获取叠加股票的最新数据
if (!realtimeData) continue;
var sourceData=item.SourceData; //叠加股票的所有数据
if (!sourceData.MergeMinuteData(realtimeData)) return;
var bindData=new ChartData();
bindData.Data=sourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data,this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
}
}
this.GetHistoryDataCount=function()
{
var frameHisdata=null;
if (!this.Frame.Data) frameHisdata=this.Frame.Data;
else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata=this.Frame.SubFrame[0].Frame.Data;
if (!frameHisdata) return -1;
var lastDataCount=frameHisdata.Data.length; //上一个的数据长度
return lastDataCount;
}
this.GetRequestDataCount=function() //K线请求数据个数 (由于可以拖拽下载历史数据,所有原来固定个数的就不能用了)
{
var result={MaxRequestDataCount:this.MaxRequestDataCount, MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount };
if (!this.SourceData || !this.SourceData.Data || this.SourceData.Data.length<=0) return result;
if (ChartData.IsDayPeriod(this.Period,true))
{
var lCount=this.SourceData.Data.length;
if (lCount>result.MaxRequestDataCount) result.MaxRequestDataCount=lCount;
}
else if (ChartData.IsMinutePeriod(this.Period,true))
{
var date;
var lCount=0;
for(var i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (item.Date!=date) ++lCount;
date=item.Date;
}
if (lCount>result.MaxRequestMinuteDayCount) result.MaxRequestMinuteDayCount=lCount;
}
return result;
}
//分笔数据
this.RequestTickData=function()
{
var self=this;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
self.ChartSplashPaint.EnableSplash(true);
self.Draw();
//下载缓存文件
var cacheUrl=g_JSChartResource.CacheDomain+'/cache/dealday/today/'+self.Symbol+'.json'
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestTickData', //类名::
Explain:'当天分笔数据',
Request:{ Url:cacheUrl, Data:{ symbol: self.Symbol }, Type:'GET' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvTickData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: cacheUrl,
data:{"symbol":self.Symbol},
type:"get",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvTickData(data);
self.AutoUpdate(1);
},
error: function(http,e)
{
self.ChartSplashPaint.EnableSplash(false);
self.AutoUpdate();
//self.RecvError(http,e,param);;
}
});
}
this.RecvTickData=function(data)
{
if (data.ver==2.0)
var aryDayData=KLineChartContainer.JsonDataToTickDataV2(data);
else
var aryDayData=KLineChartContainer.JsonDataToTickData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=2; //0=日线数据 1=分钟数据 2=分笔数据
this.SourceData=sourceData;
if (this.BeforeBindMainData) this.BeforeBindMainData("RecvTickData");
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=2;
//绑定数据
this.Symbol=data.symbol;
this.Name=data.name;
this.BindMainData(bindData,this.PageSize);
if (this.AfterBindMainData) this.AfterBindMainData("RecvTickData");
this.BindInstructionIndexData(bindData); //执行指示脚本
var firstSubFrame;
for(var i=0; i<this.Frame.SubFrame.length; ++i) //执行指标
{
if (i==0) firstSubFrame=this.Frame.SubFrame[i].Frame;
this.BindIndexData(i,bindData);
}
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
firstSubFrame.YSplitOperator.KLineChart=this.ChartPaint[0]; //绑定K线图形
}
//this.CreateChartDrawPictureByStorage(); //创建画图工具
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
//叠加指标
this.BindAllOverlayIndexData(bindData);
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
//请求最新的分笔数据
this.RequestTickRealtimeData=function()
{
var self=this;
var start=0;
if (this.SourceData && this.SourceData.Data) start=this.SourceData.Data.length;
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestTickRealtimeData', //类名::
Explain:'当天最新分笔数据',
Request:{ Url:self.TickApiUrl, Data:{ symbol: self.Symbol, start:start, end:start+1000 }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvTickRealtimeData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.TickApiUrl,
data:{"symbol":self.Symbol, start:start-10, end:start+1000 },
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvTickRealtimeData(data);
self.AutoUpdate();
}
});
}
this.RecvTickRealtimeData=function(data)
{
if (data.ver==2.0)
var aryDayData=KLineChartContainer.JsonDataToTickDataV2(data); //增量数据
else
var aryDayData=KLineChartContainer.JsonDataToTickData(data); //增量数据
if (!aryDayData || aryDayData.length<=0) return;
var redraw=false; //强制重绘
if (data.redraw==true) redraw=true;
//更新原始数据
var source=this.SourceData.Data;
var lastDataCount=this.SourceData.Data.length; //上一个的数据长度
var lastTime=0;
if (source.length>0) lastTime=source[source.length-1].Time;
var newCount=0;
for(var i in aryDayData)
{
var item=aryDayData[i];
if (item.Time<=lastTime) continue;
source.push(item);
++newCount;
}
if (newCount<=0 && redraw==false) return;
//显示的数据
var bindData=new ChartData();
bindData.Data=source;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=2;
//绑定数据
this.Symbol=data.symbol;
this.Name=data.name;
this.UpdateMainData(bindData,lastDataCount);
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//this.CreateChartDrawPictureByStorage(); //创建画图工具
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
//更新叠加指标
this.BindAllOverlayIndexData(bindData);
}
this.ClearIndexPaint=function()
{
//清空指标
if (this.Frame && this.Frame.SubFrame)
{
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
this.DeleteIndexPaint(i, true);
var item=this.Frame.SubFrame[i];
if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
{
for(var j=0; j<item.OverlayIndex.length; ++j ) //清空叠加指标
{
var overlayItem=item.OverlayIndex[j];
for(var k=0;k< overlayItem.ChartPaint.length;++k)
{
var overlayChart=overlayItem.ChartPaint[k];
if (overlayChart && overlayChart.OnDestroy) overlayChart.OnDestroy();
}
overlayItem.ChartPaint=[];
}
}
}
}
//清空叠加标题
for(var i=1;i<this.TitlePaint.length;++i)
{
var item=this.TitlePaint[i];
item.OverlayIndex=new Map();
}
}
//周期切换
this.ChangePeriod=function(period,option)
{
var oldData={ Period:this.Period, Right:this.Right, KLineDrawType:this.KLineDrawType, Symbol:this.Symbol};
var isChangeKLineDrawType=false;
var isReload=false; //是否重新请求数据
var right=null; //复权
if (option)
{
if (option.KLine)
{
if (IFrameSplitOperator.IsNumber(option.KLine.DrawType)) isChangeKLineDrawType=true;
if (IFrameSplitOperator.IsNumber(option.KLine.Right)) right=option.KLine.Right;
}
if (option.Reload==true) isReload=true;
};
if (this.Period==period && isReload==false)
{
if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType);
return;
}
if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType,false); //切换K线类型, 不重绘
var isDataTypeChange=true;
if (this.SourceData)
{
var isDataTypeChange=false;
if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)
{
if (this.SourceData.DataType!=0) isDataTypeChange=true;
}
else if ((period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) ||
(period>CUSTOM_SECOND_PERIOD_START && period<=CUSTOM_SECOND_PERIOD_END) ||
(period>CUSTOM_MILLISECOND_PERIOD_START && period<=CUSTOM_MILLISECOND_PERIOD_END) )
{
if (this.SourceData.DataType!=1) isDataTypeChange=true;
else if (ChartData.IsSecondPeriod(period)) isDataTypeChange=true;
else if (ChartData.IsMilliSecondPeriod(period)) isDataTypeChange=true;
}
else
{
switch(period)
{
case 0: //日线
case 1: //周
case 2: //月
case 3: //年
case 9: //季线
case 21: //双周
if (this.SourceData.DataType!=0) isDataTypeChange=true;
break;
case 4: //1分钟
case 5: //5分钟
case 6: //15分钟
case 7: //30分钟
case 8: //60分钟
case 11: //2小时
case 12: //4小时
if (this.SourceData.DataType!=1) isDataTypeChange=true;
break;
case 10: //分笔线
if (this.SourceData.DataType!=2) isDataTypeChange=true;
break;
}
}
}
this.Period=period;
if (right!=null) this.Right=right;
this.ReloadChartDrawPicture(); //切换周期了 清空画图工具
this.ClearRectSelect(true);
this.Frame.ClearUpDonwFrameYData();
this.ClearCustomKLine();
this.ClearKLineCaluate();
var kLineDrawType=this.GetKLineDrawType();
if (kLineDrawType==10 || kLineDrawType==11 || kLineDrawType==12 || kLineDrawType==16) isDataTypeChange=true;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CHANGE_KLINE_PERIOD);
if (event && event.Callback)
{
var sendData=
{
IsApiPeriod:this.IsApiPeriod,
Old:oldData,
Now:{ Period:this.Period, Right:this.Right, KLineDrawType:this.KLineDrawType, Symbol:this.Symbol },
IsDataTypeChange:isDataTypeChange, //数据类型是否改变 true 重新请求数据
}
event.Callback(event, sendData, this);
isDataTypeChange=sendData.IsDataTypeChange;
}
if (isDataTypeChange==false && !this.IsApiPeriod)
{
this.ClearIndexRunCount();
this.Update( {UpdateCursorIndexType:2} ); //更新的时候 取消显示十字光标
return;
}
this.ClearIndexPaint();
if (ChartData.IsDayPeriod(this.Period,true))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新
this.ResetScrollBar();
this.ResetOverlaySymbolStatus();
this.ClearIndexRunCount();
this.Frame.ClearYCoordinateMaxMin();
this.RequestHistoryData(); //请求日线数据
//this.ReqeustKLineInfoData();
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新
this.ResetScrollBar();
this.ResetOverlaySymbolStatus();
this.ClearIndexRunCount();
this.Frame.ClearYCoordinateMaxMin();
this.RequestHistoryMinuteData(); //请求分钟数据
}
else if (ChartData.IsTickPeriod(this.Period))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod');
this.ResetScrollBar();
this.ClearIndexRunCount();
this.Frame.ClearYCoordinateMaxMin();
this.RequestTickData(); //请求分笔数据
}
}
//复权切换
this.ChangeRight=function(right)
{
if (!MARKET_SUFFIX_NAME.IsEnableRight(this.Period,this.Symbol, this.RightFormula)) return;
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) return;
if (right<0 || right>2) return;
if (this.Right==right) return;
var oldData={ Period:this.Period, Right:this.Right, KLineDrawType:this.KLineDrawType, Symbol:this.Symbol };
this.Right=right;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CHANGE_KLINE_RIGHT);
if (event && event.Callback)
{
var sendData=
{
IsApiPeriod:this.IsApiPeriod,
Old:oldData,
Now:{ Period:this.Period, Right:this.Right, KLineDrawType:this.KLineDrawType, Symbol:this.Symbol },
}
event.Callback(event, sendData, this);
}
if (!this.IsApiPeriod)
{
this.Update();
return;
}
else //API周期数据 重新请求数据
{
if (ChartData.IsDayPeriod(this.Period,true))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeRight'); //切换复权先停止更新
this.ClearIndexPaint();
this.ResetOverlaySymbolStatus();
this.ResetScrollBar();
this.RequestHistoryData(); //请求日线数据
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeRight'); //切换复权先停止更新
this.ClearIndexPaint();
this.ResetOverlaySymbolStatus();
this.ResetScrollBar();
this.RequestHistoryMinuteData(); //请求分钟数据
}
}
}
//设置第1屏的起始日期
this.SetFirstShowDate=function(obj)
{
if (!obj || !obj.Date) return;
var option={ ID:JSCHART_OPERATOR_ID.OP_GOTO, Date:obj.Date };
if (IFrameSplitOperator.IsNumber(obj.Time)) option.Time=obj.Time;
if (IFrameSplitOperator.IsNumber(obj.PageSize)) option.PageSize=obj.PageSize;
this.ChartOperator(option);
}
//删除某一个窗口的指标, bCallDestory=是否调用图形销毁函数
this.DeleteIndexPaint=function(windowIndex, bCallDestroy)
{
if (!this.Frame.SubFrame[windowIndex]) return;
var subFrame=this.Frame.SubFrame[windowIndex].Frame;
if (!subFrame) return;
var paint=[]; //踢出当前窗口的指标画法
for(var i=0;i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
var bFind=(item.ChartFrame.Guid==subFrame.Guid || item.ChartFrame==subFrame);
if (i==0 || !bFind)
{
paint.push(item);
}
else
{
if (bCallDestroy===true)
{
if (item && item.OnDestroy) item.OnDestroy(); //图形销毁
}
}
}
subFrame.YSpecificMaxMin=null; //清空指定最大最小值
subFrame.IsLocked=false; //解除上锁
subFrame.YSplitScale = null; //清空固定刻度
subFrame.YSplitOperator.SplitType=subFrame.YSplitOperator.DefaultSplitType; //还原Y坐标分割模式
this.ChartPaint=paint;
//清空东条标题
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
}
//显示隐藏主图K线
this.ShowKLine=function(isShow)
{
if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return;
this.ChartPaint[0].IsShow=isShow;
}
this.SetInstructionData=function(type,instructionData)
{
if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return;
var title=this.TitlePaint[1];
if (type==2) //五彩K线
{
this.ChartPaint[0].ColorData=instructionData.Data;
if (title) title.ColorIndex={Name:instructionData.Name, Param:instructionData.Param };
}
else if (type==1) //专家指示
{
this.ChartPaint[0].TradeData={Sell:instructionData.Sell, Buy:instructionData.Buy, Name:instructionData.Name, Param:instructionData.Param };
if (title) title.TradeIndex={ Name:instructionData.Name, Param:instructionData.Param };
}
}
this.ChangeInstructionIndex=function(indexName, option)
{
let scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(indexName);
if (!indexInfo) return;
if(indexInfo.InstructionType!=1 && indexInfo.InstructionType!=2) return;
if (option)
{
if (option.Args) indexInfo.Args=option.Args;
}
indexInfo.ID=indexName;
this.ChangeInstructionScriptIndex(indexInfo);
}
this.ChangeInstructionScriptIndex=function(indexData)
{
if (indexData.InstructionType==1) //交易系统
{
this.TradeIndex=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
}
else if (indexData.InstructionType==2) //五彩K线
{
this.ColorIndex=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
}
else
{
return;
}
var bindData=this.ChartPaint[0].Data;
this.BindInstructionIndexData(bindData);
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.CancelInstructionIndex=function() //取消指示数据
{
if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return;
this.ColorIndex=null;
this.TradeIndex=null;
this.ChartPaint[0].ColorData=null; //五彩K线数据取消掉
this.ChartPaint[0].TradeData=null; //交易系统数据取消
var title=this.TitlePaint[1];
if (title)
{
title.TradeIndex=null;
title.ColorIndex=null;
}
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.SetFrameToolbar=function(windowIndex,window)
{
if (!window || !this.Frame.SubFrame[windowIndex] || !this.Frame.SubFrame[windowIndex].Frame) return;
var frame=this.Frame.SubFrame[windowIndex].Frame;
var bChanged=false;
if (IFrameSplitOperator.IsBool(window.Modify))
{
frame.ModifyIndex=window.Modify;
bChanged=true;
}
if (IFrameSplitOperator.IsBool(window.Change))
{
frame.ChangeIndex=window.Change;
bChanged=true;
}
if (IFrameSplitOperator.IsBool(window.Close))
{
frame.CloseIndex=window.Close;
bChanged=true;
}
if (IFrameSplitOperator.IsBool(window.Overlay))
{
frame.OverlayIndex=window.Overlay;
bChanged=true;
}
//工具栏变 先刷新工具栏
if (bChanged)
{
frame.SizeChange=true;
frame.ToolbarRect=null; //清空工具栏缓存
frame.DrawToolbar();
}
}
this.SetFrameAttribute=function(windowIndex, attr)
{
if (!window || !this.Frame.SubFrame[windowIndex] || !this.Frame.SubFrame[windowIndex].Frame) return;
if (!attr) return;
var frame=this.Frame.SubFrame[windowIndex].Frame;
if (!IFrameSplitOperator.IsUndefined(attr.HorizontalReserved)) frame.HorizontalReserved=attr.HorizontalReserved; //Y轴上下预留
if (IFrameSplitOperator.IsNumber(attr.TitleHeight)) frame.ChartBorder.TitleHeight=attr.TitleHeight; //指标标题高度
}
this.ResetFrameAttribute=function(windowIndex)
{
if (!window || !this.Frame.SubFrame[windowIndex] || !this.Frame.SubFrame[windowIndex].Frame) return;
var frame=this.Frame.SubFrame[windowIndex].Frame;
frame.HorizontalReserved=null;
}
//切换成 脚本指标
this.ChangeScriptIndex=function(windowIndex,indexData,option)
{
this.DeleteIndexPaint(windowIndex, true);
this.WindowIndex[windowIndex]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
this.ResetFrameAttribute(windowIndex);
this.Frame.ClearYCoordinateMaxMin(windowIndex);
if (option)
{
if (option.Window)
{
this.SetFrameToolbar(windowIndex,option.Window);
this.SetFrameAttribute(windowIndex,option.Window); //窗口属性
}
}
this.OnChangeIndexEvent(windowIndex, { ID:indexData.ID, Name:indexData.Name, FunctionName:"ChangeScriptIndex" });
this.Frame.ClearUpDonwFrameYData({ Index:windowIndex });
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.OnKLinePageChange=function(eventid)
{
if (!this.ChartPaint[0]) return;
var bindData=this.ChartPaint[0].Data;
for(var i=0;i<this.WindowIndex.length;++i)
{
var item=this.WindowIndex[i];
if (!item) continue;
if (item.IsUsePageData===true) this.BindIndexData(i,bindData, { Type:1 }); //执行脚本
}
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem && overlayItem.Script && overlayItem.Script.IsUsePageData==true)
this.BindOverlayIndexData(overlayItem,i,bindData);
}
}
}
//切换api指标
this.ChangeAPIIndex=function(windowIndex,indexData)
{
this.DeleteIndexPaint(windowIndex, true);
//使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
var apiItem=indexData.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,indexData);
this.ResetFrameAttribute(windowIndex);
this.Frame.ClearYCoordinateMaxMin(windowIndex);
this.OnChangeIndexEvent(windowIndex, { ID:indexData.ID, Name:indexData.Name, FunctionName:"ChangeAPIIndex" });
if (indexData)
{
if (indexData.Window)
{
this.SetFrameToolbar(windowIndex,indexData.Window);
this.SetFrameAttribute(windowIndex,indexData.Window); //窗口属性
}
}
this.Frame.ClearUpDonwFrameYData({ Index:windowIndex });
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.OnChangeIndexEvent=function(windowIndex, indexInfo)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CHANGE_INDEX);
if (event && event.Callback)
{
var data={ IndexInfo:indexInfo, WindowIndex:windowIndex };
event.Callback(event,data,this);
}
}
//切换指标 指定切换窗口指标
this.ChangeIndex=function(windowIndex,indexName,option)
{
if (option && option.API) //切换api指标
return this.ChangeAPIIndex(windowIndex,option);
var indexItem=JSIndexMap.Get(indexName);
if (!indexItem)
{
//查找系统指标
let scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(indexName);
if (!indexInfo) return;
if (indexInfo.IsMainIndex)
{
windowIndex = 0; //主图指标只能在主图显示
}
else
{
if (windowIndex == 0) windowIndex = 1; //幅图指标,不能再主图显示
}
JSIndexScript.ModifyAttribute(indexInfo, option);
return this.ChangeScriptIndex(windowIndex, indexInfo, option);
}
//主图指标
if (indexItem.IsMainIndex)
{
if (windowIndex>0) windowIndex=0; //主图指标只能在主图显示
}
else
{
if (windowIndex==0) windowIndex=1; //幅图指标,不能再主图显示
}
var paint=new Array(); //踢出当前窗口的指标画法
for(var i in this.ChartPaint)
{
var item=this.ChartPaint[i];
if (i==0 || item.ChartFrame!=this.Frame.SubFrame[windowIndex].Frame)
paint.push(item);
}
this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=null; //清空指定最大最小值
this.Frame.SubFrame[windowIndex].Frame.IsLocked=false; //解除上锁
this.Frame.SubFrame[windowIndex].Frame.YSplitScale = null; //清空固定刻度
this.ChartPaint=paint;
//清空东条标题
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
this.WindowIndex[windowIndex]=indexItem.Create(option);
this.CreateWindowIndex(windowIndex);
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData);
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ChangePyScriptIndex=function(windowIndex,indexData)
{
this.DeleteIndexPaint(windowIndex);
this.WindowIndex[windowIndex]=new PyScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.AddOverlayIndex=function(obj)
{
var overlay=this.CreateOverlayWindowsIndex(obj);
if (!overlay) return;
var bindData=this.ChartPaint[0].Data;
this.BindOverlayIndexData(overlay,obj.WindowIndex,bindData);
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
//创建一个叠加指标
this.CreateOverlayWindowsIndex=function(obj) // {WindowIndex:, IndexName:, Identify:, ShowRightText:, API:}
{
let indexName=obj.IndexName;
let windowIndex=obj.WindowIndex;
var apiItem=null, indexInfo=null, indexCustom=null;
if (obj.API)
{
apiItem=obj.API;
}
else if (obj.Script) //动态执行脚本
{
indexInfo={ Script:obj.Script, ID:obj.indexName, Name:obj.indexName};
if (obj.Name) indexInfo.Name=obj.Name;
}
else
{
let scriptData = new JSIndexScript();
indexInfo = scriptData.Get(indexName); //系统指标
if (!indexInfo)
{
indexCustom=JSIndexMap.Get(indexName); //定制指标
if (!indexCustom)
{
console.warn(`[KLineChartContainer::CreateOverlayIndex] can not find index[${indexName}]`);
return null;
}
}
}
var subFrame=this.Frame.SubFrame[windowIndex];
var overlayFrame=new OverlayIndexItem();
if (obj.Identify) overlayFrame.Identify=obj.Identify; //由外部指定id
//var frame= this.ClassName==='KLineChartHScreenContainer' ? new OverlayKLineHScreenFrame() : new OverlayKLineFrame();
var frame=this.CreateOverlayFrame();
frame.Canvas=this.Canvas;
frame.MainFrame=subFrame.Frame;
frame.ChartBorder=subFrame.Frame.ChartBorder;
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
if (obj.ShowRightText===true) frame.IsShow=true;
else if (obj.ShowRightText===false) frame.IsShow=false;
if (IFrameSplitOperator.IsBool(obj.ShowToolbar)) frame.IsShowToolbar=obj.ShowToolbar; //废弃
if (IFrameSplitOperator.IsBool(obj.IsShareY)) frame.IsShareY=obj.IsShareY;
if (IFrameSplitOperator.IsNumber(obj.IsShowMainFrame)) frame.IsShowMainFrame=obj.IsShowMainFrame;
//if (IFrameSplitOperator.IsBool(obj.IsShowIndexTitle)) frame.IsShowIndexTitle=obj.IsShowIndexTitle;
if (IFrameSplitOperator.IsBool(obj.IsCalculateYMaxMin)) frame.IsCalculateYMaxMin=obj.IsCalculateYMaxMin; //是否计算Y最大最小值
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=frame.ChartBorder;
frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount;
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.YSplitOperator.GetKLineChartCallback=()=> { return this.GetKLineChart(); }
frame.YSplitOperator.OverlayIndex=overlayFrame;
frame.YSplitOperator.HQChart=this;
frame.YSplitOperator.OverlayIdentify=overlayFrame.Identify;
if (obj.Frame)
{
var item=obj.Frame;
if (item.Custom) frame.YSplitOperator.Custom=item.Custom;
if (IFrameSplitOperator.IsBool(item.IsYDrawMainFrame)) frame.IsYDrawMainFrame=item.IsYDrawMainFrame; //自定义刻度绘制在主图上
if (IFrameSplitOperator.IsBool(item.IsShowToolbar)) frame.IsShowToolbar=item.IsShowToolbar; //是否显示工具栏
}
overlayFrame.Frame=frame;
if (apiItem)
{
var apiIndex=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,obj, true);
apiIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
overlayFrame.Script=apiIndex;
}
else if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo, obj);
var scriptIndex=new OverlayScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
overlayFrame.Script=scriptIndex;
}
else
{
var scriptIndex=indexCustom.Create();
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
scriptIndex.Create(this,windowIndex);
overlayFrame.Script=scriptIndex;
}
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_OVERLAY_FRAME);
if (event && event.Callback)
{
var sendData={ OverlayFrame:overlayFrame, WindowIndex:windowIndex, SubFrame:subFrame };
event.Callback(event, sendData, this);
}
subFrame.OverlayIndex.push(overlayFrame);
return overlayFrame;
}
this.DeleteOverlayWindowsIndex=function(identify) //删除叠加指标
{
if (!this.DeleteOverlayIndex(identify, null)) return;
this.UpdateFrameMaxMin(); //重新计算坐标范围
this.Frame.ResetXYSplit(true);
this.Draw();
}
this.ChangeKLineDrawType=function(drawType, isDraw, option)
{
if (this.KLineDrawType==drawType && !option) return;
var oldKLineType=this.KLineDrawType;
this.KLineDrawType=drawType;
var setKLineType=new Set([5,7,8,10,11,12,17]);
if (setKLineType.has(oldKLineType) || setKLineType.has(drawType))
{
var chart=this.ChartPaint[0];
if (chart) chart.DrawType=this.KLineDrawType;
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeKLineDrawType');
if (ChartData.IsDayPeriod(this.Period,true))
{
this.ResetOverlaySymbolStatus();
this.RequestHistoryData(); //请求日线数据
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period))
{
this.ResetOverlaySymbolStatus();
this.RequestHistoryMinuteData(); //请求分钟数据
}
return;
}
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (i==0)
{
item.DrawType=this.KLineDrawType;
if (option)
{
if (IFrameSplitOperator.IsBool(option.IsThinAKBar)) item.IsThinAKBar=option.IsThinAKBar;
}
}
else if (item.ClassName=='ChartVolStick')
{
item.KLineDrawType=this.KLineDrawType;
}
}
for(var i in this.OverlayChartPaint) //叠加K线样式修改
{
var item=this.OverlayChartPaint[i];
item.DrawType=this.KLineDrawType;
}
if (isDraw==false) return;
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
//修改坐标类型
//{ Type: 0=普通坐标 1=百分比坐标 (右边坐标刻度) 2=对数对标 3=等比坐标, IsReverse:是否反转坐标 }
this.ChangeCoordinateType=function(obj)
{
if (!this.Frame) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Frame.SubFrame)) return;
if (!this.Frame.SubFrame[0]) return;
var frame=this.Frame.SubFrame[0].Frame;
if (IFrameSplitOperator.IsNumber(obj)) //老版本
{
var type=obj;
if (type==2) //反转坐标
{
frame.CoordinateType=1;
}
else if(type==1)
{
frame.YSplitOperator.CoordinateType=type;
}
else if (type==0)
{
frame.CoordinateType=0;
frame.YSplitOperator.CoordinateType=0;
}
else if (type==3) //对数坐标
{
frame.Frame.YSplitOperator.CoordinateType=2;
}
else
{
return;
}
}
else
{
if (obj.Type>=0 && obj.Type<=5) frame.YSplitOperator.CoordinateType=obj.Type;
if (obj.IsReverse===true) frame.CoordinateType=1;
else if (obj.IsReverse==false) frame.CoordinateType=0;
}
//请求缓存的最大最小值
frame.YMaxMin.Max=null;
frame.YMaxMin.Min=null;
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
//设置指标窗口个数
this.ChangeIndexWindowCount=function(count,option)
{
if (count<=0) return;
if (this.Frame.SubFrame.length==count) return;
this.Frame.RestoreIndexWindows();
var currentLength=this.Frame.SubFrame.length;
if (currentLength>count)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
for(var i=currentLength-1;i>=count;--i)
{
this.DeleteIndexPaint(i);
this.DeleteChartPaintExtend({WindowIndex:i});
this.Frame.SubFrame[i].Frame.ClearToolbar();
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
this.Frame.SubFrame.splice(count,currentLength-count);
this.WindowIndex.splice(count,currentLength-count);
this.TitlePaint.splice(count+1,currentLength-count);
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
else
{
//创建新的指标窗口
var pixelRatio=GetDevicePixelRatio();
for(var i=currentLength;i<count;++i)
{
var subFrame=this.CreateSubFrameItem(i);
subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
this.TitlePaint[i+1]=titlePaint;
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
//创建指标
var indexName= [ {Index:"RSI"}, {Index:"MACD"}, {Index:"VOL"}, {Index:"UOS"}, {Index:"CHO"}, {Index:"BRAR"} ]; //增加的指标名字
if (option && option.Windows.length>0)
indexName=option.Windows; //外部设置增加窗口的默认指标
let scriptData = new JSIndexScript();
for(var i=currentLength;i<count;++i)
{
var item=indexName[i%indexName.length];
var name=item.Index;
let indexInfo = scriptData.Get(name);
var args=indexInfo.Args;
if (item.Args) args=item.Args;
let indexData =
{
Name:indexInfo.Name, Script:indexInfo.Script, Args: args, ID:item.Index,
//扩展属性 可以是空
KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale,
FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition,
OutName:indexInfo.OutName
};
this.WindowIndex[i]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
var subFrame=this.Frame.SubFrame[i];
if (item.Modify!=null) this.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify;
if (item.Change!=null) this.Frame.SubFrame[i].Frame.ChangeIndex=item.Change;
if (item.Close!=null) this.Frame.SubFrame[i].Frame.CloseIndex=item.Close;
if (item.Overlay!=null) chart.Frame.SubFrame[i].Frame.OverlayIndex=item.Overlay;
if (item.IsDrawTitleBG==true) this.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
if (IFrameSplitOperator.IsBool(item.IsShowNameArrow)) this.Frame.SubFrame[i].Frame.IsShowNameArrow=item.IsShowNameArrow;
if (IFrameSplitOperator.IsNumber(item.TitleHeight)) this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
else item.TitleHeight=this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight;
if (IFrameSplitOperator.IsBool(item.IsShowTitleArrow)) subFrame.Frame.IsShowTitleArrow=item.IsShowTitleArrow;
if (IFrameSplitOperator.IsNumber(item.TitleArrowType)) subFrame.Frame.TitleArrowType=item.TitleArrowType;
if (item.IsShowIndexName==false) this.Frame.SubFrame[i].Frame.IsShowIndexName=false;
if (item.IsShowOverlayIndexName==false) this.Frame.SubFrame[i].Frame.IsShowOverlayIndexName=false;
if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) this.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) this.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
if (item.IsShowXLine==false) this.Frame.SubFrame[i].Frame.IsShowXLine=false;
if (item.IsShowYLine==false) this.Frame.SubFrame[i].Frame.IsShowYLine=false;
if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) this.Frame.SubFrame[i].Frame.IsShowIndexTitle=item.IsShowIndexTitle;
if (IFrameSplitOperator.IsBool(item.IsShowLeftText))
{
subFrame.Frame.IsShowYText[0]=item.IsShowLeftText;
subFrame.Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度
}
if (IFrameSplitOperator.IsBool(item.IsShowRightText))
{
subFrame.Frame.IsShowYText[1]=item.IsShowRightText;
subFrame.Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度
}
if (item.OverlayIndexType)
{
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) subFrame.Frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) subFrame.Frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
}
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(i,bindData); //执行脚本
}
//this.UpdataDataoffset(); //更新数据偏移
}
}
this.ChangeIndexTemplate=function(option) //切换指标模板 可以设置指标窗口个数 每个窗口的指标
{
if (!option.Windows) return;
var count=option.Windows.length;
if (count<=0) return;
var currentLength=this.Frame.SubFrame.length;
var period=null, right=null, symbol=null;
if (option.Symbol) symbol=option.Symbol;
if (option.KLine)
{
if (IFrameSplitOperator.IsNumber(option.KLine.Period) && option.KLine.Period!=this.Period) period=option.KLine.Period; //周期
if (IFrameSplitOperator.IsNumber(option.KLine.Right) && option.KLine.Right!=this.Right) right=option.KLine.Right; //复权
}
var bRefreshData= (period!=null || right!=null || symbol!=null);
//清空所有的指标图型
for(var i=0;i<currentLength;++i)
{
this.DeleteIndexPaint(i);
var frame=this.Frame.SubFrame[i];
frame.YSpecificMaxMin=null;
frame.IsLocked=false;
frame.YSplitScale = null;
}
if (currentLength>count)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
for(var i=currentLength-1;i>=count;--i)
{
this.Frame.SubFrame[i].Frame.ClearToolbar();
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
this.Frame.SubFrame.splice(count,currentLength-count);
this.WindowIndex.splice(count,currentLength-count);
this.TitlePaint.splice(count+1,currentLength-count);
}
else
{
for(var i=currentLength;i<count;++i) //创建新的指标窗口
{
var subFrame=this.CreateSubFrameItem(i);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
this.TitlePaint[i+1]=titlePaint;
}
}
for(var i=0;i<count;++i)
{
var windowIndex=i;
var item=option.Windows[i];
var frameItem=null;
if(option.Frame && option.Frame.length>i) frameItem=option.Frame[i];
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
var frame=this.Frame.SubFrame[i];
this.DeleteWindowsOverlayIndex(i); //清空叠加指标
if (item.Script) //自定义指标脚本
{
this.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API) //后台指标
{
var apiItem=item.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var indexID=item.Index;
var indexItem=JSIndexMap.Get(indexID);
if (indexItem)
{
this.WindowIndex[i]=indexItem.Create();
this.CreateWindowIndex(windowIndex);
}
else
{
var systemScript = new JSIndexScript();
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo,item);
this.WindowIndex[i]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
}
}
}
this.SetSubFrameAttribute(frame, item, frameItem);
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
//叠加指标
var aryOverlayIndex=[];
if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
{
for(var i=0;i<option.OverlayIndex.length;++i)
{
var item=option.OverlayIndex[i];
if (item.Index) item.IndexName=item.Index;
if (item.Windows>=0) item.WindowIndex=item.Windows;
var overlay=this.CreateOverlayWindowsIndex(item);
if (!overlay) continue;
aryOverlayIndex.push({ WindowsIndex:item.WindowIndex, Overlay:overlay });
}
}
this.Frame.SetSizeChage(true);
if (!bRefreshData)
{
var bindData=this.ChartPaint[0].Data;
for(var i=0;i<count;++i) //请求指标
{
this.BindIndexData(i,bindData);
}
for(var i=0;i<aryOverlayIndex.length;++i)
{
var item=aryOverlayIndex[i];
this.BindOverlayIndexData(item.Overlay,item.WindowsIndex,bindData);
}
this.UpdataDataoffset(); //更新数据偏移
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
else
{
if (!symbol) symbol=this.Symbol;
var optionData={ KLine:{} };
if (IFrameSplitOperator.IsNumber(period)) optionData.KLine.Period=period;
if (IFrameSplitOperator.IsNumber(right)) optionData.KLine.Right=right;
this.ChangeSymbol(symbol, optionData);
}
}
this.RemoveIndexWindow=function(id, option)
{
JSConsole.Chart.Log('[KLineChartContainer::RemoveIndexWindow] remove id', id);
if (id==0)
{
if (option && option.DeleteMainIndex) //删除指标
{
this.DeleteIndexPaint(id);
this.WindowIndex[id]=null;
this.Frame.SetSizeChage(true);
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
return;
}
if (!this.Frame.SubFrame) return;
if (id>=this.Frame.SubFrame.length) return;
this.Frame.RestoreIndexWindows();
var delFrame=this.Frame.SubFrame[id].Frame;
this.DeleteIndexPaint(id);
this.DeleteChartPaintExtend({WindowIndex:id});
this.Frame.SubFrame[id].Frame.ClearToolbar();
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[id], WindowIndex:id };
event.Callback(event, sendData, this);
}
this.Frame.SubFrame.splice(id,1);
this.WindowIndex.splice(id,1);
this.TitlePaint.splice(id+1,1); //删除对应的动态标题
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
item.Identify=i;
}
if (this.ChartDrawPicture.length>0)
{
var aryDrawPicture=[];
for(var i in this.ChartDrawPicture)
{
var item=this.ChartDrawPicture[i];
if (item.Frame==delFrame) continue;
aryDrawPicture.push(item);
}
this.ChartDrawPicture=aryDrawPicture;
}
this.Frame.SetSizeChage(true);
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
this.CreateExtendChart=function(name, option) //创建扩展图形
{
var chart;
switch(name)
{
case '筹码分布':
chart=new StockChip();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.Left=this.Frame.ChartBorder.Right; //左边间距使用当前框架间距
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
this.Frame.ChartBorder.Right+=chart.Width; //创建筹码需要增加右边的间距
return chart;
case 'KLineTooltip':
if (option.Create && typeof(option.Create)=='function') chart=option.Create();
else chart=new KLineTooltipPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
option.LanguageID=this.LanguageID;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case "深度图":
chart=new DepthMapPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case "K线Y轴背景图":
chart=new KLineYAxisBGPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case '背景图':
chart=new BackgroundPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case "FrameSplitPaint": //框架分割
chart=new FrameSplitPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
default:
chart=g_ExtendChartPaintFactory.Create(name);
if (!chart) return null;
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
}
}
this.OnTouchFinished=function()
{
if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true && this.TouchDrawCount>0) return;
this.TouchStatus.CorssCursorShow=false;
this.DrawDynamicInfo();
return;
}
if (this.EnableClickModel===true)
{
if (this.ClickModel.IsShowCorssCursor==true && this.TouchDrawCount>0) return;
this.ClickModel.IsShowCorssCursor=false;
this.DrawDynamicInfo();
return;
}
if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失
{
if (this.TouchDrawCount>0) this.DrawDynamicInfo();
return;
}
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName==='KLineTooltipPaint')
{
this.DrawDynamicInfo();
}
}
}
//锁|解锁指标 { Index:指标名字,IsLocked:是否要锁上,Callback:回调 }
this.LockIndex=function(lockData)
{
if (!lockData) return;
if (!lockData.IndexName) return;
for(let i in this.WindowIndex)
{
let item=this.WindowIndex[i];
if (!item) conintue;
if (item.Name==lockData.IndexName)
{
item.SetLock(lockData);
this.Update();
break;
}
}
}
this.TryClickLock=function(x,y)
{
for(var i=0;i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
if (!item.Frame.IsLocked) continue;
if (!item.Frame.LockPaint) continue;
var tooltip=new TooltipData();
if (!item.Frame.LockPaint.GetTooltipData(x,y,tooltip)) continue;
tooltip.HQChart=this;
if (tooltip.Data.Callback) tooltip.Data.Callback(tooltip);
return true;
}
return false;
}
this.TryClickIndexTitle=function(x,y)
{
for(var i in this.TitlePaint)
{
var item=this.TitlePaint[i];
if (!item.IsClickTitle) continue;
if (!item.IsClickTitle(x,y)) continue;
var data={ Point:{X:x, Y:y}, Title:item.Title, FrameID:item.Frame.Identify };
JSConsole.Chart.Log('[KLineChartContainer::TryClickIndexTitle] click title ', data);
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_INDEXTITLE);
if (event && event.Callback) event.Callback(event,data,this);
return true;
}
return false;
}
this.SetSizeChange=function(bChanged)
{
this.Frame.SetSizeChage(bChanged);
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
item.SizeChange=bChanged;
}
}
this.SetSizeChage=this.SetSizeChange; //单词拼错了, 还没替换完
this.Update=function(option) //option: { UpdateCursorIndexType:更新十字光标方式 }
{
if (!this.SourceData) return;
if (this.BeforeBindMainData) this.BeforeBindMainData('Update');
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,true)) //复权(日线数据复权)
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
else if (bindData.Right>0 && ChartData.IsMinutePeriod(bindData.Period,true) && this.RightFormula>=1) //复权(分钟数据复权, 复权因子模式)
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
//绑定数据
this.BindMainData(bindData,this.PageSize);
if (this.AfterBindMainData) this.AfterBindMainData("Update");
var firstSubFrame;
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
if (i==0) firstSubFrame=this.Frame.SubFrame[i].Frame;
this.BindIndexData(i,bindData);
}
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
}
//叠加数据周期调整
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (!item.SourceData) continue;
if(ChartData.IsMinutePeriod(this.Period,true)) //分钟不支持 清空掉
{
var bindData=new ChartData();
bindData.Data=item.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
}
else //日线叠加
{
var bindData=new ChartData();
bindData.Data=item.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(item.Symbol)) //复权数据
{
var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
}
}
this.ReqeustKLineInfoData( {FunctionName:"Update"} );
this.CreateChartDrawPictureByStorage(); //创建画图工具
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
if (option && option.UpdateCursorIndexType>0) this.UpdatePointByCursorIndex(option.UpdateCursorIndexType);
else this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,bindData)
}
}
}
//切换股票代码
this.ChangeSymbol=function(symbol, option)
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeSymbol');
this.ClearRectSelect(true);
this.ClearCustomKLine();
this.ClearKLineCaluate();
this.HideTooltip();
this.ResetScrollBar();
this.ClearIndexRunCount();
this.Frame.ClearYCoordinateMaxMin();
this.Symbol=symbol;
if (!symbol)
{
this.DrawEmpty();
return;
}
if (option)
{
if (option.KLine)
{
var item=option.KLine;
if (IFrameSplitOperator.IsNumber(item.Right)) this.Right=item.Right;
if (IFrameSplitOperator.IsNumber(item.Period)) this.Period=item.Period;
}
}
if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) this.Right=0; //指数没有复权
this.ClearIndexPaint(); //清空指标
if (option)
{
if (IFrameSplitOperator.IsNonEmptyArray(option.Windows))
{
var windows=option.Windows;
for(var i=0; i<windows.length; ++i)
{
if (i>=this.WindowIndex.length) break; //暂时不支持 动态增加/减少
var item=windows[i];
if (!item) continue;
if (item.Script)
{
this.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API)
{
var apiItem=item.API;
this.WindowIndex[i]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var indexID=item.Index;
var systemScript = new JSIndexScript();
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo,item);
indexInfo.ID=indexID;
this.WindowIndex[i]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
}
}
}
}
if (option.CustomShow && IFrameSplitOperator.IsPlusNumber(option.CustomShow.Date))
{
var item=option.CustomShow;
this.CustomShow={ Date:item.Date };
if (IFrameSplitOperator.IsNumber(item.Time)) this.CustomShow.Time=item.Time;
if (IFrameSplitOperator.IsPlusNumber(item.PageSize)) this.CustomShow.PageSize=item.PageSize;
}
}
this.ReloadChartDrawPicture();
this.Frame.ClearUpDonwFrameYData();
if (ChartData.IsDayPeriod(this.Period,true))
{
this.ClearStockCache();
this.RequestHistoryData(); //请求日线数据
//this.ReqeustKLineInfoData();
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period))
{
this.ClearStockCache();
this.RequestHistoryMinuteData(); //请求分钟数据
}
else if (ChartData.IsTickPeriod(this.Period))
{
this.ClearStockCache();
this.RequestTickData();
}
}
this.ReqeustKLineInfoData=function(obj)
{
if (obj && obj.FunctionName=="RecvDragDayData") //增量更新
{
obj.Update=true;
}
else
{
if (this.ChartPaint.length>0)
{
var klinePaint=this.ChartPaint[0];
klinePaint.InfoData=new Map();
}
obj.Update=false;
}
//信息地雷信息
if (!IFrameSplitOperator.IsNonEmptyArray(this.ChartInfo)) return;
for(var i=0;i<this.ChartInfo.length; ++i)
{
this.ChartInfo[i].RequestData(this,obj);
}
}
//设置K线信息地雷
this.SetKLineInfo=function(aryInfo,bUpdate)
{
this.ChartInfo=[]; //先清空
for(var i in aryInfo)
{
var infoItem=JSKLineInfoMap.Get(aryInfo[i]);
if (!infoItem) continue;
var item=infoItem.Create();
item.MaxRequestDataCount=this.MaxRequestDataCount;
this.ChartInfo.push(item);
}
if (bUpdate==true) this.ReqeustKLineInfoData({ FunctionName:"SetKLineInfo" });
}
//添加信息地雷
this.AddKLineInfo=function(infoName,bUpdate)
{
var classInfo=JSKLineInfoMap.GetClassInfo(infoName);
if (!classInfo)
{
console.warn("[KLineChartContainer::AddKLineInfo] can't find infoname=", infoName);
return;
}
for(var i in this.ChartInfo)
{
var item=this.ChartInfo[i];
if (item.ClassName==classInfo.ClassName) //已经存在
return;
}
var infoItem=JSKLineInfoMap.Get(infoName);
if (!infoItem) return;
var item=infoItem.Create();
item.MaxRequestDataCount=this.MaxRequestDataCount;
this.ChartInfo.push(item);
if (bUpdate==true)
{
item.RequestData(this); //信息地雷信息
}
}
//删除信息地理
this.DeleteKLineInfo=function(infoName)
{
var classInfo=JSKLineInfoMap.GetClassInfo(infoName);
if (!classInfo)
{
console.warn("[KLineChartContainer::DeleteKLineInfo] can't find infoname=", infoName);
return;
}
for(var i in this.ChartInfo)
{
var item=this.ChartInfo[i];
if (item.ClassName==classInfo.ClassName)
{
this.ChartInfo.splice(i,1);
this.UpdataChartInfo();
this.Draw();
break;
}
}
}
//清空所有的信息地理
this.ClearKLineInfo=function()
{
if (!this.ChartInfo || this.ChartInfo.length<=0) return;
this.ChartInfo=[];
var klinePaint=this.ChartPaint[0];
klinePaint.InfoData=null;
this.Draw();
}
//增加叠加股票
this.OverlaySymbol=function(symbol,option)
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (item.Symbol===symbol)
{
console.warn(`[KLineChartContainer::OverlaySymbol] overlay symbol=${symbol} exist.`)
return false;
}
}
var paint=new ChartOverlayKLine();
paint.Canvas=this.Canvas;
paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
paint.ChartFrame=this.Frame.SubFrame[0].Frame;
paint.Name="Overlay-KLine";
paint.DrawType=this.KLineDrawType;
paint.Symbol=symbol;
paint.Identify=`Overlay-KLine-${symbol}`;
if (option && option.Color) paint.Color=option.Color;
else paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length];
paint.SetOption(option);
++g_JSChartResource.OverlaySymbol.Random;
if (this.ChartPaint[0] && this.ChartPaint[0].Data && this.SourceData) paint.MainData=this.ChartPaint[0].Data; //绑定主图数据
this.OverlayChartPaint.push(paint);
if (ChartData.IsDayPeriod(this.Period, true)) this.RequestOverlayHistoryData(); //请求日线数据
else if (ChartData.IsMinutePeriod(this.Period,true)) this.RequestOverlayHistoryMinuteData(); //请求分钟历史数据
return true;
}
this.RequestSingleOverlayHistoryData=function(symbol, dataCount, firstDate, item)
{
var self = this;
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestOverlayHistoryData', //类名::
Explain:'叠加股票日K线数据',
Request:{ Url:self.KLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestDataCount,"first":{ date: firstDate },
field:["name","symbol","yclose","open","price","high",'vol','amount'] }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayHistoryData(data,item);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
}
this.RequestOverlayHistoryData=function()
{
if (!this.OverlayChartPaint.length) return;
if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完
var self = this;
var dataCount=this.GetRequestDataCount();
var firstDate=this.SourceData.Data[0].Date;
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
let item=this.OverlayChartPaint[i];
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue;
let symbol=item.Symbol;
if (!symbol) continue;
this.RequestSingleOverlayHistoryData(symbol, dataCount, firstDate, item);
}
}
this.RecvOverlayHistoryData=function(data,paint)
{
if (paint.IsDelete) return;
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
//原始叠加数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=0;
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol) && !this.IsApiPeriod) //复权数据 ,A股才有有复权
{
var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
paint.Data=bindData;
paint.SourceData=sourceData;
paint.Title=data.name;
paint.Symbol=data.symbol;
paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID;
this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.RequestSingleHistoryMinuteData=function(symbol, dataCount, firstDate,firstTime, item)
{
var self=this;
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestOverlayHistoryMinuteData', //类名::
Explain:'叠加股票分钟K线数据',
Request:{ Url:self.MinuteKLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestMinuteDayCount,"first":{ date: firstDate, time:firstTime },
field:["name","symbol","yclose","open","price","high",'vol','amount'] }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOveralyHistoryMinuteData(data,item);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
}
this.RequestOverlayHistoryMinuteData=function()
{
if (!this.OverlayChartPaint.length) return;
if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完
var self = this;
var dataCount=this.GetRequestDataCount();
var firstDate=this.SourceData.Data[0].Date;
var firstTime=this.SourceData.Data[0].Time;
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
let item=this.OverlayChartPaint[i];
if (!item.MainData) continue; //等待主图股票数据未下载完
if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue;
let symbol=item.Symbol;
if (!symbol) continue;
this.RequestSingleHistoryMinuteData(symbol,dataCount,firstDate,firstTime, item );
}
}
this.RecvOveralyHistoryMinuteData=function(data,paint)
{
if (this.EnableVerifyRecvData && data.symbol!=paint.Symbol)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvOveralyHistoryMinuteData] recv data symbol not match. paint[${paint.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
if (!aryDayData) return;
//原始叠加数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=1; //0=日线数据 1=分钟数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=1;
var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据, API周期数据不用计算
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
paint.Data=bindData;
paint.SourceData=sourceData;
paint.Title=data.name;
paint.Symbol=data.symbol;
paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; //数据下载完成
this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
//取消叠加股票
this.ClearOverlaySymbol=function()
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
item.IsDelete=true;
}
this.OverlayChartPaint=[];
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标
this.UpdateFrameMaxMin();
this.Draw();
}
//删除一个叠加股票
this.DeleteOverlaySymbol=function(symbol)
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (item.Symbol===symbol)
{
item.IsDelete=true;
this.OverlayChartPaint.splice(i,1);
if (this.OverlayChartPaint.length<=0) this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标
this.UpdateFrameMaxMin();
this.Draw();
return true;
}
}
console.warn(`[KLineChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`)
return false;
}
this.RequestFlowCapitalData=function()
{
if (!this.Symbol) return;
if (this.FlowCapitalReady==true) return;
var upperSymbol=this.Symbol.toUpperCase();
var bNeedDonloadData=true;
if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol) || MARKET_SUFFIX_NAME.IsFutures(upperSymbol)) //数字货币, 期货 不需要下载流通股本
bNeedDonloadData=false;
if (this.EnableFlowCapital) //强制下载流通股
{
if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol))
{
if (this.EnableFlowCapital.BIT==true) bNeedDonloadData=true;
}
}
if (!bNeedDonloadData)
{
JSConsole.Chart.Log(`[KLineChartContainer::RequestFlowCapitalData] symbol=${this.Symbol} not need download data.`);
this.FlowCapitalReady=true;
return;
}
var self = this;
let fieldList=["name","date","symbol","capital.a"];
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestFlowCapitalData', //类名::
Explain:'流通股本数据',
Request:{ Url:self.StockHistoryDayApiUrl, Data: { symbol: [this.Symbol], orderfield:'date',field:fieldList }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvFlowCapitalData(data);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//请求数据
JSNetwork.HttpRequest({
url: this.StockHistoryDayApiUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"orderfield":"date"
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvFlowCapitalData(recvData);
}
});
}
this.RecvFlowCapitalData=function(data)
{
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
if (this.EnableVerifyRecvData && stock.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvFlowCapitalData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${stock.symbol}]`);
return;
}
var aryData=new Array();
for(let i in stock.stockday)
{
var item=stock.stockday[i];
let indexData=new SingleData();
indexData.Date=item.date;
var financeData=item.capital;
if (!financeData) continue;
if (financeData.a>0)
{
indexData.Value=financeData.a; //流通股本(股)
aryData.push(indexData);
}
}
if (this.IsApiPeriod)
{
var klineData=this.ChartPaint[0].Data;
var aryFixedData=null;
if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据
{
aryFixedData=klineData.GetMinuteFittingFinanceData(aryData);
}
else if (ChartData.IsDayPeriod(this.Period,true)) //日线数据
{
aryFixedData=klineData.GetFittingFinanceData(aryData);
}
if (aryFixedData && klineData.Data && aryFixedData.length==klineData.Data.length)
{
for(var i in klineData.Data)
{
var item=klineData.Data[i];
if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
item.FlowCapital=aryFixedData[i].Value;
}
}
}
else
{
if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据
{
var aryFixedData=this.SourceData.GetMinuteFittingFinanceData(aryData);
for(var i=0; i<this.SourceData.Data.length; ++i)
{
var item=this.SourceData.Data[i];
if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
item.FlowCapital=aryFixedData[i].Value;
}
var bindData=this.ChartPaint[0].Data;
var newBindData=new ChartData();
newBindData.Data=this.SourceData.Data;
if (bindData.Right>0 && this.RightFormula>=1) //复权
{
var rightData=newBindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
newBindData.Data=rightData;
}
if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据
{
var periodData=newBindData.GetPeriodData(bindData.Period);
newBindData.Data=periodData;
}
bindData.Data=newBindData.Data;
}
else
{
var aryFixedData=this.SourceData.GetFittingFinanceData(aryData);
for(let i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
item.FlowCapital=aryFixedData[i].Value;
}
var bindData=this.ChartPaint[0].Data;
var newBindData=new ChartData();
newBindData.Data=this.SourceData.Data;
if (bindData.Right>0) //复权
{
var rightData=newBindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
newBindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据
{
var periodData=newBindData.GetPeriodData(bindData.Period);
newBindData.Data=periodData;
}
bindData.Data=newBindData.Data;
}
}
this.FlowCapitalReady=true;
var bDraw=false;
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName=='StockChip')
{
bDraw=true;
break;
}
}
if (bDraw) this.Draw();
}
//创建画图工具
this.CreateChartDrawPicture=function(name, option, callback)
{
var drawPicture=null;
var item=IChartDrawPicture.GetDrawPictureByName(name);
if (item)
{
drawPicture=item.Create();
if (drawPicture.ClassName=='ChartDrawPictureText' || drawPicture.ClassName=="ChartDrawVolProfile") drawPicture.HQChart=this;
}
if (!drawPicture) //iconfont图标
{
if (IChartDrawPicture.MapIonFont.has(name))
{
var iconItem=IChartDrawPicture.MapIonFont.get(name);
drawPicture=new ChartDrawPictureIconFont();
drawPicture.FontOption.Family=iconItem.Family
drawPicture.Text=iconItem.Text;
if (iconItem.Color) drawPicture.LineColor=iconItem.Color;
}
}
if (!drawPicture) return false;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=0;
drawPicture.Symbol=this.Symbol;
drawPicture.Period=this.Period;
drawPicture.Right=this.Right;
drawPicture.Option=this.ChartDrawOption;
if (callback) drawPicture.FinishedCallback=callback; //完成通知上层回调
if (option) drawPicture.SetOption(option);
var self=this;
drawPicture.Update=function() //更新回调函数
{
self.DrawDynamicInfo();
};
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
this.CurrentChartDrawPicture=drawPicture;
//JSConsole.Chart.Log("[KLineChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture);
return true;
}
this.AddChartDrawPicture=function(obj)
{
if (!obj) return null;
if (obj.FrameID<0 || obj.FrameID>=this.Frame.SubFrame.length) return null;
var self=this;
var item=IChartDrawPicture.GetDrawPictureByClassName(obj.ClassName);
if (!item) return null;
var drawPicture=item.Create();
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[obj.FrameID].Frame; //绑定框架坐标
drawPicture.Symbol=this.Symbol;
drawPicture.Period=this.Period;
drawPicture.Right=this.Right;
drawPicture.Option=this.ChartDrawOption;
if (obj.Value) drawPicture.Value=obj.Value;
if (obj.Guid) drawPicture.Guid=obj.Guid;
if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(obj);
drawPicture.SetOption(obj);
if (obj.EnableUpdateXValue) drawPicture.UpdateXValue();
drawPicture.ValueToPoint();
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
this.DrawDynamicInfo();
return drawPicture;
}
this.PasteChartDrawPicture=function(data, frameID, option)
{
if (!data || !data.ClassName) return null;
if (frameID<0 || frameID>=this.Frame.SubFrame.length) return null;
var item=IChartDrawPicture.GetDrawPictureByClassName(data.ClassName);
if (!item) return null;
var drawPicture=item.Create();
if (!drawPicture) return null;
var self=this;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[frameID].Frame; //绑定框架坐标
drawPicture.Symbol=this.Symbol;
drawPicture.Period=this.Period;
drawPicture.Right=this.Right;
drawPicture.Option=this.ChartDrawOption;
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
if (drawPicture.SetOption) drawPicture.SetOption(data);
this.RandomDrawPictureValue(drawPicture, data);
drawPicture.PointToValue();
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
//存盘
if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture);
this.DrawDynamicInfo();
return drawPicture;
}
//随机生成画图的点
this.RandomDrawPictureValue=function(chart, data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.Value)) return;
var kData=this.GetKLineChart();
if (!kData || !kData.Data || !IFrameSplitOperator.IsNumber(kData.Data.DataOffset) || kData.Data.DataOffset<0) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(kData.Data.Data)) return null;
var aryKData=kData.Data.Data;
var startIndex=kData.Data.DataOffset;
var endIndex=kData.Data.DataOffset+kData.ChartFrame.XPointCount-1;
if (endIndex>=aryKData.length) endIndex=aryKData.length-1;
var frameHeight=chart.Frame.ChartBorder.GetHeight();
var max=chart.Frame.HorizontalMax;
var min=chart.Frame.HorizontalMin;
var y=chart.Frame.ChartBorder.GetBottomEx()-(frameHeight)*data.YFristScale;
const range={Max:5, Min:2};
const xRandomOffset=Math.floor(Math.random() * (range.Max - range.Min + 1)) + range.Min;
var xValue=data.Value[0].XIndex+xRandomOffset;
var firstPoint=null;
chart.Value=[];
for(var i=0; i<data.Value.length; ++i)
{
var item=data.Value[i];
chart.Value[i]=
{
XValue:xValue+item.XOffset,
}
chart.Point[i]=
{
Y:y+item.YOffset,
X:chart.Frame.GetXFromIndex((xValue+item.XOffset),false)
}
}
}
//xStep,yStep 移动的偏移量
this.MoveChartDrawPicture=function(x,y,isPhone,drag)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
if (isPhone) pixelTatio=1;
var xStep=x*pixelTatio;
var yStep=y*pixelTatio;
//JSConsole.Chart.Log("xStep="+xStep+" yStep="+yStep);
drawPicture.Move(xStep,yStep,drag);
return true;
}
//数据长度变化 需要更新画图工具X轴索引
this.UpdateChartDrawXValue=function()
{
for(var i in this.ChartDrawPicture)
{
var item=this.ChartDrawPicture[i];
item.UpdateXValue();
}
}
//注册鼠标右键事件
this.OnRightMenu=function(x,y,e)
{
var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
var frameId=this.Frame.PtInFrame(x*pixelTatio,y*pixelTatio);
this.PopupRightMenuV2({X:e.offsetX, Y:e.offsetY, FrameID:frameId}, e);
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU);
if (event)
{
var data={ X:x, Y:y, Event:e, FrameID:frameId };
event.Callback(event,data,this);
}
}
//右键菜单数据
this.GetRightMenuData=function(frameID)
{
var windowCount=this.Frame.SubFrame.length; //窗口个数
var klineChart=this.ChartPaint[0];
var klineType=klineChart.DrawType;
var bThinAKBar=klineChart.IsThinAKBar;
var priceGap=klineChart.PriceGap; //缺口配置信息
var infoPosition=klineChart.InfoPosition;
var coordinateType=null, yCoordinateType=null; //坐标类型
var mainFrame=null;
if (this.Frame.SubFrame[0] && this.Frame.SubFrame[0].Frame) mainFrame=this.Frame.SubFrame[0].Frame;
if (mainFrame)
{
coordinateType=mainFrame.CoordinateType;
if (mainFrame.YSplitOperator) yCoordinateType=mainFrame.YSplitOperator.CoordinateType;
}
var aryKLineInfo=[]; //信息地雷
for(var i=0;i<this.ChartInfo.length;++i)
{
var item=this.ChartInfo[i];
if (item && item.ClassName) aryKLineInfo.push(item.ClassName);
}
var aryOverlaySymbol=[]; //叠加的股票列表
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (item && item.Symbol) aryOverlaySymbol.push(item.Symbol)
}
var bBGSpit=false, bShowStockChip=false;
if (this.GetExtendChartByClassName("SessionBreaksPaint")) bBGSpit=true;
if (this.GetExtendChartByClassName('StockChip')) bShowStockChip=true; //筹码
var bShowCorss=false; //十字光标十字线
if (this.ChartCorssCursor) bShowCorss=this.ChartCorssCursor.IsShowCorss;
var bPopMinuteChart=false;
if (this.PopMinuteChart) bPopMinuteChart=true;
var aryMenu=
[
{
Name:"分析周期",
SubMenu:
[
{ Name:"日线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[0] }, Checked:this.Period==0 },
{ Name:"周线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[1] }, Checked:this.Period==1 },
{ Name:"双周线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[21]}, Checked:this.Period==21 },
{ Name:"月线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[2]}, Checked:this.Period==2 },
{ Name:"季线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[9]}, Checked:this.Period==9 },
{ Name:"半年", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[22]}, Checked:this.Period==22 },
{ Name:"年线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[3]}, Checked:this.Period==3 },
{ Name:"1分", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[4]}, Checked:this.Period==4 },
{ Name:"5分", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[5]}, Checked:this.Period==5 },
{ Name:"15分", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[6]}, Checked:this.Period==6 },
{ Name:"30分", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[7]}, Checked:this.Period==7 },
{ Name:"60分", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[8]}, Checked:this.Period==8 },
{ Name:"2小时", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[11]}, Checked:this.Period==11 },
{ Name:"4小时", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[12]}, Checked:this.Period==12 },
{ Name:"分笔", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[10]}, Checked:this.Period==10 },
{ Name:"自定义周期:3分钟", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[20003]}, Checked:this.Period==20003 },
{ Name:"自定义周期:35分钟", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[20035]}, Checked:this.Period==20035 },
{ Name:"自定义周期:8日", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_PERIOD_ID, Args:[40008]}, Checked:this.Period==40008 },
]
},
{
Name:"指标切换",
SubMenu:
[
{ Name:"均线", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "均线"]}},
{ Name:"BOLL", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "BOLL"]}},
{ Name:"MACD", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "MACD"]}},
{ Name:"MACD(粗)", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "MACD2"]}},
{ Name:"KDJ", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "KDJ"]}},
{ Name:"VOL", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "VOL"]}},
{ Name:"RSI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "RSI"]}},
{ Name:"BRAR", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "BRAR"]}},
{ Name:"WR", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "WR"]}},
]
},
{
Name:"五彩K线",
SubMenu:
[
{ Name:"十字星", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-十字星"]}},
{ Name:"早晨之星", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-早晨之星"]}},
{ Name:"垂死十字", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-垂死十字"]}},
{ Name:"三只乌鸦", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-三只乌鸦"]}},
{ Name:"光脚阴线", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-光脚阴线"]}},
{ Name:"黄昏之星", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COLOR_INDEX_ID, Args:["五彩K线-黄昏之星"]}},
]
},
{
Name:"专家系统",
SubMenu:
[
{ Name:"BIAS", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-BIAS"]}},
{ Name:"CCI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-CCI"]}},
{ Name:"DMI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-DMI"]}},
{ Name:"KD", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-KD"]}},
{ Name:"BOLL", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-BOLL"]}},
{ Name:"KDJ", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_TRADE_INDEX_ID, Args:["交易系统-KDJ"]}},
]
},
{
Name:"信息地雷",
SubMenu:
[
{ Name:"公告", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["公告", !aryKLineInfo.includes("AnnouncementInfo")]}, Checked:aryKLineInfo.includes("AnnouncementInfo") },
{ Name:"业绩预告", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["业绩预告", !aryKLineInfo.includes("PforecastInfo")]}, Checked:aryKLineInfo.includes("PforecastInfo") },
{ Name:"调研", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["调研", !aryKLineInfo.includes("ResearchInfo") ]}, Checked:aryKLineInfo.includes("ResearchInfo") },
{ Name:"大宗交易", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["大宗交易", !aryKLineInfo.includes("BlockTrading")]}, Checked:aryKLineInfo.includes("BlockTrading") },
{ Name:"龙虎榜", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["龙虎榜", !aryKLineInfo.includes("TradeDetail")]}, Checked:aryKLineInfo.includes("TradeDetail") },
{ Name:"互动易", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_INFO_ID, Args:["互动易", !aryKLineInfo.includes("InvestorInfo")]}, Checked:aryKLineInfo.includes("InvestorInfo") },
{ Name:JSPopMenu.SEPARATOR_LINE_NAME },
{
Name:"显示位置",
SubMenu:
[
{ Name:"底部", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INFO_POSITION_ID, Args:[1]}, Checked:infoPosition===1 },
{ Name:"K线上", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INFO_POSITION_ID, Args:[0]}, Checked:infoPosition===0 },
]
},
]
},
{
Name:"缺口提示",
SubMenu:
[
{ Name:"显示1个缺口", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_PRICE_GAP_ID, Args:[true, 1]}, Checked:(priceGap.Enable==true && priceGap.Count==1) },
{ Name:"显示2个缺口", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_PRICE_GAP_ID, Args:[true, 2]}, Checked:(priceGap.Enable==true && priceGap.Count==2) },
{ Name:"显示3个缺口", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_PRICE_GAP_ID, Args:[true, 3]}, Checked:(priceGap.Enable==true && priceGap.Count==3) },
{ Name:"隐藏缺口", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_PRICE_GAP_ID, Args:[false]}, Checked:priceGap.Enable==false },
]
},
{
Name:"叠加品种",
SubMenu:
[
{ Name:"上证指数", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["000001.sh", !aryOverlaySymbol.includes("000001.sh")]}, Checked:aryOverlaySymbol.includes("000001.sh") },
{ Name:"深证成指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399001.sz", !aryOverlaySymbol.includes("399001.sz")]}, Checked:aryOverlaySymbol.includes("399001.sz") },
{ Name:"中小板指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399005.sz", !aryOverlaySymbol.includes("399005.sz")]}, Checked:aryOverlaySymbol.includes("399005.sz") },
{ Name:"创业板指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399006.sz", !aryOverlaySymbol.includes("399006.sz")]}, Checked:aryOverlaySymbol.includes("399006.sz") },
{ Name:"沪深300", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["000300.sh", !aryOverlaySymbol.includes("000300.sh")]}, Checked:aryOverlaySymbol.includes("000300.sh")},
]
},
{
Name:"主图线型",
SubMenu:
[
{ Name:"K线(空心阳线)", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[3]}, Checked:klineType==3 },
{ Name:"K线(实心阳线)", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[0]}, Checked:klineType==0 },
{ Name:"美国线", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[2, true, { IsThinAKBar:false }]}, Checked:(klineType==2&&!bThinAKBar) },
{ Name:"美国线(细)", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[2, true, { IsThinAKBar:true }]}, Checked:(klineType==2&&bThinAKBar) },
{ Name:"收盘线", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[1]}, Checked:klineType==1},
{ Name:"收盘面积", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[4]}, Checked:klineType==4 },
{ Name:"K线(空心阳线阴线)", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[6]}, Checked:klineType==6 },
{ Name:"Heikin Ashi", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[11]}, Checked:klineType==11 },
{ Name:"Line Break", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[12]}, Checked:klineType==12 },
{ Name:"High-low", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[13]}, Checked:klineType==13 },
{ Name:"HLC Area", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_KLINE_TYPE_ID, Args:[15]}, Checked:klineType==15 },
]
},
{
Name:"坐标类型",
SubMenu:
[
{ Name:"反转坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ IsReverse:coordinateType==0 }]}, Checked:coordinateType==1 },
{ Name:JSPopMenu.SEPARATOR_LINE_NAME },
{ Name:"普通坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:0 }]}, Checked:yCoordinateType==0 },
{ Name:"百分比坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:1 }]}, Checked:yCoordinateType==1 },
{ Name:"对数坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:2 }]}, Checked:yCoordinateType==2 },
{ Name:"等比坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:3 }]}, Checked:yCoordinateType==3 },
{ Name:"等分坐标", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:4 }]}, Checked:yCoordinateType==4 },
{ Name:"黄金分割", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_COORDINATETYPE_ID, Args:[{ Type:5 }]}, Checked:yCoordinateType==5},
]
},
{
Name:"指标窗口个数",
SubMenu:
[
{ Name:"1个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[2]}, Checked:2==windowCount },
{ Name:"2个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[3]}, Checked:3==windowCount },
{ Name:"3个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[4]}, Checked:4==windowCount },
{ Name:"4个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[5]}, Checked:5==windowCount },
{ Name:"5个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[6]}, Checked:6==windowCount },
]
},
{
Name:"其他设置",
SubMenu:
[
{ Name:"禁止拖拽", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_MODE_ID, Args:[0]}, Checked:0==this.DragMode },
{ Name:"启动拖拽", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_MODE_ID, Args:[1]}, Checked:1==this.DragMode },
{ Name:"左键区间选择", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_MODE_ID, Args:[2]}, Checked:2==this.DragMode },
{ Name:JSPopMenu.SEPARATOR_LINE_NAME },
{ Name:"背景分割", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_BG_SPLIT_ID, Args:[!bBGSpit]}, Checked:bBGSpit},
{ Name:"画图工具", Data:{ ID:JSCHART_MENU_ID.CMD_SHOW_DRAWTOOL_ID, Args:[]}, Checked:this.IsShowDrawToolDialog() },
{ Name:"移动筹码图", Data:{ ID:bShowStockChip?JSCHART_MENU_ID.CMD_HIDE_STOCKCHIP_ID:JSCHART_MENU_ID.CMD_SHOW_STOCKCHIP_ID, Args:[]}, Checked:bShowStockChip},
{ Name:"十字光标线", Data:{ ID:JSCHART_MENU_ID.CMD_SHOW_CORSS_LINE_ID, Args:[!bShowCorss]}, Checked:bShowCorss },
{ Name:"双击弹分时图", Data:{ ID:JSCHART_MENU_ID.CMD_ENABLE_POP_MINUTE_CHART_ID, Args:[!bPopMinuteChart]}, Checked:bPopMinuteChart},
{ Name:JSPopMenu.SEPARATOR_LINE_NAME },
{
Name:"鼠标形状",
SubMenu:
[
{ Name:"默认", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DEFAULTCURSOR_ID, Args:["default"]}, Checked:this.DefaultCursor=="default" },
{ Name:"十字线", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DEFAULTCURSOR_ID, Args:["crosshair"]}, Checked:this.DefaultCursor=="crosshair" },
]
},
{
Name:"语言设置",
SubMenu:
[
{ Name:"中文", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["CN"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID },
{ Name:"英语", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["EN"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID },
{ Name:"繁体", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["TC"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID },
]
},
{
Name:"区间选择样式",
SubMenu:
[
{ Name:"样式1(默认)", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[0]}, Checked:0==this.ChartDragSelectRect.ShowMode },
{ Name:"样式2", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[1]}, Checked:1==this.ChartDragSelectRect.ShowMode },
{ Name:"样式3", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[2]}, Checked:2==this.ChartDragSelectRect.ShowMode },
]
},
{
Name:"K线浮动框",
SubMenu:
[
{ Name:"禁用", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:false}]}, Checked:!this.DialogTooltip },
{ Name:"样式1", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:true, Style:0}]}, Checked:(this.DialogTooltip && this.DialogTooltip.Style===0) },
{ Name:"样式2", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:true, Style:1}]}, Checked:(this.DialogTooltip && this.DialogTooltip.Style===1) },
]
},
{
Name:"K线提示框",
SubMenu:
[
{ Name:"启用", Data:{ ID:JSCHART_MENU_ID.CMD_KLINE_TOOLTIP_ATTRIBUTE, Args:[{Enable:!this.KLineTooltipConfig.Enable}]}, Checked:this.KLineTooltipConfig.Enable },
{ Name:"键盘左右显示", Data:{ ID:JSCHART_MENU_ID.CMD_KLINE_TOOLTIP_ATTRIBUTE, Args:[{EnableKeyDown:!this.KLineTooltipConfig.EnableKeyDown}]}, Checked:this.KLineTooltipConfig.EnableKeyDown },
]
}
]
}
];
//复权
if(!MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol) && !MARKET_SUFFIX_NAME.IsBIT(this.Symbol))
{
var rightMenu=
{
Name:"复权处理",
SubMenu:
[
{ Name:"不复权", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_RIGHT_ID, Args:[0]}, Checked:0==this.Right },
{ Name:"前复权", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_RIGHT_ID, Args:[1]}, Checked:1==this.Right },
{ Name:"后复权", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_RIGHT_ID, Args:[2]}, Checked:2==this.Right }
]
};
aryMenu.splice(1,0,rightMenu);
}
//删除菜单
for(var i=0;i<aryMenu.length;++i)
{
var item=aryMenu[i];
if (item.Name=="五彩K线")
{
if (this.ColorIndex)
{
item.SubMenu.push({ Name:JSPopMenu.SEPARATOR_LINE_NAME });
item.SubMenu.push({ Name:"删除五彩K线", Data:{ ID: JSCHART_MENU_ID.CMD_DELETE_COLOR_INDEX_ID} });
}
}
else if (item.Name=="专家系统")
{
if (this.TradeIndex)
{
item.SubMenu.push({ Name:JSPopMenu.SEPARATOR_LINE_NAME });
item.SubMenu.push({ Name:"删除专家系统", Data:{ ID: JSCHART_MENU_ID.CMD_DELETE_TRADE_INDEX_ID} });
}
}
else if (item.Name=="叠加品种")
{
for(var j=0;j<item.SubMenu.length;++j)
{
if (item.SubMenu[j].Checked)
{
item.SubMenu.push({ Name:JSPopMenu.SEPARATOR_LINE_NAME });
item.SubMenu.push({ Name:"取消叠加", Data:{ ID: JSCHART_MENU_ID.CMD_DELETE_ALL_OVERLAY_SYMBOL_ID} });
break;
}
}
}
else if (item.Name=="信息地雷")
{
for(var j=0;j<item.SubMenu.length;++j)
{
if (item.SubMenu[j].Checked)
{
item.SubMenu.push({ Name:JSPopMenu.SEPARATOR_LINE_NAME });
item.SubMenu.push({ Name:"删除所有", Data:{ ID: JSCHART_MENU_ID.CMD_DELETE_ALL_KLINE_INFO_ID} });
break;
}
}
}
}
return aryMenu;
}
this.PopupSelectRectMenuV2=function(data, e)
{
var aryMenu=
[
{ Name:"区间统计", Data:{ ID:JSCHART_MENU_ID.CMD_SELECTED_SUMMARY_ID, Args:[e] }},
{ Name:"区间放大", Data:{ ID:JSCHART_MENU_ID.CMD_SELECTED_ZOOM_ID, Args:[data.SelectData] }}
];
var menuData={ Menu:aryMenu, Position:JSPopMenu.POSITION_ID.RIGHT_MENU_ID };
menuData.ClickCallback=(data)=>{ this.OnClickRightMenu(data); }
var x=data.X, y=data.Y;
this.PopupMenuByRClick(menuData, x, y);
}
//重新加载画图工具(切换股票|周期)
this.ReloadChartDrawPicture=function()
{
this.ChartDrawPicture=[];
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
this.CurrentChartDrawPicture=null;
if (this.ChartDrawStorage)
{
this.ChartDrawStorageCache=this.ChartDrawStorage.GetDrawData( {Symbol:this.Symbol, Period:this.Period} );
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_LOAD_DRAWPICTURE);
if (event && event.Callback)
{
var sendData={ Symbol:this.Symbol, Period:this.Period, DrawStorage:this.ChartDrawStorage, ChartDrawStorageCache:this.ChartDrawStorageCache };
event.Callback(event,sendData,this);
}
}
}
this.CreateChartDrawPictureByStorage=function() //把缓存(this.ChartDrawStorageCache) 画图工具创建出来
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.ChartDrawStorageCache)) return;
for(var i=0; i<this.ChartDrawStorageCache.length; ++i)
{
var item=this.ChartDrawStorageCache[i];
if (item.FrameID<0 || !this.Frame.SubFrame || this.Frame.SubFrame.length<item.FrameID) continue;
var drawPicture=IChartDrawPicture.CreateChartDrawPicture(item);
if (!drawPicture) continue;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[item.FrameID].Frame; //绑定框架坐标
drawPicture.Option=this.ChartDrawOption;
if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(item);
drawPicture.UpdateXValue();
drawPicture.ValueToPoint();
var self=this;
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
}
this.ChartDrawStorageCache=null; //清空缓存
}
//更新信息地雷
this.UpdataChartInfo=function()
{
//TODO: 根据K线数据日期来做map, 不在K线上的合并到下一个k线日期里面
var mapInfoData=null;
if (this.Period==0) //日线数据 根据日期
{
mapInfoData=new Map();
for(var i in this.ChartInfo)
{
var infoData=this.ChartInfo[i].Data;
for(var j in infoData)
{
var item=infoData[j];
if (mapInfoData.has(item.Date.toString()))
{
mapInfoData.get(item.Date.toString()).Data.push(item);
}
else
{
mapInfoData.set(item.Date.toString(),{Data:new Array(item)});
}
}
}
}
else if (ChartData.IsDayPeriod(this.Period,false))
{
mapInfoData=new Map();
var hisData=this.ChartPaint[0].Data;
if (hisData && hisData.Data && hisData.Data.length>0)
{
var fristKItem=hisData.Data[0];
var aryInfo=[];
for(var i in this.ChartInfo)
{
var infoItem=this.ChartInfo[i];
for(var j in infoItem.Data)
{
var item=infoItem.Data[j];
if (item.Date>=fristKItem.Date) //在K线范围内的才显示
aryInfo.push(item);
}
}
aryInfo.sort(function(a,b) { return a.Date-b.Date }); //排序
for(var i=0;i<hisData.Data.length;)
{
var kItem=hisData.Data[i]; //K线数据
if (aryInfo.length<=0)
break;
var infoItem=aryInfo[0];
if (kItem.Date<infoItem.Date)
{
++i;
continue;
}
if (mapInfoData.has(kItem.Date.toString())) //信息地雷日期<K线上的日期 就是属于这个K线上的
{
mapInfoData.get(kItem.Date.toString()).Data.push(infoItem);
}
else
{
mapInfoData.set(kItem.Date.toString(),{Data:new Array(infoItem)});
}
aryInfo.shift();
//JSConsole.Chart.Log('[KLineChartContainer::UpdataChartInfo]',item);
}
}
}
else if (ChartData.IsMinutePeriod(this.Period, true))
{
mapInfoData=new Map();
var hisData=this.ChartPaint[0].Data;
if (hisData && hisData.Data && hisData.Data.length>0)
{
var firstKItem=hisData.Data[0];
var aryInfo=[];
for(var i=0, j=0; i<this.ChartInfo.length; ++i)
{
var infoItem=this.ChartInfo[i];
for(j=0; j<infoItem.Data.length; ++j)
{
var item=infoItem.Data[j];
if (item.Date>=firstKItem.Date || (item.Date==firstKItem.Date && item.Time>=firstKItem.Time)) //在K线范围内的才显示
aryInfo.push(item);
}
}
aryInfo.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date
}); //排序
for(var i=0;i<hisData.Data.length;)
{
var kItem=hisData.Data[i]; //K线数据
if (aryInfo.length<=0)
break;
var infoItem=aryInfo[0];
if (kItem.Date<infoItem.Date || (kItem.Date==infoItem.Date && kItem.Time<infoItem.Time))
{
++i;
continue;
}
var key=`${kItem.Date}-${kItem.Time}`;
if (mapInfoData.has(key)) //信息地雷日期<K线上的日期 就是属于这个K线上的
{
mapInfoData.get(key).Data.push(infoItem);
}
else
{
mapInfoData.set(key,{Data:new Array(infoItem)});
}
aryInfo.shift();
//JSConsole.Chart.Log('[KLineChartContainer::UpdataChartInfo]',item);
}
}
}
var klinePaint=this.ChartPaint[0];
klinePaint.InfoData=mapInfoData;
}
//接收到窗口指标数据 订阅模式
this.RecvWindowIndex=function(index, data)
{
var indexItem=this.WindowIndex[index];
if (!indexItem) return;
if (typeof(indexItem.RecvSubscribeData)=="function")
{
var hisData=this.ChartPaint[0].Data;
indexItem.RecvSubscribeData(data,this,index,hisData);
}
}
//更新窗口指标
this.UpdateWindowIndex=function(index)
{
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (this.IsApiPeriod)
{
}
else
{
if (bindData.Right>0) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
}
if (typeof(this.WindowIndex[index].ExecuteScript)=='function')
{
var hisData=this.ChartPaint[0].Data;
this.WindowIndex[index].ExecuteScript(this,index,hisData);
}
else if (typeof(this.WindowIndex[index].RequestData)=="function") //数据需要另外下载的.
{
var hisData=this.ChartPaint[0].Data;
this.WindowIndex[index].RequestData(this, index, hisData, null);
}
else
{
this.WindowIndex[index].BindData(this,index,bindData);
}
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.GetOverlayIndexByIdentify=function(identify)
{
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
if (!IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex)) continue;
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Identify===identify)
return { OverlayItem:overlayItem, WindowIndex:i };
}
}
return null;
}
this.RecvOverlayIndex=function(identify, data)
{
var overlayIndex=this.GetOverlayIndexByIdentify(identify);
if (overlayIndex==null)
{
console.warn(`[KLineChartContainer::RecvOverlayIndex] can't find overlay index. [identify=${identify}]`);
return;
}
if (!overlayIndex.Script) return;
if (typeof(overlayIndex.RecvSubscribeData)!="function") return;
if (!this.ChartPaint[0]) return;
var kData=this.ChartPaint[0].Data;
if (!kData) return;
overlayIndex.Script.RecvSubscribeData(data,this,overlayIndex.WindowIndex,kData);
}
//更新叠加指标
this.UpdateOverlayIndex=function(identify)
{
var overlayIndex=this.GetOverlayIndexByIdentify(identify);
if (overlayIndex==null)
{
console.warn(`[KLineChartContainer::UpdateOverlayIndex] can't find overlay index. [identify=${identify}]`);
return;
}
if (!this.ChartPaint[0]) return;
var kData=this.ChartPaint[0].Data;
if (!kData) return;
this.BindOverlayIndexData(overlayIndex.OverlayItem, overlayIndex.WindowIndex, kData);
}
//修改参数指标
this.ChangeWindowIndexParam=function(index)
{
this.WindowIndex[index].Index[0].Param+=1;
this.WindowIndex[index].Index[1].Param+=1;
this.UpdateWindowIndex(index);
}
this.OnDoubleClick=function(x,y,e)
{
if (this.EnableYDrag && (this.EnableYDrag.Left || this.EnableYDrag.Right) && this.Frame && this.Frame.PtInFrameY)
{
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
var dragY=this.Frame.PtInFrameY(x,y);
if (dragY && dragY.Index>=0)
{
this.CancelZoomUpDownFrameY(dragY);
}
}
var selectedChart; //图形选中
if (this.SelectedChart.EnableSelected)
{
selectedChart=this.PtInChart(x,y);
}
var dbClickInfo={ SelectedChart:selectedChart };
this.DBClickEvent(dbClickInfo, e);
if (!selectedChart && this.EnableZoomIndexWindow) //双击放大缩小
{
var frameId=this.Frame.PtInFrame(x,y);
JSConsole.Chart.Log("[KLineChartContainer::OnDoubleClick] frameId",frameId);
if (frameId>=this.Frame.ZoomStartWindowIndex)
{
if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
{
this.Frame.SetSizeChage(true);
this.Draw();
return true;
}
}
}
var tooltip=new TooltipData();
if (!this.PtInChartPaintTooltip(x,y,tooltip))
{
if (!this.PtInOverlayIndexTooltip(x, y,tooltip)) return;
}
if (!tooltip.Data) return;
var event=null;
if (this.mapEvent.has(JSCHART_EVENT_ID.DBCLICK_KLINE)) event=this.mapEvent.get(JSCHART_EVENT_ID.DBCLICK_KLINE);
if (event)
{
if (this.ClickChartTimer!=null) //清空单击定时器
{
clearTimeout(this.ClickChartTimer);
this.ClickChartTimer=null;
}
var data={ Tooltip:tooltip, Stock:{Symbol:this.Symbol, Name:this.Name }, X:e.clientX, Y:e.clientY, PreventDefault:false };
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
//内置弹分时图
if (this.PopMinuteChart && tooltip.Type===0)
this.ShowMinuteChartDialog({ Chart:this,Tooltip:tooltip, e:e }, x,y);
}
this.CancelAutoUpdate=function() //关闭停止更新
{
if (typeof (this.AutoUpdateTimer) == 'number')
{
clearTimeout(this.AutoUpdateTimer);
this.AutoUpdateTimer = undefined;
}
}
//数据自动更新
this.AutoUpdate=function(waitTime) //waitTime 更新时间
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
if (!this.Symbol) return;
var self = this;
var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol);
if (marketStatus==0 || marketStatus==3) //闭市,盘后
{ //等待开盘
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},20000);
return;
}
var frequency=this.AutoUpdateFrequency;
if (marketStatus==1) //盘前
{
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},frequency);
}
else if (marketStatus==2) //盘中
{
this.AutoUpdateTimer=setTimeout(function()
{
if (ChartData.IsDayPeriod(self.Period,true))
{
self.RequestRealtimeData(); //更新最新行情
//self.ReqeustKLineInfoData();
}
else if (ChartData.IsMinutePeriod(self.Period,true) || ChartData.IsSecondPeriod(self.Period) || ChartData.IsMilliSecondPeriod(self.Period))
{
self.RequestMinuteRealtimeData(); //请求分钟数据
}
else if (ChartData.IsTickPeriod(self.Period))
{
self.RequestTickRealtimeData(); //请求最新分笔
}
},frequency);
}
}
this.GetMaxMinPageSize = function ()
{
let pageSize={};
let width = this.Frame.ChartBorder.GetWidth();
let barWidth = (ZOOM_SEED[ZOOM_SEED.length - 1][0] + ZOOM_SEED[ZOOM_SEED.length - 1][1]);
pageSize.Max=parseInt(width / barWidth) - 2;
barWidth= (ZOOM_SEED[0][0] + ZOOM_SEED[0][1]);
pageSize.Min=parseInt(width / barWidth) - 2;
JSConsole.Chart.Log(`[KLineChartContainer::GetMaxMinPageSize] Max=${pageSize.Max} Min=${pageSize.Min}`);
return pageSize;
}
//获取图形控件的状态
this.GetChartStatus=function()
{
var subFrame=this.Frame.SubFrame[0].Frame;
if (!subFrame) return null;
var hisData=subFrame.Data;
if (!hisData) return null;
var status={ KLine:{ }, Zoom:{} };
status.KLine.Count=hisData.Data.length;
status.KLine.Offset=hisData.DataOffset;
status.KLine.PageSize=subFrame.XPointCount;
status.Zoom.Index=subFrame.ZoomIndex;
status.Zoom.Max=ZOOM_SEED.length;
return status;
}
//数据拖拽下载
this.DragDownloadData=function()
{
var data=null;
if (!this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
if (data.DataOffset>0) return;
if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period)) //下载分钟/秒数据
{
JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Minute:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}, Period=${this.Period}]`);
if (!this.DragDownload.Minute.Enable) return;
if (this.DragDownload.Minute.IsEnd) return; //全部下载完了
if (this.DragDownload.Minute.Status!=0) return;
this.RequestDragMinuteData();
}
else if (ChartData.IsDayPeriod(this.Period,true))
{
JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Day:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`);
if (!this.DragDownload.Day.Enable) return;
if (this.DragDownload.Day.IsEnd) return; //全部下载完了
if (this.DragDownload.Day.Status!=0) return;
this.RequestDragDayData();
}
else if(ChartData.IsTickPeriod(this.Period))
{
JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Tick:[Enable=${this.DragDownload.Tick.Enable}, IsEnd=${this.DragDownload.Tick.IsEnd}, Status=${this.DragDownload.Tick.Status}]`);
if (!this.DragDownload.Tick.Enable) return;
if (this.DragDownload.Tick.IsEnd) return; //全部下载完了
if (this.DragDownload.Tick.Status!=0) return;
this.RequestDragTickData();
}
}
//数据缩放下载
this.ZoomDownloadData=function(requestData)
{
var data=null;
if (!this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) return false;
if (data.DataOffset>0) return;
if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period)) //下载分钟/秒数据
{
JSConsole.Chart.Log(`[KLineChartContainer.ZoomDownloadData] Minute:[Enable=${this.ZoomDownload.Minute.Enable}, IsEnd=${this.ZoomDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}, Period=${this.Period}]`);
if (!this.ZoomDownload.Minute.Enable) return;
if (this.ZoomDownload.Minute.IsEnd) return; //全部下载完了
if (this.ZoomDownload.Minute.Status!=0) return;
this.RequestZoomMinuteData(requestData);
}
else if (ChartData.IsDayPeriod(this.Period,true))
{
JSConsole.Chart.Log(`[KLineChartContainer.ZoomDownloadData] Day:[Enable=${this.ZoomDownload.Minute.Enable}, IsEnd=${this.ZoomDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`);
if (!this.ZoomDownload.Day.Enable) return;
if (this.ZoomDownload.Day.IsEnd) return; //全部下载完了
if (this.ZoomDownload.Day.Status!=0) return;
this.RequestZoomDayData(requestData);
}
else if(ChartData.IsTickPeriod(this.Period))
{
JSConsole.Chart.Log(`[KLineChartContainer.ZoomDownloadData] Tick:[Enable=${this.ZoomDownload.Tick.Enable}, IsEnd=${this.ZoomDownload.Tick.IsEnd}, Status=${this.DragDownload.Tick.Status}]`);
if (!this.ZoomDownload.Tick.Enable) return;
if (this.ZoomDownload.Tick.IsEnd) return; //全部下载完了
if (this.ZoomDownload.Tick.Status!=0) return;
this.RequestZoomTickData(requestData);
}
}
//TODO:
this.RequestDragTickData=function()
{
JSConsole.Chart.Log(`[KLineChartContainer.RequestDragTickData] not finished.`);
}
//请求拖动或缩放的分钟历史数据
this.RequestPreviousMinuteData=function(option)
{
var funcName=option.FuncName;
var funcExplain=option.FuncExplain;
var download=option.Download;
var url=option.Url;
var count=option.Count; //请求数据个数
var self=this;
this.AutoUpdateEvent(false,funcName); //停止自动更新
this.CancelAutoUpdate();
download.Status=1;
var firstItem=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
firstItem=this.SourceData.Data[0]; //最新的一条数据
else
firstItem={Date:null, Time:null};
var postData=
{
"field": ["name","symbol", "yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"enddate": firstItem.Date,
"endtime" :firstItem.Time,
"count": count,
"first":{ date: firstItem.Date, time:firstItem.Time }
};
if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
{
postData.overlay=[];
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
postData.overlay.push({ symbol:item.Symbol });
}
}
if (this.NetworkFilter)
{
var obj=
{
Name:funcName, //类名::函数
Explain:funcExplain,
Request:{ Url:url, Type:'POST', Data: postData, Period:this.Period, Right:this.Right },
DragDownload:download,
Option:option,
Self:this,
PreventDefault:false,
ZoomData:option.ZoomData
};
this.NetworkFilter(obj, function(data)
{
self.RecvPreviousMinuteData(data,option);
download.Status=0;
self.AutoUpdateEvent(true,funcName); //自动更新
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: url,
data:postData,
type:"post",
dataType: "json",
async:true,
success: function(data)
{
self.RecvPreviousMinuteData(data, option);
download.Status=0;
self.AutoUpdateEvent(true,funcName); //自动更新
self.AutoUpdate();
}
});
}
this.RecvPreviousMinuteData=function(data, option)
{
var download=option.Download;
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
if (!aryDayData || aryDayData.length<=0)
{
download.IsEnd=true;
JSConsole.Chart.Log(`[KLineChartContainer.RecvPreviousMinuteData] ${this.Symbol} data end. FuncName=${option.FuncName}`);
this.Draw();
return;
}
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
var endIndex=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
{
var firstData=this.SourceData.Data[0];
for(var i=aryDayData.length-1;i>=0;--i)
{
var item=aryDayData[i];
if (firstData.Date>item.Date || (firstData.Date==item.Date && firstData.Time>item.Time))
{
endIndex=i;
break;
}
else if (firstData.Date==item.Date && firstData.Time==item.Time)
{
firstData.YClose=item.YClose;
endIndex=i-1;
break;
}
}
}
else
{
endIndex=aryDayData.length-1;
}
if (endIndex==null && endIndex<0) return;
for(var i=0;i<aryDayData.length && i<=endIndex;++i) //数据往前插
{
var item=aryDayData[i];
this.SourceData.Data.splice(i,0,item);
}
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (!this.IsApiPeriod)
{
if (bindData.Right>0 && this.RightFormula>=1) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula } );
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:option.RecvFuncName });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
if (option) //缩放需要调整当前屏的位置
{
if (option.ZoomData)
{
var zoomData=option.ZoomData;
var showCount=zoomData.PageSize-zoomData.RightSpaceCount; //一屏显示的数据个数
bindData.DataOffset= bindData.Data.length-showCount;
if (bindData.DataOffset<0) bindData.DataOffset=0;
}
else if (IFrameSplitOperator.IsNumber(option.DataOffset))
{
bindData.DataOffset+=option.DataOffset;
if (bindData.DataOffset<0) bindData.DataOffset=0;
}
}
this.UpdateOverlayDragMinuteData(data);
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.UpdateChartDrawXValue(); //更新画图工具X轴索引
this.Draw();
//叠加指标计算
this.BindAllOverlayIndexData(bindData, { SyncExecute:false }); //异步模式叠加指标
}
this.RequestZoomMinuteData=function(requestData)
{
var zoomData={ PageSize:requestData.PageSize, DataCount:requestData.DataCount, RightSpaceCount:requestData.RightSpaceCount };
var option=
{
FuncName:'KLineChartContainer::RequestZoomMinuteData',
FuncExplain:"缩放分钟|秒K线数据下载",
RecvFuncName:"RecvZoomMinuteData",
Download:this.ZoomDownload.Minute,
Url:this.ZoomMinuteKLineApiUrl,
Count:this.MaxRequestMinuteDayCount,
XShowCount:this.Frame.GetXShowCount(),
ZoomData:zoomData
};
this.RequestPreviousMinuteData(option);
}
this.RequestDragMinuteData=function()
{
var option=
{
FuncName:'KLineChartContainer::RequestDragMinuteData',
FuncExplain:"拖拽分钟|秒K线数据下载",
RecvFuncName:"RecvDragMinuteData",
Download:this.DragDownload.Minute,
Url:this.DragMinuteKLineApiUrl,
Count:this.MaxRequestMinuteDayCount,
XShowCount:this.Frame.GetXShowCount(),
};
this.RequestPreviousMinuteData(option);
}
this.MergeOverlaySymbolMinuteData=function(item, aryOverlayData)
{
if (!item.Symbol) false;
if (!IFrameSplitOperator.IsNonEmptyArray(aryOverlayData)) return false;
var findData=null;
for(var i=0;i<aryOverlayData.length;++i) //查找对应的叠加股票数据
{
var overlayItem=aryOverlayData[i];
if (overlayItem.symbol==item.Symbol)
{
findData=overlayItem;
break;
}
}
if (!findData) return false;
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(findData);
var sourceData=item.SourceData; //叠加股票的所有数据
var firstData=sourceData.Data[0];
var endIndex=null;
for(var i=aryDayData.length-1;i>=0;--i)
{
var itemData=aryDayData[i];
if (firstData.Date>itemData.Date)
{
endIndex=i;
break;
}
else if (firstData.Date==itemData.Date && firstData.Time>itemData.Time)
{
endIndex=i;
break;
}
else if (firstData.Date==itemData.Date && firstData.Time==itemData.Time)
{
firstData.YClose=itemData.YClose;
endIndex=i-1;
break;
}
}
if (endIndex==null && endIndex<0) return false;
for(var i=0; i<aryDayData.length && i<=endIndex;++i) //数据往前插
{
var itemData=aryDayData[i];
sourceData.Data.splice(i,0,itemData);
}
var bindData=new ChartData();
bindData.Data=sourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
return true;
}
this.UpdateOverlayDragMinuteData=function(data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint)) return;
var aryRecvOverlayData=data.overlay;
for(var i=0;i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
var bUpdate=false;
if (item.MainData && item.Status==OVERLAY_STATUS_ID.STATUS_FINISHED_ID) //等待主图股票数据未下载完
{
bUpdate=this.MergeOverlaySymbolMinuteData(item,aryRecvOverlayData);
}
if (!bUpdate) //没有更新数据 手动跟主图数据对齐
{
if (item.Data && IFrameSplitOperator.IsNonEmptyArray(item.Data.Data))
{
var bindData=item.Data;
var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
}
}
}
}
//请求拖动或缩放的日线历史数据
this.RequestPreviousDayData=function(option)
{
var funcName=option.FuncName;
var funcExplain=option.FuncExplain;
var download=option.Download;
var url=option.Url;
var count=option.Count; //请求数据个数
var self=this;
this.AutoUpdateEvent(false,funcName); //停止自动更新
this.CancelAutoUpdate();
download.Status=1;
var firstItem=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
firstItem=this.SourceData.Data[0];
else
firstItem={Date:null};
var postData=
{
"field": ["name","symbol", "yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"enddate": firstItem.Date,
"count": count,
"first":{ date: firstItem.Date }
};
if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
{
postData.overlay=[];
for(var i=0;i<this.OverlayChartPaint.length;++i)
{
var item=this.OverlayChartPaint[i];
postData.overlay.push( { symbol:item.Symbol } );
}
}
if (this.NetworkFilter)
{
var obj=
{
Name:funcName, //类名::函数
Explain:funcExplain,
Request:{ Url:url, Type:'POST' , Data: postData, Period:this.Period, Right:this.Right },
DragDownload:download,
Option:option,
Self:this,
PreventDefault:false,
ZoomData:option.ZoomData
};
this.NetworkFilter(obj, function(data)
{
self.RecvPreviousDayData(data,option);
download.Status=0;
self.AutoUpdateEvent(true,funcName); //自动更新
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: url,
data:postData,
type:"post",
dataType: "json",
async:true,
success: function(data)
{
self.RecvPreviousDayData(data, option);
download.Status=0;
self.AutoUpdateEvent(true,funcName); //自动更新
self.AutoUpdate();
}
});
}
this.RecvPreviousDayData=function(data, option)
{
var download=option.Download;
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
if (!aryDayData || aryDayData.length<=0)
{
download.IsEnd=true; //下完了
JSConsole.Chart.Log(`[KLineChartContainer.RecvPreviousDayData] ${this.Symbol} data end. FuncName=${option.FuncName}`);
return;
}
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
var endIndex=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
{
var firstData=this.SourceData.Data[0];
for(var i=aryDayData.length-1;i>=0;--i)
{
var item=aryDayData[i];
if (firstData.Date>item.Date)
{
endIndex=i;
break;
}
else if (firstData.Date==item.Date)
{
firstData.YClose=item.YClose;
endIndex=i-1;
break;
}
}
}
else
{
var firstData={ Date:null };
endIndex=aryDayData.length-1;
}
if (endIndex==null && endIndex<0) return;
for(var i=0; i<aryDayData.length && i<=endIndex;++i) //数据往前插
{
var item=aryDayData[i];
this.SourceData.Data.splice(i,0,item);
}
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=this.SourceData.DataType;
bindData.Symbol=this.Symbol;
if (!this.IsApiPeriod)
{
if (bindData.Right>0) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
}
var kLineCalculate=this.GetKLineCalulate();
if (kLineCalculate) //额外的K线图形计算
{
var newBindData=kLineCalculate.RecvHistoryData(bindData, { Symbol:this.Symbol, Function:option.RecvFuncName });
bindData=newBindData;
this.FlowCapitalReady=true;
}
//绑定数据
this.UpdateMainData(bindData,lastDataCount);
if (option) //缩放需要调整当前屏的位置
{
if (option.ZoomData)
{
var zoomData=option.ZoomData;
var showCount=zoomData.PageSize-zoomData.RightSpaceCount; //一屏显示的数据个数
bindData.DataOffset= bindData.Data.length-showCount;
if (bindData.DataOffset<0) bindData.DataOffset=0;
}
else if (IFrameSplitOperator.IsNumber(option.DataOffset))
{
bindData.DataOffset+=option.DataOffset;
if (bindData.DataOffset<0) bindData.DataOffset=0;
}
}
this.UpdateOverlayDragDayData(data);
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
this.BindAllOverlayIndexData(bindData, { SyncExecute:true }); //同步模式叠加指标
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.UpdateChartDrawXValue(); //更新画图工具X轴索引
this.Draw();
//更新信息地雷
this.ReqeustKLineInfoData( { FunctionName:option.RecvFuncName, StartDate:firstData.Date } );
//叠加指标计算
this.BindAllOverlayIndexData(bindData, { SyncExecute:false }); //异步模式叠加指标
}
this.RequestZoomDayData=function(requestData)
{
var count=this.MaxRequestDataCount;
if (requestData.Count>count) count=requestData.Count;
var zoomData={ PageSize:requestData.PageSize, DataCount:requestData.DataCount, RightSpaceCount:requestData.RightSpaceCount };
var option=
{
FuncName:'KLineChartContainer::RequestZoomDayData',
FuncExplain:"缩放日K数据下载",
RecvFuncName:"RecvZoomDayData",
Download:this.ZoomDownload.Day,
Url:this.ZoomKLineApiUrl,
XShowCount:this.Frame.GetXShowCount(),
Count:count,
ZoomData:zoomData
};
this.RequestPreviousDayData(option);
}
this.RequestDragDayData=function()
{
var option=
{
FuncName:'KLineChartContainer::RequestDragDayData',
FuncExplain:"拖拽日K数据下载",
RecvFuncName:"RecvDragDayData",
Download:this.DragDownload.Day,
Url:this.DragKLineApiUrl,
Count:this.MaxRequestDataCount,
XShowCount:this.Frame.GetXShowCount(),
};
this.RequestPreviousDayData(option);
}
this.MergeOverlaySymbolDayData=function(item, aryOverlayData)
{
if (!item.Symbol) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(aryOverlayData)) return false;
var findData=null;
for(var i=0;i<aryOverlayData.length;++i) //查找对应的叠加股票数据
{
var overlayItem=aryOverlayData[i];
if (overlayItem.symbol==item.Symbol)
{
findData=overlayItem;
break;
}
}
if (!findData) return false;
var aryDayData=KLineChartContainer.JsonDataToHistoryData(findData);
var sourceData=item.SourceData; //叠加股票的所有数据
var firstData=sourceData.Data[0];
var endIndex=null;
for(var i=aryDayData.length-1;i>=0;--i)
{
var itemData=aryDayData[i];
if (firstData.Date>itemData.Date)
{
endIndex=i;
break;
}
else if (firstData.Date==itemData.Date)
{
firstData.YClose=itemData.YClose;
endIndex=i-1;
break;
}
}
if (endIndex==null && endIndex<0) return false;
for(var i=0; i<aryDayData.length && i<=endIndex;++i) //数据往前插
{
var itemData=aryDayData[i];
sourceData.Data.splice(i,0,itemData);
}
var bindData=new ChartData();
bindData.Data=sourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(findData.symbol) && !this.IsApiPeriod) //复权数据 ,A股才有有复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=bindData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
item.Data=bindData;
return true;
}
//更新叠加数据
this.UpdateOverlayDragDayData=function(data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint)) return;
var aryRecvOverlayData=data.overlay;
for(var i=0;i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (!item.Symbol) continue;
var bUpdate=false;
if (item.MainData && item.Status==OVERLAY_STATUS_ID.STATUS_FINISHED_ID) //等待主图股票数据未下载完
{
bUpdate=this.MergeOverlaySymbolDayData(item, aryRecvOverlayData);
}
if (!bUpdate) //没有更新数据 手动跟主图数据对齐
{
if (item.Data && IFrameSplitOperator.IsNonEmptyArray(item.Data.Data))
{
var bindData=item.Data;
var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod); //和主图数据拟合以后的数据
bindData.Data=aryOverlayData;
}
}
}
}
this.SetCustomVerical=function(windowId, data)
{
if (!this.Frame) return;
if (windowId>=this.Frame.SubFrame.length) return;
var item=this.Frame.SubFrame[windowId];
if (item.Frame) item.Frame.CustomVerticalInfo=data;
}
this.OnSize=function()
{
if (!this.Frame) return;
if (!this.Frame.OnSize) return;
//this.Frame.CalculateChartBorder();
var obj=this.Frame.OnSize();
this.Frame.SetSizeChage(true);
if (obj.Changed)
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex(2);
this.UpdateFrameMaxMin();
}
this.Draw();
}
this.ClickFrameButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_FRAME_TOOLBAR);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
if (button.ID==JSCHART_BUTTON_ID.CLOSE_OVERLAY_INDEX)
{
var id=button.IndexID;
if (id) this.DeleteOverlayWindowsIndex(id);
}
else if (button.ID==JSCHART_BUTTON_ID.MODIFY_OVERLAY_INDEX_PARAM)
{
var id=button.IndexID;
var frame=button.Frame;
e.data={ Chart:this, Identify:id, IsOverlay:true };
if (frame.ModifyIndexEvent)
frame.ModifyIndexEvent(e);
}
else if (button.ID==JSCHART_BUTTON_ID.CLOSE_INDEX_WINDOW)
{
var frame=button.Frame;
this.RemoveIndexWindow(frame.Identify);
}
else if (button.ID==JSCHART_BUTTON_ID.CHANGE_INDEX)
{
var frame=button.Frame;
var sendData={ e:e, WindowIndex:frame.Identify, OpType:1 };
this.ShowChangeIndexDialog(sendData);
/*
e.data={ Chart:this, Identify:frame.Identify, IsOverlay:false };
if (frame.ChangeIndexEvent)
frame.ChangeIndexEvent(e);
*/
}
else if (button.ID==JSCHART_BUTTON_ID.MODIFY_INDEX_PARAM)
{
var frame=button.Frame;
e.data={ Chart:this, Identify:frame.Identify, IsOverlay:false };
if (frame.ModifyIndexEvent)
frame.ModifyIndexEvent(e);
}
else if (button.ID==JSCHART_BUTTON_ID.OVERLAY_INDEX)
{
var frame=button.Frame;
var sendData={ e:e, WindowIndex:frame.Identify, OpType:2 };
this.ShowAddOverlayIndexDialog(sendData);
/*
e.data={ Chart:this, Identify:frame.Identify, IsOverlay:true };
if (frame.ChangeIndexEvent)
frame.ChangeIndexEvent(e);
*/
}
else if (button.ID==JSCHART_BUTTON_ID.MAX_MIN_WINDOW)
{
var id=button.IndexID;
var frame=button.Frame;
var frameId=button.FrameID;
if (frameId>=this.Frame.ZoomStartWindowIndex)
{
if (this.ZoomIndexWindow(frameId, null))
{
this.Frame.SetSizeChage(true);
this.Draw();
}
}
}
else if (button.ID==JSCHART_BUTTON_ID.TITLE_WINDOW) //标题模式
{
var id=button.IndexID;
var frame=button.Frame;
var frameId=button.FrameID;
if (this.ShowIndexTitleOnly(frameId))
{
this.Frame.SetSizeChage(true);
this.Draw();
}
}
else if (button.ID==JSCHART_BUTTON_ID.EXPORT_DATA) //数据导出
{
var data=this.ExportData({Type:"CSV"});
if (!data) return;
var date=Date.now();
var fileName = `hqchart_${this.Symbol}_${date}.csv`;
var alink = document.createElement("a");
var csvDataBlob = new Blob([data], { type: "text/csv" });
alink.href = URL.createObjectURL(csvDataBlob);
document.body.appendChild(alink);
alink.setAttribute("download", fileName);
alink.click();
document.body.removeChild(alink);
}
}
this.ClickTitleButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_TITLE_BUTTON);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false, e:e }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
}
this.ClickExtendChartButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_EXTENDCHART_BUTTON);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false, e:e }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
//筹码按钮
if (button.ID==JSCHART_BUTTON_ID.CHIP_DEFULT)
{
button.Chart.ShowType=0;
this.Draw();
}
else if (button.ID==JSCHART_BUTTON_ID.CHIP_LONG)
{
button.Chart.ShowType=1;
this.Draw();
}
else if (button.ID==JSCHART_BUTTON_ID.CHIP_RECENT)
{
button.Chart.ShowType=2;
this.Draw();
}
}
//成交量分布图数据请求
this.RequestVolumeProfileData=function(option)
{
var self=this;
var chart=option.Chart;
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestVolumeProfileData', //类名::函数
Explain:'成交量分布图下载',
Request:{ Period:this.Period, Right:this.Right, Start:option.Start, End:option.End, Symbol:this.Symbol, ValueAreaVol:option.ValueAreaVol },
Self:this,
VolProfile:chart,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvVolumeProfileData(data, chart);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
}
this.RecvVolumeProfileData=function(data, chart)
{
chart.OnRecvVolumeProfileData(data);
this.Draw();
}
this.ExportMainData=function(data, option)
{
var aryData=data.ExportKLineData(option); //导出K线
return aryData;
}
this.UpdateScrollBar=function()
{
if (!this.ScrollBar) return;
var data=this.GetChartStatus();
if (!data) return;
var kData=this.ChartPaint[0].Data;
var start=data.KLine.Offset;
var end=start+data.KLine.PageSize-1;
//if (end>=kData.Data.length) end=kData.Data.length-1;
var obj={ Start:start, End:end, Data:kData, Draw:true, RightSpaceCount:this.RightSpaceCount };
if (this.Frame && this.Frame.ChartBorder)
{
var border=this.Frame.ChartBorder;
obj.Border={ Left:border.Left, Right:border.Right };
}
this.ScrollBar.UpdateSlider(obj);
}
this.ResetScrollBar=function()
{
if (!this.ScrollBar) return;
this.ScrollBar.Reset({Draw:true});
}
this.ChangePriceGap=function(obj)
{
if (!obj) return;
var klineChart=this.ChartPaint[0];
if (!klineChart) return;
if (IFrameSplitOperator.IsNumber(obj.Count)) klineChart.PriceGap.Count=obj.Count;
if (IFrameSplitOperator.IsBool(obj.Enable)) klineChart.PriceGap.Enable=obj.Enable;
this.Draw();
}
this.DrawTooltipDialog=function()
{
if (!this.DialogTooltip) return;
this.UpdateTooltipDialog();
}
this.UpdateTooltipDialog=function()
{
if (!this.DialogTooltip) return false;
if (!this.ChartCorssCursor) return false;
var dataType=0;
var kItem=null;
if (this.ChartCorssCursor.ClientPos>=0)
{
var hisData=this.ChartOperator_Temp_GetHistroyData();;
if (!hisData) return false; //数据还没有到达
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return false;
var dataIndex=hisData.DataOffset+this.ChartCorssCursor.CursorIndex;
if (dataIndex>=hisData.Data.length) dataIndex=hisData.Data.length-1;
var kItem=hisData.Data[dataIndex];
}
else //取最后一个数据
{
var hisData=this.ChartOperator_Temp_GetHistroyData();;
if (!hisData) return false; //数据还没有到达
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return false;
var kItem=hisData.Data[hisData.Data.length-1];
var dataID={ Symbol:this.Symbol, Date:kItem.Date };
if (IFrameSplitOperator.IsNumber(kItem.Time)) dataID.Time=kItem.Time;
if (!this.DialogTooltip.IsEqualDataID(dataID)) return false;
dataType=1;
}
var sendData=
{
DataType:dataType, //0=全部更新 1=更新实时K线
ClientPos:this.ChartCorssCursor.ClientPos, //位置
IsShowCorss:this.ChartCorssCursor.IsShowCorss, //是否显示十字线
KItem:kItem,
Symbol:this.Symbol, Name:this.Name,
LastValue:this.ChartCorssCursor.LastValue,
};
this.DialogTooltip.Update(sendData);
return true;
}
this.DrawSelectRectDialog=function(e)
{
if (!this.DialogSelectRect) return;
this.UpdateSelectRectDialog(e);
}
this.UpdateSelectRectDialog=function(e)
{
if (!this.DialogSelectRect) return false;
var data=e.data; //区间统计数据
var x,y;
if (data && IFrameSplitOperator.IsNumber(data.X) && IFrameSplitOperator.IsNumber(data.Y))
{
var pixelRatio=GetDevicePixelRatio();
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
x=data.X
y=data.Y;
x+=(rtClient.left+rtScroll.Left);
y+=(rtClient.top+rtScroll.Top);
}
var sendData=
{
Symbol:this.Symbol, Name:this.Name,
SelectData:data.SelectData,
X:x, Y:y,
e:e
}
this.DialogSelectRect.Update(sendData);
}
this.UpdateHQFloatTooltip=function(kData)
{
if (!this.FloatTooltip) return;
if (!this.FloatTooltip.IsShow()) return;
if (!kData || !IFrameSplitOperator.IsNonEmptyArray(kData.Data)) return;
var lastItem=kData.Data[kData.Data.length-1];
if (!lastItem) return;
var dataID={ Symbol:kData.Symbol, Date:lastItem.Date, Time:lastItem.Time };
if (!this.FloatTooltip.IsEqualHQID(dataID)) return;
var sendData=
{
Data:lastItem,
Symbol:this.Symbol,
Name:this.Name,
DataType:2,
};
this.FloatTooltip.Update(sendData);
}
}
//API 返回数据 转化为array[]
KLineChartContainer.JsonDataToHistoryData=function(data)
{
var aryDayData=[];
if (!data.data) return aryDayData;
var upperSymbol=null;
if (data.symbol) upperSymbol=data.symbol.toUpperCase();
var isFutures=false; //是否是期货
if (upperSymbol) isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
var list = data.data;
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, position=8;
var fclose=9, yfclose=10; //结算价, 前结算价
var bfactor=11, afactor=12; //前, 后复权因子
var bVirtual=13; //虚拟数据
var bNonTrade=14; //非交易日
var flowCapital=15; //流通股本
var orderFlow=JSCHART_DATA_FIELD_ID.KLINE_ORDERFLOW;
var colorData=JSCHART_DATA_FIELD_ID.KLINE_COLOR_DATA;
var heatMapIndex=JSCHART_DATA_FIELD_ID.KLINE_HEATMAP;
var extendDataIndex=JSCHART_DATA_FIELD_ID.KLINE_DAY_EXTENDDATA; //k线扩展数据
for (var i = 0; i < list.length; ++i)
{
var item = new HistoryData();
var jsData=list[i];
item.Date = jsData[date];
item.Open = jsData[open];
item.YClose = jsData[yclose];
item.Close = jsData[close];
item.High = jsData[high];
item.Low = jsData[low];
item.Vol = jsData[vol]; //原始单位股
item.Amount = jsData[amount];
if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position];//期货持仓
if (IFrameSplitOperator.IsNumber(jsData[fclose])) item.FClose=jsData[fclose]; //期货结算价
if (IFrameSplitOperator.IsNumber(jsData[yfclose])) item.YFClose=jsData[yfclose]; //期货前结算价
if (IFrameSplitOperator.IsNumber(jsData[flowCapital])) item.FlowCapital=jsData[flowCapital]; //流通股本
if (IFrameSplitOperator.IsNumber(jsData[bfactor])) item.BFactor=jsData[bfactor]; //前复权因子
if (IFrameSplitOperator.IsNumber(jsData[afactor])) item.AFactor=jsData[afactor]; //后复权因子
if (IFrameSplitOperator.IsBool(jsData[bVirtual])) item.IsVirtual=jsData[bVirtual]; //虚拟数据
if (IFrameSplitOperator.IsBool(jsData[bNonTrade])) item.IsNonTrade=jsData[bNonTrade]; //虚拟数据
if (!IFrameSplitOperator.IsNumber(item.Open) && !(item.IsVirtual===true)) continue;
if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];
if (jsData[colorData]) item.ColorData=jsData[colorData];
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
if (jsData[heatMapIndex]) item.HeatMap=jsData[heatMapIndex];
aryDayData.push(item);
}
return aryDayData;
}
KLineChartContainer.JsonDataToRealtimeData=function(data, symbol)
{
if (!data.stock) return null;
var stock;
for(var i in data.stock) //查找对应的股票数据
{
var stockItem=data.stock[i];
if (stockItem && stockItem.symbol==symbol)
{
stock=stockItem;
break;
}
}
if (!stock) return null;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var item=new HistoryData();
item.Date=stock.date;
item.Open=stock.open;
item.YClose=stock.yclose;
item.High=stock.high;
item.Low=stock.low;
item.Vol=stock.vol; //股
item.Amount=stock.amount;
item.Close=stock.price;
if (IFrameSplitOperator.IsNumber(stock.position)) item.Position=stock.position; //持仓量
if (IFrameSplitOperator.IsNumber(stock.yclearing)) item.YFClose=stock.yclearing; //前结算价
if (IFrameSplitOperator.IsNumber(stock.clearing)) item.FClose=stock.clearing; //结算价
if (IFrameSplitOperator.IsNumber(stock.bfactor)) item.BFactor=stock.bfactor; //前复权因子
if (IFrameSplitOperator.IsNumber(stock.afactor)) item.AFactor=stock.afactor; //后复权因子
if (stock.colordata) item.ColorData=stock.colordata; //自定义颜色
if (stock.extendData) item.ExtendData=stock.extendData;
if (stock.heatmapData) item.HeatMap=stock.heatmapData;
if (IFrameSplitOperator.IsBool(stock.isvirtual)) item.IsVirtual=stock.isvirtual; //虚拟数据
if (IFrameSplitOperator.IsBool(stock.isnontrade)) item.IsNonTrade=stock.isnontrade; //虚拟数据
return item;
}
KLineChartContainer.JsonDataToMinuteRealtimeData=function(data,symbol)
{
if (!data.stock) return null;
var stock;
for(var i in data.stock) //查找对应的股票数据
{
var stockItem=data.stock[i];
if (stockItem && stockItem.symbol==symbol)
{
stock=stockItem;
break;
}
}
if (!stock) return null;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
var aryMinuteData=new Array();
var preClose=stock.yclose; //前一个数据价格
var date=stock.date;
if (isFutures && stock.yclearing)preClose=stock.yclearing; //期货使用昨结算价
for(var i in stock.minute)
{
var jsData=stock.minute[i];
var item = new HistoryData();
item.Close=jsData.price;
item.Open=jsData.open;
item.High=jsData.high;
item.Low=jsData.low;
item.Vol=jsData.vol; //股
item.Amount=jsData.amount;
if (jsData.date>0) item.Date=jsData.date;
else item.Date=date;
item.Time=jsData.time;
item.YClose=preClose;
if (IFrameSplitOperator.IsNumber(jsData.position)) item.Position=jsData.position; //持仓量
if (!IFrameSplitOperator.IsNumber(item.Close)) //当前没有价格 使用上一个价格填充
{
item.Close=preClose;
item.Open=item.High=item.Low=item.Close;
}
//价格是0的 都用空
if (!IFrameSplitOperator.IsNumber(item.Open)) item.Open=null;
if (!IFrameSplitOperator.IsNumber(item.Close)) item.Close=null;
if (!IFrameSplitOperator.IsNumber(item.High)) item.High=null;
if (!IFrameSplitOperator.IsNumber(item.Low)) item.Low=null;
//上次价格
if (IFrameSplitOperator.IsNumber(jsData.price)) preClose=jsData.price;
aryMinuteData[i]=item;
}
return aryMinuteData;
}
//分钟K线叠加数据增量更新v2版本
KLineChartContainer.JsonDataToMinuteRealtimeDataV2=function(data,symbol)
{
if (!data || !data.overlay || !symbol) return null;
var overlayData=null;
for(var i=0;i<data.overlay.length;++i) //overlay={ symbol:, name:, data:[] }
{
var item=data.overlay[i];
if (item.symbol==symbol)
{
overlayData=item;
break;
}
}
if (!overlayData) return null;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //是否是期货
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8, position=9;
var orderFlow=JSCHART_DATA_FIELD_ID.KLINE_ORDERFLOW;
var yClose=null;
var aryMinuteData=[];
for (var i = 0; i < overlayData.data.length; ++i)
{
var item = new HistoryData();
var jsData=overlayData.data[i];
item.Date = jsData[date];
item.Open = jsData[open];
item.YClose = jsData[yclose];
item.Close = jsData[close];
item.High = jsData[high];
item.Low = jsData[low];
item.Vol = jsData[vol]; //股
item.Amount = jsData[amount];
item.Time=jsData[time];
if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position]; //期货持仓
if (!IFrameSplitOperator.IsNumber(item.YClose))
{
if (IFrameSplitOperator.IsNumber(yClose)) item.YClose=yClose;
}
if (IFrameSplitOperator.IsNumber(item.Close)) yClose=item.Close;
if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];
aryMinuteData.push(item);
}
return aryMinuteData;
}
//API 返回数据 转化为array[]
KLineChartContainer.JsonDataToMinuteHistoryData=function(data)
{
var upperSymbol=null;
if (data.symbol) upperSymbol=data.symbol.toUpperCase();
var isSHSZ=false;
if (upperSymbol) isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=false; //是否是期货
if (upperSymbol) isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
var list = data.data;
var aryDayData=new Array();
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8, position=9;
var fclose=10, yfclose=11; //结算价, 前结算价
var bfactor=12, afactor=13; //前, 后复权因子
var orderFlow=JSCHART_DATA_FIELD_ID.KLINE_ORDERFLOW;
var colorData=JSCHART_DATA_FIELD_ID.KLINE_COLOR_DATA;
var heatMapIndex=JSCHART_DATA_FIELD_ID.KLINE_HEATMAP;
var extendDataIndex=JSCHART_DATA_FIELD_ID.KLINE_MINUTE_EXTENDDATA; //k线扩展数据
var yClose=null;
for (var i = 0; i < list.length; ++i)
{
var item = new HistoryData();
var jsData=list[i];
item.Date = jsData[date];
item.Open = jsData[open];
item.YClose = jsData[yclose];
item.Close = jsData[close];
item.High = jsData[high];
item.Low = jsData[low];
item.Vol = jsData[vol]; //股
item.Amount = jsData[amount];
item.Time=jsData[time];
if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position]; //期货持仓
if (IFrameSplitOperator.IsNumber(jsData[fclose])) item.FClose=jsData[fclose]; //期货结算价
if (IFrameSplitOperator.IsNumber(jsData[yfclose])) item.YFClose=jsData[yfclose]; //期货前结算价
if (IFrameSplitOperator.IsNumber(jsData[bfactor])) item.BFactor=jsData[bfactor]; //前复权因子
if (IFrameSplitOperator.IsNumber(jsData[afactor])) item.AFactor=jsData[afactor]; //后复权因子
if (!IFrameSplitOperator.IsNumber(item.YClose))
{
if (IFrameSplitOperator.IsNumber(yClose)) item.YClose=yClose;
}
if (IFrameSplitOperator.IsNumber(item.Close)) yClose=item.Close;
if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];
if (jsData[colorData]) item.ColorData=jsData[colorData];
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
if (jsData[heatMapIndex]) item.HeatMap=jsData[heatMapIndex];
aryDayData.push(item);
}
/* 内部不处理无效数据, 确保外部传过来的数据是对的.
// 无效数据处理
for(var i = 0; i < aryDayData.length; ++i)
{
var minData = aryDayData[i];
if (minData == null) coninue;
if (isNaN(minData.Open) || minData.Open <= 0 || isNaN(minData.High) || minData.High <= 0 || isNaN(minData.Low) || minData.Low <= 0
|| isNaN(minData.Close) || minData.Close <= 0 )
{
if (i == 0)
{
if (minData.YClose > 0)
{
minData.Open = minData.YClose;
minData.High = minData.YClose;
minData.Low = minData.YClose;
minData.Close = minData.YClose;
}
}
else // 用前一个有效数据填充
{
for(var j = i-1; j >= 0; --j)
{
var minData2 = aryDayData[j];
if (minData2 == null) coninue;
if (minData2.Open > 0 && minData2.High > 0 && minData2.Low > 0 && minData2.Close > 0)
{
if (minData.YClose <= 0) minData.YClose = minData2.Close;
minData.Open = minData2.Open;
minData.High = minData2.High;
minData.Low = minData2.Low;
minData.Close = minData2.Close;
break;
}
}
}
}
}
*/
return aryDayData;
}
KLineChartContainer.JsonDataToTickData=function(data)
{
var aryDayData=[];
if (!data.detail) return aryDayData;
var date=data.date;
var yClose=data.yclose;
for(var i in data.detail)
{
var item = new HistoryData();
var tick=data.detail[i];
if (!tick) continue;
item.Date = date;
item.Time=tick[0];
item.Low=item.High=item.Close=item.Open = tick[1];
item.YClose = yClose; //当前数据的前收盘
item.Vol = tick[2]; //原始单位股
item.Amount = tick[3];
item.Flag=tick[4];
if (!IFrameSplitOperator.IsNumber(item.Open)) continue; //停牌的数据剔除
//yClose=item.Close;
aryDayData.push(item);
}
return aryDayData;
}
KLineChartContainer.JsonDataToTickDataV2=function(data)
{
var aryDayData=[];
if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return aryDayData;
for(var i=0;i<data.data.length;++i)
{
var item = new HistoryData();
var tick=data.data[i]; //[ date, time, yClose, price, extendData]
if (!tick) continue;
item.Date = tick[0];
item.Time=tick[1];
item.YClose = tick[2];
item.Low=item.High=item.Close=item.Open = tick[3];
aryDayData.push(item);
if (tick[4]) item.ExtendData=tick[4];
}
return aryDayData;
}
///////////////////////////////////////////////////////////////////////////////////////////
// 走势图
//
function MinuteChartContainer(uielement,offscreenElement,cacheElement)
{
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement,offscreenElement,cacheElement);
delete this.newMethod;
this.ClassName='MinuteChartContainer';
this.WindowIndex=new Array();
this.Symbol;
this.Name;
this.SourceData; //原始的历史数据
this.IndexBindData; //计算指标需要绑定的分钟数据
this.IsAutoUpdate=true; //是否自动更新行情数据
this.AutoUpdateFrequency=30000; //30秒更新一次数据
this.AutoUpdateTimer; //自动更新定时器
this.TradeDate=0; //行情交易日期
this.DayCount=1; //显示几天的数据
this.DayData; //多日分钟数据
this.LimitPrice; //涨停价格 { Max:null, Min:null };
this.IsShowBeforeData=false; //是否显示盘前集合竞价数据 (当日)
this.BeforeOpenData=null; //盘前集合竞价数据
this.IsBeforeData=false; //是否支持显示盘前集合竞价数据(当日)
this.IsShowAfterData=false; //收盘集合竞价
this.AfterCloseData=null; //收盘集合竞价数据
this.IsAfterData=false; //是否支持显示收盘集合竞价数据(当日)
this.ShareAfterVol=0; //1=盘后数据成交量Y坐标和主图共享 2=盘后数据成交量Y坐标和盘前共享
this.ExtendWidth={ Left: 120, Right:120 } ; //单日分时图 左右扩展图形宽度
this.IsShowLead=true; //指数是否显示领先指标
this.IsShowMultiDayBeforeData=false; //多日分时图 是否显示盘前集合竞价
this.MultiDayBeforeOpenData=null; //多日分时图 盘前集合竞价数据
this.IsShowMultiDayAfterData=false; //多日分时图 是否显示收盘集合竞价
this.MultiDayAfterCloseData=null; //多日分时图 收盘集合竞价数据
this.MultiDayExtendWidth={ Left:40, Right:20 }; //多日分时图 左右扩展图形宽度
this.ChartDrawStorage=new ChartDrawStorage();
this.ChartDrawStorageCache=null; //首次需要创建的画图工具数据
this.MinuteApiUrl=g_JSChartResource.Domain+"/API/Stock";
this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData'; //历史分钟数据
this.ColorLineData; //主图价格线颜色自定义配置
this.EnableSelectRect=false; //是否可以区间选择
this.CorssCursorIndex={ DayIndex:-1, DataIndex:-1, Point:{X:-1, Y:-1} ,Type:-1 };
this.EnableNewIndex=false //是否使用新的索引版本
this.DayOffset={ Offset:0, ShowDayCount:-1, DataOffset:0, DayCount:1, }; //Offset 日期偏移 , DataOffset数据偏移
this.PageInfo={ Enable:false, Offset:-8888, ShowDayCount:4 }; //分页配置
this.DataStatus={ MultiDay:false, LatestDay:false, LatestDate:null}; //MultiDay=多日 LatestDay:当天 LatestDate:最后的日期
this.ZoomStepPixel=50;
this.BaselineType=0; //基准线类型 0=最新昨收盘 1=多日前昨收盘
this.EnableNightDayBG=false; //是否启动夜盘背景色
//集合竞价设置 obj={ Left:true/false, Right:true/false, MultiDay:{Left:, Right:} }
this.SetCallCationDataBorder=function(obj)
{
if (!obj) return;
var extendWidth=
{
Left: obj.Left?this.ExtendWidth.Left:0,
Right: obj.Right?this.ExtendWidth.Right:0
};
this.Frame.SetExtendWidth(extendWidth);
if (obj.MultiDay)
{
var item=obj.MultiDay;
var DayMinuteWidth=
{
Left:item.Left? this.MultiDayExtendWidth.Left:0,
Right:item.Right? this.MultiDayExtendWidth.Right:0
};
this.Frame.SetMultiDayMinuteWidth(DayMinuteWidth);
}
}
this.ReloadChartPaint=function(resource)
{
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (!item) continue;
if (item.ReloadResource) item.ReloadResource(resource);
if (i==0)
{
if (item.Name=="Minute-Line")
{
item.Color=g_JSChartResource.Minute.PriceColor;
item.AreaColor=g_JSChartResource.Minute.AreaPriceColor;
}
}
else if (i==1)
{
if (item.Name=="Minute-Average-Line")
{
item.Color=g_JSChartResource.Minute.AvPriceColor;
}
}
else if (i==2)
{
if (item.Name=="Minute-Vol-Bar")
{
item.Color=g_JSChartResource.Minute.VolBarColor;
}
}
}
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
this.IsAutoUpdate=false;
}
this.ClickFrameButton=function(button, e)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_FRAME_TOOLBAR);
if (event && event.Callback)
{
var data={ Info:button, PreventDefault:false }; //PreventDefault 是否阻止内置的点击处理
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
if (button.ID==JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID)
{
this.ShowCallAuctionData({ Left:false, Right:false, MultiDay:{ Left:false, Right:false } });
}
else if (button.ID==JSCHART_BUTTON_ID.CLOSE_OVERLAY_INDEX)
{
var id=button.IndexID;
if (id) this.DeleteOverlayWindowsIndex(id);
}
else if (button.ID==JSCHART_BUTTON_ID.MODIFY_OVERLAY_INDEX_PARAM)
{
var id=button.IndexID;
var frame=button.Frame;
e.data={ Chart:this, Identify:id, IsOverlay:true };
if (frame.ModifyIndexEvent)
frame.ModifyIndexEvent(e);
}
else if (button.ID==JSCHART_BUTTON_ID.CLOSE_INDEX_WINDOW)
{
var frame=button.Frame;
this.RemoveIndexWindow(frame.Identify);
}
else if (button.ID==JSCHART_BUTTON_ID.CHANGE_INDEX)
{
var frame=button.Frame;
var sendData={ e:e, WindowIndex:frame.Identify, OpType:1 };
this.ShowChangeIndexDialog(sendData);
}
else if (button.ID==JSCHART_BUTTON_ID.MODIFY_INDEX_PARAM)
{
var frame=button.Frame;
e.data={ Chart:this, Identify:frame.Identify, IsOverlay:false };
if (frame.ModifyIndexEvent)
frame.ModifyIndexEvent(e);
}
else if (button.ID==JSCHART_BUTTON_ID.OVERLAY_INDEX)
{
var frame=button.Frame;
var sendData={ e:e, WindowIndex:frame.Identify, OpType:2 };
this.ShowAddOverlayIndexDialog(sendData);
}
else if (button.ID==JSCHART_BUTTON_ID.MAX_MIN_WINDOW)
{
var id=button.IndexID;
var frame=button.Frame;
var frameId=button.FrameID;
if (frameId>=this.Frame.ZoomStartWindowIndex)
{
if (this.ZoomIndexWindow(frameId, null))
{
this.Frame.SetSizeChage(true);
this.Draw();
}
}
}
else if (button.ID==JSCHART_BUTTON_ID.TITLE_WINDOW) //标题模式
{
var id=button.IndexID;
var frame=button.Frame;
var frameId=button.FrameID;
if (this.ShowIndexTitleOnly(frameId))
{
this.Frame.SetSizeChage(true);
this.Draw();
}
}
else if (button.ID==JSCHART_BUTTON_ID.EXPORT_DATA) //数据导出
{
var data=this.ExportData({Type:"CSV"});
if (!data) return;
var date=Date.now();
var fileName = `hqchart_${this.Symbol}_${date}.csv`;
var alink = document.createElement("a");
var csvDataBlob = new Blob([data], { type: "text/csv" });
alink.href = URL.createObjectURL(csvDataBlob);
document.body.appendChild(alink);
alink.setAttribute("download", fileName);
alink.click();
document.body.removeChild(alink);
}
}
//图形控制 { ID:, ....参数 }
this.ChartOperator=function(obj)
{
var id=obj.ID;
if (id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT || id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT ) //左右移动 { Step:移动天数 }
{
if (this.DayCount==1) return false;
if (!this.PageInfo.Enable) return false;
if (!this.DayData) return false; //数据还没有下载好
var isLeft=(id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT ? true:false);
var step=1;
if (obj.Step>0) step=obj.Step;
if (!this.DayOffset) return false;
if (isLeft)
{
var offset=this.DayOffset.Offset;
offset+=step;
if (offset+this.DayOffset.ShowDayCount>this.DayOffset.DayCount) offset=this.DayOffset.DayCount-this.DayOffset.ShowDayCount;
if (offset==this.DayOffset.Offset) return false;
this.DayOffset.Offset=offset;
}
else
{
var offset=this.DayOffset.Offset;
offset-=step;
if (offset<0) offset=0;
if (offset==this.DayOffset.Offset) return false;
this.DayOffset.Offset=offset;
}
this.UpdateHistoryMinuteUI(null);
this.SendPageChangedEvent();
return true;
}
else if (id==JSCHART_OPERATOR_ID.OP_SCROLL_GOTO)
{
if (this.DayCount==1) return false;
if (!this.PageInfo.Enable) return false;
if (!this.DayData) return false; //数据还没有下载好
if (IFrameSplitOperator.IsNumber(obj.ShowDayCount))
{
this.PageInfo.ShowDayCount=obj.ShowDayCount;
this.DayOffset.ShowDayCount=obj.ShowDayCount;
}
if (IFrameSplitOperator.IsNumber(obj.Offset))
{
var offset=obj.Offset;
if (this.DayOffset.ShowDayCount>0 && offset+this.DayOffset.ShowDayCount>=this.DayOffset.DayCount) offset=this.DayOffset.DayCount-this.DayOffset.ShowDayCount;
if (offset==this.DayOffset.Offset) return false;
this.DayOffset.Offset=offset;
}
this.UpdateHistoryMinuteUI(null);
this.SendPageChangedEvent();
return true;
}
else if (id==JSCHART_OPERATOR_ID.OP_CORSSCURSOR_GOTO) //{ Type:1 如果不存在 就隐藏十字光标}
{
if (!this.SourceData) return false;
if (!this.Frame || !this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return false;
var frame=this.Frame.SubFrame[0].Frame;
if (!IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data)) return false;
if (IFrameSplitOperator.IsNumber(obj.Time) && IFrameSplitOperator.IsNumber(obj.Date))
{
var findIndex=-1, value=null, lastPrice=null;
for(var i=0;i<this.SourceData.Data.length;++i)
{
var item=this.SourceData.Data[i];
if (IFrameSplitOperator.IsNumber(item.Close)) lastPrice=item.Close;
if (item.Time==obj.Time && item.Date==obj.Date)
{
findIndex=i;
value=item.Close;
break;
}
}
if (findIndex<0 && this.DayCount==1 && !(IFrameSplitOperator.IsNumber(obj.Type) && obj.Type>0))
{
var timeData = g_MinuteTimeStringData.GetTimeData(this.Symbol);
for(var i=0;i<timeData.length;++i)
{
if (timeData[i]==obj.Time)
{
findIndex=i;
value=lastPrice;
break;
}
}
}
if (findIndex<0)
{
if (obj.Type==1) // 如果不存在 就隐藏十字光标
{
var x=-1,y=-1;
var MoveStatus={ X:x, Y:y, IsInClient: this.IsMouseOnClient(x,y) };
this.LastMouseStatus.OnMouseMove=MoveStatus;
this.LastMouseStatus.MoveOnPoint={X:x, Y:y}; //鼠标移动的位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MOUSE_MOVE);
var titleChart=this.TitlePaint[0];
if (event && titleChart) titleChart.OnMouseMoveEvent=event;
var e={clientX:x, clientY:y};
this.MoveOnPoint={X:x, Y:y};
this.OnMouseMove(x,y,e);
this.LastMouseStatus.MoveOnPoint=null;
if (titleChart) titleChart.OnMouseMoveEvent=null;
}
return;
}
}
var x=frame.GetXFromIndex(findIndex);
var y=frame.GetYFromData(value);
//保存最后一次鼠标移动信息
var MoveStatus={ X:x, Y:y, IsInClient: this.IsMouseOnClient(x,y) };
this.LastMouseStatus.OnMouseMove=MoveStatus;
this.LastMouseStatus.MoveOnPoint={X:x, Y:y}; //鼠标移动的位置
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MOUSE_MOVE);
var titleChart=this.TitlePaint[0];
if (event && titleChart) titleChart.OnMouseMoveEvent=event;
this.MoveOnPoint={X:x, Y:y};
this.OnMouseMove(x,y,{});
this.LastMouseStatus.MoveOnPoint=null;
if (titleChart) titleChart.OnMouseMoveEvent=null;
}
}
this.SendPageChangedEvent=function()
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MINUTE_PAGE_CHANGED); //选中画图工具事件
if (!event || !event.Callback) return;
var sendData={ DayOffset:this.DayOffset, DayData:this.DayData };
event.Callback(event,sendData,this);
}
this.IsMouseOnClient=function(x,y)
{
var border=this.Frame.IsHScreen?this.Frame.ChartBorder.GetHScreenBorder():this.Frame.ChartBorder.GetBorder();
var rect={ Left:border.Left, Top:border.Top, Right:border.Right, Bottom:border.Bottom };
if (x>=rect.Left && x<=rect.Right && y>=rect.Top && y<=rect.Bottom) return true;
return false;
}
//左右拖拽
this.OnDragMode_One=function(moveData, e)
{
var drag=this.MouseDrag;
var moveSetp=moveData.X;
var yMoveSetp=moveData.Y;
if (this.RectSelectDrag && this.RectSelectDrag.Index>=0) //区间选择
{
if (moveSetp<5) return;
var obj={ X:e.clientX, Y:e.clientY, PointIndex:this.RectSelectDrag.Index, Name:"MoveRectSelectLine" };
if (this.MoveRectSelectPoint(obj))
{
drag.LastMove.X=e.clientX;
this.Draw();
}
}
else
{
if (moveSetp<5 && yMoveSetp<5) return;
if (!this.EnableSelectRect) return;
//this.UIElement.style.cursor="default";
this.SetCursor({Cursor:"default"});
var ptStart=this.PointAbsoluteToRelative(drag.Click.X, drag.Click.Y);
var ptEnd=this.PointAbsoluteToRelative(e.clientX, e.clientY);
this.ShowDragSelectRect(ptStart, ptEnd);
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
}
this.OnMinuteSelectRectMouseUp=function(e)
{
var drag=this.MouseDrag;
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
var selectData=new SelectRectData();
var pixelTatio = GetDevicePixelRatio();
//区间起始位置 结束位子
selectData.XStart=(drag.Click.X-uielement.getBoundingClientRect().left)*pixelTatio;
selectData.YStart=(drag.Click.Y-uielement.getBoundingClientRect().top)*pixelTatio;
selectData.XEnd=(drag.LastMove.X-uielement.getBoundingClientRect().left)*pixelTatio;
selectData.YEnd=(drag.LastMove.Y-uielement.getBoundingClientRect().top)*pixelTatio;
selectData.JSChartContainer=this;
selectData.Stock={Symbol:this.Symbol, Name:this.Name};
if (this.EnableSelectRect && !this.BorderDrag && this.GetSelectRectData(selectData))
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SELECT_RECT);
var paint=this.GetRectSelectPaint();
var isShowDialog=true; //是否显示内置区间选择框
if (event && event.Callback)
{
var data=
{
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
e:e
};
event.Callback(event,data,this);
isShowDialog=false; //外部调用了区间选择事件,不弹框
}
if (isShowDialog && this.DialogSelectRect)
{
e.data=
{
Chart:this,
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
this.HideSelectRect();
this.UpdateSelectRect(selectData.Start,selectData.End);
this.DrawSelectRectDialog(e);
}
else
{
this.HideSelectRect();
this.UpdateSelectRect(selectData.Start,selectData.End);
}
}
else
{
this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
this.ClickEvent(e);
}
}
this.OnDragSelectRectMouseUp=function(e)
{
var paint=this.GetRectSelectPaint();
if (!paint) return;
var selectData=paint.GetSelectRectData();
if (!selectData) return;
var pixelTatio = GetDevicePixelRatio();
var corssCursor=this.ChartCorssCursor; //十字光标
var x=corssCursor.LastPoint.X/pixelTatio;
var y=corssCursor.LastPoint.Y/pixelTatio;
var isShowDialog=true; //是否显示内置区间选择框
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT_MOUSEUP);
if (event)
{
var data=
{
X:x,
Y:y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
IsShowDialog:false
};
event.Callback(event,data,this);
isShowDialog=data.IsShowDialog;
}
if (isShowDialog)
{
var data =
{
Chart:this,
X:x,
Y:y,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
e.data=data;
this.UpdateSelectRectDialog(e);
}
}
this.UpdateSelectRect=function(start,end)
{
if (!this.SourceData || !this.SourceData.Data) return;
var paint=this.GetRectSelectPaint();
if (!paint) return;
var data=this.SourceData;
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
var count=data.Data.length;
var startItem=data.Data[start];
if (end>=count) end=count-1;
var endItem=data.Data[end];
if (!startItem || !endItem) return;
JSConsole.Chart.Log('[MinuteChartContainer::UpdateSelectRect]',startItem,endItem);
paint.SetPoint(startItem, { Index:0 });
paint.SetPoint(endItem, { Index:1 });
this.Draw();
}
this.MoveRectSelectPoint=function(obj)
{
var paint=this.GetRectSelectPaint();
if (!paint) return false;
if (!this.SourceData || !this.SourceData.Data) return false;
var kData=this.SourceData;
if (!this.Frame.SubFrame[0]) return false;
var subFrame=this.Frame.SubFrame[0].Frame;
if (!subFrame) false;
var pixelTatio = GetDevicePixelRatio();
var x=(obj.X-uielement.getBoundingClientRect().left)*pixelTatio;
var index=subFrame.GetXData(x);
index=parseInt(index.toFixed(0));
var dataIndex=index+kData.DataOffset;
if (dataIndex>=kData.Data.length) dataIndex=kData.Data.length-1;
var item = kData.Data[dataIndex];
JSConsole.Chart.Log("[MinuteChartContainer::MoveRectSelectPoint] point, item", obj.PointIndex, item);
if (!paint.SetPoint(item,{ Index: obj.PointIndex })) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT);
if (event)
{
var selectData=paint.GetSelectRectData();
var data={ X:obj.X, Y:obj.Y, SelectData:selectData, RectSelectPaint:paint };
event.Callback(event,data,this);
}
if (this.IsShowSelectRectDialog()) //区间统计
{
var selectData=paint.GetSelectRectData();
var data={ X:obj.X, Y:obj.Y, SelectData:selectData, RectSelectPaint:paint };
var e={ data:data };
this.DrawSelectRectDialog(e);
}
return true;
}
this.GetLastCursorIndex=function(obj)
{
if (obj.DataType==1)
{
for(var i=obj.Data.length-1;i>=0;--i)
{
var item=obj.Data[i];
if (!item || !item.DayItem || !item.DayItem.Data) continue;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=item.DayItem.Data.length-1;
obj.IndexData.Type=item.Type;
return;
}
}
else if (obj.DataType==2)
{
for(var i=obj.Data.length-1;i>=0;--i)
{
var dayItem=obj.Data[i];
for(var j=dayItem.length-1;j>=0;--j)
{
var item=dayItem[j];
if (!item || !item.DayItem || !item.DayItem.Data) continue;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=item.DayItem.Data.length-1;
obj.IndexData.Type=item.Type;
return;
}
}
}
}
this.GetFirstCursorIndex=function(obj)
{
if (obj.DataType==1)
{
for(var i=0;i<obj.Data.length;++i)
{
var item=obj.Data[i];
if (!item || !item.DayItem || !item.DayItem.Data) continue;
obj.IndexData.DayIndex=0;
obj.IndexData.DataIndex=0;
obj.IndexData.Type=item.Type;
return;
}
}
else if (obj.DataType==2)
{
for(var i=0;i<obj.Data.length;++i)
{
var dayItem=obj.Data[i];
for(var j=0;j<dayItem.length;++j)
{
var item=dayItem[j];
if (!item || !item.DayItem || !item.DayItem.Data) continue;
obj.IndexData.DayIndex=i;
obj.IndexData.DataIndex=0;
obj.IndexData.Type=item.Type;
return;
}
}
}
}
//获取单日 盘后集合竞价数据
this.GetAfterCloseData=function()
{
var dayItem=null;
if (this.AfterCloseData && this.IsShowAfterData) dayItem=this.AfterCloseData;
return dayItem;
}
//获取单日 盘前集合竞价数据
this.GetBeforeOpenData=function()
{
var dayItem=null;
if (this.BeforeOpenData && this.IsShowBeforeData) dayItem=this.BeforeOpenData;
return dayItem;
}
this.MoveCorssCursorIndex=function(option)
{
if (!this.EnableNewIndex) return false;
if (!this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return false;
var frame=this.Frame.SubFrame[0].Frame;
if (this.CorssCursorIndex.Type==1 || this.CorssCursorIndex.Type==2 || this.CorssCursorIndex.Type==3 || this.CorssCursorIndex.Type==-1)
{
var aryData=[];
var dayItem=this.GetBeforeOpenData();
aryData.push({DayItem:dayItem, Type:2});
var dayItem=null;
if (this.SourceData) dayItem=this.SourceData;
aryData.push({DayItem:dayItem, Type:1});
var dayItem=this.GetAfterCloseData();;
aryData.push({DayItem:dayItem, Type:3});
var obj={ DataType:1, Data: aryData, IndexData:this.CorssCursorIndex, Point:{ X:null, Y:null }};
var step=1;
if (option.IsMoveLeft)
{
if (this.CorssCursorIndex.DayIndex<0 && this.CorssCursorIndex.DataIndex<0)
{
this.GetLastCursorIndex(obj);
step=0;
}
if (frame.MoveXIndexLeft(step, obj))
{
this.LastPoint.X=obj.Point.X;
this.LastPoint.Y=obj.Point.Y;
if (this.CorssCursorIndex.Type==1) this.CursorIndex=this.CorssCursorIndex.CursorIndex;
var option={ ParentFunction:'MoveCorssCursorIndex', Point:{X:obj.Point.X, Y:obj.Point.Y}, IsPhone:false, ClientPos:this.CorssCursorIndex.Type };
this.DrawDynamicInfo(option);
}
}
else
{
if (this.CorssCursorIndex.DayIndex<0 && this.CorssCursorIndex.DataIndex<0)
{
this.GetFirstCursorIndex(obj);
step=0;
}
if (frame.MoveXIndexRight(step, obj))
{
this.LastPoint.X=obj.Point.X;
this.LastPoint.Y=obj.Point.Y;
if (this.CorssCursorIndex.Type==1) this.CursorIndex=this.CorssCursorIndex.CursorIndex;
var option={ ParentFunction:'MoveCorssCursorIndex', Point:{X:obj.Point.X, Y:obj.Point.Y}, IsPhone:false, ClientPos:this.CorssCursorIndex.Type };
this.DrawDynamicInfo(option);
}
}
}
else if (this.CorssCursorIndex.Type==10 || this.CorssCursorIndex.Type==20 || this.CorssCursorIndex.Type==30 || this.CorssCursorIndex.Type==-2 )
{
var aryData=[];
var offset=0, showDayCount=this.DayData.length;
if (this.DayOffset)
{
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
}
for(var i=offset,j=0; i<this.DayData.length && j<showDayCount; ++i,++j)
{
var item=[];
var dayItem=null;
if (this.MultiDayBeforeOpenData && this.IsShowMultiDayBeforeData) dayItem=this.MultiDayBeforeOpenData[i];
item.push({DayItem:dayItem, Type:20});
//倒序排的
var dayItem=null;
if (this.DayData) dayItem=this.DayData[this.DayData.length-1-i];
item.push({DayItem:dayItem, Type:10});
var dayItem=null;
if (this.MultiDayAfterCloseData && this.IsShowMultiDayAfterData) dayItem=this.MultiDayAfterCloseData[i];
item.push({DayItem:dayItem, Type:30});
aryData.push(item);
}
var obj={ DataType:2, Data: aryData, IndexData:this.CorssCursorIndex, Point:{ X:null, Y:null }};
var step=1;
if (option.IsMoveLeft)
{
if (this.CorssCursorIndex.DayIndex<0 && this.CorssCursorIndex.DataIndex<0)
{
this.GetLastCursorIndex(obj);
step=0;
}
if (frame.MoveXIndexLeft(step, obj))
{
this.LastPoint.X=obj.Point.X;
this.LastPoint.Y=obj.Point.Y;
if (this.CorssCursorIndex.Type==10) this.CursorIndex=this.CorssCursorIndex.CursorIndex;
var option={ ParentFunction:'MoveCorssCursorIndex', Point:{X:obj.Point.X, Y:obj.Point.Y}, IsPhone:false, ClientPos:null };
if (this.CorssCursorIndex.Type==10) option.ClientPos=1;
else if (this.CorssCursorIndex.Type==20) option.ClientPos=this.CorssCursorIndex.DayIndex+200;
else if (this.CorssCursorIndex.Type==30) option.ClientPos=this.CorssCursorIndex.DayIndex+300;
this.DrawDynamicInfo(option);
}
}
else
{
if (this.CorssCursorIndex.DayIndex<0 && this.CorssCursorIndex.DataIndex<0)
{
this.GetFirstCursorIndex(obj);
step=0;
}
if (frame.MoveXIndexRight(step, obj))
{
this.LastPoint.X=obj.Point.X;
this.LastPoint.Y=obj.Point.Y;
if (this.CorssCursorIndex.Type==10) this.CursorIndex=this.CorssCursorIndex.CursorIndex;
var option={ ParentFunction:'MoveCorssCursorIndex', Point:{X:obj.Point.X, Y:obj.Point.Y}, IsPhone:false, ClientPos:null };
if (this.CorssCursorIndex.Type==10) option.ClientPos=1;
else if (this.CorssCursorIndex.Type==20) option.ClientPos=this.CorssCursorIndex.DayIndex+200;
else if (this.CorssCursorIndex.Type==30) option.ClientPos=this.CorssCursorIndex.DayIndex+300;
this.DrawDynamicInfo(option);
}
}
}
}
this.SetCorssCursorIndex=function(option)
{
if (!this.EnableNewIndex) return;
JSConsole.Chart.Log("[MinuteChartContainer::SetCorssCursorIndex] option ", option);
if (option.ParentFunction=="OnMouseMove")
{
this.CorssCursorIndex.Point.X=option.Point.X;
this.CorssCursorIndex.Point.Y=option.Point.Y;
var clientPos=this.PtInClient_V2(option.Point.X,option.Point.Y);
JSConsole.Chart.Log("[MinuteChartContainer::SetCorssCursorIndex] clientPos ", clientPos);
if (clientPos<=0)
{
this.CorssCursorIndex={ DayIndex:-1, DataIndex:-1, Point:{X:-1, Y:-1}, Type:clientPos };
return;
}
if (!this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame)
{
this.CorssCursorIndex={ DayIndex:-1, DataIndex:-1, Point:{X:-1, Y:-1}, Type:-1 };
return;
}
var frame=this.Frame.SubFrame[0].Frame;
if (clientPos==1 || clientPos==2 || clientPos==3)
{
this.CorssCursorIndex.DayIndex=0;
this.CorssCursorIndex.Type=clientPos;
if (clientPos==2)
{
frame.GetLeftExtendXValidData(option.Point.X,{ Data: this.BeforeOpenData, IndexData: this.CorssCursorIndex });
}
else if (clientPos==3)
{
frame.GetRightExtendXValidData(option.Point.X,{ Data: this.AfterCloseData, IndexData: this.CorssCursorIndex });
}
else if (clientPos==1)
{
var value=frame.GetXData(option.Point.X);
this.CorssCursorIndex.DataIndex=parseInt(value.toFixed(0));
}
}
else if (clientPos>=100 && clientPos<=199)
{
this.CorssCursorIndex.DayIndex=clientPos-100;
this.CorssCursorIndex.Type=10;
var value=frame.GetXData(option.Point.X);
var index=parseInt(value.toFixed(0));
this.CorssCursorIndex.DataIndex=index%frame.MinuteCount;
}
else if (clientPos>=200 && clientPos<=299)
{
this.CorssCursorIndex.DayIndex=clientPos-200;
this.CorssCursorIndex.Type=20;
var aryData=this.MultiDayBeforeOpenData;
if (this.DayOffset)
{
var offset=0, showDayCount=this.MultiDayBeforeOpenData.length;
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
aryData=this.MultiDayBeforeOpenData.slice(offset,offset+showDayCount);
}
frame.GetLeftExtendXValidData(option.Point.X,{ Data: aryData, IndexData: this.CorssCursorIndex });
}
else if (clientPos>=300 && clientPos<=399)
{
this.CorssCursorIndex.DayIndex=clientPos-300;
this.CorssCursorIndex.Type=30;
var aryData=this.MultiDayAfterCloseData;
if (this.DayOffset && this.MultiDayAfterCloseData)
{
var offset=0, showDayCount=this.MultiDayAfterCloseData.length;
if (IFrameSplitOperator.IsNumber(this.DayOffset.Offset)) offset=this.DayOffset.Offset;
if (IFrameSplitOperator.IsNumber(this.DayOffset.ShowDayCount)) showDayCount=this.DayOffset.ShowDayCount;
aryData=this.MultiDayAfterCloseData.slice(offset,offset+showDayCount);
}
frame.GetRightExtendXValidData(option.Point.X,{ Data: aryData, IndexData: this.CorssCursorIndex });
}
this.LastPoint.X=this.CorssCursorIndex.Point.X;
option.Point.X=this.CorssCursorIndex.Point.X;
}
}
// 100-199=多日分时主图 200-299=盘前 300-399=盘后 1=主图 2=盘前 3=盘后
this.PtInClient_V2=function(x,y)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
var border=this.Frame.ChartBorder.GetHScreenBorder();
this.Canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
}
else
{
var border=this.Frame.ChartBorder.GetBorder();
if (border.DayBorder) //多日分时+多日集合竞价
{
for(var i=0;i<border.DayBorder.length;++i)
{
var client=border.DayBorder[i];
this.Canvas.beginPath();
this.Canvas.rect(client.LeftEx,border.TopEx,client.RightEx-client.LeftEx,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y)) return 100+i;
//盘前
this.Canvas.beginPath();
this.Canvas.rect(client.Left,border.TopEx,client.LeftEx-client.Left,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y))
return 200+i;
//盘后
this.Canvas.beginPath();
this.Canvas.rect(client.RightEx,border.TopEx,client.Right-client.RightEx,border.BottomEx-border.TopEx);
if (this.Canvas.isPointInPath(x,y))
return 300+i;
}
return -2;
}
this.Canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y)) return 1;
if (this.Frame.ChartBorder.LeftExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
}
else
{
this.Canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y))
return 2;
}
if (this.Frame.ChartBorder.RightExtendWidth>10)
{
this.Canvas.beginPath();
if (this.Frame.IsHScreen===true)
{
this.Canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
}
else
{
this.Canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
}
if (this.Canvas.isPointInPath(x,y))
return 3;
}
return -1;
}
//手势
this.OnTouchStart=function(e)
{
if(this.DragMode==0) return;
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.IsPress=false;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.PhonePinch=null;
this.StopDragTimer();
if (this.EnableScrollUpDown==false) e.preventDefault(); //上下拖动图形不能阻止事件
if (this.IsPhoneDragging(e))
{
var drag= { Click:{}, LastMove:{} };//LastMove=最后移动的位置
var touches=this.GetToucheData(e,this.IsForceLandscape);
var pt=this.PointAbsoluteToRelative(touches[0].clientX, touches[0].clientY, true);
if (this.TryClickLock || this.TryClickIndexTitle) //指标枷锁区域 , 指标标题点击
{
var x = pt.X;
var y = pt.Y;
if (this.TryClickLock && this.TryClickLock(x, y)) return;
if (this.TryClickIndexTitle && this.TryClickIndexTitle(x,y)) return;
}
if (this.ClickFrameButton)
{
var button=this.Frame.PtInButtons(pt.X,pt.Y);
if (button)
{
this.ClickFrameButton(button, e);
return;
}
}
drag.Click.X=touches[0].clientX;
drag.Click.Y=touches[0].clientY;
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
var self=this;
var T_ShowCorssCursor=function() //临时函数(Temp_) T_开头
{
if (self.ChartCorssCursor.IsShow === true) //移动十字光标
{
var pt=self.PointAbsoluteToRelative(drag.Click.X, drag.Click.Y, true);
var x = pt.X;
var y = pt.Y
self.OnMouseMove(x, y, e);
}
}
if (this.ChartDrawOption.IsLockScreen)
{
this.MouseDrag=drag;
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y,true);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo({Corss:false, Tooltip:false});
}
if (e.cancelable) e.preventDefault();
return;
}
else
{
var drawPictrueData={};
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
drawPictrueData.X=(touches[0].clientX-uielement.getBoundingClientRect().left);
drawPictrueData.Y=(touches[0].clientY-uielement.getBoundingClientRect().top);
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
if (drawPictrueData.ChartDrawPicture.EnableMove==true)
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
drawPictrueData.ChartDrawPicture.IsSelected=true;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
if (e.cancelable) e.preventDefault();
return;
}
}
}
else
{
if (this.EnableScrollUpDown==true)
{
this.DragTimer=setTimeout(function()
{
self.IsPress=true;
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y)
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
T_ShowCorssCursor();
self.PreventTouchEvent(e)
}
}, 800);
}
this.MouseDrag=drag;
this.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } };
this.SelectChartDrawPicture=null;
var bStartTimer=true; //长按计时开始
if (this.EnableClickModel)
{
if (this.ClickModel.IsShowCorssCursor==true) bStartTimer=false;
else bStartTimer= true;
}
if (bStartTimer)
{
this.StopDragTimer();
this.DragTimer = setTimeout(()=>{
this.IsPress=true;
if (drag.Click.X == drag.LastMove.X && drag.Click.Y == drag.LastMove.Y) //手指没有移动,出现十字光标
{
this.MouseDrag = null;
//移动十字光标
var x = drag.Click.X;
var y = drag.Click.Y;
if (this.EnableClickModel===true) this.ClickModel.IsShowCorssCursor=true;
self.MoveCorssCursor(drag.Click,e);//移动十字光标
}
}, this.PressTime);
}
else if (!this.EnableClickModel)
{
if (this.EnableScrollUpDown==false)
T_ShowCorssCursor(); //移动十字光标
else if (this.IsClickShowCorssCursor)
T_ShowCorssCursor();
}
}
if (this.EnableZoomIndexWindow)
{
this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now());
JSConsole.Chart.Log("[MinuteChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick);
}
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, e);
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.GetToucheData(e,this.IsForceLandscape);
phonePinch.Start={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
this.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
}
}
this.OnTouchMove=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var touches=this.GetToucheData(e,this.IsForceLandscape);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
else
{
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveSetp=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
moveSetp=parseInt(moveSetp);
if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.EnableMove===true)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.SetChartDrawPictureSecondPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.MoveChartDrawPicture(touches[0].clientX-drag.LastMove.X,touches[0].clientY-drag.LastMove.Y,true))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
else if (this.EnableClickModel && this.ClickModel.IsShowCorssCursor===false)
{
//点击模式 十字光标隐藏 不做任何操作
}
else
{
//上下滚动
if ( ((moveUpDown>0 && moveSetp<=3) || moveAngle<=this.TouchMoveMinAngle) && this.EnableScrollUpDown==true )
{
this.StopDragTimer();
return;
}
this.PreventTouchEvent(e);
this.MouseDrag=null;
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
}
if (this.PhoneTouchInfo)
{
this.PhoneTouchInfo.End.X=touches[0].clientX;
this.PhoneTouchInfo.End.Y=touches[0].clientY;
}
}
else if (this.IsPhonePinching(e))
{
this.PreventTouchEvent(e);
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
var yHeight=Math.abs(touches[0].pageY-touches[1].pageY);
var yLastHeight=Math.abs(phonePinch.Last.Y-phonePinch.Last.Y2);
var yStep=yHeight-yLastHeight;
var xHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var xLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var xStep=xHeight-xLastHeight;
var minStep=this.ZoomStepPixel;
if (Math.abs(xStep)>minStep)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MINUTE_TOUCH_ZOOM)
if (event && event.Callback)
{
var data={ XStep:xStep, YStep:yStep, PreventDefault:false };
event.Callback(event,data,this);
if (data.PreventDefault)
{
this.PhonePinch=null;
this.StopDragTimer();
return;
}
}
}
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
if (this.EnableScrollUpDown==false)
{
e.preventDefault();
}
else
{
if (drag==null)
{
this.PreventTouchEvent(e); //十字光标出来了,阻止消息
}
else
{
this.StopDragTimer(); //上下推动图片,停止定时器,消息传递下去
}
}
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[MinuteChartContainer::OnTouchEnd]',e);
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
if (this.EnableZoomIndexWindow)
{
var time=Date.now();
this.PhoneDBClick.AddTouchEnd(time);
if (this.PhoneDBClick.IsVaildDBClick())
{
this.OnTouchDBClick(this.PhoneDBClick.Start);
this.PhoneDBClick.Clear();
}
}
this.IsOnTouch = false;
this.StopDragTimer();
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e);
this.OnTouchFinished();
this.TouchDrawCount=0;
}
//键盘左右移动十字光标
this.OnKeyDown=function(e)
{
this.StopDisplayLatest();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
//回调事件
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN);
if (event && event.Callback)
{
var sendData={ e:e, PreventDefault:false };
event.Callback(event, sendData, this);
if (sendData.PreventDefault) return;
}
var keyID = e.keyCode ? e.keyCode :e.which;
var draw=false;
if (this.ChartCorssCursor && this.ChartCorssCursor.OnKeyDown) //十字光标 隐藏显示
{
var sendData={ e:e, KeyID:keyID, Draw:false, PreventDefault:false };
this.ChartCorssCursor.OnKeyDown(sendData);
draw=sendData.Draw;
}
switch(keyID)
{
case 37: //left
if (this.EnableNewIndex)
{
this.MoveCorssCursorIndex({IsMoveLeft:true});
}
else
{
if (!IFrameSplitOperator.IsNumber(this.CursorIndex))
{
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
this.CursorIndex=xPointcount-1;
}
this.CursorIndex=parseInt(this.CursorIndex);
if (this.CursorIndex<=0.99999)
{
if (!this.DataMoveLeft()) break;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
}
else
{
--this.CursorIndex;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
}
}
break;
case 39: //right
if (this.EnableNewIndex)
{
this.MoveCorssCursorIndex({IsMoveLeft:false});
}
else
{
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (!IFrameSplitOperator.IsNumber(this.CursorIndex)) this.CursorIndex=0;
this.CursorIndex=parseInt(this.CursorIndex);
if (this.CursorIndex+1>=xPointcount)
{
if (!this.DataMoveRight()) break;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
}
else
{
//判断是否在最后一个数据上
var data=null;
if (this.Frame.Data) data=this.Frame.Data;
else data=this.Frame.SubFrame[0].Frame.Data;
if (!data) break;
if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break;
++this.CursorIndex;
this.UpdatePointByCursorIndex();
this.DrawDynamicInfo();
}
}
break;
case 46: //del
if (this.SelectChartDrawPicture)
{
var drawPicture=this.SelectChartDrawPicture;
JSConsole.Chart.Log(drawPicture,"drawPicturedrawPicturedrawPicture")
this.SelectChartDrawPicture=null;
this.ClearChartDrawPicture(drawPicture); //删除选中的画图工具
}
else if (this.SelectedChart && this.SelectedChart.Selected.Identify)
{
var selectedInfo=this.GetSelectedChartInfo(this.SelectedChart.Selected);
if (selectedInfo)
{
if (selectedInfo.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_INDEX)
this.DeleteOverlayWindowsIndex(selectedInfo.IndexID);
else if (selectedInfo.Type==JSCHART_DRAGCHART_TYPE_ID.OVERLAY_MINUTE)
this.DeleteOverlaySymbol(selectedInfo.Symbol);
}
}
break;
case 32: //space
this.OnMarkRectSelect(e);
break;
case 33: //page up
if (this.PageInfo.Enable)
{
var option={ID:JSCHART_OPERATOR_ID.OP_SCROLL_LEFT, Step:this.PageInfo.ShowDayCount };
this.ChartOperator(option);
}
break;
case 34: //page down
if (this.PageInfo.Enable)
{
var option={ID:JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT, Step:this.PageInfo.ShowDayCount };
this.ChartOperator(option);
}
break;
case 27:
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status!=20) //画布移动的时候不能取消
this.CurrentChartDrawPicture=null;
}
break;
default:
return;
}
if (draw) this.DrawDynamicInfo();
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnMarkRectSelect=function(e)
{
var corssCursor=this.ChartCorssCursor; //十字光标
if (!corssCursor || corssCursor.Status==0) return;
if (!IFrameSplitOperator.IsNumber(corssCursor.CursorIndex)) return;
if (!this.SourceData || !this.SourceData.Data) return;
var paint=this.GetRectSelectPaint();
if (!paint) return;
var cursorIndex=corssCursor.CursorIndex;
JSConsole.Chart.Log("[MinuteChartContainer::OnMarkRectSelect] dataIndex", cursorIndex);
var kData=this.SourceData;
cursorIndex=parseInt(cursorIndex.toFixed(0));
var index=cursorIndex+kData.DataOffset;
if (index>=kData.Data.length) index=kData.Data.length-1;
var item = kData.Data[index];
JSConsole.Chart.Log("[MinuteChartContainer::OnMarkRectSelect] item", item);
if (!this.SetRectSelectData(item)) return;
var pointCount=paint.GetPointCount();
var pixelTatio = GetDevicePixelRatio();
if (pointCount==1) //第1个位置
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT_FIRST);
if (event && event.Callback)
{
var data=
{
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
Item:item,
Index:index,
RectSelectPaint:paint, //区间选择背景
e:e,
};
event.Callback(event,data,this);
}
}
else if (pointCount==2) //第2个位置
{
var selectData=paint.GetSelectRectData();
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT);
if (event && event.Callback)
{
var data=
{
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint, //区间选择背景
e:e,
};
event.Callback(event,data,this);
}
if (this.DialogSelectRect)
{
e.data=
{
Chart:this,
X:corssCursor.LastPoint.X/pixelTatio,
Y:corssCursor.LastPoint.Y/pixelTatio,
SelectData:selectData, //区间选择的数据
RectSelectPaint:paint //区间选择背景
};
this.DrawSelectRectDialog(e);
}
}
this.Draw();
}
//注册鼠标右键事件
this.OnRightMenu=function(x,y,e)
{
var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
var frameId=this.Frame.PtInFrame(x*pixelTatio,y*pixelTatio);
this.PopupRightMenuV2({X:e.offsetX, Y:e.offsetY, FrameID:frameId}, e);
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU);
if (event)
{
var data={ X:x, Y:y, Event:e, FrameID:frameId };
event.Callback(event,data,this);
}
}
//右键菜单数据
this.GetRightMenuData=function(frameID)
{
var windowCount=this.Frame.SubFrame.length; //窗口个数
var aryOverlaySymbol=[]; //叠加的股票列表
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
if (item && item.Symbol) aryOverlaySymbol.push(item.Symbol)
}
var bShowCorss=false; //十字光标十字线
if (this.ChartCorssCursor) bShowCorss=this.ChartCorssCursor.IsShowCorss;
var aryMenu=
[
{
Name:"叠加品种",
SubMenu:
[
{ Name:"上证指数", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["000001.sh", !aryOverlaySymbol.includes("000001.sh")]}, Checked:aryOverlaySymbol.includes("000001.sh") },
{ Name:"深证成指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399001.sz", !aryOverlaySymbol.includes("399001.sz")]}, Checked:aryOverlaySymbol.includes("399001.sz") },
{ Name:"中小板指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399005.sz", !aryOverlaySymbol.includes("399005.sz")]}, Checked:aryOverlaySymbol.includes("399005.sz") },
{ Name:"创业板指", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["399006.sz", !aryOverlaySymbol.includes("399006.sz")]}, Checked:aryOverlaySymbol.includes("399006.sz") },
{ Name:"沪深300", Data:{ ID: JSCHART_MENU_ID.CMD_OVERLAY_SYMBOL_ID, Args:["000300.sh", !aryOverlaySymbol.includes("000300.sh")]}, Checked:aryOverlaySymbol.includes("000300.sh")},
]
},
{
Name:"多日分时图",
SubMenu:
[
{ Name:"当日分时图", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID, Args:[1]}, Checked:this.DayCount==1 },
{ Name:"最近2日", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID, Args:[2]}, Checked:this.DayCount==2 },
{ Name:"最近3日", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID, Args:[3]}, Checked:this.DayCount==3 },
{ Name:"最近4日", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID, Args:[4]}, Checked:this.DayCount==4 },
{ Name:"最近5日", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_DAY_COUNT_ID, Args:[5]}, Checked:this.DayCount==5 },
{
Name:"基准线选择",
SubMenu:
[
{ Name:"最新昨收价", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_BASELINE_ID, Args:[0]}, Checked:this.BaselineType===0 },
{ Name:"多日前昨收价", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_BASELINE_ID, Args:[1]}, Checked:this.BaselineType===1 }
]
}
]
},
{
Name:"指标窗口个数",
SubMenu:
[
{ Name:"1个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[2]}, Checked:3==windowCount },
{ Name:"2个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[3]}, Checked:4==windowCount },
{ Name:"3个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[4]}, Checked:5==windowCount },
{ Name:"4个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[5]}, Checked:6==windowCount },
{ Name:"5个窗口", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_WINDOW_COUNT_ID, Args:[6]}, Checked:7==windowCount },
]
},
{
Name:"指标切换",
SubMenu:
[
{ Name:"MACD", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "MACD"]}},
{ Name:"DMI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "DMI"]}},
{ Name:"DMA", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "DMA"]}},
{ Name:"BRAR", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "BRAR"]}},
{ Name:"KDJ", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "KDJ"]}},
{ Name:"RSI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "RSI"]}},
{ Name:"WR", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "WR"]}},
{ Name:"CCI", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "CCI"]}},
{ Name:"TRIX", Data:{ ID: JSCHART_MENU_ID.CMD_CHANGE_INDEX_ID, Args:[frameID, "TRIX"]}},
]
},
{
Name:"区间选择",Data:{ ID: JSCHART_MENU_ID.CMD_ENABLE_SELECT_RECT_ID, Args:[!this.EnableSelectRect]}, Checked:this.EnableSelectRect
},
{
Name:"其他设置",
SubMenu:
[
{ Name:"画图工具", Data:{ ID:JSCHART_MENU_ID.CMD_SHOW_DRAWTOOL_ID, Args:[]}, Checked:this.IsShowDrawToolDialog()},
{ Name:"十字光标线", Data:{ ID:JSCHART_MENU_ID.CMD_SHOW_CORSS_LINE_ID, Args:[!bShowCorss]}, Checked:bShowCorss },
{ Name:JSPopMenu.SEPARATOR_LINE_NAME },
{
Name:"语言设置",
SubMenu:
[
{ Name:"中文", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["CN"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID },
{ Name:"英语", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["EN"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID },
{ Name:"繁体", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_LANGUAGE_ID, Args:["TC"]}, Checked:this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID },
]
},
{
Name:"区间选择样式",
SubMenu:
[
{ Name:"样式1(默认)", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[0]}, Checked:0==this.ChartDragSelectRect.ShowMode },
{ Name:"样式2", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[1]}, Checked:1==this.ChartDragSelectRect.ShowMode },
{ Name:"样式3", Data:{ ID:JSCHART_MENU_ID.CMD_CHANGE_DRAG_RECT_SHOW_MODE_ID, Args:[2]}, Checked:2==this.ChartDragSelectRect.ShowMode },
]
},
{
Name:"K线浮动框",
SubMenu:
[
{ Name:"禁用", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:false}]}, Checked:!this.DialogTooltip },
{ Name:"样式1", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:true, Style:0}]}, Checked:(this.DialogTooltip && this.DialogTooltip.Style===0) },
{ Name:"样式2", Data:{ ID:JSCHART_MENU_ID.CMD_DIALOG_TOOLTIP_ATTRIBUTE, Args:[{Enable:true, Style:1}]}, Checked:(this.DialogTooltip && this.DialogTooltip.Style===1) },
]
}
]
}
];
if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol))
{
var item={ Name:"集合竞价",Data:{ ID: JSCHART_MENU_ID.CMD_SHOW_BEFORE_DATA_ID, Args:[!this.IsShowBeforeData] }, Checked:this.IsShowBeforeData };
aryMenu.splice(4,0,item);
}
//删除菜单
for(var i=0;i<aryMenu.length;++i)
{
var item=aryMenu[i];
if (item.Name=="叠加品种")
{
for(var j=0;j<item.SubMenu.length;++j)
{
if (item.SubMenu[j].Checked)
{
item.SubMenu.push({ Name:JSPopMenu.SEPARATOR_LINE_NAME });
item.SubMenu.push({ Name:"取消叠加", Data:{ ID: JSCHART_MENU_ID.CMD_DELETE_ALL_OVERLAY_SYMBOL_ID} });
break;
}
}
}
}
return aryMenu;
}
this.OnWheel=function(e)
{
JSConsole.Chart.Log('[MinuteChartContainer::OnWheel]',e);
}
this.OnDoubleClick=function(x,y,e)
{
JSConsole.Chart.Log("[MinuteChartContainer::OnDoubleClick]", e);
if (this.ClickChartTimer!=null)
{
clearTimeout(this.ClickChartTimer);
this.ClickChartTimer=null;
}
var selectedChart; //图形选中
if (this.SelectedChart.EnableSelected)
{
selectedChart=this.PtInChart(x,y);
}
var dbClickInfo={SelectedChart:selectedChart};
this.DBClickEvent(dbClickInfo, e);
//没有图形选中,双击缩放窗口
if (!selectedChart && this.EnableZoomIndexWindow)
{
var frameId=this.Frame.PtInFrame(x,y);
JSConsole.Chart.Log("[MinuteChartContainer::OnDoubleClick] frameId",frameId);
if (frameId>=this.Frame.ZoomStartWindowIndex)
{
if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
{
this.Frame.SetSizeChage(true);
this.Draw();
}
}
}
}
this.GetDataItem=function(pointInfo)
{
if (!pointInfo) return null;
if (!IFrameSplitOperator.IsNumber(pointInfo.Index)) return null;
if (!this.SourceData || !this.SourceData.Data) return null;
var data=this.SourceData;
var clientPos=pointInfo.ClientPos;
if (clientPos==2 || clientPos==3 || (clientPos>=200&& clientPos<=299) || (clientPos>=300&& clientPos<=399))
{
if (!this.ChartCorssCursor || !this.ChartCorssCursor.CallAcutionXOperator) return null;
var isHScreen=this.Frame.IsHScreen===true;
var callAcutionXOper=this.ChartCorssCursor.CallAcutionXOperator;
callAcutionXOper.Value=isHScreen?pointInfo.Point.Y:pointInfo.Point.X;
callAcutionXOper.Point={X:pointInfo.Point.X, Y:pointInfo.Point.Y};
callAcutionXOper.ClientPos=clientPos;
if (clientPos==2)
{
if (!this.BeforeOpenData) return null;
}
else if (clientPos==3)
{
if (!this.AfterCloseData) return null;
}
else if (clientPos>=200 && clientPos<=299)
{
if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData) ) return;
}
else if (clientPos>=300 && tclientPos<=399)
{
if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData) ) return;
}
if (callAcutionXOper.Operator())
{
var item=callAcutionXOper.Item;
return {Type:clientPos, Item:item, Index:callAcutionXOper.DataIndex };
}
return null;
}
var index=parseInt(pointInfo.Index.toFixed(0));
var dataIndex=index+data.DataOffset;
if (dataIndex>=data.Data.length) return null;
var item=data.Data[dataIndex];
return {Type:clientPos, Item:item, Index:dataIndex };
}
this.UpdatePointByCursorIndex=function()
{
this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex);
var index=this.CursorIndex;
index=parseInt(index.toFixed(0));
var data=this.Frame.SourceData;
if (data.DataOffset+index>=data.Data.length)
{
return;
}
var item=data.Data[data.DataOffset+index];
var close=null;
if (item.Before) close=item.Before.Close;
else close=item.Close
this.LastPoint.Y=this.Frame.GetYFromData(close);
}
//创建
//windowCount 窗口个数
this.Create=function(windowCount,option)
{
this.UIElement.JSChartContainer=this;
//创建十字光标
this.ChartCorssCursor=new ChartCorssCursor();
this.ChartCorssCursor.PtInClient=(x,y)=>{ return this.PtInClient(x,y); }
this.ChartCorssCursor.Canvas=this.Canvas;
this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_Minute_XStringFormat");
this.ChartCorssCursor.StringFormatX.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
this.ChartCorssCursor.StringFormatY.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
this.ChartCorssCursor.StringFormatY.ShareAfterVol=this.ShareAfterVol;
this.ChartCorssCursor.CallAcutionXOperator=new CallAcutionXOperator();
this.ChartCorssCursor.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.HQChart=this;
//创建框架容器
this.Frame=new HQTradeFrame();
this.Frame.ChartBorder=new ChartBorder();
this.Frame.ChartBorder.UIElement=this.UIElement;
this.Frame.ChartBorder.Top=25;
this.Frame.ChartBorder.TitleHeight=0;
this.Frame.ChartBorder.Left=50;
this.Frame.ChartBorder.Bottom=20;
this.Frame.Canvas=this.Canvas;
this.Frame.GetExtendChartRightWidth=()=> { return this.GetExtendChartRightWidth() }
this.Frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.Frame.ZoomStartWindowIndex=2;
this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
this.CreateChildWindow(windowCount);
this.CreateMainKLine();
this.CreateExtendChart("RectSelectPaint", option? option.SelectRect:null); //区间统计
if (this.EnableIndexChartDrag) this.CreateExtendChart("DragMovePaint");
this.CreateDragSelectRect(option? option.DragSelectRect:null);
//子窗口动态标题
for(var i=0;i<this.Frame.SubFrame.length; ++i)
{
var titlePaint=new DynamicChartTitlePainting();
if (i==0 || i==1) titlePaint.IsShowMainIndexTitle=false;
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
titlePaint.MainTitlePaint=this.TitlePaint[0];
this.TitlePaint.push(titlePaint);
}
this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame;
this.ChartCorssCursor.StringFormatY.Frame=this.Frame;
if (this.ChartCorssCursor.CallAcutionXOperator)
this.ChartCorssCursor.CallAcutionXOperator.Frame=this.Frame.SubFrame[0].Frame;
var bRegisterKeydown=true;
var bRegisterWheel=true;
if (option && option.Listener)
{
var item=option.Listener;
if (item.KeyDown===false)
{
bRegisterKeydown=false;
JSConsole.Chart.Log('[MinuteChartContainer::Create] not register keydown event.');
}
if (item.Wheel===false)
{
bRegisterWheel=false;
JSConsole.Chart.Log('[MinuteChartContainer::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.CreateChildWindow=function(windowCount)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_FRAME);
for(var i=0;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new MinuteFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=i;
frame.GlobalOption=this.GlobalOption;
if (i<2) frame.ChartBorder.TitleHeight=0;
frame.XPointCount=243;
frame.HQChart=this;
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i>=2)
{
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
}
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
if (i==0)
{
frame.YSplitOperator=new FrameSplitMinutePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.YSplitOperator.DayOffset=this.DayOffset;
frame.YSplitOperator.GlobalOption=this.GlobalOption;
frame.YSplitOperator.HQChart=this;
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i==1) frame.YSplitOperator.ShareAfterVol=this.ShareAfterVol;
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.DayOffset=this.DayOffset;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.Operator();
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
}
this.CreateSubFrameItem=function(id, mainFrame)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
if (mainFrame && mainFrame.ChartBorder && mainFrame.ChartBorder.MultiDayMinute)
{
var item=mainFrame.ChartBorder.MultiDayMinute;
border.MultiDayMinute.Count=item.Count;
border.MultiDayMinute.Left=item.Left;
border.MultiDayMinute.Right=item.Right;
}
var frame=null;
if (this.ClassName=="MinuteChartHScreenContainer") frame=new MinuteHScreenFrame();
else frame=new MinuteFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=id; //窗口序号
frame.XPointCount=243;
frame.GlobalOption=this.GlobalOption;
frame.HQChart=this;
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (id>=2)
{
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
}
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.DayOffset=this.DayOffset;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.XSplitOperator.Symbol=this.Symbol;
if (this.DayCount>1)
{
frame.XSplitOperator.DayCount=this.DayData.length;
frame.XSplitOperator.DayData=this.DayData;
frame.DayCount=this.DayData.length;
}
//K线数据绑定
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
frame.Data=this.ChartPaint[0].Data;
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
subFrame.Height=10;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_FRAME);
if (event && event.Callback)
{
var sendData={ SubFrame:subFrame, WindowIndex:id };
event.Callback(event, sendData, this);
}
return subFrame;
}
this.AddNewSubFrame=function(option)
{
var mainFrame=this.Frame.SubFrame[0].Frame;
var index=this.Frame.SubFrame.length;
var subFrame=this.CreateSubFrameItem(index,mainFrame);
var pixelRatio=GetDevicePixelRatio();
subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
this.Frame.SubFrame[index]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[index].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
titlePaint.MainTitlePaint=this.TitlePaint[0];
this.TitlePaint[index+1]=titlePaint;
this.SetSubFrameOption(subFrame,option);
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
this.Frame.SetSizeChage(true);
if (this.UpdateXShowText) this.UpdateXShowText();
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
return index;
}
this.UpdateXShowText=function()
{
var bLastFrame=true;
for(var i=this.Frame.SubFrame.length-1;i>=0;--i)
{
var item=this.Frame.SubFrame[i].Frame;
var subFrame=this.Frame.SubFrame[i];
if (bLastFrame)
{
item.XSplitOperator.ShowText=true;
if (subFrame.Height>0) bLastFrame=false;
}
else
{
item.XSplitOperator.ShowText=false;
}
}
}
//删除某一个窗口的指标
this.DeleteIndexPaint=function(windowIndex,bCallDestroy)
{
var subFrame=this.Frame.SubFrame[windowIndex].Frame;
if (!subFrame) return;
var paint=[]; //踢出当前窗口的指标画法
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
var bFind=(item.ChartFrame.Guid==subFrame.Guid || item.ChartFrame==subFrame);
if (i==0 || !bFind)
{
paint.push(item);
}
else
{
if (bCallDestroy===true)
{
if (item && item.OnDestroy) item.OnDestroy(); //图形销毁
}
}
}
//清空指定最大最小值
subFrame.YSpecificMaxMin=null;
subFrame.IsLocked=false; //解除上锁
subFrame.YSplitOperator.SplitType=subFrame.YSplitOperator.DefaultSplitType; //还原Y坐标分割模式
this.ChartPaint=paint;
//清空东条标题
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
}
this.CreateStockInfo=function()
{
this.ExtendChartPaint[0]=new StockInfoExtendChartPaint();
this.ExtendChartPaint[0].Canvas=this.Canvas;
this.ExtendChartPaint[0].ChartBorder=this.Frame.ChartBorder;
this.ExtendChartPaint[0].ChartFrame=this.Frame;
this.Frame.ChartBorder.Right=300;
}
//创建主图K线画法
this.CreateMainKLine=function()
{
//分钟线
var minuteLine=g_ChartPaintFactory.Create("ChartMinutePriceLine");
minuteLine.Canvas=this.Canvas;
minuteLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
minuteLine.ChartFrame=this.Frame.SubFrame[0].Frame;
minuteLine.Name="Minute-Line";
minuteLine.Identify="Minute-Line";
minuteLine.Color=g_JSChartResource.Minute.PriceColor;
minuteLine.LineWidth=g_JSChartResource.Minute.PriceLineWidth;
minuteLine.AreaColor=g_JSChartResource.Minute.AreaPriceColor;
minuteLine.GetEventCallback=(id)=>{ return this.GetEventCallback(id); };
this.ChartPaint[0]=minuteLine;
//分钟线均线
var averageLine=new ChartMinutePriceLine();
averageLine.Canvas=this.Canvas;
averageLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
averageLine.ChartFrame=this.Frame.SubFrame[0].Frame;
averageLine.Name="Minute-Average-Line";
averageLine.Identify="Minute-Average-Line";
averageLine.Color=g_JSChartResource.Minute.AvPriceColor;
averageLine.IsDrawArea=false;
this.ChartPaint[1]=averageLine;
//成交量
var volLine=g_ChartPaintFactory.Create("ChartMinuteVolumBar");
volLine.Color=g_JSChartResource.Minute.VolBarColor;
volLine.Canvas=this.Canvas;
volLine.ChartBorder=this.Frame.SubFrame[1].Frame.ChartBorder;
volLine.ChartFrame=this.Frame.SubFrame[1].Frame;
volLine.Name="Minute-Vol-Bar";
volLine.Identify="Minute-Vol-Bar";
volLine.ShareAfterVol=this.ShareAfterVol;
this.ChartPaint[2]=volLine;
this.TitlePaint[0]=new DynamicMinuteTitlePainting();
this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].Canvas=this.Canvas;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.TitlePaint[0].LanguageID=this.LanguageID;
this.TitlePaint[0].CallAcutionXOperator=new CallAcutionXOperator();
this.TitlePaint[0].CallAcutionXOperator.Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].HQChart=this;
}
//切换成 脚本指标
this.ChangeScriptIndex=function(windowIndex,indexData,option)
{
this.DeleteIndexPaint(windowIndex, true);
this.WindowIndex[windowIndex]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
var bindData=this.SourceData;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
//切换api指标
this.ChangeAPIIndex=function(windowIndex,indexData)
{
this.DeleteIndexPaint(windowIndex, true);
//使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
var apiItem=indexData.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,indexData);
if (indexData)
{
if (indexData.Window) this.SetFrameToolbar(windowIndex,indexData.Window);
}
this.Frame.ClearUpDonwFrameYData({ Index:windowIndex });
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ChangeIndex=function(windowIndex,indexName,option)
{
if (this.Frame.SubFrame.length<3) return;
if (option && option.API)
return this.ChangeAPIIndex(windowIndex,option);
//查找系统指标
let scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(indexName);
if (!indexInfo) return;
if (windowIndex<2) windowIndex=2;
if (windowIndex>=this.Frame.SubFrame.length) windowIndex=2;
JSIndexScript.ModifyAttribute(indexInfo, option)
return this.ChangeScriptIndex(windowIndex, indexInfo, option);
}
//设置指标窗口个数
this.ChangeIndexWindowCount=function(count)
{
if (count<2) return; //1,2个窗口固定的不能动
if (this.Frame.SubFrame.length==count) return;
var currentLength=this.Frame.SubFrame.length;
if (currentLength>count)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
for(var i=currentLength-1;i>=count;--i)
{
this.DeleteIndexPaint(i);
this.DeleteChartPaintExtend({WindowIndex:i});
var item=this.Frame.SubFrame[i].Frame;
if (item.ClearToolbar) item.ClearToolbar();
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
this.Frame.SubFrame.splice(count,currentLength-count);
this.WindowIndex.splice(count,currentLength-count);
this.TitlePaint.splice(count+1,currentLength-count);
}
else
{
//创建新的指标窗口
var mainFrame=this.Frame.SubFrame[0].Frame;
for(var i=currentLength;i<count;++i)
{
var subFrame=this.CreateSubFrameItem(i, mainFrame);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
titlePaint.MainTitlePaint=this.TitlePaint[0];
this.TitlePaint[i+1]=titlePaint;
}
//创建指标
const indexName=["RSI","MACD","DMA","DMI","KDJ","WR"];
let scriptData = new JSIndexScript();
for(var i=currentLength;i<count;++i)
{
var name=indexName[i%indexName.length];
let indexInfo = scriptData.Get(name);
this.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
var bindData=this.SourceData;
this.BindIndexData(i,bindData); //执行脚本
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
}
this.UpdateXShowText();
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ChangeIndexTemplate=function(option) //切换指标模板 可以设置指标窗口个数 每个窗口的指标, 只能从第3个指标窗口开始设置,前面2个指标窗口固定无法设置
{
if (!Array.isArray(option.Windows)) return;
var count=option.Windows.length;
var currentLength=this.Frame.SubFrame.length;
var startWindowIndex=2;
count+=startWindowIndex;
var dayCount=null, symbol=null;
if (IFrameSplitOperator.IsNumber(option.DayCount) && option.DayCount!=this.DayCount) dayCount= option.DayCount; //天数
if (option.Symbol) symbol=option.Symbol;
var bRefreshData= (dayCount!=null || symbol!=null);
//清空所有的指标图型
for(var i=startWindowIndex;i<currentLength;++i)
{
this.DeleteIndexPaint(i);
var frame=this.Frame.SubFrame[i];
frame.YSpecificMaxMin=null;
frame.IsLocked=false;
frame.YSplitScale = null;
}
if (currentLength>count)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
for(var i=currentLength-1;i>=count;--i)
{
this.Frame.SubFrame[i].Frame.ClearToolbar();
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[i], WindowIndex:i };
event.Callback(event, sendData, this);
}
}
this.Frame.SubFrame.splice(count,currentLength-count);
this.WindowIndex.splice(count,currentLength-count);
this.TitlePaint.splice(count+1,currentLength-count);
}
else
{
for(var i=currentLength;i<count;++i) //创建新的指标窗口
{
var subFrame=this.CreateSubFrameItem(i);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
titlePaint.MainTitlePaint=this.TitlePaint[0];
this.TitlePaint[i+1]=titlePaint;
}
}
for(var i=0;i<count;++i)
{
var windowIndex=i;
var item=null,frameItem=null;
if (option.Frame && option.Frame.length>i) frameItem=option.Frame[windowIndex];
if (windowIndex>=startWindowIndex) item=option.Windows[windowIndex-startWindowIndex];
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
if (item)
{
if (item.Script) //自定义指标脚本
{
this.WindowIndex[windowIndex]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API) //后台指标
{
var apiItem=item.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var indexID=item.Index;
var indexItem=JSIndexMap.Get(indexID);
if (indexItem)
{
this.WindowIndex[windowIndex]=indexItem.Create();
this.CreateWindowIndex(windowIndex);
}
else
{
var systemScript = new JSIndexScript();
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo,item);
this.WindowIndex[windowIndex]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
}
}
}
}
this.SetSubFrameAttribute(this.Frame.SubFrame[windowIndex], item, frameItem);
}
//清空叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
this.DeleteWindowsOverlayIndex(i);
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
//叠加指标
var aryOverlayIndex=[];
if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
{
for(var i=0;i<option.OverlayIndex.length;++i)
{
var item=option.OverlayIndex[i];
if (item.Index) item.IndexName=item.Index;
if (item.Windows>=0) item.WindowIndex=item.Windows;
var overlay=this.CreateOverlayWindowsIndex(item);
if (!overlay) continue;
aryOverlayIndex.push({ WindowsIndex:item.WindowIndex, Overlay:overlay });
}
}
this.Frame.SetSizeChage(true);
if (!bRefreshData)
{
if (!this.SourceData) //无数据 不需要执行指标
{
this.Draw();
return;
}
var bindData=this.SourceData;
for(var i=0;i<count;++i)
{
this.BindIndexData(i,bindData); //执行脚本
}
for(var i=0;i<aryOverlayIndex.length;++i)
{
var item=aryOverlayIndex[i];
this.BindOverlayIndexData(item.Overlay,item.WindowsIndex,bindData);
}
this.UpdataDataoffset(); //更新数据偏移
if (this.UpdateXShowText) this.UpdateXShowText();
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
else
{
if (!symbol) symbol=this.Symbol;
var option={ };
if (IFrameSplitOperator.IsNumber(dayCount)) option.DayCount=dayCount;
this.ChangeSymbol(symbol, option);
}
}
this.RemoveIndexWindow=function(id)
{
JSConsole.Chart.Log('[MinuteChartContainer::RemoveIndexWindow] remove id', id);
if (id<2) return;
if (!this.Frame.SubFrame) return;
if (id>=this.Frame.SubFrame.length) return;
this.Frame.RestoreIndexWindows();
var delFrame=this.Frame.SubFrame[id].Frame;
this.DeleteIndexPaint(id);
this.DeleteChartPaintExtend({WindowIndex:id});
this.Frame.SubFrame[id].Frame.ClearToolbar();
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DELETE_FRAME);
if (event && event.Callback)
{
var sendData={ SubFrame:this.Frame.SubFrame[id], WindowIndex:id };
event.Callback(event, sendData, this);
}
this.Frame.SubFrame.splice(id,1);
this.WindowIndex.splice(id,1);
this.TitlePaint.splice(id+1,1); //删除对应的动态标题
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
item.Identify=i;
}
/*
if (this.ChartDrawPicture.length>0)
{
var aryDrawPicture=[];
for(var i in this.ChartDrawPicture)
{
var item=this.ChartDrawPicture[i];
if (item.Frame==delFrame) continue;
aryDrawPicture.push(item);
}
this.ChartDrawPicture=aryDrawPicture;
}
*/
this.Frame.SetSizeChage(true);
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
this.AutoUpdateEvent=function(bStart, explain) //自定更新事件, 是给websocket使用
{
var eventID=bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE:JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE;
if (!this.mapEvent.has(eventID)) return;
var self=this;
var event=this.mapEvent.get(eventID);
var data={ Stock:{ Symbol:this.Symbol, Name:this.Name, DayCount:this.DayCount }, Explain: explain };
if (bStart)
{
data.Callback=function(data) //数据到达更新回调
{
self.RecvMinuteData(data);
}
}
event.Callback(event,data,this);
}
this.ClearIndexPaint=function()
{
//清空指标
if (this.Frame && this.Frame.SubFrame)
{
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
if (i>=2) this.DeleteIndexPaint(i, true);
var item=this.Frame.SubFrame[i];
if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
{
for(var j=0; j<item.OverlayIndex.length; ++j ) //清空叠加指标
{
var overlayItem=item.OverlayIndex[j];
for(var k=0;k< overlayItem.ChartPaint.length;++k)
{
var overlayChart=overlayItem.ChartPaint[k];
if (overlayChart && overlayChart.OnDestroy) overlayChart.OnDestroy();
}
overlayItem.ChartPaint=[];
}
}
}
}
//清空叠加标题
for(var i=1;i<this.TitlePaint.length;++i)
{
var item=this.TitlePaint[i];
item.OverlayIndex=new Map();
}
}
this.ResetDayOffset=function()
{
if (this.PageInfo.Enable)
{
this.DayOffset.Offset=this.PageInfo.Offset;
this.DayOffset.ShowDayCount=this.PageInfo.ShowDayCount;
}
else
{
this.DayOffset.Offset=0;
this.DayOffset.ShowDayCount=-1;
}
this.DayOffset.PageInfo=null;
}
this.ResetDataStatus=function()
{
this.DataStatus.MultiDay=false;
this.DataStatus.LatestDay=false;
this.DataStatus.LatestDate=null;
}
this.ClearOverlaySymbolData=function()
{
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var chart=this.OverlayChartPaint[i];
chart.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; //重置状态
chart.Data.Data=[]; //清空数据
}
}
//切换股票代码
this.ChangeSymbol=function(symbol,option)
{
this.StopDisplayLatest();
this.CancelAutoUpdate();
this.AutoUpdateEvent(false, "MinuteChartContainer::ChangeSymbol");
this.Symbol=symbol;
this.ResetDayOffset();
this.ResetDataStatus();
this.ClearIndexPaint(); //清空指标
this.ResetOverlaySymbolStatus();
this.ReloadChartDrawPicture();
this.ClearIndexRunCount();
this.ClearStockCache();
this.Frame.ClearYCoordinateMaxMin();
if (option)
{
if (IFrameSplitOperator.IsNumber(option.DayCount)) this.DayCount=option.DayCount;
if (IFrameSplitOperator.IsNonEmptyArray(option.Windows)) //切换指标
{
for(var i=0; i<option.Windows.length; ++i)
{
var index=2+i;
if (index>=this.WindowIndex.length) break; //暂时不支持 动态增加/减少
var item=option.Windows[i];
if (!item) continue;
if (item.Script)
{
this.WindowIndex[index]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行
}
else if (item.API)
{
var apiItem=item.API;
this.WindowIndex[index]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
}
else
{
var systemScript = new JSIndexScript();
var indexID=item.Index;
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo,item);
indexInfo.ID=indexID;
this.WindowIndex[index]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
}
}
}
}
//清空叠加股票
if (option.ClearOverlay===true)
{
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
item.IsDelete=true;
}
this.OverlayChartPaint=[];
this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
}
//叠加股票
if (option.Overlay && IFrameSplitOperator.IsNonEmptyArray(option.Overlay))
{
var setSymbol=new Set();
for(var i=0;i<this.OverlayChartPaint.length;++i) //已有的叠加
{
var item=this.OverlayChartPaint[i];
setSymbol.add(item.Symbol);
}
for(var i=0;i<option.Overlay.length;++i)
{
var item=option.Overlay[i];
if (setSymbol.has(item.Symbol)) continue;
var paint=new ChartOverlayMinutePriceLine();
paint.Canvas=this.Canvas;
paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
paint.ChartFrame=this.Frame.SubFrame[0].Frame;
paint.Name="Overlay-Minute";
paint.Symbol=item.Symbol;
paint.Identify=`Overlay-Minute-${item.Symbol}`;
if (item.Color) paint.Color=item.Color; //外部设置颜色
else paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length];
++g_JSChartResource.OverlaySymbol.Random;
paint.MainData=this.SourceData; //绑定主图数据
if (paint.SetOption) paint.SetOption(item);
this.OverlayChartPaint.push(paint);
}
}
}
if (!symbol || this.DayCount<=0)
{
this.DrawEmpty();
}
else
{
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true); //增加下载动画
this.Draw();
this.RequestData();
}
}
this.SetPageInfo=function(pageInfo)
{
if (!pageInfo) return;
if (IFrameSplitOperator.IsBool(pageInfo.Enable)) this.PageInfo.Enable=pageInfo.Enable;
if (IFrameSplitOperator.IsNumber(pageInfo.Offset)) this.PageInfo.Offset=pageInfo.Offset;
if (IFrameSplitOperator.IsNumber(pageInfo.ShowDayCount)) this.PageInfo.ShowDayCount=pageInfo.ShowDayCount;
}
this.ClearMinuteData=function()
{
this.SourceData=null;
this.DayData=null;
this.BeforeOpenData=null;
this.AfterCloseData=null;
this.MultiDayBeforeOpenData=null;
this.MultiDayAfterCloseData=null;
}
this.ChangeDayCount=function(count, option)
{
if (count<0) return;
this.StopDisplayLatest();
this.CancelAutoUpdate();
this.AutoUpdateEvent(false, "MinuteChartContainer::ChangeDayCount");
this.DayCount=count;
this.ClearMinuteData();
if (option && option.PageInfo)
{
this.SetPageInfo(option.PageInfo);
this.ResetDayOffset();
}
this.ReloadChartDrawPicture();
this.ResetDataStatus();
this.ClearIndexPaint(); //清空指标
this.Frame.ClearYCoordinateMaxMin();
this.ResetOverlaySymbolStatus();
this.RequestData();
}
this.ChangeBaselineType=function(type)
{
if (this.BaselineType==type) return;
this.BaselineType=type;
if (this.DayCount>1) this.RequestData();
}
//[{ Symbol: , Color, Option: }]
this.OverlaySymbols=function(aryData, option)
{
if (option && option.ClearAll===true) //全部清空
{
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
item.IsDelete=true;
}
this.OverlayChartPaint=[];
}
var aryNewOverlay=[];
for(var i=0, j=0;i<aryData.length;++i) //去重,已经叠加过的不用在叠加
{
var overlayItem=aryData[i];
var strSymbol=overlayItem.Symbol;
var bFind=false;
for(j=0;j<this.OverlayChartPaint.length; ++j)
{
var item=this.OverlayChartPaint[j];
if (item.Symbol==strSymbol)
{
bFind=true;
console.warn(`[MinuteChartContainer::OverlaySymbols] overlay symbol=${strSymbol} exist.`);
break;
}
}
if (!bFind) aryNewOverlay.push(overlayItem);
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryNewOverlay)) return true;
for(var i=0;i<aryNewOverlay.length;++i)
{
var overlayItem=aryNewOverlay[i];
var strSymbol=overlayItem.Symbol;
var paint=new ChartOverlayMinutePriceLine();
paint.Canvas=this.Canvas;
paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
paint.ChartFrame=this.Frame.SubFrame[0].Frame;
paint.Name="Overlay-Minute";
paint.Symbol=strSymbol;
paint.Identify=`Overlay-Minute-${strSymbol}`;
if (overlayItem.Option && overlayItem.Option.Color) paint.Color=overlayItem.Option.Color; //外部设置颜色
else paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length];
++g_JSChartResource.OverlaySymbol.Random;
paint.MainData=this.SourceData; //绑定主图数据
if (paint.SetOption) paint.SetOption(overlayItem.Option);
this.OverlayChartPaint.push(paint);
}
if (this.DayCount<=1) this.RequestOverlayMinuteData(); //请求数据
else this.RequestOverlayHistoryMinuteData();
return true;
}
//叠加股票 symbol支持数据 ["600000.sh", "0000001.sz"]
this.OverlaySymbol=function(symbol,option)
{
var arySymbol=null;
if (IFrameSplitOperator.IsString(symbol)) arySymbol=[symbol];
else if (Array.isArray(symbol)) arySymbol=symbol;
if (!IFrameSplitOperator.IsNonEmptyArray(arySymbol)) return false;
var aryNewSymbol=[];
for(var i=0, j=0;i<arySymbol.length;++i)
{
var strSymbol=arySymbol[i];
var bFind=false;
for(j=0;j<this.OverlayChartPaint.length; ++j)
{
var item=this.OverlayChartPaint[j];
if (item.Symbol==strSymbol)
{
bFind=true;
console.warn(`[MinuteChartContainer::OverlaySymbol] overlay symbol=${strSymbol} exist.`);
break;
}
}
if (!bFind) aryNewSymbol.push(strSymbol);
}
if (!IFrameSplitOperator.IsNonEmptyArray(aryNewSymbol)) return true;
for(var i=0;i<aryNewSymbol.length;++i)
{
var strSymbol=aryNewSymbol[i];
var paint=new ChartOverlayMinutePriceLine();
paint.Canvas=this.Canvas;
paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
paint.ChartFrame=this.Frame.SubFrame[0].Frame;
paint.Name="Overlay-Minute";
paint.Symbol=strSymbol;
paint.Identify=`Overlay-Minute-${strSymbol}`;
if (option && option.Color) paint.Color=option.Color; //外部设置颜色
else paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length];
++g_JSChartResource.OverlaySymbol.Random;
paint.MainData=this.SourceData; //绑定主图数据
if (paint.SetOption) paint.SetOption(option);
this.OverlayChartPaint.push(paint);
}
if (this.DayCount<=1) this.RequestOverlayMinuteData(); //请求数据
else this.RequestOverlayHistoryMinuteData();
return true;
}
//删除一个叠加股票
this.DeleteOverlaySymbol=function(symbol)
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (item.Symbol===symbol)
{
item.IsDelete=true;
this.OverlayChartPaint.splice(i,1);
this.UpdateFrameMaxMin();
this.Draw();
return true;
}
}
console.warn(`[MinuteChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`)
return false;
}
//取消叠加股票
this.ClearOverlaySymbol=function()
{
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
item.IsDelete=true;
}
this.OverlayChartPaint=[];
this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.UpdateFrameMaxMin();
this.Draw();
}
this.ShowBeforeData=function(isShow, option)
{
this.ShowCallAuctionData({Left:isShow}, option);
}
//集合竞价设置 obj={ Left:, Right: }
this.ShowCallAuctionData=function(obj, option)
{
if (!obj) return;
var optionChanged=false; //配置修改
if (IFrameSplitOperator.IsBool(obj.Left) && this.IsShowBeforeData!=obj.Left)
{
this.IsShowBeforeData=obj.Left;
optionChanged=true;
}
if (IFrameSplitOperator.IsBool(obj.Right) && this.IsShowAfterData!=obj.Right)
{
this.IsShowAfterData=obj.Right;
optionChanged=true;
}
if (obj.MultiDay)
{
var item=obj.MultiDay;
if (IFrameSplitOperator.IsBool(item.Left) && this.IsShowMultiDayBeforeData!=item.Left)
{
this.IsShowMultiDayBeforeData=item.Left;
optionChanged=true;
}
if (IFrameSplitOperator.IsBool(item.Right) && this.IsShowMultiDayAfterData!=item.Right)
{
this.IsShowMultiDayAfterData=item.Right;
optionChanged=true;
}
}
if (option)
{
if (option.BeforeOpen)
{
var item=option.BeforeOpen;
if (IFrameSplitOperator.IsNumber(item.Left) && this.ExtendWidth.Left!=item.Left)
{
this.ExtendWidth.Left=item.Left;
optionChanged=true;
}
}
if (option.AfterClose)
{
var item=option.AfterClose;
if (IFrameSplitOperator.IsNumber(item.Right) && this.ExtendWidth.Right!=item.Right)
{
this.ExtendWidth.Right=item.Right;
optionChanged=true;
}
}
if (option.MultiDay)
{
var item=option.MultiDay;
if (IFrameSplitOperator.IsNumber(item.Left) && this.MultiDayExtendWidth.Left!=item.Left)
{
this.MultiDayExtendWidth.Left=item.Left;
optionChanged=true;
}
if (IFrameSplitOperator.IsNumber(item.Right)&& this.MultiDayExtendWidth.Right!=item.Right)
{
this.MultiDayExtendWidth.Right=item.Right;
optionChanged=true;
}
}
}
if (optionChanged)
{
this.Frame.ClearYCoordinateMaxMin();
this.RequestData();
}
}
this.RequestData=function()
{
if (this.DayCount<=1) this.RequestMinuteData();
else this.RequestHistoryMinuteData();
}
this.ChangeDrawType=function(type)
{
if (this.ChartPaint.length<=0) return;
if (type==0) this.ChartPaint[0].IsDrawArea=true;
else if (type==1) this.ChartPaint[0].IsDrawArea=false;
else return;
this.Draw();
}
this.UpdateDataOffset=function()
{
this.SourceData.DataOffset=this.DayOffset.DataOffset;
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item =this.ChartPaint[i];
if (!item.Data) continue;
item.Data.DataOffset=this.DayOffset.DataOffset;
if (item.ClassName=="ChartMinuteVolumBar" || item.ClassName=="ChartMinutePriceLine")
item.DayOffset=this.DayOffset;
}
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item =this.OverlayChartPaint[i];
if (!item.Data) continue;
item.Data.DataOffset=this.DayOffset.DataOffset;
}
//叠加指标当前显示的数据偏移
for (var i=0; i<this.Frame.SubFrame.length; ++i)
{
var subFrame=this.Frame.SubFrame[i];
for(var j=0; j<subFrame.OverlayIndex.length; ++j)
{
var overlayItem=subFrame.OverlayIndex[j];
for(var k=0; k<overlayItem.ChartPaint.length; ++k)
{
var item=overlayItem.ChartPaint[k];
if (!item.Data) continue;
item.Data.DataOffset=this.DayOffset.DataOffset;
}
}
}
}
//请求历史分钟数据
this.RequestHistoryMinuteData=function()
{
var self=this;
this.IsBeforeData=false;
this.IsAfterData=false;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.Draw();
if (this.NetworkFilter)
{
var callCation=
{
Before:this.IsShowMultiDayBeforeData ,
After:this.IsShowMultiDayAfterData
} //集合竞价
var obj=
{
Name:'MinuteChartContainer::RequestHistoryMinuteData', //类名::函数
Explain:'多日分时数据',
Request:{ Url:self.HistoryMinuteApiUrl, Data:{daycount:self.DayCount, symbol:self.Symbol, callcation:callCation }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryMinuteData(data);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:
{
"symbol": self.Symbol,
"daycount": self.DayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryMinuteData(data);
}
});
}
this.RecvHistoryMinuteData=function(data)
{
if (this.EnableVerifyRecvData && data.symbol!=this.Symbol)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvHistoryMinuteData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.symbol}]`);
return;
}
this.DayData=MinuteChartContainer.JsonDataToMinuteDataArray(data);
this.ColorLineData=MinuteChartContainer.JsonDataToHistoryMinuteLineColorData(data);
this.MultiDayBeforeOpenData=MinuteChartContainer.JosnDataToBeforeOpenDataArray(data);
this.MultiDayAfterCloseData=MinuteChartContainer.JosnDataToAfterCloseDataArray(data);
var updateTime=MinuteChartContainer.JsonDataToHistoryMinuteLastUpdateTime(data);
this.DataStatus.MultiDay=true;
this.CaclutateCallCationYRange();
this.Symbol=data.symbol;
this.Name=data.name;
this.SetCallCationDataBorder(
{
Left:false, Right:false,
MultiDay:{ Left:this.IsShowMultiDayBeforeData, Right:this.IsShowMultiDayAfterData }
} );
this.CaclutateLimitPrice(this.DayData[0].YClose, data.data[0].limitprice); //计算涨停价格
this.UpdateHistoryMinuteUI(updateTime);
this.RecvMinuteDataEvent( {FunctionName:"RecvHistoryMinuteData"} );
this.RequestOverlayHistoryMinuteData();
this.BindAllOverlayIndexData(this.SourceData);
this.AutoUpdateEvent(true, "MinuteChartContainer::RequestHistoryMinuteData");
this.AutoUpdate();
}
this.CaclutateCallCationYRange=function()
{
//多日集合竞价Y轴统一成交量
var afterRange=null, beforeRange=null;
if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
{
var range={ Max:null, Min:null };
for(var i=0; i<this.MultiDayAfterCloseData.length; ++i)
{
var item=this.MultiDayAfterCloseData[i];
if (range.Max==null) range.Max=item.VolMax;
else if (range.Max<item.VolMax) range.Max=item.VolMax;
if (range.Min==null) range.Min=item.VolMin;
else if (range.Min>item.VolMin) range.Min=item.VolMin;
}
afterRange=range;
}
if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
{
var range={ Max:null, Min:null };
for(var i=0; i<this.MultiDayBeforeOpenData.length; ++i)
{
var item=this.MultiDayBeforeOpenData[i];
if (range.Max==null) range.Max=item.VolMax;
else if (range.Max<item.VolMax) range.Max=item.VolMax;
if (range.Min==null) range.Min=item.VolMin;
else if (range.Min>item.VolMin) range.Min=item.VolMin;
}
beforeRange=range;
}
if (this.ShareAfterVol==2) // 公用坐标
{
if (afterRange && beforeRange)
{
var max=Math.max(afterRange.Max, beforeRange.Max);
var min=Math.min(afterRange.Min, beforeRange.Min);
afterRange.Max=beforeRange.Max=max;
afterRange.Min=beforeRange.Min=min;
}
}
if (afterRange)
{
for(var i=0; i<this.MultiDayAfterCloseData.length; ++i)
{
var item=this.MultiDayAfterCloseData[i];
item.VolMax=afterRange.Max;
item.VolMin=afterRange.Min;
}
}
if (beforeRange)
{
for(var i=0; i<this.MultiDayBeforeOpenData.length; ++i)
{
var item=this.MultiDayBeforeOpenData[i];
item.VolMax=beforeRange.Max;
item.VolMin=beforeRange.Min;
}
}
}
this.UpdateHistoryMinuteUI=function(updateTime)
{
var allMinuteData=this.HistoryMinuteDataToArray(this.DayData);
//原始数据
var sourceData=new ChartData();
sourceData.Data=allMinuteData;
if (updateTime) sourceData.UpdateTime=updateTime;
this.SourceData=sourceData;
this.TradeDate=this.DayData[0].Date;
if (this.PageInfo && this.PageInfo.Enable)
{
this.DayOffset.DayCount=this.DayData.length; //一共的数据
if (this.DayOffset.ShowDayCount==-1) this.DayOffset.ShowDayCount=this.DayData.length; //全部显示
if (this.DayOffset.Offset==-8888) this.DayOffset.Offset=this.DayOffset.DayCount-this.DayOffset.ShowDayCount; //最后一页
var showDayCount=this.DayOffset.ShowDayCount;
this.Frame.SetDayCount(showDayCount);
}
else
{
this.DayOffset.Offset=0;
this.DayOffset.ShowDayCount=this.DayData.length;
var showDayCount=this.DayOffset.ShowDayCount;
this.Frame.SetDayCount(this.DayData.length);
}
var upperSymbol=this.Symbol.toUpperCase();
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
var dayItem=this.DayData[0]; //最新
if (this.BaselineType===1) dayItem=this.DayData[this.DayData.length-1]; //多日前
var yClose=dayItem.YClose;
if (IFrameSplitOperator.IsNumber(dayItem.YClearing) && isFutures) yClose=dayItem.YClearing; //期货使用前结算价
this.BindMainData(sourceData,yClose);
//外汇 均线暂时不用
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) this.ChartPaint[1].Data=null;
for(let i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
item.Frame.XSplitOperator.Symbol=this.Symbol;
item.Frame.XSplitOperator.DayCount=showDayCount;
item.Frame.XSplitOperator.DayData=this.DayData;
item.Frame.XSplitOperator.Operator(); //调整X轴个数
item.Frame.XSplitOperator.IsBeforeData=this.IsBeforeData;
item.Frame.XSplitOperator.IsAfterData=this.IsAfterData;
item.Frame.YSplitOperator.Symbol=this.Symbol;
item.Frame.YSplitOperator.IsBeforeData=this.IsBeforeData;
item.Frame.YSplitOperator.IsAfterData=this.IsAfterData;
for(var j in item.OverlayIndex) //子坐标X轴个数同步
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.MinuteCount=item.Frame.MinuteCount;
}
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.IsBeforeData=this.IsBeforeData;
this.ChartCorssCursor.StringFormatX.IsAfterData=this.IsAfterData;
this.TitlePaint[0].IsShowDate=true;
this.UpdateDataOffset();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.CreateChartDrawPictureByStorage(); //创建画图工具
//执行脚本
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=allMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
this.Frame.SetSizeChage(true);
this.Draw();
}
this.HistoryMinuteDataToArray=function(data)
{
var result=[];
for(var i=data.length-1; i>=0;--i)
{
var item=data[i];
for(var j=0; j<item.Data.length; ++j)
{
result.push(item.Data[j]);
}
}
return result;
}
//更新一天的数据
this.UpdateLatestMinuteData=function(data,date, stock)
{
if (!this.DayData) return;
for(var i=0; i<this.DayData.length; ++i)
{
var item=this.DayData[i];
if (item.Date===date)
{
item.Data=data; //整一天的数据都替换掉
if (stock && IFrameSplitOperator.IsNumber(stock.yclose)) item.YClose=stock.yclose;
if (stock && IFrameSplitOperator.IsNumber(stock.yclearing)) item.YClearing=stock.yclearing;
return;
}
}
if (this.DayData.length>0)
{
if (this.DayData[0].Date<date) //新的一天 插入
{
var dayItem=new ChartData();
dayItem.Date=date;
dayItem.Data=data;
if (stock && IFrameSplitOperator.IsNumber(stock.yclose)) dayItem.YClose=stock.yclose;
if (stock && IFrameSplitOperator.IsNumber(stock.yclearing)) dayItem.YClearing=stock.yclearing;
this.DayData.unshift(dayItem);
}
}
}
//更新最新的几条数据
this.UpdateLatestMinuteDataV2=function(minuteData)
{
if (this.DayCount>1)
{
if (!this.DayData) return;
var findItem=null;
for(var i=0; i<this.DayData.length; ++i)
{
var item=this.DayData[i];
if (item.Date===date)
{
findItem=item;
break;
}
}
if (!findItem) return;
var findIndex=-1;
var firstItem=minuteData.Data[0];
for(var i=0;i<findItem.Data.length;++i)
{
var item=findItem.Data[i];
if (item.Date==firstItem.Date && item.Time==firstItem.Time)
{
findIndex=i;
break;
}
}
if (findIndex<0) findIndex=findItem.Data.length;
for(var i=0, j=findIndex; i<minuteData.Data.length; ++i, ++j)
{
var item=minuteData.Data[i];
findItem.Data[j]=item;
}
}
else
{
if (!this.SourceData) return;
var findIndex=-1;
var firstItem=minuteData.Data[0];
for(var i=0;i<this.SourceData.Data.length;++i)
{
var item=this.SourceData.Data[i];
if (item.Date==firstItem.Date && item.Time==firstItem.Time)
{
findIndex=i;
break;
}
}
if (findIndex<0) findIndex=this.SourceData.Data.length;
for(var i=0, j=findIndex; i<minuteData.Data.length; ++i, ++j)
{
var item=minuteData.Data[i];
this.SourceData.Data[j]=item;
}
}
}
//请求分钟数据
this.RequestMinuteData=function()
{
var self=this;
var fields=
[
"name","symbol",
"yclose","open","price","high","low",
"vol","amount",
"date","time",
"minute","minutecount"
];
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol))
{ //期货的需要加上结算价
fields.push("clearing");
fields.push("yclearing");
}
// 盘前数据(A股)
this.IsBeforeData=false;
if (this.IsShowBeforeData && this.DayCount===1 && MARKET_SUFFIX_NAME.IsSHSZStockA(self.Symbol))
{
this.IsBeforeData=true;
fields.push('before');
}
this.IsAfterData=false;
if (this.IsShowAfterData && this.DayCount===1 && MARKET_SUFFIX_NAME.IsSHSZStockA(self.Symbol))
{
this.IsAfterData=true;
}
if (this.NetworkFilter)
{
var dateRange=null;
if (this.DayCount>1)
{
if (IFrameSplitOperator.IsNonEmptyArray(this.DayData))
{
var dayData=this.DayData[0];
dateRange=dayData.GetDateRange();
}
}
else
{
if (this.SourceData)
dateRange=this.SourceData.GetDateRange();
}
var callCation={ Before:this.IsShowBeforeData, After:this.IsShowAfterData } //集合竞价
if (this.DayCount>1) callCation={ Before:this.IsShowMultiDayBeforeData, After:this.IsShowMultiDayAfterData } //多日集合竞价
var obj=
{
Name:'MinuteChartContainer::RequestMinuteData', //类名::函数名
Explain:'最新分时数据',
Request:{ Url:self.MinuteApiUrl, Data:{field:fields, symbol:[self.Symbol], callcation:callCation }, Type:'POST' },
Self:this,
PreventDefault:false
};
if (dateRange) obj.DateRange=dateRange; //本地数据日期范围
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvMinuteData(data);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.MinuteApiUrl,
data:
{
"field": fields,
"symbol": [self.Symbol],
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvMinuteData(data);
}
});
}
this.RecvMinuteDataEvent=function(option)
{
if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_MINUTE_DATA)) return;
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_MINUTE_DATA);
var data={ MinuteData:this.SourceData, Stock:{ Symbol:this.Symbol, Name:this.Name }, Option:option, DataStatus:this.DataStatus };
event.Callback(event,data,this);
}
this.UpdateLineColorData=function(data, date)
{
if (!this.ColorLineData)
{
this.ColorLineData=data;
return;
}
//移除当前的
var aryColorLineData=this.ColorLineData.filter(function(item, index, arr)
{
return item.Date!=date;
});
if (IFrameSplitOperator.IsNonEmptyArray(data))
{
for(var i in data)
{
aryColorLineData.push(data[i]);
}
}
this.ColorLineData=aryColorLineData;
}
this.UpdateCallCationData=function(beforeOpenData,afterCloseData)
{
if (beforeOpenData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
{
var lastItem=this.MultiDayBeforeOpenData[this.MultiDayBeforeOpenData.length-1];
if (lastItem.Date==beforeOpenData.Date) //存在更新
this.MultiDayBeforeOpenData[this.MultiDayBeforeOpenData.length-1]=beforeOpenData;
else if (lastItem.Date<beforeOpenData.Date) //新的一天插入
this.MultiDayBeforeOpenData.push(beforeOpenData);
}
if (afterCloseData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
{
var lastItem=this.MultiDayAfterCloseData[this.MultiDayAfterCloseData.length-1];
if (lastItem.Date==afterCloseData.Date)
this.MultiDayAfterCloseData[this.MultiDayAfterCloseData.length-1]=afterCloseData;
else if (lastItem.Date<afterCloseData.Date)
this.MultiDayAfterCloseData.push(afterCloseData);
}
this.CaclutateCallCationYRange();
}
this.RecvUpdateMinuteData=function(data)
{
var minuteData=MinuteChartContainer.JsonDataToUpdateMinuteData(data);
var aryColorData=MinuteChartContainer.JsonDataToMinuteLineColorData(data);
this.BeforeOpenData=null;
this.AfterCloseData=null;
var beforeOpenData=MinuteChartContainer.JsonDataToBeforeOpenData(data);
var afterCloseData=MinuteChartContainer.JsonDataToAfterCloseData(data);
var updateTime=MinuteChartContainer.JsonDataToMinuteLastUpdateTime(data); //数据最后的更新时间
if (this.DayCount>1) //多日走势图
{
this.UpdateCallCationData(beforeOpenData,afterCloseData);
this.UpdateLineColorData(aryColorData,minuteData.date);
this.UpdateLatestMinuteDataV2(minuteData);
this.UpdateHistoryMinuteUI(updateTime);
this.RecvMinuteDataEvent({FunctionName:"RecvUpdateMinuteData"} );
this.RequestOverlayMinuteData(); //请求叠加数据 (主数据下载完再下载)
this.BindAllOverlayIndexData(this.SourceData);
this.AutoUpdateEvent(true, "MinuteChartContainer::RecvUpdateMinuteData");
this.AutoUpdate();
return;
}
//原始数据
this.UpdateLatestMinuteDataV2(minuteData);
var sourceData=this.SourceData;
var aryMinuteData=this.SourceData.Data;
this.ColorLineData=aryColorData;
this.TradeDate=data.stock[0].date;
this.Frame.SetDayCount(1); //单日数据
this.SourceData.UpdateTime=updateTime;
this.Symbol=minuteData.Symbol;
this.Name=minuteData.Name;
this.SetCallCationDataBorder( { Left:this.IsBeforeData, Right:this.IsAfterData , MultiDay:{ Left:false, Right:false }} );
if (this.ShareAfterVol==2) //盘前, 盘后成交量公用坐标
{
if (this.BeforeOpenData && this.AfterCloseData)
{
var max=Math.max(this.BeforeOpenData.VolMax, this.AfterCloseData.VolMax);
var min=Math.min(this.BeforeOpenData.VolMin, this.AfterCloseData.VolMin);
this.BeforeOpenData.VolMax=this.AfterCloseData.VolMax=max;
this.BeforeOpenData.VolMin=this.AfterCloseData.VolMin=min;
}
}
var yClose=minuteData.YClose;
var upperSymbol=this.Symbol.toUpperCase();
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
if (minuteData.YClearing>0 && isFutures) yClose=minuteData.YClearing; //期货使用前结算价
this.CaclutateLimitPrice(yClose, minuteData.LimitPrice); //计算涨停价格
var extendData=null;
if (minuteData.High>0 && minuteData.Low>0) extendData={ High:minuteData.High, Low:minuteData.Low };
this.BindMainData(sourceData,yClose, extendData);
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=aryMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
for(let i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
item.Frame.XSplitOperator.Symbol=this.Symbol;
item.Frame.XSplitOperator.DayCount=1;
item.Frame.XSplitOperator.Operator(); //调整X轴个数
item.Frame.YSplitOperator.Symbol=this.Symbol;
if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
{
for(var j=0;j<item.OverlayIndex.length; ++j) //子坐标X轴个数同步
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.MinuteCount=item.Frame.MinuteCount;
}
}
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.Symbol=this.Symbol;
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) this.TitlePaint[0].IsShowDate=false;
if (data.stock[0].IsHistoryMinute==true) this.TitlePaint[0].IsShowDate=true;
var chartInfo=this.GetChartMinuteInfo();
if (chartInfo) chartInfo.SourceData=this.SourceData; //数据绑定到信息地雷上
this.RecvMinuteDataEvent( {FunctionName:"RecvUpdateMinuteData"} );
this.RequestMinuteInfoData();
this.RequestOverlayMinuteData();//请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.BindAllOverlayIndexData(this.SourceData);
this.AutoUpdateEvent(true, "MinuteChartContainer::RecvUpdateMinuteData");
this.AutoUpdate();
}
this.RecvMinuteData=function(data)
{
if (!data)
{
JSConsole.Chart.Warn("[MinuteChartContainer::RecvMinuteData] recv data is null");
return;
}
if (data.dataType==1) //增量更新数据模式
{
this.RecvUpdateMinuteData(data);
return;
}
if (!data.stock[0]) return;
if (data.stock[0].symbol!=this.Symbol && this.EnableVerifyRecvData)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvMinuteData] recv data symbol not match. HQChart[${this.Symbol}] , Recv[${data.stock[0].symbol}]`);
return;
}
var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData(data);
var aryColorData=MinuteChartContainer.JsonDataToMinuteLineColorData(data);
this.BeforeOpenData=null;
this.AfterCloseData=null;
var beforeOpenData=MinuteChartContainer.JsonDataToBeforeOpenData(data);
var afterCloseData=MinuteChartContainer.JsonDataToAfterCloseData(data);
var updateTime=MinuteChartContainer.JsonDataToMinuteLastUpdateTime(data); //数据最后的更新时间
if (this.IsBeforeData) this.BeforeOpenData=beforeOpenData;
if (this.IsAfterData) this.AfterCloseData=afterCloseData;
var bFirstData=(this.DataStatus.LatestDay==false); //首条单日数据
this.DataStatus.LatestDate=data.stock[0].date; //保存下最后一天的日期
this.DataStatus.LatestDay=true;
if (this.DayCount>1) //多日走势图
{
this.UpdateCallCationData(beforeOpenData,afterCloseData);
this.UpdateLineColorData(aryColorData,data.stock[0].date);
this.UpdateLatestMinuteData(aryMinuteData, data.stock[0].date, data.stock[0]);
this.UpdateHistoryMinuteUI(updateTime);
this.RecvMinuteDataEvent({FunctionName:"RecvMinuteData"} );
this.RequestOverlayMinuteData(); //请求叠加数据 (主数据下载完再下载)
this.BindAllOverlayIndexData(this.SourceData);
this.AutoUpdateEvent(true, "MinuteChartContainer::RecvMinuteData");
this.AutoUpdate();
return;
}
if (this.IsOnTouch==true) //正在操作中不更新数据
{
if (this.SourceData && IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
{
this.AutoUpdate();
return;
}
}
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryMinuteData;
sourceData.UpdateTime=updateTime;
this.ColorLineData=aryColorData;
this.TradeDate=data.stock[0].date;
this.Frame.SetDayCount(1); //单日数据
this.SourceData=sourceData;
this.Symbol=data.stock[0].symbol;
this.Name=data.stock[0].name;
this.SetCallCationDataBorder( { Left:this.IsBeforeData, Right:this.IsAfterData , MultiDay:{ Left:false, Right:false }} );
if (this.ShareAfterVol==2) //盘前, 盘后成交量公用坐标
{
if (this.BeforeOpenData && this.AfterCloseData)
{
var max=Math.max(this.BeforeOpenData.VolMax, this.AfterCloseData.VolMax);
var min=Math.min(this.BeforeOpenData.VolMin, this.AfterCloseData.VolMin);
this.BeforeOpenData.VolMax=this.AfterCloseData.VolMax=max;
this.BeforeOpenData.VolMin=this.AfterCloseData.VolMin=min;
}
}
var yClose=data.stock[0].yclose;
var upperSymbol=this.Symbol.toUpperCase();
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
if (data.stock[0].yclearing>0 && isFutures) yClose=data.stock[0].yclearing; //期货使用前结算价
this.CaclutateLimitPrice(yClose, data.stock[0].limitprice); //计算涨停价格
var extendData=null;
if (data.stock[0].high>0 && data.stock[0].low>0) extendData={ High:data.stock[0].high, Low:data.stock[0].low };
this.BindMainData(sourceData,yClose, extendData);
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=aryMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
for(let i in this.Frame.SubFrame)
{
var item=this.Frame.SubFrame[i];
item.Frame.XSplitOperator.Symbol=this.Symbol;
item.Frame.XSplitOperator.DayCount=1;
item.Frame.XSplitOperator.Operator(); //调整X轴个数
item.Frame.YSplitOperator.Symbol=this.Symbol;
for(var j in item.OverlayIndex) //子坐标X轴个数同步
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.MinuteCount=item.Frame.MinuteCount;
}
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.Symbol=this.Symbol;
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) this.TitlePaint[0].IsShowDate=false;
if (data.stock[0].IsHistoryMinute==true) this.TitlePaint[0].IsShowDate=true;
var chartInfo=this.GetChartMinuteInfo();
if (chartInfo) chartInfo.SourceData=this.SourceData; //数据绑定到信息地雷上
this.RecvMinuteDataEvent( {FunctionName:"RecvMinuteData", Day:{ IsFirstData:bFirstData} } );
this.RequestMinuteInfoData();
this.RequestOverlayMinuteData();//请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.BindAllOverlayIndexData(this.SourceData);
if (data.AutoUpdate===false) //不执行自动更新
{
}
else
{
this.AutoUpdateEvent(true, "MinuteChartContainer::RecvMinuteData");
this.AutoUpdate();
}
}
this.CaclutateLimitPrice=function(yClose, limitData)
{
this.LimitPrice=null;
//var limitData=data.stock[0].limitprice;
if (limitData && limitData.max>0 && limitData.min>0) //API里带涨停价格 直接使用
{
this.LimitPrice={ Max:limitData.max, Min:limitData.min };
return;
}
var range=MARKET_SUFFIX_NAME.GetLimitPriceRange(this.Symbol, this.Name); //通过规则获取涨停价格
if (!range)
{
JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} no limit price.`)
return;
}
//var yClose=data.stock[0].yclose;
if (yClose<=0) return;
this.LimitPrice={ Max:yClose*(1+range.Max), Min:yClose*(1+range.Min) };
JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} yClose:${yClose} max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`);
this.LimitPrice.Max=parseFloat(this.LimitPrice.Max.toFixed(2));
this.LimitPrice.Min=parseFloat(this.LimitPrice.Min.toFixed(2));
JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} tofixed(2) max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`);
}
this.RequestSingleOverlayMinuteData=function(symbol, date, item)
{
var self = this;
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'MinuteChartContainer::RequestOverlayMinuteData', //类名::函数名
Explain:'叠加股票最新分时数据',
Request:{ Url:this.HistoryMinuteApiUrl, Data:{days:[date], symbol:symbol}, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayMinuteData(data,item);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//请求数据
JSNetwork.HttpRequest({
url: this.HistoryMinuteApiUrl,
data:
{
"symbol":symbol,
"days": [date],
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
//self.RecvMultiOverlayMinuteData([data]);
self.RecvOverlayMinuteData(data,item);
}
});
}
//请求叠加数据 (主数据下载完再下载))
this.RequestOverlayMinuteData=function()
{
var self = this;
var date=this.TradeDate; //最后一个交易日期
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
let item=this.OverlayChartPaint[i];
if (!item.MainData) continue;
if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue;
var symbol=item.Symbol;
if (!symbol) continue;
this.RequestSingleOverlayMinuteData(symbol, date, item);
/*
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'MinuteChartContainer::RequestOverlayMinuteData', //类名::函数名
Explain:'叠加股票最新分时数据',
Request:{ Url:self.HistoryMinuteApiUrl, Data:{days:[date], symbol:symbol}, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayMinuteData(data,item);
});
if (obj.PreventDefault==true) continue; //已被上层替换,不调用默认的网络请求
}
//请求数据
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:
{
"symbol":symbol,
"days": [date],
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
//self.RecvMultiOverlayMinuteData([data]);
self.RecvOverlayMinuteData(data,item);
}
});
*/
}
}
//一次接收多个叠加品种
this.RecvMultiOverlayMinuteData=function(aryData)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryData)) return;
var bUpdate=false;
for(var i=0;i<aryData.length; ++i)
{
var overlayData=aryData[i];
if (!overlayData.symbol) continue;
for(var j=0; j<this.OverlayChartPaint.length; ++j)
{
var item=this.OverlayChartPaint[j];
if (!item.MainData) continue;
if (overlayData.symbol==item.Symbol)
{
this.RecvOverlayMinuteData(overlayData, item, { Redraw:false });
bUpdate=true;
break;
}
}
}
if (bUpdate)
{
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
}
this.RecvOverlayMinuteData=function(data,paint,option)
{
if (paint.IsDelete) return;
if (this.EnableVerifyRecvData && data.symbol!=paint.Symbol)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvOverlayMinuteData] recv data symbol not match. paint[${paint.Symbol}] , Recv[${data.symbol}]`);
return;
}
var aryMinuteData=MinuteChartContainer.JsonDataToMinuteDataArray(data);
var sourceData=null;
var yClose;
if (this.DayCount>1) //多日数据
{
if (aryMinuteData.length<=0) return;
var minuteData=aryMinuteData[0];
for(var i in paint.SourceData)
{
var item=paint.SourceData[i];
if (item.Date==minuteData.Date)
{
paint.SourceData[i]=minuteData;
var allMinuteData=this.HistoryMinuteDataToArray(paint.SourceData);
var sourceData=new ChartData();
sourceData.Data=allMinuteData;
yClose=minuteData.YClose;
break;
}
}
if (sourceData==null) return;
}
else
{
if (aryMinuteData.length>0) sourceData=aryMinuteData[0];
else sourceData=new ChartData();
yClose=sourceData.YClose;
}
paint.Data=sourceData;
paint.Title=data.name;
paint.Symbol=data.symbol;
paint.YClose=yClose;
paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID;
var bRedraw=true;
if (option && option.Redraw==false) bRedraw=false;
if (bRedraw)
{
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
}
this.RequestSingleOverlayHistoryMinuteData=function(symbol, days, item)
{
var self = this;
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'MinuteChartContainer::RequestOverlayHistoryMinuteData', //类名::函数名
Explain:'叠加股票多日分时数据',
Request:{ Url:self.HistoryMinuteApiUrl, Data:{days:days, symbol:symbol}, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayHistoryMinuteData(data,item);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:{ "symbol": symbol, "days": days },
type:"post",
dataType: "json",
async:true,
success: function (data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayHistoryMinuteData(data,item);
}
});
}
this.RequestOverlayHistoryMinuteData=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.DayData)) return;
var self = this;
var days=[];
for(var i=0; i<this.DayData.length; ++i)
{
var item=this.DayData[i];
days.push(item.Date);
}
if (days.length<=0) return;
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i]
var symbol=item.Symbol;
if (!symbol) continue;
if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue;
this.RequestSingleOverlayHistoryMinuteData(symbol, days, item);
/*
item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID;
if (this.NetworkFilter)
{
var obj=
{
Name:'MinuteChartContainer::RequestOverlayHistoryMinuteData', //类名::函数名
Explain:'叠加股票多日分时数据',
Request:{ Url:self.HistoryMinuteApiUrl, Data:{days:days, symbol:symbol}, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayHistoryMinuteData(data,item);
});
if (obj.PreventDefault==true) continue; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:{ "symbol": symbol, "days": days },
type:"post",
dataType: "json",
async:true,
success: function (data)
{
item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID;
self.RecvOverlayHistoryMinuteData(data,item);
}
});
*/
}
}
this.RecvOverlayHistoryMinuteData=function(data,paint) //叠加历史的分钟数据
{
if (this.EnableVerifyRecvData && data.symbol!=paint.Symbol)
{
JSConsole.Chart.Warn(`[MinuteChartContainer::RecvOverlayHistoryMinuteData] recv data symbol not match. paint[${paint.Symbol}] , Recv[${data.symbol}]`);
return;
}
if (!IFrameSplitOperator.IsNonEmptyArray(this.DayData)) return;
var dayData=MinuteChartContainer.JsonDataToMinuteDataArray(data);
if (!IFrameSplitOperator.IsNonEmptyArray(dayData)) return;
var overlayDayData=[];
for(var i=0; i<this.DayData.length; ++i)
{
var item=this.DayData[i];
var bFind=false;
for(var j=0; j<dayData.length; ++j)
{
if (item.Date==dayData[j].Date)
{
overlayDayData.push(dayData[j]);
bFind=true;
break;
}
}
if (!bFind) //当天不存在叠加数据, 存空
{
var empytData=new ChartData();
empytData.Date=item.Date;
empytData.Data.length=item.Data.length;
overlayDayData.push(empytData);
}
}
paint.SourceData=overlayDayData;
var allMinuteData=this.HistoryMinuteDataToArray(overlayDayData);
var yClose=overlayDayData[0].YClose; //取最近一个交易日前收盘最为中轴线
//原始数据
var sourceData=new ChartData();
sourceData.Data=allMinuteData;
paint.Data=sourceData;
paint.Title=data.name;
paint.Symbol=data.symbol;
paint.YClose=yClose;
paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID;
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.CancelAutoUpdate=function() //关闭停止更新
{
if (typeof (this.AutoUpdateTimer) == 'number')
{
clearTimeout(this.AutoUpdateTimer);
this.AutoUpdateTimer = undefined;
}
}
//数据自动更新
this.AutoUpdate=function()
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
if (!this.Symbol) return;
var self = this;
var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol);
if (marketStatus==0 || marketStatus==3) //闭市,盘后
{ //等待开盘
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},20000);
return;
}
var frequency=this.AutoUpdateFrequency;
if (marketStatus==1) //盘前
{
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},frequency);
}
else if (marketStatus==2) //盘中
{
this.AutoUpdateTimer=setTimeout(function()
{
self.ResetOverlaySymbolStatus();
self.RequestMinuteData();
},frequency);
}
}
this.BindIndexData=function(windowIndex, hisData, option)
{
if (!this.WindowIndex[windowIndex]) return;
if (typeof(this.WindowIndex[windowIndex].RequestData)=="function") //数据需要另外下载的.
{
this.WindowIndex[windowIndex].RequestData(this,windowIndex,hisData);
return;
}
if (typeof(this.WindowIndex[windowIndex].ExecuteScript)=='function')
{
this.WindowIndex[windowIndex].ExecuteScript(this,windowIndex,hisData);
return;
}
this.WindowIndex[windowIndex].BindData(this,windowIndex,hisData);
}
//绑定分钟数据
this.BindMainData=function(minuteData,yClose, extendData)
{
var multiBeforeOpenData=this.IsShowMultiDayBeforeData?this.MultiDayBeforeOpenData:null;
var multiAfterCloseData=this.IsShowMultiDayAfterData?this.MultiDayAfterCloseData:null;
//分钟数据
var bindData=new ChartData();
bindData.Data=minuteData.GetClose();
this.ChartPaint[0].Data=bindData;
this.ChartPaint[0].YClose=yClose;
this.ChartPaint[0].NotSupportMessage=null;
this.ChartPaint[0].IsShowLead=false;
this.ChartPaint[0].LeadData=null;
this.ChartPaint[0].BeforeOpenData=this.BeforeOpenData;
this.ChartPaint[0].AfterCloseData=this.AfterCloseData;
this.ChartPaint[0].MultiDayBeforeOpenData=multiBeforeOpenData;
this.ChartPaint[0].MultiDayAfterCloseData=multiAfterCloseData;
this.ChartPaint[0].ColorLineData=this.ColorLineData; //自定义分段颜色
this.ChartPaint[0].Source=minuteData;
if (MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol) && this.DayCount==1 && this.IsShowLead) //指数显示领先指标
{
var bindLeadData=new ChartData();
bindLeadData.Data=minuteData.GetLead();
this.ChartPaint[0].LeadData=bindLeadData;
this.ChartPaint[0].IsShowLead=true;
}
var firstFrame=this.Frame.SubFrame[0].Frame;
firstFrame.YSplitOperator.YClose=yClose;
firstFrame.YSplitOperator.Data=bindData;
this.Frame.Data=this.ChartPaint[0].Data;
this.Frame.SourceData=minuteData;
for(var i in this.Frame.SubFrame)
{
var item=this.Frame.SubFrame[i].Frame;
item.Data=minuteData; //每个子窗口都绑定下数据
}
//均线
bindData=new ChartData();
bindData.Data=minuteData.GetMinuteAvPrice();
this.ChartPaint[1].Data=bindData;
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) //外汇没有均线
this.ChartPaint[1].Data=null;
else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) //外部控制是否显示均线
this.ChartPaint[1].Data=null;
firstFrame.YSplitOperator.AverageData=bindData; //均线
firstFrame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint;
firstFrame.YSplitOperator.LimitPrice=this.LimitPrice;
firstFrame.YSplitOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
firstFrame.YSplitOperator.MultiDayAfterCloseData=multiAfterCloseData;
firstFrame.YSplitOperator.DayCount=this.DayCount;
if (extendData)
{
firstFrame.YSplitOperator.High=extendData.High;
firstFrame.YSplitOperator.Low=extendData.Low;
}
else
{
firstFrame.YSplitOperator.High=null;
firstFrame.YSplitOperator.Low=null;
}
//成交量
this.ChartPaint[2].Data=minuteData;
this.ChartPaint[2].YClose=yClose;
this.ChartPaint[2].Symbol=this.Symbol;
this.ChartPaint[2].BeforeOpenData=this.BeforeOpenData;
this.ChartPaint[2].AfterCloseData=this.AfterCloseData;
this.ChartPaint[2].MultiDayBeforeOpenData=multiBeforeOpenData;
this.ChartPaint[2].MultiDayAfterCloseData=multiAfterCloseData;
for(var i in this.Frame.SubFrame)
{
var item=this.Frame.SubFrame[i];
item.Frame.YSplitOperator.BeforeOpenData=this.BeforeOpenData;
item.Frame.YSplitOperator.IsBeforeData=this.IsBeforeData;
item.Frame.YSplitOperator.AfterCloseData=this.AfterCloseData;
item.Frame.YSplitOperator.IsAfterData=this.IsAfterData;
item.Frame.YSplitOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
item.Frame.YSplitOperator.MultiDayAfterCloseData=multiAfterCloseData;
}
if(MARKET_SUFFIX_NAME.IsShowMinutePostionLine(upperSymbol))
this.BindOverlayPositionData(minuteData,yClose); //期货,期权 持仓量
else
this.ClearBindOverlayPositionData();
this.TitlePaint[0].Data=this.SourceData; //动态标题
this.TitlePaint[0].Symbol=this.Symbol;
this.TitlePaint[0].Name=this.Name;
this.TitlePaint[0].YClose=yClose;
this.TitlePaint[0].BeforeOpenData=this.BeforeOpenData;
this.TitlePaint[0].AfterCloseData=this.AfterCloseData;
this.TitlePaint[0].MultiDayBeforeOpenData=this.IsShowMultiDayBeforeData?this.MultiDayBeforeOpenData:null;
this.TitlePaint[0].MultiDayAfterCloseData=this.IsShowMultiDayAfterData?this.MultiDayAfterCloseData:null;
if (this.TitlePaint[0].CallAcutionXOperator)
{
this.TitlePaint[0].CallAcutionXOperator.BeforeOpenData=this.BeforeOpenData;
this.TitlePaint[0].CallAcutionXOperator.AfterCloseData=this.AfterCloseData;
this.TitlePaint[0].CallAcutionXOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
this.TitlePaint[0].CallAcutionXOperator.MultiDayAfterCloseData=multiAfterCloseData;
this.TitlePaint[0].CallAcutionXOperator.DayOffset=this.DayOffset;
}
if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY)
{
this.ChartCorssCursor.StringFormatY.YClose=yClose;
this.ChartCorssCursor.StringFormatY.BeforeOpenData=this.BeforeOpenData;
this.ChartCorssCursor.StringFormatY.AfterCloseData=this.AfterCloseData;
this.ChartCorssCursor.StringFormatY.MultiDayBeforeOpenData=multiBeforeOpenData;
this.ChartCorssCursor.StringFormatY.MultiDayAfterCloseData=multiAfterCloseData;
this.ChartCorssCursor.StringFormatY.DayOffset=this.DayOffset;
this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标
this.ChartCorssCursor.StringFormatX.BeforeOpenData=this.BeforeOpenData;
this.ChartCorssCursor.StringFormatX.AfterCloseData=this.AfterCloseData;
this.ChartCorssCursor.StringFormatX.MultiDayBeforeOpenData=multiBeforeOpenData;
this.ChartCorssCursor.StringFormatX.MultiDayAfterCloseData=multiAfterCloseData;
this.ChartCorssCursor.StringFormatX.DayOffset=this.DayOffset;;
if (this.ChartCorssCursor.CallAcutionXOperator)
{
this.ChartCorssCursor.CallAcutionXOperator.BeforeOpenData=this.BeforeOpenData;
this.ChartCorssCursor.CallAcutionXOperator.AfterCloseData=this.AfterCloseData;
this.ChartCorssCursor.CallAcutionXOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
this.ChartCorssCursor.CallAcutionXOperator.MultiDayAfterCloseData=multiAfterCloseData;
this.ChartCorssCursor.CallAcutionXOperator.DayOffset=this.DayOffset;
}
}
if (this.ExtendChartPaint[0])
{
this.ExtendChartPaint[0].Symbol=this.Symbol;
this.ExtendChartPaint[0].Name=this.Name;
}
for(var i=0; i<this.OverlayChartPaint.length; ++i)
{
var item=this.OverlayChartPaint[i];
item.MainData=minuteData; //绑定主图数据
}
}
//绑定分钟叠加指标数据(持仓量)
this.BindOverlayPositionData=function(minuteData,yClose)
{
if (this.Frame.SubFrame.length<2) return;
var chart=null;
var frame=null;
var subFrame=this.Frame.SubFrame[1]; //第2个窗口
var overlayFrame=null;
for(var i=0; i<subFrame.OverlayIndex.length; ++i)
{
var item=subFrame.OverlayIndex[i];
if (item.Identify=='Position_Line_Frame')
{
overlayFrame=item;
break;
}
}
if (!overlayFrame)
{
overlayFrame=new OverlayIndexItem();
overlayFrame.Identify='Position_Line_Frame';
if (this.ClassName=="MinuteChartContainer") frame=new OverlayMinuteFrame();
else frame=new OverlayMinuteHScreenFrame();
frame.Canvas=this.Canvas;
frame.MainFrame=subFrame.Frame;
frame.ChartBorder=subFrame.Frame.ChartBorder;
frame.GlobalOption=this.GlobalOption;
overlayFrame.Frame=frame;
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=frame.ChartBorder;
frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount;
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.YSplitOperator.OverlayIdentify=overlayFrame.Identify;
var chart=new ChartMinutePositionLine();
chart.Canvas=this.Canvas
chart.Name='Position-Line';
chart.ChartBorder=frame.ChartBorder;
chart.ChartFrame=frame
chart.Identify=overlayFrame.Identify;
chart.Color=g_JSChartResource.Minute.PositionColor;
overlayFrame.ChartPaint.push(chart);
subFrame.OverlayIndex.push(overlayFrame);
subFrame.Frame.RightFrame=frame; //右边坐标绑定到主坐标上
}
else
{
frame=overlayFrame.Frame;
for(var i=0;i<overlayFrame.ChartPaint.length;++i)
{
var item=overlayFrame.ChartPaint[i];
if (item.Name=='Position-Line')
{
chart=item;
break;
}
}
if (!chart) //图形不存在就创建一个
{
chart=new ChartMinutePositionLine();
chart.Canvas=this.Canvas
chart.Name='Position-Line';
chart.ChartBorder=frame.ChartBorder;
chart.ChartFrame=frame
chart.Identify=overlayFrame.Identify;
chart.Color=g_JSChartResource.Minute.PositionColor;
overlayFrame.ChartPaint.push(chart);
}
}
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
subFrame.Frame.IsShowPositionTitle=true;
var bindData=new ChartData();
bindData.Data=minuteData.GetPosition();
chart.Data=bindData;
}
this.ClearBindOverlayPositionData=function()
{
if (this.Frame.SubFrame.length<2) return;
var subFrame=this.Frame.SubFrame[1]; //第2个窗口
subFrame.Frame.RightFrame=null;
subFrame.Frame.IsShowPositionTitle=false;
for(var i in subFrame.OverlayIndex)
{
var item=subFrame.OverlayIndex[i];
if (item.Identify=='Position_Line_Frame')
{
subFrame.OverlayIndex.splice(i,1);
break;
}
}
}
this.GetOverlayIndexByIdentify=function(identify)
{
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
var item=this.Frame.SubFrame[i];
if (!IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex)) continue;
for(var j=0; j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
if (overlayItem.Identify===identify)
return { OverlayItem:overlayItem, WindowIndex:i };
}
}
return null;
}
this.RecvOverlayIndex=function(identify, data)
{
var overlayIndex=this.GetOverlayIndexByIdentify(identify);
if (overlayIndex==null)
{
console.warn(`[MinuteChartContainer::RecvOverlayIndex] can't find overlay index. [identify=${identify}]`);
return;
}
if (!overlayIndex.Script) return;
if (typeof(overlayIndex.RecvSubscribeData)!="function") return;
var bindData=this.SourceData;
if (!bindData) return;
overlayIndex.Script.RecvSubscribeData(data,this,overlayIndex.WindowIndex,bindData);
}
//更新叠加指标
this.UpdateOverlayIndex=function(identify)
{
var overlayIndex=this.GetOverlayIndexByIdentify(identify)
if (overlayIndex==null)
{
console.warn(`[MinuteChartContainer::UpdateOverlayIndex] can't find overlay index. [identify=${identify}]`);
return;
}
var bindData=this.SourceData;
if (!bindData) return;
this.BindOverlayIndexData(overlayIndex.OverlayItem, overlayIndex.WindowIndex, bindData);
}
//添加叠加指标
this.AddOverlayIndex=function(obj)
{
var overlay=this.CreateOverlayWindowsIndex(obj);
if (!overlay) return;
var bindData=this.SourceData;
this.BindOverlayIndexData(overlay,obj.WindowIndex,bindData);
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
//创建一个叠加指标
this.CreateOverlayWindowsIndex=function(obj) //{WindowIndex:, IndexName:, Identify:, ShowRightText:, API:}
{
let indexName=obj.IndexName;
let windowIndex=obj.WindowIndex;
var apiItem=null, indexInfo=null, indexCustom=null;
if (obj.API)
{
apiItem=obj.API;
}
else if (obj.Script) //动态执行脚本
{
indexInfo={ Script:obj.Script, ID:obj.indexName, Name:obj.indexName};
if (obj.Name) indexInfo.Name=obj.Name;
}
else
{
let scriptData = new JSIndexScript();
indexInfo = scriptData.Get(indexName); //系统指标
if (!indexInfo)
{
indexCustom=JSIndexMap.Get(indexName); //定制指标
if (!indexCustom)
{
console.warn(`[MinuteChartContainer::CreateOverlayIndex] can not find index[${indexName}]`);
return null;
}
}
}
var subFrame=this.Frame.SubFrame[windowIndex];
var overlayFrame=new OverlayIndexItem();
if (obj.Identify) overlayFrame.Identify=obj.Identify; //由外部指定id
var frame=null;
if (this.ClassName=="MinuteChartContainer") frame=new OverlayMinuteFrame();
else frame=new OverlayMinuteHScreenFrame();
frame.Canvas=this.Canvas;
frame.MainFrame=subFrame.Frame;
frame.ChartBorder=subFrame.Frame.ChartBorder;
frame.GlobalOption=this.GlobalOption;
if (IFrameSplitOperator.IsBool(obj.ShowRightText)) frame.IsShow=obj.ShowRightText;
if (IFrameSplitOperator.IsBool(obj.IsShareY)) frame.IsShareY=obj.IsShareY;
if (IFrameSplitOperator.IsBool(obj.IsCalculateYMaxMin)) frame.IsCalculateYMaxMin=obj.IsCalculateYMaxMin; //是否计算Y最大最小值
if (IFrameSplitOperator.IsNumber(obj.IsShowMainFrame)) frame.IsShowMainFrame=obj.IsShowMainFrame;
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=frame.ChartBorder;
frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount;
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
frame.YSplitOperator.HQChart=this;
frame.YSplitOperator.OverlayIdentify=overlayFrame.Identify;
if (obj.Frame)
{
var item=obj.Frame;
if (item.Custom) frame.YSplitOperator.Custom=item.Custom;
}
overlayFrame.Frame=frame;
if (apiItem)
{
var apiIndex=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,obj, true);
apiIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
overlayFrame.Script=apiIndex;
}
else if (indexInfo)
{
JSIndexScript.ModifyAttribute(indexInfo, obj);
var scriptIndex=new OverlayScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo); //脚本执行
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
overlayFrame.Script=scriptIndex;
}
else
{
var scriptIndex=indexCustom.Create();
scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息
scriptIndex.Create(this,windowIndex);
overlayFrame.Script=scriptIndex;
}
subFrame.OverlayIndex.push(overlayFrame);
return overlayFrame;
}
this.DeleteOverlayWindowsIndex=function(identify) //删除叠加指标
{
if (!this.DeleteOverlayIndex(identify, null)) return;
this.Frame.ResetXYSplit(true);
this.Draw();
}
//计算叠加指标
this.BindAllOverlayIndexData=function(hisData, option)
{
if (!this.Frame || !this.Frame.SubFrame) return;
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j=0;j<item.OverlayIndex.length; ++j)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,hisData,option)
}
}
}
//叠加指标
this.BindOverlayIndexData=function(overlayItem, windowIndex, hisData, option)
{
if (!overlayItem.Script) return;
if (typeof(overlayItem.Script.RequestData)=='function')
{
overlayItem.Script.RequestData(this,windowIndex,hisData);
return;
}
if (typeof(overlayItem.Script.ExecuteScript)=='function')
{
overlayItem.Script.ExecuteScript(this,windowIndex,hisData);
return;
}
overlayItem.Script.BindData(this,windowIndex,hisData);
}
//获取子窗口的所有画法
this.GetChartPaint=function(windowIndex)
{
var paint=new Array();
for(var i in this.ChartPaint)
{
if (i<3) continue; //分钟 均线 成交量 3个线不能改
var item=this.ChartPaint[i];
if (item.ChartFrame==this.Frame.SubFrame[windowIndex].Frame)
paint.push(item);
}
return paint;
}
//创建指定窗口指标
this.CreateWindowIndex=function(windowIndex)
{
this.WindowIndex[windowIndex].Create(this,windowIndex);
}
this.OnTouchFinished=function()
{
if (this.EnableClickModel===true)
{
if (this.ClickModel.IsShowCorssCursor==true && this.TouchDrawCount>0) return;
this.ClickModel.IsShowCorssCursor=false;
this.DrawDynamicInfo();
return;
}
if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失
{
this.DrawDynamicInfo();
return;
}
/* 以后放日线的tooltip
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName==='KLineTooltipPaint')
{
this.DrawDynamicInfo();
}
}
*/
}
this.CreateExtendChart=function(name, option) //创建扩展图形
{
var chart;
switch(name)
{
case 'MinuteTooltip':
if (option.Create && typeof(option.Create)=='function') chart=option.Create();
else chart=new MinuteTooltipPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
option.LanguageID=this.LanguageID;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case "MinutePCTooltip":
if (option.Create && typeof(option.Create)=="function") chart=option.Create();
else chart=new MinuteLeftTooltipPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
option.LanguageID=this.LanguageID;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
case "MinuteBackgroundPaint":
chart=new MinuteBackgroundPaint();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
option.LanguageID=this.LanguageID;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
default:
chart=g_ExtendChartPaintFactory.Create(name);
if (!chart) return null;
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.ChartBorder;
chart.ChartFrame=this.Frame;
chart.HQChart=this;
chart.SetOption(option);
this.ExtendChartPaint.push(chart);
return chart;
}
}
this.SetMinuteInfo=function(aryInfo,bUpdate)
{
this.ChartInfo=[]; //先清空
for(var i in aryInfo)
{
var infoItem=JSMinuteInfoMap.Get(aryInfo[i]);
if (!infoItem) continue;
var item=infoItem.Create();
this.ChartInfo.push(item);
}
if (bUpdate==true) this.RequestMinuteInfoData();
}
this.GetChartMinuteInfo=function()
{
return this.ChartInfoPaint;
}
this.CreateMinuteInfo=function(option) //在Create()以后 在调用
{
var chart=new ChartMinuteInfo();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
chart.ChartFrame=this.Frame.SubFrame[0].Frame;
chart.HQChartBorder=this.Frame.ChartBorder;
chart.ChartMinutePrice=this.ChartPaint[0];
if (option && chart.SetOption) chart.SetOption(option);
this.ChartInfoPaint=chart;
return chart;
}
//信息地雷数据请求
this.RequestMinuteInfoData=function()
{
if (this.ChartInfo.length<=0) return;
var chart=this.GetChartMinuteInfo();
if (!chart) chart=this.CreateMinuteInfo(null); //不存在就创建
chart.SourceData=this.SourceData;
//信息地雷信息
for(var i in this.ChartInfo)
{
this.ChartInfo[i].RequestData(this);
}
}
//更新信息地雷
this.UpdataChartInfo=function()
{
var chart=this.GetChartMinuteInfo();
if (!chart) return;
var infoMap=new Map();
for(var i in this.ChartInfo)
{
var infoData=this.ChartInfo[i].Data;
for(var j in infoData)
{
var item=infoData[j];
var dateTime=`${item.Date} ${item.Time}`;
if (infoMap.has(dateTime))
{
infoMap.get(dateTime).Data.push(item);
}
else
{
infoMap.set(dateTime,{Data:new Array(item)});
}
}
}
chart.Data=infoMap;
}
//接收到窗口指标数据 订阅模式
this.RecvWindowIndex=function(index, data)
{
var indexItem=this.WindowIndex[index];
if (!indexItem) return;
if (typeof(indexItem.RecvSubscribeData)=="function")
{
var bindData=this.SourceData;
indexItem.RecvSubscribeData(data,this,index,bindData);
}
}
this.UpdateWindowIndex=function(index)
{
if (index<2) return;
var bindData=this.SourceData;
this.BindIndexData(index,bindData)
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.CreateChartDrawPicture=function(name, option, callback)
{
var drawPicture=null;
var item=IChartDrawPicture.GetDrawPictureByName(name);
if (item)
{
drawPicture=item.Create();
if (drawPicture.ClassName=='ChartDrawPictureText') drawPicture.HQChart=this;
}
if (!drawPicture) //iconfont图标
{
if (IChartDrawPicture.MapIonFont.has(name))
{
var iconItem=IChartDrawPicture.MapIonFont.get(name);
drawPicture=new ChartDrawPictureIconFont();
drawPicture.FontOption.Family=iconItem.Family
drawPicture.Text=iconItem.Text;
if (iconItem.Color) drawPicture.LineColor=iconItem.Color;
}
}
if (!drawPicture) return false;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=0;
drawPicture.Symbol=this.Symbol;
drawPicture.Period=888888888;
drawPicture.Option=this.ChartDrawOption;
if (callback) drawPicture.FinishedCallback=callback; //完成通知上层回调
if (option) drawPicture.SetOption(option);
var self=this;
drawPicture.Update=function() //更新回调函数
{
self.DrawDynamicInfo();
};
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
this.CurrentChartDrawPicture=drawPicture;
JSConsole.Chart.Log("[MinuteChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture);
return true;
}
//手动添加画线
this.AddChartDrawPicture=function(obj)
{
if (!obj) return null;
if (obj.FrameID<0 || obj.FrameID>=this.Frame.SubFrame.length) return null;
var self=this;
var item=IChartDrawPicture.GetDrawPictureByClassName(obj.ClassName);
if (!item) return null;
var drawPicture=item.Create();
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[obj.FrameID].Frame; //绑定框架坐标
drawPicture.Symbol=this.Symbol;
drawPicture.Period=888888888;
if (obj.Value) drawPicture.Value=obj.Value;
if (obj.Guid) drawPicture.Guid=obj.Guid;
if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(obj);
drawPicture.SetOption(obj);
if (obj.EnableUpdateXValue) drawPicture.UpdateXValue();
drawPicture.ValueToPoint();
drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
if (obj.Draw==true) this.DrawDynamicInfo();
return drawPicture;
}
this.ReloadChartDrawPicture=function()
{
this.ChartDrawPicture=[];
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
this.CurrentChartDrawPicture=null;
this.MoveOnChartDrawPicture=null;
if (this.ChartDrawStorage)
{
this.ChartDrawStorageCache=this.ChartDrawStorage.GetDrawData( { Symbol:this.Symbol, Period:888888888 } );
}
}
this.CreateChartDrawPictureByStorage=function() //把缓存(this.ChartDrawStorageCache) 画图工具创建出来
{
if (!this.ChartDrawStorageCache || this.ChartDrawStorageCache.length<=0) return;
var self=this;
for(var i=0; i<this.ChartDrawStorageCache.length; ++i)
{
var item=this.ChartDrawStorageCache[i];
if (item.FrameID<0 || !this.Frame.SubFrame || this.Frame.SubFrame.length<item.FrameID) continue;
var drawPicture=IChartDrawPicture.CreateChartDrawPicture(item);
if (!drawPicture) continue;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[item.FrameID].Frame; //绑定框架坐标
if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(item);
drawPicture.ResetXValue();
drawPicture.UpdateXValue();
drawPicture.ValueToPoint();
drawPicture.GetActiveDrawPicture=()=>{ return this.GetActiveDrawPicture(); }
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
}
this.ChartDrawStorageCache=null; //清空缓存
}
this.SetSizeChange=function(bChanged)
{
this.Frame.SetSizeChage(bChanged);
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
item.SizeChange=bChanged;
}
}
this.SetSizeChage=this.SetSizeChange;
//根据X坐标获取数据索引
this.GetDataIndexByPoint=function(x)
{
var frame=this.Frame;
if (this.Frame.SubFrame && this.Frame.SubFrame.length>0) frame=this.Frame.SubFrame[0].Frame;
if (!frame) return;
var value=frame.GetXData(x);
var index=parseInt(value.toFixed(0));
return index;
}
//不支持未来时间 目前只支持主图
this.GetDateTimeByPoint=function(x,y)
{
var clientPos=this.PtInClient_V2(x,y); // 100-199=多日分时主图 200-299=盘前 300-399=盘后 1=主图 2=盘前 3=盘后
if (clientPos<=0) return null;
if (!this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return null;
var frame=this.Frame.SubFrame[0].Frame;
var data=this.Frame.SourceData;
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return null;
var index=-1;
var result={ ClientPos:clientPos };
if (clientPos==1)
{
var value=frame.GetXData(x);
index=parseInt(value.toFixed(0));
if (IFrameSplitOperator.IsNumber(data.DataOffset)) index+=data.DataOffset; //加上数据偏移
}
else if (clientPos>=100 && clientPos<=199)
{
var dayIndex=clientPos-100;
var value=frame.GetXData(x);
index=parseInt(value.toFixed(0));
var dataIndex=index%frame.MinuteCount;
result.DayIndex=dayIndex;
result.DataIndex=dataIndex;
}
else
{
return null;
}
if (index<0 || index>=data.Data.length) return null;
result.Index=index;
var item=data.Data[index];
if (!item) return null;
result.Date=item.Date;
result.Time=item.Time;
return result;
}
//获取主数据
this.GetSelectRectData=function(selectData)
{
if (Math.abs(selectData.XStart-selectData.XEnd)<5) return false;
var startClientPos=this.PtInClient(selectData.XStart, selectData.YStart);
var endClientPos=this.PtInClient(selectData.XEnd, selectData.YEnd);
selectData.StartClientPos=startClientPos;
selectData.EndClientPos=endClientPos;
var data=this.SourceData;
if (!data) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(data.Data)) return false;
var start=this.GetDataIndexByPoint(selectData.XStart);
var end=this.GetDataIndexByPoint(selectData.XEnd);
if (Math.abs(start-end)<2) return false;
selectData.Data=data;
var offset=data.DataOffset;
start+=offset;
end+=offset;
if (start>end)
{
selectData.Start=end;
selectData.End=start;
}
else
{
selectData.Start=start;
selectData.End=end;
}
var count=data.Data.length;
if (selectData.End>=count) selectData.End=count-1;
return true;
}
this.Super_UpdateFrameMaxMin=this.UpdateFrameMaxMin;
this.UpdateFrameMaxMin=function()
{
this.Super_UpdateFrameMaxMin();
if (this.DayCount==1) //集合竞价多坐标,Y轴强制都计算
{
var subFrame=this.Frame.SubFrame[1];
if (subFrame.Frame) subFrame.Frame.XYSplit=true;
}
}
this.ExportMainData=function(data, option)
{
var aryData=data.ExportMinuteData(option); //导出K线
return aryData;
}
this.DisplayLatest=function()
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DISPLAY_LATEST); //选中画图工具事件
if (event)
{
var sendData={ PreventDefault:false };
event.Callback(event,sendData,this);
if (sendData.PreventDefault) return;
}
this.CursorIndex=null;
this.LastPoint.X=0;
this.LastPoint.Y=0;
this.GlobalOption.IsDisplayLatest=true;
this.DrawDynamicInfo();
}
this.TryClickIndexTitle=function(x,y)
{
for(var i=0; i<this.TitlePaint.length; ++i)
{
var item=this.TitlePaint[i];
if (!item.IsClickTitle) continue;
if (!item.IsClickTitle(x,y)) continue;
var data={ Point:{X:x, Y:y}, Title:item.Title, FrameID:item.Frame.Identify };
JSConsole.Chart.Log('[MinuteChartContainer::TryClickIndexTitle] click title ', data);
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_INDEXTITLE);
if (event && event.Callback) event.Callback(event,data,this);
return true;
}
return false;
}
this.ClearSelectedXBorder=function()
{
if (!this.GlobalOption || !this.GlobalOption.SelectedXBorder) return;
var item=this.GlobalOption.SelectedXBorder;
item.Date=null;
}
this.DrawSelectedXBorder=function()
{
if (this.DayCount<=1) return null;
if (this.Frame.IsHScreen===true) return null;
if (!this.GlobalOption || !this.GlobalOption.SelectedXBorder) return;
var item=this.GlobalOption.SelectedXBorder;
if (!IFrameSplitOperator.IsPlusNumber(item.Mode)) return;
if (!IFrameSplitOperator.IsPlusNumber(item.Date)) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.DayData)) return;
var rtSelected=null;
var dayIndex=item.DayIndex;
var border=this.Frame.ChartBorder.GetBorder();
var rtClient={ Left:border.Left, Top:border.Top, Right:border.Right, Bottom: border.Bottom };
rtClient.Width=rtClient.Right-rtClient.Left;
var mainFrame=this.Frame.SubFrame[0].Frame; //主图框架
var xPointCount=mainFrame.XPointCount;
var minuteCount=mainFrame.MinuteCount;
var lDayCount=xPointCount/minuteCount;
var dayWidth=rtClient.Width/lDayCount;
if (border.DayBorder)
{
var dayIndex=-1;
for(var i=0;i<this.DayData.length;++i)
{
var dayItem=this.DayData[i];
if (dayItem.Date==item.Date)
{
dayIndex=this.DayData.length-1-i;
break;
}
}
if (dayIndex<0) return;
var item=border.DayBorder[dayIndex];
if (!item) return;
rtSelected={ Left:item.LeftEx, Right:item.RightEx, Top:border.Bottom, Bottom:border.ChartHeight };
rtSelected.Width=rtSelected.Right-rtSelected.Left;
rtSelected.Height=rtSelected.Bottom-rtSelected.Top;
}
else
{
var dayIndex=-1;
for(var i=0;i<this.DayData.length;++i)
{
var dayItem=this.DayData[i];
if (dayItem.Date==item.Date)
{
dayIndex=this.DayData.length-1-i;
break;
}
}
if (dayIndex<0) return;
rtSelected={ Left:border.Left+dayIndex*dayWidth, Width:dayWidth, Top:border.Bottom, Bottom:border.ChartHeight };
rtSelected.Right=rtSelected.Left+rtSelected.Width;
rtSelected.Height=rtSelected.Bottom-rtSelected.Top;
}
mainFrame.Canvas.strokeStyle=g_JSChartResource.SelFrameBorderColor;
mainFrame.Canvas.strokeRect(ToFixedPoint(rtSelected.Left),ToFixedPoint(rtSelected.Top),ToFixedRect(rtSelected.Width),ToFixedRect(rtSelected.Height)-1);
}
this.PtInMulitDayMinute=function(x,y)
{
if (this.DayCount<=1) return null;
if (this.Frame.IsHScreen===true) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.DayData)) return null;
var border=this.Frame.ChartBorder.GetBorder();
var rtClient={ Left:border.Left, Top:border.Top, Right:border.Right, Bottom: border.Bottom };
rtClient.Width=rtClient.Right-rtClient.Left;
if (!(x>rtClient.Left && x<rtClient.Right && y>rtClient.Top && y<rtClient.Bottom)) return null; //不在窗口里面
if (border.DayBorder)
{
for(var i=0;i<border.DayBorder.length;++i)
{
var item=border.DayBorder[i];
var rtDay={ Left:item.LeftEx, Right:item.RightEx };
if (x>=rtDay.Left && x<=rtDay.Right)
{
var dayItem=this.DayData[this.DayData.length-1-i];
if (!dayItem) return null;
return dayItem.Date;
}
}
}
else
{
var mainFrame=this.Frame.SubFrame[0].Frame; //主图框架
var xPointCount=mainFrame.XPointCount;
var minuteCount=mainFrame.MinuteCount;
var lDayCount=xPointCount/minuteCount;
var dayWidth=rtClient.Width/lDayCount;
var rtDay={ Left:rtClient.Left, Right:dayWidth+rtClient.Left };
for(var i=0;i<lDayCount;++i)
{
if (x>=rtDay.Left && x<=rtDay.Right)
{
var dayItem=this.DayData[this.DayData.length-1-i];
if (!dayItem) return null;
return dayItem.Date;
}
rtDay.Left+=dayWidth;
rtDay.Right+=dayWidth;
}
}
return null;
}
this.DrawTooltipDialog=function()
{
if (!this.DialogTooltip) return;
this.UpdateTooltipDialog();
}
this.UpdateTooltipDialog=function()
{
if (!this.DialogTooltip) return false;
if (!this.ChartCorssCursor) return false;
var minuteItem=null; //{ Type:0=连续交易 1=集合竞价, Data:数据 }
var dataType=0; //0=全部更新 2=分时实时数据更新
if (this.ChartCorssCursor.ClientPos>=0)
{
var titlePaint=this.TitlePaint[0];
if (titlePaint && titlePaint.PointInfo)
{
var pointInfo=titlePaint.PointInfo;
if ((pointInfo.ClientPos==2 || pointInfo.ClientPos==3 || (pointInfo.ClientPos>=200&& pointInfo.ClientPos<=299) || (pointInfo.ClientPos>=300&& pointInfo.ClientPos<=399)))
{
var auctionData=titlePaint.GetCurrentAuctionData();
if (!auctionData) return false;
minuteItem={ Type:1, Data:auctionData };
}
else
{
var minuteData=titlePaint.GetCurrentKLineData();
if (!minuteData) return false;
minuteItem={ Type:0, Data:minuteData };
}
}
}
else //实时数据更新
{
if (!this.SourceData || !IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data)) return false;
var minuteData=this.SourceData.Data[this.SourceData.Data.length-1];
var dataID={ Symbol:this.Symbol, Date:minuteData.Date, Time:minuteData.Time };
if (!this.DialogTooltip.IsEqualDataID(dataID)) return false;
minuteItem={ Type:0, Data:minuteData };
dataType=2;
}
var sendData=
{
DataType:dataType,
ClientPos:this.ChartCorssCursor.ClientPos, //位置
IsShowCorss:this.ChartCorssCursor.IsShowCorss, //是否显示十字线
MinItem:minuteItem,
Symbol:this.Symbol, Name:this.Name,
LastValue:this.ChartCorssCursor.LastValue,
};
this.DialogTooltip.Update(sendData);
return true;
}
this.DrawSelectRectDialog=function(e)
{
if (!this.DialogSelectRect) return;
this.UpdateSelectRectDialog(e);
}
this.UpdateSelectRectDialog=function(e)
{
if (!this.DialogSelectRect) return false;
var data=e.data; //区间统计数据
var x,y;
if (data && IFrameSplitOperator.IsNumber(data.X) && IFrameSplitOperator.IsNumber(data.Y))
{
var pixelRatio=GetDevicePixelRatio();
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
x=data.X
y=data.Y;
x+=(rtClient.left+rtScroll.Left);
y+=(rtClient.top+rtScroll.Top);
}
var sendData=
{
Symbol:this.Symbol, Name:this.Name,
SelectData:data.SelectData,
X:x, Y:y,
e:e
}
this.DialogSelectRect.Update(sendData);
}
}
//盘前数据
MinuteChartContainer.JsonDataToBeforeOpenData=function(data)
{
var symbol=data.stock[0].symbol;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var yClose=data.stock[0].yclose;
var preClose=data.stock[0].yclose; //前一个数据价格
var stockData=data.stock[0];
var date=stockData.date; //日期
var beforeOpenData={ Data:[], TotalCount:15, Ver:1.0, Date:date };
var extendDataIndex=JSCHART_DATA_FIELD_ID.MINUTE_BEFOREOPEN_EXTENDDATA; //扩展数据序号
if (stockData.beforeinfo)
{
if (IFrameSplitOperator.IsNumber(stockData.beforeinfo.totalcount)) beforeOpenData.TotalCount=stockData.beforeinfo.totalcount;
if (IFrameSplitOperator.IsNumber(stockData.beforeinfo.ver)) beforeOpenData.Ver=stockData.beforeinfo.ver;
}
if (beforeOpenData.Ver==1.0)
{
if (IFrameSplitOperator.IsNonEmptyArray(stockData.before))
{
for(var i=0; i<stockData.before.length; ++i)
{
var item=new BeforeOpenData();
var jsData=stockData.before[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
if (!item.Price) item.Price=preClose;
else preClose=item.Price;
if (isSHSZ) item.Vol[0]=jsData[2]/100; //沪深股票原始单位股
else item.Vol[0]=jsData[2];
item.Amount=jsData[3];
if (IFrameSplitOperator.IsNumber(jsData[4]) && jsData[4]>19000101) //日期
item.Date=jsData[4];
item.DateTime=`${item.Date} ${item.Time}`;
beforeOpenData.Data.push(item);
}
}
}
else if (beforeOpenData.Ver==2.0)
{
var max=0;
for(var i in stockData.before)
{
var item=new BeforeOpenData();
var jsData=stockData.before[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.Vol[0]=jsData[2]; //匹配量
item.Vol[1]=jsData[3]; //未匹配量
item.ColorID=jsData[4]; //柱子颜色ID
if (IFrameSplitOperator.IsNumber(jsData[6])) item.Date=jsData[6] //日期
item.DateTime=`${item.Date} ${item.Time})`;
var totalVol=item.Vol[0]+item.Vol[1];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
beforeOpenData.Data.push(item);
}
beforeOpenData.VolMax=max;
beforeOpenData.VolMin=0;
}
else if (beforeOpenData.Ver==3.0)
{
var max=0;
for(var i in stockData.before)
{
var item=new BeforeOpenData();
var jsData=stockData.before[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.AvPrice=jsData[2]; //均价
item.Vol[0]=jsData[3]; //匹配量
item.ColorID=jsData[4]; //柱子颜色ID
item.DateTime=date.toString()+" "+item.Time.toString();
var totalVol=item.Vol[0];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
beforeOpenData.Data.push(item);
}
beforeOpenData.VolMax=max;
beforeOpenData.VolMin=0;
}
return beforeOpenData;
}
//收盘集合竞价
MinuteChartContainer.JsonDataToAfterCloseData=function(data)
{
var yClose=data.stock[0].yclose;
var preClose=data.stock[0].yclose; //前一个数据价格
var stockData=data.stock[0];
var date=stockData.date; //日期
if (!stockData.afterinfo) return null;
var afterCloseData={ Data:[], TotalCount:3*60, Ver:2.0, Date:date };
var item=stockData.afterinfo;
if (IFrameSplitOperator.IsNumber(item.totalcount)) afterCloseData.TotalCount=item.totalcount;
if (IFrameSplitOperator.IsNumber(item.ver)) afterCloseData.Ver=item.ver;
var extendDataIndex=JSCHART_DATA_FIELD_ID.MINUTE_AFTERCLOSE_EXTENDDATA; //扩展数据序号
if (afterCloseData.Ver==1.0)
{
for(var i=0; i<stockData.after.length; ++i)
{
var item=new AfterCloseData();
var jsData=stockData.after[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.Vol[0]=jsData[2];
item.Amount=jsData[3];
if (IFrameSplitOperator.IsNumber(jsData[4])) //日期
item.Date=jsData[4];
item.DateTime=`${item.Date} ${item.Time}`;
afterCloseData.Data.push(item);
}
}
else if (afterCloseData.Ver==2.0)
{
var max=0;
for(var i in stockData.after)
{
var item=new AfterCloseData();
var jsData=stockData.after[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.Vol[0]=jsData[2]; //匹配量
item.Vol[1]=jsData[3]; //未匹配量
item.ColorID=jsData[4]; //柱子颜色ID
item.DateTime=date.toString()+" "+item.Time.toString();
var totalVol=item.Vol[0]+item.Vol[1];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
afterCloseData.Data.push(item);
}
afterCloseData.VolMax=max;
afterCloseData.VolMin=0;
}
else if (afterCloseData.Ver==3.0)
{
var max=0;
for(var i in stockData.after)
{
var item=new AfterCloseData();
var jsData=stockData.after[i];
item.YClose=yClose;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.AvPrice=jsData[2]; //均价
item.Vol[0]=jsData[3]; //匹配量
item.ColorID=jsData[4]; //柱子颜色ID
item.DateTime=date.toString()+" "+item.Time.toString();
var totalVol=item.Vol[0];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
afterCloseData.Data.push(item);
}
afterCloseData.VolMax=max;
afterCloseData.VolMin=0;
}
return afterCloseData;
}
//API 返回数据 转化为array[]
MinuteChartContainer.JsonDataToMinuteData=function(data,isBeforeData)
{
var symbol=data.stock[0].symbol;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
var isSHO=MARKET_SUFFIX_NAME.IsSHO(upperSymbol); //上海股票期权
var isSZO=MARKET_SUFFIX_NAME.IsSZO(upperSymbol); //深证股票期权
var aryMinuteData=[];
var preClose=data.stock[0].yclose; //前一个数据价格
var preAvPrice=data.stock[0].yclose; //前一个均价
var yClose=data.stock[0].yclose;
var yClearing=data.stock[0].yclearing;
if (isFutures && yClearing) preClose=preAvPrice=yClearing; //期货使用昨结算价
if (!IFrameSplitOperator.IsNonEmptyArray(data.stock[0].minute)) return aryMinuteData;
var date=data.stock[0].date; //默认使用外部日期, 但跨天的 走势图使用内部的日期
for(var i=0; i<data.stock[0].minute.length; ++i)
{
var jsData=data.stock[0].minute[i];
var item=new MinuteData();
item.YClearing=yClearing;
item.YClose=yClose;
item.Close=jsData.price;
item.Open=jsData.open;
item.High=jsData.high;
item.Low=jsData.low;
if (isSHSZ) item.Vol=jsData.vol/100; //沪深股票原始单位股
else item.Vol=jsData.vol;
item.Amount=jsData.amount;
if (jsData.date>0) date=jsData.date; //分钟数据中有日期 优先使用
item.DateTime=date.toString()+" "+jsData.time.toString();
item.Date=date;
item.Time=jsData.time;
if (isFutures || isSHO || isSZO) item.Position=jsData.position; //期货 期权有持仓
else if (IFrameSplitOperator.IsNumber(jsData.position)) item.Position=jsData.position;
item.Increase=jsData.increase;
item.Risefall=jsData.risefall;
item.AvPrice=jsData.avprice;
if (IFrameSplitOperator.IsNumber(jsData.lead))
item.Lead=jsData.lead; //领先指标 指数才有
if (!IFrameSplitOperator.IsNumber(item.Close)) //当前没有价格 使用上一个价格填充
{
item.Close=preClose;
item.Open=item.High=item.Low=item.Close;
}
if (!item.AvPrice) item.AvPrice=preAvPrice;
if (yClose && item.Close)
item.Increase=(item.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100;
if (isFutures && yClearing && item.Close)
item.Increase=(item.Close-yClearing)/yClearing*100; //涨幅 (最新价格-昨结算价)/昨结算价*100;
//上次价格
if (IFrameSplitOperator.IsNumber(jsData.price)) preClose=jsData.price;
if (IFrameSplitOperator.IsNumber(jsData.avprice) && item.AvPrice===jsData.avprice) preAvPrice=jsData.avprice;
if (jsData.ExtendData) item.ExtendData=jsData.ExtendData; //扩展数据
aryMinuteData[i]=item;
}
return aryMinuteData;
}
//分钟增量数据 stock: [ { date:, yclose:, yclearing: , minute:[ [],]} 0=日期 1=时间 2=开 3=高 4=低 5=收 6=均价 7=量 8=金额 9=涨幅 10=涨跌 11=领先指标 ]
MinuteChartContainer.JsonDataToUpdateMinuteData=function(data)
{
if (!data || !data.stock) return null;
var stock=data.stock[0];
if (!IFrameSplitOperator.IsNumber(stock.date)) return null;
var symbol=data.stock[0].symbol;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
var minuteData={ Date:stock.date, Data:[] , Symbol:symbol, Name:stock.name };
var extendDataIndex=JSCHART_DATA_FIELD_ID.MINUTE_DAY_EXTENDDATA; //扩展数据序号
if (IFrameSplitOperator.IsNumber(stock.high)) minuteData.High=stock.high;
if (IFrameSplitOperator.IsNumber(stock.low)) minuteData.Low=stock.low;
if (IFrameSplitOperator.IsNumber(stock.yclose)) minuteData.YClose=stock.yclose;
if (IFrameSplitOperator.IsNumber(stock.YClearing)) minuteData.YClearing=stock.yclearing;
if (IFrameSplitOperator.IsNonEmptyArray(stock.minute))
{
for(var i=0;i<stock.minute.length;++i)
{
var jsData=stock.minute[i];
var item=new MinuteData();
item.YClearing=minuteData.YClearing;
item.YClose=minuteData.YClose;
item.Date=jsData[0];
item.Time=jsData[1];
item.Open=jsData[2];
item.High=jsData[3];
item.Low=jsData[4];
item.Close=jsData[5];
item.AvPrice=jsData[6];
item.Vol=jsData[7];
item.Amount=jsData[8];
if (IFrameSplitOperator.IsNumber(jsData[9])) item.Increase=jsData[9];
if (IFrameSplitOperator.IsNumber(jsData[10])) item.Risefall=jsData[10];
if (IFrameSplitOperator.IsNumber(jsData[11])) item.Lead=jsData[11];
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
item.DateTime=item.Date.toString()+" "+item.Time.toString();
if (isSHSZ) item.Vol=item.Vol/100; //沪深股票原始单位股
if (IFrameSplitOperator.IsNumber(minuteData.YClose) && item.Close)
item.Increase=(item.Close-minuteData.YClose)/minuteData.YClose*100; //涨幅 (最新价格-昨收)/昨收*100;
if (isFutures && minuteData.YClearing && item.Close)
item.Increase=(item.Close-minuteData.YClearing)/minuteData.YClearing*100; //涨幅 (最新价格-昨结算价)/昨结算价*100;
minuteData.Data.push(item);
}
}
return minuteData;
}
MinuteChartContainer.JsonDataToMinuteLineColorData=function(data)
{
if (!data || !data.stock[0]) return null;
var stockItem=data.stock[0];
if (!stockItem.linecolor || !IFrameSplitOperator.IsNonEmptyArray(stockItem.linecolor.data)) return null;
var aryLineColor=[];
for(var i in stockItem.linecolor.data)
{
var item=stockItem.linecolor.data[i];
if (!IFrameSplitOperator.IsNumber(item.type) || !IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.start) ||
!IFrameSplitOperator.IsNumber(item.end) || !item.color) continue;
if (item.start>=item.end) continue;
var newItem={ Type:item.type, Date:item.date, Start:item.start, End:item.end, Color:item.color };
if (IFrameSplitOperator.IsPlusNumber(item.linewidth)) newItem.LineWidth=item.linewidth;
aryLineColor.push(newItem);
}
return aryLineColor;
}
//获取最后的数据更新时间
MinuteChartContainer.JsonDataToMinuteLastUpdateTime=function(data)
{
if (!data || !data.stock[0]) return null;
var stock=data.stock[0];
if (!IFrameSplitOperator.IsNumber(stock.date) || !IFrameSplitOperator.IsNumber(stock.time)) return null;
return { Date:stock.date, Time:stock.time };
}
MinuteChartContainer.JsonDataToHistoryMinuteLastUpdateTime=function(data)
{
if (!data || !data.updatetime) return null;
var item=data.updatetime;
if (!IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.time)) return null;
return { Date:item.date, Time:item.time };
}
//多日日线数据API 转化成array[];
MinuteChartContainer.JsonDataToMinuteDataArray=function(data)
{
var symbol=data.symbol;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isSHO=MARKET_SUFFIX_NAME.IsSHO(upperSymbol); //上海股票期权
var isSZO=MARKET_SUFFIX_NAME.IsSZO(upperSymbol); //深证股票期权
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //国内期货, 纽约期货交易所
var result=[];
var extendDataIndex=JSCHART_DATA_FIELD_ID.MINUTE_MULTI_DAY_EXTENDDATA; //扩展数据序号
for(var i in data.data)
{
var minuteData=[];
var dayData=data.data[i];
var date=dayData.date;
var yClearing=dayData.yclearing; //昨结算价
var yClose=dayData.yclose; //前收盘 计算涨幅
var preClose=yClose; //前一个数据价格
var preAvPrice=null; //上一个均价
if (isFutures && yClearing) preClose=preAvPrice=yClearing; //期货使用昨结算价
for(var j in dayData.minute)
{
var jsData=dayData.minute[j];
if (jsData[2]) preClose=jsData[2]; //保存上一个收盘数据
var item=new MinuteData();
item.YClearing=yClearing;
item.YClose=yClose;
item.Close=jsData[2];
item.Open=jsData[1];
item.High=jsData[3];
item.Low=jsData[4];
item.Increase=null;
if (isSHSZ) item.Vol=jsData[5]/100; //原始单位股
else item.Vol=jsData[5];
item.Amount=jsData[6];
if (7<jsData.length && jsData[7]>0) item.AvPrice=jsData[7]; //均价
item.DateTime=date.toString()+" "+jsData[0].toString();
item.Date=date;
item.Time=jsData[0];
if (8<jsData.length && jsData[8]>0)
{
item.Date=jsData[8]; //日期
item.DateTime=item.Date.toString()+" "+jsData[0].toString();
}
if ((isFutures || isSHO || isSZO) && 9<jsData.length) item.Position=jsData[9]; //持仓
if (!IFrameSplitOperator.IsNumber(item.Close)) //当前没有价格 使用上一个价格填充
{
item.Close=preClose;
item.Open=item.High=item.Low=item.Close;
}
if (!item.AvPrice && preAvPrice) item.AvPrice=preAvPrice;
if (item.Close && yClose)
item.Increase = (item.Close - yClose)/yClose*100;
if (item.Close && yClearing && isFutures)
item.Increase = (item.Close - yClearing)/yClearing*100;
if (jsData.length>7 && jsData[7]>0 && item.AvPrice===jsData[7]) preAvPrice=jsData[7];
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
minuteData[j]=item;
}
var newData=new ChartData();
newData.Data=minuteData;
newData.YClose=yClose;
if (IFrameSplitOperator.IsNumber(yClearing)) newData.YClearing=yClearing;
newData.Close=dayData.close;
newData.Date=date;
result.push(newData);
}
return result;
}
MinuteChartContainer.JsonDataToHistoryMinuteLineColorData=function(data)
{
if (!data) return null;
var aryLineColor=[];
for(var i in data.data)
{
var dayData=data.data[i];
if (!dayData.linecolor) continue;
for(var j in dayData.linecolor.data)
{
var item=dayData.linecolor.data[j];
if (!IFrameSplitOperator.IsNumber(item.type) || !IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.start) ||
!IFrameSplitOperator.IsNumber(item.end) || !item.color) continue;
if (item.start>=item.end) continue;
var newItem={ Type:item.type, Date:item.date, Start:item.start, End:item.end, Color:item.color };
if (IFrameSplitOperator.IsPlusNumber(item.linewidth)) newItem.LineWidth=item.linewidth;
aryLineColor.push(newItem);
}
}
return aryLineColor.length>0? aryLineColor : null;
}
MinuteChartContainer.JsonDataToCallAuctionItem=function(data, callAuctionData, isBeforeOpen, symbol)
{
var isSHSZ=false;
if (symbol)
{
var upperSymbol=symbol.toUpperCase();
isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
}
var date=callAuctionData.Date;
var yClose=callAuctionData.YClose;
var yClearing=callAuctionData.YClearing;
var extendDataIndex=isBeforeOpen? JSCHART_DATA_FIELD_ID.MINUTE_BEFOREOPEN_EXTENDDATA:JSCHART_DATA_FIELD_ID.MINUTE_AFTERCLOSE_EXTENDDATA; //扩展数据序号
if (callAuctionData.Ver==1.0)
{
var preClose=null;
for(var i in data)
{
var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
var jsData=data[i];
item.YClose=yClose;
item.YClearing=yClearing;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
if (!item.Price) item.Price=preClose;
else preClose=item.Price;
item.Vol[0]=isSHSZ ? jsData[2]/100 : jsData[2]; //沪深股票原始单位股
item.Amount=jsData[3];
if (IFrameSplitOperator.IsNumber(jsData[4])) //日期
item.Date=jsData[4];
item.DateTime=`${item.Date} ${item.Time}`;
callAuctionData.Data.push(item);
}
}
else if (callAuctionData.Ver==2.0)
{
var max=0;
for(var i in data)
{
var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
var jsData=data[i];
item.YClose=yClose;
item.YClearing=yClearing;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.Vol[0]=jsData[2]; //匹配量
item.Vol[1]=jsData[3]; //未匹配量
item.ColorID=jsData[4]; //柱子颜色ID
item.DateTime=date.toString()+" "+item.Time.toString();
var totalVol=item.Vol[0]+item.Vol[1];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
callAuctionData.Data.push(item);
}
callAuctionData.VolMax=max;
callAuctionData.VolMin=0;
}
else if (beforeOpenData.Ver==3.0)
{
var max=0;
for(var i in data)
{
var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
var jsData=data[i];
item.YClose=yClose;
item.YClearing=yClearing;
item.Time=jsData[0];
item.Date=date;
item.Price=jsData[1];
item.AvPrice=jsData[2]; //均价
item.Vol[0]=jsData[3]; //匹配量
item.ColorID=jsData[4]; //柱子颜色ID
item.DateTime=date.toString()+" "+item.Time.toString();
var totalVol=item.Vol[0];
if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
if (totalVol>max) max=totalVol;
if (jsData[extendDataIndex]) item.ExtendData=jsData[extendDataIndex];
callAuctionData.Data.push(item);
}
callAuctionData.VolMax=max;
callAuctionData.VolMin=0;
}
}
MinuteChartContainer.JosnDataToBeforeOpenDataArray=function(data)
{
if (!data || !data.data) return null;
var aryDay=[];
for(var i in data.data)
{
var dayItem=data.data[i];
var beforeOpenData={ Data:[], TotalCount:15, Ver:1.0, Date:dayItem.date, YClose:dayItem.yclose, YClearing:dayItem.YClearing };
if (dayItem.beforeinfo)
{
if (IFrameSplitOperator.IsNumber(dayItem.beforeinfo.totalcount)) beforeOpenData.TotalCount=dayItem.beforeinfo.totalcount;
if (IFrameSplitOperator.IsNumber(dayItem.beforeinfo.ver)) beforeOpenData.Ver=dayItem.beforeinfo.ver;
}
MinuteChartContainer.JsonDataToCallAuctionItem(dayItem.before, beforeOpenData, true, data.symbol);
aryDay.push(beforeOpenData);
}
aryDay.sort((left, right)=>{return left.Date - right.Date});
return aryDay;
}
MinuteChartContainer.JosnDataToAfterCloseDataArray=function(data)
{
if (!data || !data.data) return null;
var aryDay=[];
for(var i in data.data)
{
var dayItem=data.data[i];
var afterCloseData={ Data:[], TotalCount:15, Ver:1.0, Date:dayItem.date, YClose:dayItem.yclose, YClearing:dayItem.YClearing };
if (dayItem.afterinfo)
{
if (IFrameSplitOperator.IsNumber(dayItem.afterinfo.totalcount)) afterCloseData.TotalCount=dayItem.afterinfo.totalcount;
if (IFrameSplitOperator.IsNumber(dayItem.afterinfo.ver)) afterCloseData.Ver=dayItem.afterinfo.ver;
}
MinuteChartContainer.JsonDataToCallAuctionItem(dayItem.after, afterCloseData, false, data.symbol);
aryDay.push(afterCloseData);
}
aryDay.sort((left, right)=>{return left.Date - right.Date});
return aryDay;
}
/*
历史分钟走势图
*/
/* 废弃 统一使用 MinuteChartContainer
function HistoryMinuteChartContainer(uielement)
{
this.newMethod=MinuteChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.HistoryMinuteApiUrl="http://127.0.0.1:8080/cache/minuteday/day/";
this.ClassName='HistoryMinuteChartContainer';
//创建主图K线画法
this.CreateMainKLine=function()
{
//分钟线
var minuteLine=new ChartMinutePriceLine();
minuteLine.Canvas=this.Canvas;
minuteLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
minuteLine.ChartFrame=this.Frame.SubFrame[0].Frame;
minuteLine.Name="Minute-Line";
minuteLine.Color=g_JSChartResource.Minute.PriceColor;
this.ChartPaint[0]=minuteLine;
//分钟线均线
var averageLine=new ChartLine();
averageLine.Canvas=this.Canvas;
averageLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
averageLine.ChartFrame=this.Frame.SubFrame[0].Frame;
averageLine.Name="Minute-Average-Line";
averageLine.Color=g_JSChartResource.Minute.AvPriceColor;
this.ChartPaint[1]=averageLine;
var averageLine=new ChartMinuteVolumBar();
averageLine.Color=g_JSChartResource.Minute.VolBarColor;
averageLine.Canvas=this.Canvas;
averageLine.ChartBorder=this.Frame.SubFrame[1].Frame.ChartBorder;
averageLine.ChartFrame=this.Frame.SubFrame[1].Frame;
averageLine.Name="Minute-Vol-Bar";
this.ChartPaint[2]=averageLine;
this.TitlePaint[0]=new DynamicMinuteTitlePainting();
this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].Canvas=this.Canvas;
this.TitlePaint[0].IsShowDate=true;
}
//设置交易日期
this.ChangeTradeDate=function(trdateDate)
{
if (!trdateDate) return;
this.TradeDate=trdateDate;
this.RequestData(); //更新数据
}
this.RequestData=function()
{
var date=new Date();
var nowDate=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate();
if (nowDate==this.TradeDate) this.RequestMinuteData();
else this.RequestHistoryMinuteData();
}
//请求分钟数据
this.RequestHistoryMinuteData=function()
{
var self=this;
var url=this.HistoryMinuteApiUrl+this.TradeDate.toString()+"/"+this.Symbol+".json";
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryMinuteData(data);
},
error:function(reqeust)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryMinuteError(reqeust);
}
});
}
this.RecvHistoryMinuteError=function(reqeust)
{
if (reqeust.status!=404) return;
var sourceData=new ChartData();
this.SourceData=sourceData;
for(var i in this.ChartPaint)
{
this.ChartPaint[i].Data=sourceData;
if (i==0) this.ChartPaint[i].NotSupportMessage='没有权限访问!';
}
this.TitlePaint[0].Data=this.SourceData; //动态标题
this.TitlePaint[0].Symbol=this.Symbol;
this.TitlePaint[0].Name=null;
this.Draw();
}
this.RecvHistoryMinuteData=function(data)
{
var aryMinuteData=HistoryMinuteChartContainer.JsonDataToMinuteData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryMinuteData;
this.TradeDate=data.date;
this.SourceData=sourceData;
this.Symbol=data.symbol;
this.Name=data.name;
this.BindMainData(sourceData,data.day.yclose);
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=aryMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
//this.AutoUpdata();
}
}
//API 返回数据 转化为array[]
HistoryMinuteChartContainer.JsonDataToMinuteData=function(data)
{
var aryMinuteData=[];
for(var i in data.minute.time)
{
var item=new MinuteData();
if (data.minute.price[i]<=0 && i>0) //当前这一分钟价格为空,使用上一分钟的数据
{
item.Close=aryMinuteData[i-1].Close;
item.Open=aryMinuteData[i-1].Close;
item.High=item.Close;
item.Low=item.Close;
item.Vol=data.minute.vol[i]; //原始单位股
item.Amount=data.minute.amount[i];
item.DateTime=data.date.toString()+" "+data.minute.time[i].toString();
//item.Increate=jsData.increate;
//item.Risefall=jsData.risefall;
item.AvPrice=aryMinuteData[i-1].AvPrice;
}
else
{
item.Close=data.minute.price[i];
item.Open=data.minute.open[i];
item.High=data.minute.high[i];
item.Low=data.minute.low[i];
item.Vol=data.minute.vol[i]; //原始单位股
item.Amount=data.minute.amount[i];
item.DateTime=data.date.toString()+" "+data.minute.time[i].toString();
//item.Increate=jsData.increate;
//item.Risefall=jsData.risefall;
item.AvPrice=data.minute.avprice[i];
}
//价格是0的 都用空
if (item.Open<=0) item.Open=null;
if (item.Close<=0) item.Close=null;
if (item.AvPrice<=0) item.AvPrice=null;
if (item.High<=0) item.High=null;
if (item.Low<=0) item.Low=null;
aryMinuteData[i]=item;
}
return aryMinuteData;
}
*/
/////////////////////////////////////////////////////////////////////////////
// 自定义指数
//
function CustomKLineChartContainer(uielement)
{
this.newMethod=KLineChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName='CustomKLineChartContainer';
this.CustomKLineApiUrl=g_JSChartResource.Domain+"/API/IndexCalculate"; //自定义指数计算地址
this.CustomStock; //成分
this.QueryDate={Start:20180101,End:20180627} ; //计算时间区间
this.RequestHistoryData=function()
{
var self=this;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.Draw();
JSNetwork.HttpRequest({
url: this.CustomKLineApiUrl,
data:
{
"stock": self.CustomStock,
"Name": self.Symbol,
"date": { "startdate":self.QueryDate.Start,"enddate":self.QueryDate.End }
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvHistoryData(data);
}
});
}
this.RecvHistoryData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=0; //0=日线数据 1=分钟数据
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=0;
if (bindData.Right>0) //复权
{
var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
bindData.Data=rightData;
}
if (ChartData.IsDayPeriod(this.Period,false)) //周期数据
{
var periodData=sourceData.GetPeriodData(bindData.Period);
bindData.Data=periodData;
}
//绑定数据
this.SourceData=sourceData;
this.Name=data.name;
this.BindMainData(bindData,this.PageSize);
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
}
////////////////////////////////////////////////////////////////////////////////
// K线训练 新版本
//
function KLineTrainChartContainer(uielement, bHScreen)
{
if (bHScreen===true)
{
this.newMethod=KLineChartHScreenContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
}
else
{
this.newMethod=KLineChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
}
this.BuySellPaint; //买卖点画法
this.TrainDataCount=300; //训练数据个数
this.TrainStartDate; //训练开始日期时间 { Date:, Time: }
this.AutoRunTimer=null; //K线自动前进定时器
this.BuySellData=[]; //模拟买卖数据 {Buy:{Price:价格,Date:日期, Time:时间} , Sell:{Price:价格,Date:日期, Time:时间}
this.TrainCallback; //训练回调 (K线每前进一次就调用一次)
this.DragMode=1;
this.IsAutoUpdate=false;
this.KLineSourceData; //原始K线数据 对应 SourceData
this.TrainInfo={ Start:{ }, End:{ } }; // Index:数据索引, Date:日期 Time:时间
this.Super_RecvFlowCapitalData=this.RecvFlowCapitalData;
this.CreateBuySellPaint=function() //在主窗口建立以后 创建买卖点
{
var chart=new ChartBuySell();
chart.Canvas=this.Canvas;
chart.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
chart.ChartFrame=this.Frame.SubFrame[0].Frame;
chart.Name="KLine-Train-BuySell";
this.ChartPaintEx[0]=chart;
}
this.GetKDataIndexByDateTime=function(kData, dateTime)
{
if (!dateTime || !kData) return -1;
for(var i=0;i<kData.length; ++i)
{
var item=kData[i];
if (ChartData.IsMinutePeriod(this.Period, true))
{
if (IFrameSplitOperator.IsNumber(this.TrainStartDate.Time))
{
if (item.Date>=this.TrainStartDate.Date && item.Time>=this.TrainStartDate.Time)
return i;
}
else
{
if (item.Date>=this.TrainStartDate.Date)
return i;
}
}
else if (ChartData.IsDayPeriod(this.Period, true) || ChartData.IsTickPeriod(this.Period))
{
if (item.Date>=this.TrainStartDate.Date)
return i;
}
}
return -1;
}
this.AfterBindMainData=function(funcName)
{
if (!this.ChartPaintEx[0]) this.CreateBuySellPaint();
var hisData=this.ChartPaint[0].Data;
this.ChartPaintEx[0].Data=hisData;
var showItem=hisData.Data[hisData.Data.length-1];
//最后一个显示数据
this.TrainInfo.LastShowData=showItem;
this.TrainInfo.LastData = this.SourceData.Data[this.SourceData.Data.length - 1];
if (funcName!='Update')
this.UpdateTrainUICallback("开始");
}
this.BeforeBindMainData=function(funcName)
{
if (funcName=="Update") return;
//全量数据 需要过滤
this.KLineSourceData=new ChartData();
this.KLineSourceData.Data=this.SourceData.Data.slice(0);
var count=this.SourceData.Data.length;
var lEnd=count-this.TrainDataCount-20;
var findIndex=this.GetKDataIndexByDateTime(this.SourceData.Data, this.TrainStartDate);
if (findIndex>=0)
{
lEnd=findIndex+1;
if (count-lEnd<this.TrainDataCount) this.TrainDataCount=count-lEnd;
}
//训练起始日期
var index=lEnd-1;
var kItem=this.SourceData.Data[index];
this.TrainInfo.Start.Index=index;
this.TrainInfo.Start.Date=kItem.Date;
this.TrainInfo.Start.Time=kItem.Time;
//训练结束日期
this.TrainInfo.End.Index=index;
this.TrainInfo.End.Date=kItem.Date;
this.TrainInfo.End.Time=kItem.Time;
//最后一个数据
this.TrainInfo.LastData=kItem;
//修改数据个数
this.SourceData.Data.length=lEnd;
}
this.Run=function(option)
{
if (this.AutoRunTimer) return;
if (this.TrainDataCount<=0) return;
var self=this;
this.AutoRunTimer=setInterval(function()
{
if (!self.MoveNextKLineData(option)) clearInterval(self.AutoRunTimer);
}, 1000);
}
this.MoveNextKLineData=function(option) //{PageSize:, Step:}
{
if (this.TrainDataCount<=0) return false;
var step=1;
if (option && option.Step>1) step=option.Step;
var moveStep=0;
for(var i=0; i<step; ++i)
{
var index=this.TrainInfo.End.Index+1;
if (index>=this.KLineSourceData.Data.length) break;
var kItem=this.KLineSourceData.Data[index];
this.SourceData.Data.push(kItem);
this.TrainInfo.End.Index=index;
this.TrainInfo.End.Date=kItem.Date;
this.TrainInfo.End.Time=kItem.Time;
--this.TrainDataCount;
++moveStep;
if (this.TrainDataCount<=0) break;
}
if (moveStep==0) return false;
//使用当前页数据个数移动K线
var pageSize=this.Frame.GetCurrentPageSize();
if (IFrameSplitOperator.IsNumber(pageSize))
this.PageSize=pageSize-this.RightSpaceCount;
if (option && option.PageSize>0) this.PageSize=option.PageSize;
this.Update();
if (this.TrainDataCount<=0)
{
this.FinishTrainData();
this.UpdateTrainUICallback("结束");
return false;
}
this.UpdateTrainUICallback("训练中");
return true;
}
this.UpdateTrainUICallback=function(description)
{
//新的监听事件
if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP)) return;
var item=this.mapEvent.get(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP);
if (!item.Callback) return;
var data=
{
TrainDataCount:this.TrainDataCount,
BuySellData:this.BuySellData,
KLine:
{
Start: { Index: this.TrainInfo.Start.Index, Date:this.TrainInfo.Start.Date },
End:{ Index: this.TrainInfo.End.Index, Date:this.TrainInfo.End.Date }
},
LastData:this.TrainInfo.LastData,
LastShowData:this.TrainInfo.LastShowData
};
if (IFrameSplitOperator.IsNumber(this.TrainInfo.Start.Time)) data.KLine.Start.Time=this.TrainInfo.Start.Time;
if (IFrameSplitOperator.IsNumber(this.TrainInfo.End.Time)) data.KLine.End.Time=this.TrainInfo.End.Time;
if (description) data.Description=description
if (this.TrainDataCount<=0)
{
data.Symbol=this.Symbol;
data.Name=this.Name;
}
item.Callback(item,data,this);
}
this.FinishTrainData=function()
{
JSConsole.Chart.Log('[KLineTrainChartContainer::FinishTrainData] trian end ');
}
this.Stop=function()
{
if (this.AutoRunTimer!=null) clearInterval(this.AutoRunTimer);
this.AutoRunTimer=null;
}
this.BuyOrSell=function(obj, bDraw) //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 } bDraw是否立即绘制图标
{
var kItem=this.TrainInfo.LastShowData;
if (!kItem) return false;
var buySellPaint=this.ChartPaintEx[0];
if (!buySellPaint) return false;
var hisData=this.ChartPaint[0].Data;
if (!hisData || hisData.Data.length<=0) return false;
var index=hisData.Data.length-1; //数据索引
var buyItem={ Date:this.TrainInfo.End.Date, Time:this.TrainInfo.End.Time, Price:obj.Price, Vol:obj.Vol, Op:0, ID:obj.ID };
if (obj.Op==1) buyItem.Op=1;
var key=index;
buyItem.Key=key;
this.BuySellData.push(buyItem);
buySellPaint.AddTradeItem(buyItem);
if (bDraw==true) this.Draw();
}
this.RestartTrain=function(option) // { Symbol:, Period:周期, Right:复权, Train:{ DataCount:, DateTime: } }
{
JSConsole.Chart.Log('[KLineTrainChartContainer::RestartTrain] option ', option);
this.TrainInfo={ Start:{ }, End:{ } };
this.BuySellData=[];
this.KLineSourceData=null;
var buySellPaint=this.ChartPaintEx[0];
if (buySellPaint)
{
buySellPaint.Data=null;
buySellPaint.ClearTradeData();
}
if (option.Symbol) this.Symbol=option.Symbol;
if (IFrameSplitOperator.IsNumber(option.Period)) this.Period=option.Period;
if (IFrameSplitOperator.IsNumber(option.Right)) this.Right=option.Right;
if (option.Train)
{
if (option.Train.DataCount>1) this.TrainDataCount=option.Train.DataCount;
if (option.Train.DateTime) this.TrainStartDate=option.Train.DateTime;
}
var symbol=this.Symbol;
this.ChangeSymbol(symbol);
}
this.RecvFlowCapitalData=function(data)
{
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
var aryData=new Array();
for(let i in stock.stockday)
{
var item=stock.stockday[i];
let indexData=new SingleData();
indexData.Date=item.date;
var financeData=item.capital;
if (!financeData) continue;
if (financeData.a>0)
{
indexData.Value=financeData.a; //流通股本(股)
aryData.push(indexData);
}
}
if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据
{
var aryFixedData=this.SourceData.GetMinuteFittingFinanceData(aryData);
for(let i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (!aryFixedData[i]) continue;
item.FlowCapital=aryFixedData[i].Value;
}
var bindData=this.ChartPaint[0].Data;
var newBindData=new ChartData();
newBindData.Data=this.SourceData.Data;
if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据
{
var periodData=newBindData.GetPeriodData(bindData.Period);
newBindData.Data=periodData;
}
bindData.Data=newBindData.Data;
var aryFixedData=this.KLineSourceData.GetMinuteFittingFinanceData(aryData); //数据添加到备份数据中
for(let i in this.KLineSourceData.Data)
{
var item=this.KLineSourceData.Data[i];
if (!aryFixedData[i]) continue;
item.FlowCapital=aryFixedData[i].Value;
}
}
else
{
var aryFixedData=this.SourceData.GetFittingFinanceData(aryData);
for(let i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (!aryFixedData[i]) continue;
item.FlowCapital=aryFixedData[i].Value;
}
var bindData=this.ChartPaint[0].Data;
var newBindData=new ChartData();
newBindData.Data=this.SourceData.Data;
if (bindData.Right>0) //复权
{
var rightData=newBindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
newBindData.Data=rightData;
}
if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据
{
var periodData=newBindData.GetPeriodData(bindData.Period);
newBindData.Data=periodData;
}
bindData.Data=newBindData.Data;
var aryFixedData=this.KLineSourceData.GetFittingFinanceData(aryData); //数据添加到备份数据中
for(let i in this.KLineSourceData.Data)
{
var item=this.KLineSourceData.Data[i];
if (!aryFixedData[i]) continue;
item.FlowCapital=aryFixedData[i].Value;
}
}
this.FlowCapitalReady=true;
var bDraw=false;
for(var i in this.ExtendChartPaint)
{
var item=this.ExtendChartPaint[i];
if (item.ClassName=='StockChip')
{
bDraw=true;
break;
}
}
if (bDraw) this.Draw();
}
this.AutoUpdate()
{
}
}
function KLineTrainSimpleChartContainer(uielement, bHScreen)
{
this.newMethod=KLineTrainChartContainer; //派生
this.newMethod(uielement, bHScreen);
delete this.newMethod;
this.IsHScreen=bHScreen;
this.IsZoomLockRight=true;
this.RightSpaceCount=0;
this.RecvFlowCapitalData=function(data)
{
this.Super_RecvFlowCapitalData(data);
}
this.BeforeBindMainData=function(funcName)
{
}
this.UpdateLastDataIcon=function()
{
if (!this.ChartPaintEx[0]) return;
var chart=this.ChartPaintEx[0];
chart.LastDataIndex=this.TrainInfo.End.Index;
}
this.AfterBindMainData=function(funcName)
{
if (!this.ChartPaintEx[0])
{
this.CreateBuySellPaint();
this.ChartPaintEx[0].LastDataDrawType=1;
}
if (funcName!="Update")
{
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return false;
var count=hisData.Data.length;
var lEnd=count-this.TrainDataCount-20;
var xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
var findIndex=this.GetKDataIndexByDateTime(hisData.Data, this.TrainStartDate);
if (findIndex>=0)
{
lEnd=findIndex+1;
if (count-lEnd<this.TrainDataCount) this.TrainDataCount=count-lEnd;
}
var xOffset=lEnd-xPointcount;
hisData.DataOffset=xOffset;
var index=lEnd-1;
var kItem=hisData.Data[index];
//最后一个显示数据
this.TrainInfo.LastShowData=kItem;
this.TrainInfo.LastData = kItem;
//训练起始日期
this.TrainInfo.Start.Index=index;
this.TrainInfo.Start.Date=kItem.Date;
this.TrainInfo.Start.Time=kItem.Time;
//训练结束日期
this.TrainInfo.End.Index=index;
this.TrainInfo.End.Date=kItem.Date;
this.TrainInfo.End.Time=kItem.Time;
this.UpdateLastDataIcon();
this.UpdateTrainUICallback("开始");
}
}
this.Super_UpdataDataoffset=this.UpdataDataoffset;
this.UpdataDataoffset=function()
{
this.Super_UpdataDataoffset();
var hisData=this.ChartPaint[0].Data;
this.ChartPaintEx[0].Data=hisData;
}
this.MoveNextKLineData=function(option) //{PageSize:, Step:}
{
if (this.TrainDataCount<=0) return false;
var hisData=this.ChartOperator_Temp_GetHistroyData();
if (!hisData) return false;
var step=1;
if (option && option.Step>1) step=option.Step;
var count=hisData.Data.length;
var moveStep=0;
for(var i=0; i<step; ++i)
{
var index=this.TrainInfo.End.Index+1;
if (index>=count) break;
var kItem=hisData.Data[index];
this.TrainInfo.End.Index=index;
this.TrainInfo.End.Date=kItem.Date;
this.TrainInfo.End.Time=kItem.Time;
--this.TrainDataCount;
++moveStep;
if (this.TrainDataCount<=0) break;
}
if (moveStep==0) return false;
//最后一个显示数据
this.TrainInfo.LastShowData=kItem;
this.TrainInfo.LastData = kItem;
//调整x轴索引位置
var lEnd=this.TrainInfo.End.Index;
var xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
var xOffset=lEnd-xPointcount+1;
hisData.DataOffset=xOffset;
this.UpdateLastDataIcon();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.Draw();
if (this.TrainDataCount<=0)
{
this.FinishTrainData();
this.UpdateTrainUICallback("结束");
return false;
}
this.UpdateTrainUICallback("训练中");
return true;
}
this.BuyOrSell=function(obj, bDraw) //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 } bDraw是否立即绘制图标
{
var kItem=this.TrainInfo.LastShowData;
if (!kItem) return false;
var buySellPaint=this.ChartPaintEx[0];
if (!buySellPaint) return false;
var hisData=this.ChartPaint[0].Data;
if (!hisData || hisData.Data.length<=0) return false;
var index=this.TrainInfo.End.Index; //数据索引
var buyItem={ Date:this.TrainInfo.End.Date, Time:this.TrainInfo.End.Time, Price:obj.Price, Vol:obj.Vol, Op:0, ID:obj.ID };
if (obj.Op==1) buyItem.Op=1;
var key=index;
buyItem.Key=key;
this.BuySellData.push(buyItem);
buySellPaint.AddTradeItem(buyItem);
if (bDraw==true) this.Draw();
}
this.DataMove=function(step,isLeft)
{
var oneStepWidth=this.GetMoveOneStepWidth();
var moveStep=step;
step=parseInt(step/oneStepWidth); //除以4个像素
if (step<=0) return false;
var data=this.ChartOperator_Temp_GetHistroyData();
if (!data) return false;
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (!xPointcount) return false;
if (this.Frame.SubFrame && this.Frame.SubFrame.length>0 && this.Frame.SubFrame[0].Frame)
{
var fristFrame=this.Frame.SubFrame[0].Frame;
if (fristFrame.DataWidth<=1 || fristFrame.DistanceWidth<=1) //K线在缩放很小的时候 移动加速
{
if (IFrameSplitOperator.IsPlusNumber(this.StepPixel))
step=moveStep*this.StepPixel;
}
}
if (isLeft) //-->
{
if (this.RightSpaceCount>0)
{
//TODO: not support
if (xPointcount+data.DataOffset>=data.Data.length+this.RightSpaceCount-1) return false;
data.DataOffset+=step;
if (data.DataOffset+xPointcount>=data.Data.length+this.RightSpaceCount)
data.DataOffset=data.Data.length-(xPointcount-this.RightSpaceCount);
}
else
{
var end=this.TrainInfo.End.Index+1;
if (xPointcount+data.DataOffset>=end) return false;
data.DataOffset+=step;
if (data.DataOffset+xPointcount>=end)
data.DataOffset=end-xPointcount;
}
return true;
}
else //<--
{
if (data.DataOffset<=0) return false;
data.DataOffset-=step;
if (data.DataOffset<0) data.DataOffset=0;
return true;
}
}
this.DataMoveRight=function()
{
var data=this.ChartOperator_Temp_GetHistroyData();
if (!data) return false;
var xPointcount=0;
if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount;
else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount;
if (!xPointcount) return false;
var end=this.TrainInfo.End.Index+1;
if (xPointcount+data.DataOffset>=end) return false;
++data.DataOffset;
return true;
}
}
////////////////////////////////////////////////////////////////////////////////
// K线横屏显示
//
function KLineChartHScreenContainer(uielement)
{
this.newMethod=KLineChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName='KLineChartHScreenContainer';
this.OnMouseMove=function(x,y,e,isPhone)
{
this.LastPoint.X=x;
this.LastPoint.Y=y;
this.CursorIndex=this.Frame.GetXData(y);
var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true };
this.DrawDynamicInfo(option);
}
uielement.onmousedown=function(e) //鼠标拖拽
{
if(!this.JSChartContainer) return;
if(this.JSChartContainer.DragMode==0) return;
var pixelTatio = GetDevicePixelRatio();
if (this.JSChartContainer.TryClickLock)
{
var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio;
if (this.JSChartContainer.TryClickLock(x,y)) return;
}
var drag=
{
"Click":{},
"LastMove":{} //最后移动的位置
};
drag.Click.X=e.clientX;
drag.Click.Y=e.clientY;
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
this.JSChartContainer.MouseDrag=drag;
document.JSChartContainer=this.JSChartContainer;
this.JSChartContainer.SelectChartDrawPicture=null;
uielement.ondblclick=function(e)
{
var x = e.clientX-this.getBoundingClientRect().left;
var y = e.clientY-this.getBoundingClientRect().top;
if(this.JSChartContainer)
this.JSChartContainer.OnDoubleClick(x,y,e);
}
document.onmousemove=function(e)
{
if(!this.JSChartContainer) return;
//加载数据中,禁用鼠标事件
if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return;
var drag=this.JSChartContainer.MouseDrag;
if (!drag) return;
var moveSetp=Math.abs(drag.LastMove.Y-e.clientY);
if (this.JSChartContainer.DragMode==1) //数据左右拖拽
{
if (moveSetp<5) return;
var oneStepWidth=this.JSChartContainer.GetMoveOneStepWidth();
if (moveSetp<oneStepWidth) return;
var isLeft=true;
if (drag.LastMove.Y<e.clientY) isLeft=false;//右移数据
if(this.JSChartContainer.DataMove(moveSetp,isLeft))
{
this.JSChartContainer.UpdataDataoffset();
this.JSChartContainer.UpdatePointByCursorIndex();
this.JSChartContainer.UpdateFrameMaxMin();
this.JSChartContainer.ResetFrameXYSplit();
this.JSChartContainer.Draw();
}
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
};
document.onmouseup=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
//清空数据
this.JSChartContainer.MouseDrag=null;
this.JSChartContainer.CurrentChartDrawPicture=null;
this.JSChartContainer=null;
}
}
//手机拖拽
this.OnTouchStart=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.IsPress=false;
this.PhonePinch=null;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.StopDragTimer();
var isSingleTouch=this.IsSingleTouch(e);
if (e.cancelable) e.preventDefault();
if (this.IsPhoneDragging(e))
{
var touches = this.GetToucheData(e, false);
var pt=this.PointAbsoluteToRelative(touches[0].clientX, touches[0].clientY, true);
if (this.TryClickLock || this.TryClickIndexTitle) //指标枷锁区域, 指标标题点击
{
var x = pt.X;
var y = pt.Y;
if (this.TryClickLock && this.TryClickLock(x, y)) return;
if (this.TryClickIndexTitle && this.TryClickIndexTitle(x,y)) return;
}
if (this.ClickFrameButton)
{
var button=this.Frame.PtInButtons(pt.X,pt.Y);
if (button)
{
this.ClickFrameButton(button, e);
return;
}
}
if (this.EnableVerticalDrag )
{
this.VerticalDrag={ IsDrag:false };
if (this.Frame.PtInFrameVertical(pt.X, pt.Y))
this.VerticalDrag.IsDrag=true;
}
var bStartTimer=true;
if (this.ChartDrawOption.IsLockScreen)
{
bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
bStartTimer=false;
}
else
{
if (!isSingleTouch) bStartTimer=false;
}
if (this.VerticalDrag) bStartTimer=false;
var drag= { Click:{}, LastMove:{} }; //LastMove=最后移动的位置
//var touches=this.GetToucheData(e,false);
drag.Click.X=touches[0].clientX;
drag.Click.Y=touches[0].clientY;
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
this.MouseDrag=drag;
this.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } };
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y,true);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo({Corss:false, Tooltip:false});
}
if (e.cancelable) e.preventDefault();
return;
}
else
{
var drawPictrueData={};
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
drawPictrueData.X=(touches[0].clientX-uielement.getBoundingClientRect().left);
drawPictrueData.Y=(touches[0].clientY-uielement.getBoundingClientRect().top);
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
drawPictrueData.ChartDrawPicture.IsSelected=true;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
if (e.cancelable) e.preventDefault();
return;
}
}
if (bStartTimer) //长按2秒,十字光标
{
var self=this;
this.DragTimer=setTimeout(function()
{
self.IsPress=false;
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
self.MoveCorssCursor(drag.Click,e);//移动十字光标
}
}, self.PressTime);
}
if (this.ChartDrawOption.IsLockScreen)
{
this.MouseDrag=null;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e);
}
else if (this.VerticalDrag)
{
if (!this.VerticalDrag.IsDrag) this.MoveCorssCursor(drag.Click,e); //没有点击X轴, 就显示十字光标
}
else if (this.IsClickShowCorssCursor)
{
this.MoveCorssCursor(drag.Click,e);
}
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.GetToucheData(e,false);
phonePinch.Start={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
this.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
//if (this.ChartDrawOption.IsLockScreen) this.PhonePinch=null; //锁屏禁止缩放
}
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, e);
}
this.OnTouchMove=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
if (e.cancelable) e.preventDefault();
var touches=this.GetToucheData(e,false);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
if (!this.ChartDrawOption.IsLockScreen) this.MoveCorssCursor({X:touches[0].clientX, Y:touches[0].clientY},e);
}
else
{
var moveSetp=Math.abs(drag.LastMove.Y-touches[0].clientY);
var moveUpDown=Math.abs(drag.LastMove.X-touches[0].clientX);
var isMoveCorssCursor=(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true); //是否移动十字光标
if (this.VerticalDrag)
{
if (this.VerticalDrag.IsDrag===true) isMoveCorssCursor=false;
else isMoveCorssCursor=true;
}
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.SetChartDrawPictureSecondPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.MoveChartDrawPicture(touches[0].clientX-drag.LastMove.X,touches[0].clientY-drag.LastMove.Y,true))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
else if (isMoveCorssCursor) //点击模式下 十字光标显示 左右移动十字光标
{
var mouseDrag=this.MouseDrag;
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e); //移动十字光标
}
else if (this.DragMode==1 || isMoveCorssCursor==false) //数据左右拖拽
{
if (moveSetp<5) return;
var oneStepWidth=this.GetMoveOneStepWidth();
if (moveSetp<oneStepWidth) return;
if (this.EnableVerticalDrag)
{
if (!this.VerticalDrag) return;
if (!this.VerticalDrag.IsDrag) return;
}
var isLeft=true;
if (drag.LastMove.Y<touches[0].clientY) isLeft=false;//右移数据
if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
this.OnKLinePageChange("OnTouchMove");
}
else
{
if (this.DragDownloadData) this.DragDownloadData();
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
}
if (this.PhoneTouchInfo)
{
this.PhoneTouchInfo.End.X=touches[0].clientX;
this.PhoneTouchInfo.End.Y=touches[0].clientY;
}
}
else if (this.IsPhonePinching(e))
{
if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID) return;
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
var yHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var yLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var yStep=yHeight-yLastHeight;
if (Math.abs(yStep)<5) return;
if (yStep>0) //放大
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomUp(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("OnTouchMove");
}
else //缩小
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomDown(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.OnKLinePageChange("OnTouchMove");
}
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[KLineChartHScreenContainer:OnTouchEnd]',e);
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
this.IsOnTouch = false;
this.VerticalDrag=null;
this.StopDragTimer();
this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e);
this.OnTouchFinished();
this.TouchDrawCount=0;
}
//创建
//windowCount 窗口个数
this.Create=function(windowCount)
{
this.UIElement.JSChartContainer=this;
//创建十字光标
this.ChartCorssCursor=new ChartCorssCursor();
this.ChartCorssCursor.Canvas=this.Canvas;
this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
this.ChartCorssCursor.StringFormatY.ExtendChartPaint=this.ExtendChartPaint;
this.ChartCorssCursor.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.HQChart=this;
//创建框架容器
this.Frame=new HQTradeHScreenFrame();
this.Frame.ChartBorder=new ChartBorder();
this.Frame.ChartBorder.UIElement=this.UIElement;
this.Frame.ChartBorder.Top=30;
this.Frame.ChartBorder.Left=5;
this.Frame.ChartBorder.Bottom=20;
this.Frame.Canvas=this.Canvas;
this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
this.CreateChildWindow(windowCount);
this.CreateMainKLine();
//子窗口动态标题
for(var i in this.Frame.SubFrame)
{
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
this.TitlePaint.push(titlePaint);
}
this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息
}
//创建子窗口
this.CreateChildWindow=function(windowCount)
{
for(var i=0;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=g_ChartFrameFactory.Create("KLineHScreenFrame", { ID:i });
frame.Canvas=this.Canvas;
frame.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); };
frame.ChartBorder=border;
frame.Identify=i; //窗口序号
frame.RightSpaceCount=this.RightSpaceCount; //右边
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
frame.HorizontalMax=20;
frame.HorizontalMin=10;
if (i==0)
{
frame.YSplitOperator=new FrameSplitKLinePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
frame.YSplitOperator.FrameSplitData2=this.FrameSplitData.get('double');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
//主图上下间距
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
border.TopSpace=12*pixelTatio;
border.BottomSpace=12*pixelTatio;
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
//frame.IsLocked = true;
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// 走势图横屏显示
//
function MinuteChartHScreenContainer(uielement)
{
this.newMethod=MinuteChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName='MinuteChartHScreenContainer';
this.OnMouseMove=function(x,y,e,isPhone)
{
this.LastPoint.X=x;
this.LastPoint.Y=y;
this.CursorIndex=this.Frame.GetXData(y);
var clientPos=this.PtInClient(x,y);
var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true,ClientPos:clientPos };
this.DrawDynamicInfo(option);
}
//创建
//windowCount 窗口个数
this.Create=function(windowCount)
{
this.UIElement.JSChartContainer=this;
//创建十字光标
this.ChartCorssCursor=new ChartCorssCursor();
this.ChartCorssCursor.PtInClient=(x,y)=>{ return this.PtInClient(x,y); }
this.ChartCorssCursor.Canvas=this.Canvas;
this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_Minute_XStringFormat");
this.ChartCorssCursor.StringFormatX.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
this.ChartCorssCursor.StringFormatY.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartCorssCursor.CallAcutionXOperator=new CallAcutionXOperator();
this.ChartCorssCursor.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.HQChart=this;
//创建框架容器
this.Frame=new HQTradeHScreenFrame();
this.Frame.ChartBorder=new ChartBorder();
this.Frame.ChartBorder.UIElement=this.UIElement;
this.Frame.ChartBorder.Top=25;
this.Frame.ChartBorder.Left=50;
this.Frame.ChartBorder.Bottom=20;
this.Frame.Canvas=this.Canvas;
this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
this.CreateChildWindow(windowCount);
this.CreateMainKLine();
//子窗口动态标题
for(var i in this.Frame.SubFrame)
{
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
titlePaint.SelectedChart=this.SelectedChart;
this.TitlePaint.push(titlePaint);
}
this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame;
this.ChartCorssCursor.StringFormatY.Frame=this.Frame;
this.ChartCorssCursor.CallAcutionXOperator.Frame=this.Frame.SubFrame[0].Frame;
this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息
}
//创建子窗口
this.CreateChildWindow=function(windowCount)
{
for(var i=0;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new MinuteHScreenFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=i;
if (i<2) frame.ChartBorder.TitleHeight=0;
frame.XPointCount=243;
frame.HQChart=this;
frame.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
if (i==0)
{
frame.YSplitOperator=new FrameSplitMinutePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
frame.YSplitOperator.DayOffset=this.DayOffset;
frame.YSplitOperator.HQChart=this;
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.DayOffset=this.DayOffset;
frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.Operator();
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
frame.FrameData.SubFrameItem=subFrame;
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// 深度图
//
function DepthChartContainer(uielement)
{
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName="DepthChartContainer";
this.Symbol;
//数据
this.MapAsk=new Map();
this.MapBid=new Map();
this.IsAutoUpdate=false; //是否自动更新行情数据
this.AutoUpdateFrequency=30000; //30秒更新一次数据
this.AutoUpdateTimer;
this.DefaultZoom=0.8; //默认显示80%的盘口 (0 - 1)
this.MaxVolRate=1.1;
this.Create=function(option)
{
this.UIElement.JSChartContainer=this;
//创建十字光标
this.ChartCorssCursor=new DepthChartCorssCursor();
this.ChartCorssCursor.Canvas=this.Canvas;
this.ChartCorssCursor.HQChart=this;
//this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
//this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
//this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
//this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
//创建框架
this.Frame=new DepthChartFrame();
this.Frame.ChartBorder=new ChartBorder();
this.Frame.ChartBorder.UIElement=this.UIElement;
this.Frame.ChartBorder.Top=30;
this.Frame.ChartBorder.Left=5;
this.Frame.ChartBorder.Bottom=20;
this.Frame.ChartBorder.TitleHeight=0;
this.Frame.Canvas=this.Canvas;
this.Frame.Identify=0;
var ySplitOper=new FrameSplitY();
ySplitOper.FrameSplitData=this.FrameSplitData.get('double');
ySplitOper.LanguageID=this.LanguageID;
ySplitOper.Frame=this.Frame;
ySplitOper.SplitCount=5;
ySplitOper.LineType=3;
ySplitOper.IgnoreYValue=[0];
//ySplitOper.SplitType=2;
ySplitOper.ChartBorder=this.Frame.ChartBorder;
ySplitOper.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.Frame.YSplitOperator=ySplitOper;
var xSplitOper=new FrameSplitXDepth();
xSplitOper.Frame=this.Frame;;
xSplitOper.ChartBorder=this.Frame.ChartBorder;;
xSplitOper.LanguageID=this.LanguageID;
xSplitOper.LineType=3;
xSplitOper.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
this.Frame.XSplitOperator=xSplitOper
if (this.ChartCorssCursor) this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
var chartItem=new ChartOrderbookDepth();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name="深度图"
this.ChartPaint.push(chartItem);
var bRegisterKeydown=true;
var bRegisterWheel=true;
if (option)
{
if (option.Wheel===false)
{
bRegisterWheel=false;
JSConsole.Chart.Log('[DepthChartContainer::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.OnWheel=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer::OnWheel]',e);
var x = e.clientX-this.UIElement.getBoundingClientRect().left;
var y = e.clientY-this.UIElement.getBoundingClientRect().top;
var isInClient=false;
this.Canvas.beginPath();
this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight());
isInClient=this.Canvas.isPointInPath(x,y);
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
var enableZoomUpDown=true; //是否允许缩放
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Wheel===false) enableZoomUpDown=false;
if (isInClient && wheelValue<0 && enableZoomUpDown) //缩小
{
if (this.Frame.ZoomDown())
{
this.UpdateFrameMaxMin();
this.Draw();
}
}
else if (isInClient && wheelValue>0 && enableZoomUpDown) //放大
{
if (this.Frame.ZoomUp())
{
this.UpdateFrameMaxMin();
this.Draw();
}
}
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.UIOnMouseDown=function(e)
{
}
this.OnTouchStart=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.PhonePinch=null;
var isSingleTouch=this.IsSingleTouch(e);
if (this.EnableScrollUpDown==false || !isSingleTouch) //多点触屏
{
if (e.cancelable) e.preventDefault();
}
if (this.IsPhoneDragging(e))
{
var drag=
{
"Click":{},
"LastMove":{} //最后移动的位置
};
var touches=this.GetToucheData(e,this.IsForceLandscape);
drag.Click.X=touches[0].clientX;
drag.Click.Y=touches[0].clientY;
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
this.MouseDrag=drag;
this.MoveCorssCursor(drag.Click,e);
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.GetToucheData(e,this.IsForceLandscape);
phonePinch.Start={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
this.PhonePinch=phonePinch;
}
}
this.OnTouchMove=function(e)
{
var touches=this.GetToucheData(e,false);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
else
{
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveSetp=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
moveSetp=parseInt(moveSetp);
//上下滚动
if ( ((moveUpDown>0 && moveSetp<=3) || moveAngle<=this.TouchMoveMinAngle) && this.EnableScrollUpDown==true )
{
return;
}
this.PreventTouchEvent(e);
this.MouseDrag=null;
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
}
else if (this.IsPhonePinching(e))
{
this.PreventTouchEvent(e);
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) return;
var yHeight=Math.abs(touches[0].pageY-touches[1].pageY);
var yLastHeight=Math.abs(phonePinch.Last.Y-phonePinch.Last.Y2);
var yStep=yHeight-yLastHeight;
var xHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var xLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var xStep=xHeight-xLastHeight;
var minStep=this.ZoomStepPixel;
if (Math.abs(yStep)<minStep && Math.abs(xStep)<minStep) return;
var step=yStep;
if (Math.abs(yStep)<minStep) step=xStep;
if (step>0) //放大
{
if (!this.Frame.ZoomUp()) return;
this.UpdateFrameMaxMin();
this.Draw();
}
else //缩小
{
if (!this.Frame.ZoomDown()) return;
this.UpdateFrameMaxMin();
this.Draw();
}
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
this.PreventTouchEvent(e);
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[DepthChartContainer::OnTouchEnd]',e);
this.IsOnTouch = false;
this.OnTouchFinished();
this.TouchDrawCount=0;
}
this.OnTouchFinished=function()
{
if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失
{
this.DrawDynamicInfo();
return;
}
}
this.ChangeSymbol=function(symbol)
{
this.CancelAutoUpdate(); //先停止定时器
this.Symbol=symbol;
this.MapBid=new Map();
this.MapAsk=new Map();
this.Frame.VerticalRange.Differ=null;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.Draw();
this.RequestDepthData();
}
this.RequestDepthData=function() //全量历史数据
{
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'DepthChartContainer::RequestDepthData', //类名::
Explain:'深度图数据',
Request:{ Data: { symbol:self.Symbol } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvDepthData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
}
this.RecvDepthData=function(data)
{
this.UpdateAskAndBid(data);
var aryAsk=Array.from(this.MapAsk.values()); //卖 右边
aryAsk.sort((a,b)=> { return a.Price-b.Price; });
var sumVol=0;
for(var i in aryAsk)
{
var item=aryAsk[i];
sumVol+=item.Vol;
aryAsk[i]={Price:item.Price, Vol:sumVol };
}
var aryBid=Array.from(this.MapBid.values()); //买 左边
aryBid.sort((a,b)=> { return b.Price-a.Price; });
var sumVol=0;
for(var i in aryBid)
{
var item=aryBid[i];
sumVol+=item.Vol;
aryBid[i]={Price:item.Price, Vol:sumVol };
}
var drawData={ Asks:aryAsk, Bids:aryBid };
var chart=this.ChartPaint[0];
chart.Data=drawData;
this.Frame.XSplitOperator.Symbol=this.Symbol;
this.ChartCorssCursor.Data=drawData;
this.ChartCorssCursor.Symbol=this.Symbol;
this.UpdateFramePriceList();
this.UpdateFrameMaxMin();
this.Draw();
}
this.UpdateAskAndBid=function(data) //更新数据
{
if(data.datatype=="snapshot") //全量数据
{
this.MapBid=new Map();
this.MapAsk=new Map();
}
for(var i in data.asks)
{
var item=data.asks[i];
var price=parseFloat(item[0]);
var vol=parseFloat(item[1]);
if (this.MapAsk.has(price))
{
var value=this.MapAsk.get(price);
if (vol<=0) this.MapAsk.delete(price);
else value.Vol=vol;
}
else
{
if (vol>0) this.MapAsk.set(price, { Price:price, Vol:vol});
}
}
for(var i in data.bids)
{
var item=data.bids[i];
var price=parseFloat(item[0]);
var vol=parseFloat(item[1]);
if (this.MapBid.has(price))
{
var value=this.MapBid.get(price);
if (vol<=0) this.MapBid.delete(price);
else value.Vol=vol;
}
else
{
if (vol>0) this.MapBid.set(price, { Price:price, Vol:vol});
}
}
}
this.UpdateFramePriceList=function()
{
var aryAskPrice=Array.from(this.MapAsk.keys());
var aryBidPrice=Array.from(this.MapBid.keys());
aryAskPrice.sort((a,b)=> { return a-b; });
aryBidPrice.sort((a,b)=> { return a-b; });
var range={ Max:88, Min:8 };
if (aryAskPrice.length>1 && aryBidPrice.length>1)
{
var askMin=aryAskPrice[0], askMax=aryAskPrice[aryAskPrice.length-1];
var bidMin=aryBidPrice[0], bidMax=aryBidPrice[aryBidPrice.length-1];
var askDifference=askMax-askMin; //卖差值
var bidDifference=bidMax-bidMin; //买差值
var difference=Math.max(askDifference, bidDifference); //取最大的差值,2边调整
var ask={Min:askMin, Max:askMin+difference};
var bid={Max:bidMax, Min:bidMax-difference};
range={ Max:ask.Max, Min:bid.Min };
}
this.Frame.SetPriceList(aryAskPrice,aryBidPrice);
var xRange=this.Frame.VerticalRange;
xRange.Max=range.Max;
xRange.Center=range.Min+(range.Max-range.Min)/2;
xRange.Min=range.Min;
xRange.MaxDiffer=difference; //差值
xRange.Ask=ask;
xRange.Bid=bid;
if (!IFrameSplitOperator.IsNumber(xRange.Differ))
xRange.Differ=difference*this.DefaultZoom;
xRange.Min=xRange.Center-xRange.Differ;
xRange.Max=xRange.Center+xRange.Differ;
}
this.UpdateFrameMaxMin=function()
{
var range=this.ChartPaint[0].GetMaxMin();
this.Frame.HorizontalMax=range.Max*this.MaxVolRate;
this.Frame.HorizontalMin=0;
this.Frame.XYSplit=true;
}
this.CancelAutoUpdate=function() //关闭停止更新
{
if (typeof (this.AutoUpdateTimer) == 'number')
{
clearTimeout(this.AutoUpdateTimer);
this.AutoUpdateTimer = undefined;
}
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
this.IsAutoUpdate=false;
}
this.AutoUpdate=function() //数据自动更新
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
if (!this.Symbol) return;
var self = this;
var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol);
if (marketStatus==0 || marketStatus==3) return; //闭市,盘后
var frequency=this.AutoUpdateFrequency;
if (marketStatus==1) //盘前
{
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},frequency);
}
else if (marketStatus==2) //盘中
{
this.AutoUpdateTimer=setTimeout(function()
{
self.RequestDepthData();
},frequency);
}
}
}
//////////////////////////////////////////////////////////
//
// 指标信息
//
function IndexInfo(name,param)
{
this.Name=name; //名字
this.Param=param; //参数
this.LineColor; //线段颜色
this.ReqeustData=null; //数据请求
}
function BaseIndex(name)
{
this.Index; //指标阐述
this.Name=name; //指标名字
this.Script=null; //通达信脚本
this.ClassName="BaseIndex";
this.OverlayIndex=null; //叠加指标{ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }
this.GetEventCallback; //事件回调函数
this.Status=0; //0=空闲 1=计算
this.Guid=Guid(); //指标唯一标准
//默认创建都是线段
this.Create=function(hqChart,windowIndex)
{
}
//指标不支持 周期/复权/股票等
this.NotSupport=function(hqChart,windowIndex,message)
{
var isOverlay=this.IsOverlay();
if (isOverlay) return;
hqChart.DeleteIndexPaint(windowIndex); //清空
var frame=hqChart.Frame.SubFrame[windowIndex].Frame;
var paint=new ChartErrorMessage();
paint.Canvas=hqChart.Canvas;
paint.ChartBorder=frame.ChartBorder;
paint.ChartFrame=frame;
paint.NotSupportMessage=message;
hqChart.ChartPaint.push(paint);
}
//格式化指标名字+参数
//格式:指标名(参数1,参数2,参数3,...)
this.FormatIndexTitle=function()
{
var title=this.Name;
var param=null;
for(var i in this.Index)
{
var item = this.Index[i];
if (item.Param==null) continue;
if (param)
param+=','+item.Param.toString();
else
param=item.Param.toString();
}
if (param)
{
title+='('+param+')';
}
return title;
}
this.IsOverlay=function() //是否是叠加指标
{
if (!this.OverlayIndex || this.OverlayIndex.IsOverlay!=true) return false;
return true;
}
this.CreateChart=function(id) //创建图形
{
return new ChartLine();
}
this.CreatePaints=function(hqChart,windowIndex)
{
var frame=null;
var isOverlay=this.IsOverlay();
if (isOverlay)
{
frame=this.OverlayIndex.Frame.Frame;
this.OverlayIndex.Frame.ChartPaint=[]; //清空
}
else
{
frame=hqChart.Frame.SubFrame[windowIndex].Frame;
hqChart.DeleteIndexPaint(windowIndex); //清空
}
var aryPaint=[];
for(var i in this.Index)
{
var paint=this.CreateChart(i);
paint.Color=this.Index[i].LineColor;
paint.Canvas=hqChart.Canvas;
paint.Name=this.Name+"-"+i.toString();
paint.ChartBorder=frame.ChartBorder;
paint.ChartFrame=frame
if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint);
else hqChart.ChartPaint.push(paint);
aryPaint.push(paint);
}
return aryPaint;
}
this.SendEvent=function(hqChart,windowIndex,hisData, error)
{
if (!hqChart.GetIndexEvent) return;
var event=hqChart.GetIndexEvent(); //指标计算完成回调
if (!event) return;
var data={ Data:this.GetOutData(), WindowIndex: windowIndex, Name: this.Name, HistoryData: hisData,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
if (error) data.Error=error;
event.Callback(event,data,self);
}
this.GetOutData=function()
{
return null;
}
}
function JSIndex_OX()
{
this.newMethod=BaseIndex; //派生
this.newMethod('OX');
delete this.newMethod;
this.ClassName="JSIndex_OX";
this.IsUsePageData=true;
this.BlockSize=0.5;
this.Arguments=
[
{ Name:"Reversal", Value:3 }
];
this.SetArgs=function(args)
{
if (!args || !IFrameSplitOperator.IsNonEmptyArray(args)) return;
for(var i=0;i<args.length;++i)
{
var item=args[i];
if (item.Name=="Reversal") this.SetParamValue(item.Name,item.Value);
}
}
this.SetParamValue=function(name, value)
{
for(var i=0;i<this.Arguments.length;++i)
{
var item=this.Arguments[i];
if (item.Name==name) item.Value=value;
}
}
this.GetParamValue=function(name)
{
for(var i=0;i<this.Arguments.length;++i)
{
var item=this.Arguments[i];
if (item.Name==name) return item.Value;
}
}
this.RequestData=function(hqChart,windowIndex,hisData)
{
this.BindData(hqChart,windowIndex,hisData);
hqChart.UpdataDataoffset(); //更新数据偏移
hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
hqChart.Draw();
return true;
}
this.CreatePaints=function(hqChart,windowIndex)
{
var frame=null;
var isOverlay=this.IsOverlay();
if (isOverlay)
{
frame=this.OverlayIndex.Frame.Frame;
this.OverlayIndex.Frame.ChartPaint=[]; //清空
}
else
{
frame=hqChart.Frame.SubFrame[windowIndex].Frame;
hqChart.DeleteIndexPaint(windowIndex); //清空
}
var aryPaint=[];
var paint=new ChartOX();
paint.Canvas=hqChart.Canvas;
paint.Name=this.Name+"-0";
paint.ChartBorder=frame.ChartBorder;
paint.ChartFrame=frame
if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint);
else hqChart.ChartPaint.push(paint);
aryPaint.push(paint);
return aryPaint;
}
//根据最大最小值 调整格子价位
this.CalculateBlockSize=function(max, min)
{
var value=max-min;
if (value<=5) return 0.25; //[1,5]=>0.25
else if (value<=20) return 0.5; //[5,20)=>0.5
else if (value<=100) return 1; //[10,100]=>1
else if (value<=200) return 2; //[100,200]=>2
else if (value<=500) return 5; //[200,500]=>5
else if (value<=1000) return 10; //[500,1000]=>10
else return 50;
}
this.Calculate=function(hqChart, hisData)
{
if (!hqChart.ChartPaint[0]) return null;
var range=hqChart.ChartPaint[0].ShowRange;
if (!range) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(hisData.Data)) return null;
var max=null, min=null;
var startPrice=null;
for(var i=range.Start; i<=range.End && i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (max==null)
{
if (IFrameSplitOperator.IsNumber(item.High)) max=item.High;
}
else
{
if (IFrameSplitOperator.IsNumber(item.High) && max<item.High) max=item.High;
}
if (min==null)
{
if (IFrameSplitOperator.IsNumber(item.Low)) min=item.Low;
}
else
{
if (IFrameSplitOperator.IsNumber(item.Low) && min>item.Low) min=item.Low;
}
if (startPrice==null)
{
if (IFrameSplitOperator.IsNumber(item.High)) startPrice=item.High;
}
}
var reversal=this.GetParamValue("Reversal");
var blockSize=this.CalculateBlockSize(max, min);
this.BlockSize=blockSize;
var oxData={ Max:max+blockSize, Min:min-blockSize, StartPrice:startPrice, Data:[], BlockSize:blockSize };
var currentTrend=1;
var currentPrice=startPrice;
var itemData={ Type:0, Data:[], Start:null, End:null };
for(var i=range.Start, j=0; i<=range.End && i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (currentTrend==1)
{
if (item.High >= currentPrice + blockSize)
{
var count=parseInt((item.High-currentPrice)/blockSize);
for(j=0;j<count;++j)
{
currentPrice+=blockSize;
itemData.Data.push(currentPrice);
}
}
else
{
if (item.Low <= currentPrice - (blockSize * reversal))
{
currentTrend=0;
if (itemData && IFrameSplitOperator.IsNonEmptyArray(itemData.Data))
oxData.Data.push(itemData);
itemData={ Type:1, Data:[], Start:null, End:null };
var count=parseInt((currentPrice-item.Low)/blockSize);
for(j=0;j<count;++j)
{
currentPrice-=blockSize;
itemData.Data.push(currentPrice);
}
}
}
}
else
{
if (item.Low <= currentPrice - blockSize)
{
var count=parseInt((currentPrice-item.Low)/blockSize);
for(j=0;j<count;++j)
{
currentPrice-=blockSize;
itemData.Data.push(currentPrice);
}
}
else
{
if (item.High >= currentPrice + (blockSize*reversal))
{
currentTrend=1;
if (itemData && IFrameSplitOperator.IsNonEmptyArray(itemData.Data))
oxData.Data.push(itemData);
itemData={ Type:0, Data:[], Start:null, End:null };
var count=parseInt((item.High-currentPrice)/blockSize);
for(j=0;j<count;++j)
{
currentPrice+=blockSize;
itemData.Data.push(currentPrice);
}
}
}
}
if (itemData.Start==null) itemData.Start=item;
itemData.End=item;
}
if (itemData && IFrameSplitOperator.IsNonEmptyArray(itemData.Data))
oxData.Data.push(itemData);
return oxData;
}
this.BindData=function(hqChart,windowIndex,hisData)
{
var aryPaint=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
var event=hqChart.GetEventCallback(JSCHART_EVENT_ID.ON_CALCULATE_INDEX_OX)
if (event && event.Callback)
{
var eventData={ HQChart:hqChart, WidnowIndex:windowIndex, HisData:hisData, OXData:null };
event.Callback(event,eventData,this);
aryPaint[0].OXData=eventData.OXData;
}
else
{
aryPaint[0].OXData=this.Calculate(hqChart, hisData);
}
var blockSize=this.BlockSize, reversal=this.GetParamValue("Reversal");
var title=`${this.Name} BlockSize=${blockSize} Reversal=${reversal}`;
var titleIndex=windowIndex+1;
if (isOverlay)
{
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleInfo={ Data:[], Title:'' };
titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo);
}
else
{
hqChart.TitlePaint[titleIndex].Title =title;
}
return true;
}
}
//成交量分布图-可视范围
function VolProfileVisibleRangeIndex(option)
{
this.newMethod=BaseIndex; //派生
this.newMethod('VRVR');
delete this.newMethod;
this.ClassName="VolProfileVisibleRangeIndex";
this.IsUsePageData=true;
this.ChartVolProfile;
this.HQChart;
this.WindowIndex;
this.RequestTimer=null;
this.DelayRequestFrequency=500; //延迟请求数据
this.VolType=0; //0=up|down bar 1=total bar
this.BarPosition=1; //柱子方向 0=左边 1=右边
this.BarWidthRate=0.3;
this.Arguments=
[
{ Name:"VAVol", Value:70 },
{ Name:"BarPosition", Value:0 }
];
this.SetArgs=function(args)
{
if (!args || !IFrameSplitOperator.IsNonEmptyArray(args)) return;
for(var i=0;i<args.length;++i)
{
var item=args[i];
if (item.Name=="VAVol") this.SetParamValue(item.Name,item.Value);
else if (item.Name=="BarPosition") this.SetParamValue(item.Name,item.Value);
}
}
this.SetParamValue=function(name, value)
{
for(var i=0;i<this.Arguments.length;++i)
{
var item=this.Arguments[i];
if (item.Name==name) item.Value=value;
}
}
if (option)
{
if (IFrameSplitOperator.IsNumber(option.VolType)) this.VolType=option.VolType;
if (IFrameSplitOperator.IsNumber(option.BarWidthRate)) this.BarWidthRate=option.BarWidthRate;
if (IFrameSplitOperator.IsNumber(option.DelayRequestFrequency)) this.DelayRequestFrequency=option.DelayRequestFrequency;
if (option.Args) this.SetArgs(option.Args);
if (IFrameSplitOperator.IsNumber(option.BarPosition))
{
this.BarPosition=option.BarPosition;
this.SetParamValue("BarPosition",this.BarPosition);
}
}
this.GetParamValue=function(name)
{
for(var i=0;i<this.Arguments.length;++i)
{
var item=this.Arguments[i];
if (item.Name==name) return item.Value;
}
}
this.Create=function(hqChart,windowIndex)
{
this.HQChart=hqChart;
this.WindowIndex=windowIndex;
}
this.CreateChart=function(hqChart,windowIndex)
{
var frame=null;
var isOverlay=this.IsOverlay();
if (isOverlay)
{
frame=this.OverlayIndex.Frame.Frame;
this.OverlayIndex.Frame.ChartPaint=[]; //清空
}
else
{
frame=hqChart.Frame.SubFrame[windowIndex].Frame;
hqChart.DeleteIndexPaint(windowIndex); //清空
}
var aryPaint=[];
var paint=new ChartVolProfileVisibleRange();
paint.Canvas=hqChart.Canvas;
paint.Name=this.Name+"-0";
paint.ChartBorder=frame.ChartBorder;
paint.ChartFrame=frame;
paint.HQChart=this.HQChart;
paint.Identify=this.Guid;
paint.SetOption(this);
if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint);
else hqChart.ChartPaint.push(paint);
aryPaint.push(paint);
this.ChartVolProfile=paint;
return aryPaint;
}
this.CancelRequestTimer=function()
{
if (this.RequestTimer)
{
clearTimeout(this.RequestTimer);
this.RequestTimer = null;
}
}
//请求数据
this.RequestData=function(hqChart,windowIndex,hisData, option)
{
this.CancelRequestTimer();
var T_RequestData=()=>
{
//请求数据
var klineChart=hqChart.ChartPaint[0]; //获取当前K线图实例
var kData=klineChart.Data; //K线数据
if (!kData || IFrameSplitOperator.IsNonEmptyArray(!kData.Data)) return;
var pageKRange=klineChart.DrawKRange; //当前显示的K线索引
if (!pageKRange || !IFrameSplitOperator.IsNumber(pageKRange.Start) || !IFrameSplitOperator.IsNumber(pageKRange.End)) return;
var startKItem=kData.Data[pageKRange.Start];
var endKItem=kData.Data[pageKRange.End];
var option={ Start:{ Date:startKItem.Date, DataIndex:pageKRange.Start }, End:{ Date:endKItem.Date, DataIndex:pageKRange.End }, Chart:this };
if (IFrameSplitOperator.IsNumber(startKItem.Time)) option.Start.Time=startKItem.Time;
if (IFrameSplitOperator.IsNumber(endKItem.Time)) option.End.Time=endKItem.Time;
option.ValueAreaVol=this.Arguments[0].Value;
if (this.Arguments[1].Value>0) this.BarPosition=1;
else this.BarPosition=0;
if (this.ChartVolProfile)
{
this.ChartVolProfile.SetOption( { BarPosition:this.BarPosition} );
}
this.DataStatus=0
if (hqChart && hqChart.RequestVolumeProfileData)
{
hqChart.RequestVolumeProfileData(option);
}
}
if (option && option.Type==1) //页面缩放或移动延迟更新
{
this.RequestTimer=setTimeout(function()
{
T_RequestData();
}, this.DelayRequestFrequency);
}
else
{
T_RequestData();
}
return true;
}
this.OnRecvVolumeProfileData=function(data)
{
this.BindData(data);
this.HQChart.UpdataDataoffset(); //更新数据偏移
this.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.HQChart.Draw();
return true;
}
this.BindData=function(data)
{
if (!this.ChartVolProfile || this.ChartVolProfile.IsDestroy==true) this.CreateChart(this.HQChart, this.WindowIndex);
var chart=this.ChartVolProfile;
chart.Data=null;
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
if (!IFrameSplitOperator.IsNumber(data.MaxPrice) || !IFrameSplitOperator.IsNumber(data.MinPrice)) return;
var maxVol=0,vol=0;
var maxVolPrice=null;
for(var i=0, j=0;i<data.Data.length;++i)
{
var item=data.Data[i];
vol=0;
for(j=0; j<item.Vol.length;++j)
{
var volItem=item.Vol[j];
if (IFrameSplitOperator.IsNumber(volItem.Value)) vol+=volItem.Value;
}
if (maxVol<vol)
{
maxVol=vol;
maxVolPrice=item.Price;
}
}
if (this.maxVolPrice<=0 || this.maxVol<=0) return;
chart.MaxVolPrice=maxVolPrice;
chart.MaxVol=maxVol;
chart.MaxPrice=data.MaxPrice;
chart.MinPrice=data.MinPrice;
chart.Data=data;
var titleIndex=this.WindowIndex+1;
this.HQChart.TitlePaint[titleIndex].Title ="VPVR";
this.HQChart.TitlePaint[titleIndex].Identify=this.Guid; //指标ID
var titleData=new DynamicTitleData(chart.Data, "VPVR", chart.Data);
titleData.ChartClassName="ChartVolProfileVisibleRange";
titleData.Chart=chart;
this.HQChart.TitlePaint[titleIndex].Data[0]=titleData;
}
}
function JSIndex_CJL()
{
this.newMethod=BaseIndex; //派生
this.newMethod('CJL');
delete this.newMethod;
this.Index=new Array(
new IndexInfo("VOL",null),
new IndexInfo("OPID",null),
);
this.Index[0].LineColor=g_JSChartResource.Index.LineColor[0];
this.Index[1].LineColor=g_JSChartResource.Index.LineColor[1];
this.CreateChart=function(id)
{
if (id==0)
{
var chart=new ChartVolStick();
return chart;
}
else if (id==1)
{
var chart = new ChartSubLine();
chart.LineWidth = 1*GetDevicePixelRatio();
return chart;
}
}
//请求数据
this.RequestData=function(hqChart,windowIndex,hisData)
{
this.BindData(hqChart,windowIndex,hisData);
hqChart.UpdataDataoffset(); //更新数据偏移
hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
hqChart.Draw();
return true;
}
this.BindData=function(hqChart,windowIndex,hisData)
{
var paint=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
if (paint.length!=this.Index.length) return false;
var vol=hisData.GetVol();
var position=hisData.GetPosition();
paint[0].HistoryData=hisData;
paint[0].Data.Data=vol;
paint[1].Data.Data=position;
var titleIndex=windowIndex+1;
if (isOverlay)
{
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleInfo={ Data:[], Title:'' };
titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo);
for(var i in paint)
{
var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor);
titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData;
}
}
else
{
hqChart.TitlePaint[titleIndex].Data[0]=new DynamicTitleData(paint[0].Data,this.Index[0].Name,this.Index[0].LineColor);
hqChart.TitlePaint[titleIndex].Data[1]=new DynamicTitleData(paint[1].Data,this.Index[1].Name,this.Index[1].LineColor);
hqChart.TitlePaint[titleIndex].Title = this.Name;
}
return true;
}
}
/*
py指标 服务器端执行
*/
function PyScriptIndex(name,script,args,option)
{
this.newMethod=BaseIndex; //派生
this.newMethod(name);
delete this.newMethod;
this.Script=script; //脚本
this.Arguments=[]; //参数
this.OutVar=[]; //输出数据
this.ApiUrl=g_JSChartResource.PyIndexDomain+'/hq/code';
if (args) this.Arguments=args;
this.RequestData=function(hqChart,windowIndex,hisData)
{
this.OutVar=[];
var self = this;
var param=
{
HQChart:hqChart,
WindowIndex:windowIndex,
HistoryData:hisData
};
//参数
var strParam='';
for(let i in this.Arguments)
{
if (strParam.length>0) strParam+=',';
var item=this.Arguments[i];
strParam+='"'+item.Name+'"'+':'+item.Value;
}
strParam='{'+strParam+'}';
var indexParam=JSON.parse(strParam);
var data=JSON.stringify(
{
code:this.Script, //脚本
symbol:param.HQChart.Symbol, //股票代码
period:param.HQChart.Period, //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟
right:param.HQChart.Right, //复权 0 不复权 1 前复权 2 后复权
params:indexParam, //指标参数
numcount:hqChart.MaxRequestDataCount,
});
//请求数据
JSNetwork.HttpRequest({
url: this.ApiUrl,
data:data,
type:"post",
dataType: "json",
contentType:' application/json; charset=utf-8',
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
},
complete:function(h)
{
//JSConsole.Chart.Log(h);
},
error: function(http,e)
{
self.RecvError(http,e,param);;
}
});
return true;
}
this.RecvError=function(http,e,param)
{
JSConsole.Chart.Log("[PyScriptIndex::RecvError] error",e);
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e);
}
this.RecvData=function(recvData,param)
{
if (recvData.code!=0)
{
JSConsole.Chart.Log("[PyScriptIndex::RecvData] failed.", recvData);
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(recvData.msg);
return; //失败了
}
JSConsole.Chart.Log('[PyScriptIndex::RecvData] recv data.',recvData);
var aryDate=recvData.date;
for(var i in recvData.data)
{
var item=recvData.data[i];
var indexData=[];
for(var j=0;j<aryDate.length && j<aryDate.length;++j)
{
if (j>=item.data.length) continue;
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=aryDate[j];
indexItem.Value=item.data[j];
indexData.push(indexItem);
}
var aryFittingData=param.HistoryData.GetFittingData(indexData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
bindData.Period=param.HQChart.Period; //周期
bindData.Right=param.HQChart.Right; //复权
var indexInfo={Name:item.name,Type:item.graph,LineWidth:item.width,Data:bindData.GetValue(),Color:item.color};
this.OutVar.push(indexInfo);
}
this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); //把数据绑定到图形上
param.HQChart.UpdataDataoffset(); //更新数据偏移
param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
param.HQChart.Draw();
}
this.BindData=function(hqChart,windowIndex,hisData)
{
hqChart.DeleteIndexPaint(windowIndex); //清空指标图形
for(let i in this.OutVar)
{
let item=this.OutVar[i];
switch(item.Type)
{
case 'line':
this.CreateLine(hqChart,windowIndex,item,i);
break;
case 'colorstick': //上下柱子
this.CreateColorStock(hqChart,windowIndex,item,i);
break;
}
}
var titleIndex=windowIndex+1;
hqChart.TitlePaint[titleIndex].Title=this.Name; //这是指标名称
let indexParam=''; //指标参数
for(let i in this.Arguments)
{
let item=this.Arguments[i];
if (indexParam.length>0) indexParam+=',';
indexParam+=item.Value.toString();
}
if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')';
return true;
}
this.CreateLine=function(hqChart,windowIndex,varItem,id)
{
let line=new ChartLine();
line.Canvas=hqChart.Canvas;
line.DrawType=1;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) line.Color=varItem.Color;
else line.Color=this.GetDefaultColor(id);
if (varItem.LineWidth>0) line.LineWidth=varItem.LineWidth;
if (varItem.IsShow==false) line.IsShow=false;
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Data;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
hqChart.ChartPaint.push(line);
}
this.CreateColorStock=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartMACD();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,this.GetDefaultColor(id));
hqChart.ChartPaint.push(chart);
}
//给一个默认的颜色
this.GetDefaultColor=function(id)
{
let COLOR_ARRAY=
[
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
];
let number=parseInt(id);
return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)];
}
}
/*
json格式数据指标 用来显示本地数据
*/
function JsonDataIndex(name,script,args,option)
{
this.newMethod=PyScriptIndex; //派生
this.newMethod(name);
delete this.newMethod;
this.JsonData; //json格式数据
if (option.JsonData) this.JsonData=option.JsonData;
this.RequestData=function(hqChart,windowIndex,hisData)
{
if (!this.JsonData)
{
console.warn("[PyScriptIndex::RequestData] JsonData is null");
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback('json 数据不能为空');
}
else
{
var param=
{
HQChart:hqChart,
WindowIndex:windowIndex,
HistoryData:hisData
};
this.JsonData.code=0;
var recvData=this.JsonData;
this.RecvData(recvData,param);
}
}
}
//给一个默认的颜色
PyScriptIndex.prototype.GetDefaultColor=function(id)
{
let COLOR_ARRAY=
[
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
];
let number=parseInt(id);
return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)];
}
/*
信息地雷
*/
/*
信息地雷列表
*/
function JSKLineInfoMap()
{
}
JSKLineInfoMap.Get=function(id)
{
var infoMap=new Map(
[
["互动易", {Create:function(){ return new InvestorInfo()} }],
["公告", {Create:function(){ return new AnnouncementInfo()} }],
["业绩预告", {Create:function(){ return new PforecastInfo()} }],
["调研", {Create:function(){ return new ResearchInfo()} }],
["大宗交易", {Create:function(){ return new BlockTrading()} }],
["龙虎榜", {Create:function(){ return new TradeDetail()} }]
]
);
return infoMap.get(id);
}
JSKLineInfoMap.GetClassInfo=function(id)
{
var infoMap=new Map(
[
["互动易", { ClassName:"InvestorInfo" }],
["公告", { ClassName:"AnnouncementInfo" }],
["业绩预告", { ClassName:"PforecastInfo" } ],
["调研", { ClassName:"ResearchInfo" }],
["大宗交易", { ClassName:"BlockTrading" }],
["龙虎榜", { ClassName:"TradeDetail"} ]
]
);
return infoMap.get(id);
}
JSKLineInfoMap.GetIconUrl=function(type)
{
switch(type)
{
case KLINE_INFO_TYPE.INVESTOR:
return g_JSChartResource.KLine.Info.Investor.Icon;
break;
case KLINE_INFO_TYPE.PFORECAST:
return g_JSChartResource.KLine.Info.Pforecast.Icon;
case KLINE_INFO_TYPE.ANNOUNCEMENT:
return g_JSChartResource.KLine.Info.Announcement.Icon;
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4:
return g_JSChartResource.KLine.Info.Announcement.IconQuarter;
case KLINE_INFO_TYPE.RESEARCH:
return g_JSChartResource.KLine.Info.Research.Icon;
case KLINE_INFO_TYPE.BLOCKTRADING:
return g_JSChartResource.KLine.Info.BlockTrading.Icon;
case KLINE_INFO_TYPE.TRADEDETAIL:
return g_JSChartResource.KLine.Info.TradeDetail.Icon;
default:
return g_JSChartResource.KLine.Info.Announcement.Icon;
}
}
JSKLineInfoMap.GetIconLibrary=function(index)
{
var iconLib=g_JSChartResource.KLine.Info.IconLibrary;
if (!iconLib || !iconLib.Icon) return g_JSChartResource.KLine.Info.Announcement.IconFont;
if (index>=0 && index<iconLib.Icon.length)
{
var item=iconLib.Icon[index];
var obj={ Text:item.Text, HScreenText:item.HScreenText, Color:item.Color, Family:iconLib.Family };
return obj;
}
return g_JSChartResource.KLine.Info.Announcement.IconFont;
}
JSKLineInfoMap.GetIconFont=function(type)
{
//公告扩展数据
if (type>=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START && type<=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_END)
{
var index=type-KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START;
return JSKLineInfoMap.GetIconLibrary(index);
}
switch(type)
{
case KLINE_INFO_TYPE.INVESTOR:
return g_JSChartResource.KLine.Info.Investor.IconFont;
break;
case KLINE_INFO_TYPE.PFORECAST:
return g_JSChartResource.KLine.Info.Pforecast.IconFont;
case KLINE_INFO_TYPE.ANNOUNCEMENT:
return g_JSChartResource.KLine.Info.Announcement.IconFont;
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3:
case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4:
return g_JSChartResource.KLine.Info.Announcement.IconFont2;
case KLINE_INFO_TYPE.RESEARCH:
return g_JSChartResource.KLine.Info.Research.IconFont;
case KLINE_INFO_TYPE.BLOCKTRADING:
return g_JSChartResource.KLine.Info.BlockTrading.IconFont;
case KLINE_INFO_TYPE.TRADEDETAIL:
return g_JSChartResource.KLine.Info.TradeDetail.IconFont;
default:
return g_JSChartResource.KLine.Info.Announcement.IconFont;
}
}
function IKLineInfo()
{
this.MaxRequestDataCount=1000;
this.StartDate=20160101;
this.Data;
this.ClassName='IKLineInfo';
this.Explain="IKLineInfo";
this.GetToday=function()
{
var date=new Date();
var today=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate();
return today;
}
this.GetRequestData=function(hqChart)
{
var obj=
{
Symbol:hqChart.Symbol ,
MaxRequestDataCount: hqChart.MaxRequestDataCount, //日线数据个数
MaxRequestMinuteDayCount:hqChart.MaxRequestMinuteDayCount, //分钟数据请求的天数
Period:hqChart.Period //周期
};
//K线数据范围
var hisData=null;
if (hqChart.ChartOperator_Temp_GetHistroyData) hisData=hqChart.ChartOperator_Temp_GetHistroyData();
if (hisData)
obj.DateRange=hisData.GetDateRange();
return obj;
}
this.NetworkFilter=function(hqChart,callInfo)
{
if (!hqChart.NetworkFilter) return false;
var self=this;
var param=
{
HQChart:hqChart,
};
var obj=
{
Name:`${this.ClassName}::RequestData`, //类名::函数
Explain:this.Explain,
Request:this.GetRequestData(hqChart),
Self:this,
HQChart:hqChart,
PreventDefault:false
};
if (callInfo)
{
if (callInfo.Update==true)
{
obj.Update={ Start:{ Date: callInfo.StartDate } };
param.Update={ Start:{ Date: callInfo.StartDate } };
}
obj.CallFunctionName=callInfo.FunctionName; //内部调用函数名
}
hqChart.NetworkFilter(obj, function(data)
{
self.RecvData(data,param);
});
if (obj.PreventDefault==true) return true; //已被上层替换,不调用默认的网络请求
return false;
}
}
//互动易
function InvestorInfo()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='InvestorInfo';
this.Explain='互动易'
this.RequestData=function(hqChart, obj)
{
var self = this;
var param=
{
HQChart:hqChart,
};
this.Data=[];
if (this.NetworkFilter(hqChart,obj)) return; //已被上层替换,不调用默认的网络请求
var postData=
{
filed: ["question","answerdate","symbol","id"],
symbol: [param.HQChart.Symbol],
querydate:{"StartDate":this.StartDate,"EndDate":this.GetToday()},
start:0,
end:this.MaxRequestDataCount,
};
//请求数据
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Investor.ApiUrl;
JSNetwork.HttpRequest({
url: url,
data:postData,
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
}
});
return true;
}
this.RecvData=function(recvData,param)
{
if (recvData.list.length<=0) return;
for(var i in recvData.list)
{
var item=recvData.list[i];
var infoData=new KLineInfoData();
infoData.Date=item.answerdate;
infoData.Title=item.question;
infoData.InfoType=KLINE_INFO_TYPE.INVESTOR;
this.Data.push(infoData);
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
//公告 支持增量更新
function AnnouncementInfo()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='AnnouncementInfo';
this.Explain='公告';
this.ApiType=1; //0=读API 1=读OSS缓存文件
this.RequestData=function(hqChart,obj)
{
var self = this;
var param=
{
HQChart:hqChart,
};
if (obj && obj.Update===true) //更新模式 不清内存数据
{
}
else
{
this.Data=[];
}
if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求
if (this.ApiType==1) //取缓存文件
{
var url=`${g_JSChartResource.CacheDomain}/cache/analyze/shszreportlist/${param.HQChart.Symbol}.json`;
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
},
error: function(http,e)
{
self.RecvError(http,e,param);;
}
});
}
else //取api
{
//请求数据
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Announcement.ApiUrl;
JSNetwork.HttpRequest({
url: url,
data:
{
"filed": ["title","releasedate","symbol","id"],
"symbol": [param.HQChart.Symbol],
"querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()},
"start":0,
"end":this.MaxRequestDataCount,
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
},
error: function(http,e)
{
self.RecvError(http,e,param);;
}
});
}
}
this.RecvData=function(recvData,param)
{
if (!IFrameSplitOperator.IsNonEmptyArray(recvData.report)) return;
var aryReport=[];
for(var i=0;i<recvData.report.length; ++i)
{
var item=recvData.report[i];
var infoData=new KLineInfoData();
infoData.Date=item.releasedate;
infoData.Title=item.title;
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT;
if (IFrameSplitOperator.IsNumber(item.time)) infoData.Time=item.time;
for(var j in item.type)
{
var typeItem=item.type[j];
switch(typeItem)
{
case "一季度报告":
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1;
break;
case "半年度报告":
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2;
break;
case "三季度报告":
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3;
break;
case "年度报告":
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4;
break;
}
}
//目前只支持1个类型
for(var j in item.typeex)
{
var id=item.typeex[j];
infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START+id;
break;
}
aryReport.push(infoData);
}
if (recvData.Update===true && this.Data.length>0)
{
this.UpdateData(aryReport);
}
else
{
this.Data=aryReport;
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
//增量更新
this.UpdateData=function(aryData)
{
if (!aryData || aryData.length<=0) return;
var setKeys=new Set(); //通过 日期+类型+标题去重
for(var i in this.Data)
{
var item=this.Data[i];
var strKey=`${item.Date}-${item.Time}-${item.InfoType}-${item.Title}`;
setKeys.add(strKey);
}
var count=0;
for(var i in aryData)
{
var item=aryData[i];
var strKey=`${item.Date}-${item.Time}-${item.InfoType}-${item.Title}`;
if (setKeys.has(strKey)) continue;
this.Data.push(item);
++count;
}
JSConsole.Chart.Log(`[AnnouncementInfo::UpdateData] add new count=${count}`);
}
this.RecvError=function(http,e,param)
{
console.warn("[AnnouncementInfo::RecvError] error, http ",e, http);
//if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e);
}
}
//业绩预告
function PforecastInfo()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='PforecastInfo';
this.Explain='业绩预告';
this.RequestData=function(hqChart,obj)
{
var self = this;
var param=
{
HQChart:hqChart,
};
this.Data=[];
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Pforecast.ApiUrl;
if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求
console.warn("[PforecastInfo::RequestData] NetworkFilter error.");
return true;
}
this.RecvData=function(recvData,param)
{
if (!IFrameSplitOperator.IsNonEmptyArray(recvData.report)) return;
for(var i=0; i<recvData.report.length; ++i)
{
var item=recvData.report[i];
var infoData=new KLineInfoData();
infoData.Date= item.date;
infoData.Title=item.title;
infoData.InfoType=KLINE_INFO_TYPE.PFORECAST;
infoData.ExtendData={ Type:item.title, ReportDate:item.reportdate}
if(item.fweek) //未来周涨幅
{
infoData.ExtendData.FWeek={};
if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1;
if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4;
}
this.Data.push(infoData);
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
//投资者关系 (调研)
function ResearchInfo()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ResearchInfo';
this.Explain='调研';
this.RequestData=function(hqChart,obj)
{
var self = this;
var param=
{
HQChart:hqChart
};
this.Data=[];
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Research.ApiUrl;
if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求
console.warn("[ResearchInfo::RequestData] NetworkFilter error.");
return true;
}
this.RecvData=function(recvData,param)
{
if (!IFrameSplitOperator.IsNonEmptyArray(recvData.list)) return;
for(var i=0;i<recvData.list.length; ++i)
{
var item=recvData.list[i];
var infoData=new KLineInfoData();
infoData.ID=item.id;
infoData.Date= item.researchdate;
infoData.InfoType=KLINE_INFO_TYPE.RESEARCH;
infoData.ExtendData={ Level:item.level , Type:item.type};
this.Data.push(infoData);
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
//大宗交易
function BlockTrading()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='BlockTrading';
this.Explain='大宗交易';
this.RequestData=function(hqChart,obj)
{
var self = this;
var param=
{
HQChart:hqChart
};
this.Data=[];
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.BlockTrading.ApiUrl;
if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求
//请求数据
JSNetwork.HttpRequest({
url: url,
data:
{
"field": ["blocktrading.price","blocktrading.vol","blocktrading.premium","fweek","price"],
"condition":
[
{"item":["date","int32","gte",this.StartDate]},
{"item":["blocktrading.vol","int32","gte","0"]}
],
"symbol": [param.HQChart.Symbol],
"start":0,
"end":this.MaxRequestDataCount,
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
}
});
return true;
}
this.RecvData=function(recvData,param)
{
if (recvData.stock.length!=1) return;
if (recvData.stock[0].stockday.length<=0) return;
for(var i in recvData.stock[0].stockday)
{
var item=recvData.stock[0].stockday[i];
var infoData=new KLineInfoData();
infoData.Date= item.date;
infoData.InfoType=KLINE_INFO_TYPE.BLOCKTRADING;
infoData.ExtendData=
{
Price:item.blocktrading.price, //交易价格
Premium:item.blocktrading.premium, //溢价 (百分比%)
Vol:item.blocktrading.vol, //交易金额单位(万元)
ClosePrice:item.price, //收盘价
};
if(item.fweek) //未来周涨幅
{
infoData.ExtendData.FWeek={};
if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1;
if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4;
}
this.Data.push(infoData);
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
//龙虎榜
function TradeDetail()
{
this.newMethod=IKLineInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='TradeDetail';
this.Explain='大宗交易';
this.RequestData=function(hqChart, obj)
{
var self = this;
var param=
{
HQChart:hqChart
};
this.Data=[];
var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.TradeDetail.ApiUrl;
if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求
//请求数据
JSNetwork.HttpRequest({
url: url,
data:
{
"field": ["tradedetail.typeexplain","tradedetail.type","fweek"],
"condition":
[
{"item":["date","int32","gte",this.StartDate]},
{"item":["tradedetail.type","int32","gte","0"]}
],
"symbol": [param.HQChart.Symbol],
"start":0,
"end":this.MaxRequestDataCount,
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
}
});
return true;
}
this.RecvData=function(recvData,param)
{
if (recvData.stock.length!=1) return;
if (recvData.stock[0].stockday.length<=0) return;
for(var i in recvData.stock[0].stockday)
{
var item=recvData.stock[0].stockday[i];
var infoData=new KLineInfoData();
infoData.Date= item.date;
infoData.InfoType=KLINE_INFO_TYPE.TRADEDETAIL;
infoData.ExtendData={Detail:new Array()};
for(var j in item.tradedetail)
{
var tradeItem=item.tradedetail[j];
infoData.ExtendData.Detail.push({"Type":tradeItem.type,"TypeExplain":tradeItem.typeexplain});
}
if(item.fweek) //未来周涨幅
{
infoData.ExtendData.FWeek={};
if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1;
if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4;
}
this.Data.push(infoData);
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
function JSMinuteInfoMap()
{
}
JSMinuteInfoMap.InfoMap=new Map(
[
["大盘异动", {Create:function(){ return new MarketEventInfo()} }],
]);
JSMinuteInfoMap.Get=function(id)
{
return JSMinuteInfoMap.InfoMap.get(id);
}
function IMinuteInfo()
{
this.Data;
this.ClassName='IMinuteInfo';
}
//////////////////////////////////////////////////////////////////////
// 大盘异动
// 结构 {Date:日期 Time:时间, Title:标题, Type:0 }
////////////////////////////////////////////////////////////////////
function MarketEventInfo()
{
this.newMethod=IMinuteInfo; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='MarketEventInfo';
this.RequestData=function(hqChart)
{
var self = this;
this.Data=[];
var param=
{
HQChart:hqChart
};
var url=g_JSChartResource.CacheDomain+'/cache/analyze/shszevent/marketevent/concept/'+hqChart.TradeDate+'.json';
if (hqChart.NetworkFilter)
{
var obj=
{
Name:'MarketEventInfo::RequestData', //类名::
Explain:'大盘异动',
Request:{ Url:url, Type:'Get', Data: { Date:hqChart.TradeDate, Symbol:hqChart.Symbol } },
Self:this,
PreventDefault:false
};
hqChart.NetworkFilter(obj, function(data)
{
self.RecvData(data,param);
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
},
error: function(http,e)
{
console.warn("[MarketEventInfo::RequestData] error, http ",e, http);
}
});
return true;
}
this.RecvData=function(recvData,param)
{
for(var i in recvData.event)
{
var event=recvData.event[i];
for(var j in event.data)
{
var item=event.data[j];
if (Array.isArray(item))
{
if (item.length<2) continue;
var info={Date:event.date, Time:item[0], Title:item[1], Type:0};
if (item.length>=3 && item[2] && typeof(item[2])=='string') info.Color=item[2]; //[3]=字体颜色
if (item.length>=4 && item[3] && typeof(item[3])=='string') info.BGColor=item[3]; //[3]=背景颜色
this.Data.push(info);
}
else //新格式
{
if (!IFrameSplitOperator.IsNumber(item.Date) || !IFrameSplitOperator.IsNumber(item.Time) || !item.Title) continue;
var info={ Date:item.Date, Time:item.Time, Title:item.Title, Type:0 };
if (item.Color) info.Color=item.Color;
if (item.BGColor) info.BGColor=item.BGColor;
if (IFrameSplitOperator.IsNumber(item.Price)) info.Price=item.Price;
if (item.Content) info.Content=item.Content;
if (item.Link) info.Link=item.Link;
this.Data.push(info);
}
}
}
param.HQChart.UpdataChartInfo();
param.HQChart.Draw();
}
}
//注意!!! 这个函数已经不用了
//是否是指数代码
function IsIndexSymbol(symbol)
{
var upperSymbol=symbol.toUpperCase();
if (upperSymbol.indexOf('.SH')>0)
{
upperSymbol=upperSymbol.replace('.SH','');
if (upperSymbol.charAt(0)=='0' && parseInt(upperSymbol)<=3000) return true;
}
else if (upperSymbol.indexOf('.SZ')>0)
{
upperSymbol=upperSymbol.replace('.SZ','');
if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='9') return true;
}
else if (upperSymbol.indexOf('.CI')>0) //自定义指数
{
return true;
}
return false;
}
//注意!!! 这个函数已经不用了
//是否是基金代码
function IsFundSymbol(symbol)
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (upperSymbol.indexOf('.SH')>0)
{
upperSymbol=upperSymbol.replace('.SH',''); //51XXXX.sh
if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true;
}
else if (upperSymbol.indexOf('.SZ')>0)
{
upperSymbol=upperSymbol.replace('.SZ',''); //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz
if (upperSymbol.charAt(0)=='1' &&
(upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true;
}
return false;
}
//设置对话框工厂类
function DialogFactory()
{
//[key:name, { Create:function(divElement) { return new class(divElement); }} ]
this.DataMap=new Map(
[
["ChartPictureSettingMenu", { Create:function(divElement) { return new ChartPictureSettingMenu(divElement); } }],
["ChartPictureTextSettingMenu", { Create:function(divElement) { return new ChartPictureTextSettingMenu(divElement); } }]
]);
this.Create=function(name, option)
{
if (!this.DataMap.has(name))
{
JSConsole.Warn(`[DialogFactory::Create] can't find class=${name}.`);
return null;
}
var item=this.DataMap.get(name);
return item.Create(option);
}
this.Add=function(name, option)
{
this.DataMap.set(name, { Create:option.Create } );
}
}
var g_DialogFactory=new DialogFactory();
//设置窗口基类
function IDivDialog(divElement)
{
this.DivElement=divElement; //父节点
this.ID=null; //div id
this.TimeOut=null; //定时器
//隐藏窗口
this.Hide=function()
{
$("#"+this.ID).hide();
}
//显示窗口
this.Show=function(left,top,width,height)
{
var cssData={display:'block'};
if (IFrameSplitOperator.IsNumber(left)) cssData.left=left+'px';
if (IFrameSplitOperator.IsNumber(top)) cssData.top=top+'px';
if (IFrameSplitOperator.IsNumber(width)) cssData.width=width+'px';
if (IFrameSplitOperator.IsNumber(height)) cssData.height=height+'px';
$("#"+this.ID).css(cssData);
}
}
//修改指标
function ModifyIndexDialog(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.Title={ ID:Guid() }; //标题
this.ParamList={ID:Guid() }; //参数列表 class='parameter-content'
this.ParamData=[]; //{ ID:参数ID, Value:参数值}
this.Identify;
this.HQChart;
this.IsOverlay=false; //是否是叠加指标
this.IndexScript;
//创建
this.Create=function()
{
this.ID=Guid();
var div=document.createElement('div');
div.className='jchart-modifyindex-box';
div.id=this.ID;
div.innerHTML=
"<div class='parameter'>\
<div class='parameter-header'>\
<span></span>\
<strong id='close' class='icon iconfont icon-close'></strong>\
</div>\
<div class='parameter-content'><input/>MA</div>\
<div class='parameter-footer'>\
<button class='submit' >确定</button>\
<button class='cancel' >取消</button>\
</div>\
</div>";
this.DivElement.appendChild(div);
//确定按钮
$("#"+this.ID+" .submit").click(
{
divBox:this,
},
function(event)
{
event.data.divBox.Hide();
});
//给一个id 后面查找方便
var titleElement=div.getElementsByTagName('span')[0];
titleElement.id=this.Title.ID;
var paramListElement=div.getElementsByClassName('parameter-content')[0];
paramListElement.id=this.ParamList.ID;
}
//设置标题
this.SetTitle=function(title)
{
$("#"+this.Title.ID).html(title);
}
//清空参数
this.ClearParamList=function()
{
$("#"+this.ParamList.ID).empty();
this.ParamData=[];
}
this.BindParam=function()
{
for(var i=0; i<this.IndexScript.Arguments.length; ++i)
{
var item=this.IndexScript.Arguments[i];
if (item.Name==null || isNaN(item.Value)) break;
var guid=Guid();
var param = '<input class="row-line" id="'+guid+'" value="'+item.Value+'" type="number" step="1"/>'+ item.Name +'<br>';
$("#"+this.ParamList.ID).append(param);
this.ParamData.push({ID:guid,Value:item.Value});
}
//绑定参数修改事件
var self=this;
for(var i=0; i<this.ParamData.length; ++i)
{
var item=this.ParamData[i];
$("#"+item.ID).mouseup(
{
ParamIndex:i //参数序号
},
function(event)
{
var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型
if (!IFrameSplitOperator.IsNumber(value))
{
alert("参数不能为空");
return;
}
var chart=self.HQChart;
var identify=self.Identify;
var paramIndex=event.data.ParamIndex;
var script=self.IndexScript;
var isOverlay=self.IsOverlay;
script.Arguments[paramIndex].Value = value; //为参数属性重新赋值
if (isOverlay) chart.UpdateOverlayIndex(identify);
else chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口
}
)
$("#"+item.ID).keyup(
{
ParamIndex:i //参数序号
},
function(event)
{
var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型
if (!IFrameSplitOperator.IsNumber(value))
{
alert("参数不能为空");
return;
}
var chart=self.HQChart;
var identify=self.Identify;
var paramIndex=event.data.ParamIndex;
var script=self.IndexScript;
var isOverlay=self.IsOverlay;
script.Arguments[paramIndex].Value = value; //为参数属性重新赋值
if (isOverlay) chart.UpdateOverlayIndex(identify);
else chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口
}
)
}
}
//绑定取消事件
this.BindCancel=function()
{
//取消按钮事件
var self=this;
var test=$("#"+this.ID+" .cancel");
$("#"+this.ID+" .cancel").unbind("click").click(
function(event)
{
var chart=self.HQChart;
var identify=self.Identify;
self.RestoreParam();
var isOverlay=self.IsOverlay;
if (isOverlay) chart.UpdateOverlayIndex(identify);
else chart.UpdateWindowIndex(identify);
self.IndexScript=null;
self.Hide();
}
);
//关闭和取消是一样的
$("#"+this.ID+" #close").unbind("click").click(
function(event)
{
var chart=self.HQChart;
var identify=self.Identify;
var isOverlay=self.IsOverlay;
self.RestoreParam();
if (isOverlay) chart.UpdateOverlayIndex(identify);
else chart.UpdateWindowIndex(identify);
self.IndexScript=null;
self.Hide();
}
);
}
//还原参数
this.RestoreParam=function()
{
if (!this.IndexScript) return;
for(var i=0; i<this.ParamData.length; ++i)
{
var item=this.ParamData[i];
this.IndexScript.Arguments[i].Value=item.Value;
}
}
//显示
this.DoModal=function(event)
{
var chart=event.data.Chart;
var identify=event.data.Identify;
var dialog=chart.ModifyIndexDialog;
var isOverlay=event.data.IsOverlay===true;
if(!dialog) return;
if (dialog.ID==null) dialog.Create(); //第1次 需要创建div
dialog.Identify=identify;
dialog.HQChart=chart;
dialog.IsOverlay=isOverlay
if (isOverlay)
{
var overlayIndex=chart.GetOverlayIndexByIdentify(identify);
if (!overlayIndex || !overlayIndex.OverlayItem.Script) return;
dialog.IndexScript=overlayIndex.OverlayItem.Script;
dialog.SetTitle(dialog.IndexScript.Name+" 叠加指标参数设置"); //设置标题
}
else
{
dialog.IndexScript=chart.WindowIndex[identify];
dialog.SetTitle(dialog.IndexScript.Name+" 指标参数设置"); //设置标题
}
dialog.ClearParamList(); //清空参数
dialog.BindParam(chart,identify); //绑定参数
dialog.BindCancel(); //绑定取消和关闭事件
dialog.Show();//显示, 在css里调整居中
}
}
//等待动画窗口
function WaitDialog(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.Title='加载中......';
this.Dialog;
//隐藏窗口
this.Close=function()
{
if (this.Dialog)
{
this.DivElement.removeChild(this.Dialog);
this.Dialog=null;
}
}
this.SetTitle=function(title)
{
this.Title=title;
if (!this.Dialog) return;
//TODO: 更新标题数据
}
this.Create=function()
{
this.ID=Guid();
var div=document.createElement('div');
div.className='jchart-wait-box';
div.id=this.ID;
div.innerHTML=
`<div class='parameter jchart-kline-match-box'>
<div class='parameter-header'>
<span>${this.Title}</span>
</div>
</div>`.trim();
this.DivElement.appendChild(div);
this.Dialog=div;
}
//显示
this.DoModal=function(event)
{
this.Title=event.data.Title;
var chart=event.data.Chart;
if (this.ID==null) this.Create(); //第1次 需要创建div
//居中显示
var border=chart.Frame.ChartBorder;
var scrollPos=GetScrollPosition();
var left=border.GetWidth()/2;
var top=border.GetHeight()/2;
this.Show(left,top,200,40); //显示
}
}
//画图工具 单个图形设置
function ChartPictureSettingMenu(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.HQChart;
this.ChartPicture;
this.SubToolsDiv;
this.SettingMenu;
this.SettingPV;
this.DoModal=function(event)
{
var $body;
if (!this.SubToolsDiv)
{
this.ID=Guid();
var div=document.createElement("div");
div.className='subTolls';
div.id=this.ID;
this.DivElement.appendChild(div);
//$body = $("."+event.data.HQChart.ClassName).context.body;
//$body.append(div);
this.SubToolsDiv=div;
}
this.HQChart=event.data.HQChart;
this.ChartPicture=event.data.ChartPicture;
var pixelTatio = GetDevicePixelRatio();
var frame=this.HQChart.Frame.SubFrame[0].Frame;
// var top=frame.ChartBorder.GetTopTitle();
var top=frame.ChartBorder.Top + 40;
// var right=frame.ChartBorder.GetRight();
var right=frame.ChartBorder.Right;
var left=frame.ChartBorder.GetLeft();
var className = this.ChartPicture.ClassName; //='ChartDrawPictureText'时加“设置”
var lineColor=this.ChartPicture.LineColor;
if (lineColor.indexOf("rgb(")==0 || lineColor.indexOf("RGB(")==0)
lineColor=IChartDrawPicture.RGBToHex(lineColor.toLowerCase());
var toolsDiv = "";
if(className === 'ChartDrawPictureText')
{
toolsDiv = '<span class="changes-color" title="改变图形颜色">'+
'<i class="iconfont icon-bianji"></i>'+
'<input type="color" name="color" id="color" class="change-color" value="'+ lineColor +'">'+
'</span>\n' +
'<span class="subtool-set" title="设置"><i class="iconfont icon-shezhi"></i></span>'+
'<span class="subtool-del"><i class="iconfont icon-recycle_bin"></i></span>';
}
else if (className=="ChartDrawVolProfile")
{
toolsDiv='<span class="vp-set" title="设置"><i class="iconfont icon-shezhi"></i></span>'+
'<span class="subtool-del"><i class="iconfont icon-recycle_bin"></i></span>';
}
else
{
toolsDiv =
'<p class="changes-color" title="改变图形颜色"><i class="iconfont icon-bianji"></i>' +
'<input type="color" name="color" id="color" class="change-color" value="'+ lineColor +'"></p>\n' +
' <p class="subtool-del"><i class="iconfont icon-recycle_bin"></i></p>';
}
this.SubToolsDiv.style.right = right/pixelTatio + "px";
this.SubToolsDiv.style.top = top/pixelTatio + "px";
this.SubToolsDiv.innerHTML = toolsDiv;
this.SubToolsDiv.style.position = "absolute";
this.SubToolsDiv.style.display = "block";
var hqChart = this.HQChart;
var picture = this.ChartPicture;
var subToolDiv = this.SubToolsDiv;
$(".subtool-del").click(function(){
hqChart.SelectChartDrawPicture=null;
hqChart.ClearChartDrawPicture(picture);
// subToolDiv.innerHTML = "";
$(".subTolls").css("display","none");
});
var self = this;
$(".subtool-set").click(function(){
$(self.SubToolsDiv).hide();
//创建div设置窗口
if (!self.SettingMenu) self.SettingMenu=new ChartPictureTextSettingMenu(frame.ChartBorder.UIElement.parentNode);
self.SettingMenu.ChartPicture=picture;
self.SettingMenu.HQChart=hqChart;
self.SettingMenu.Position={Left:right + 80,Top:top + 20};
self.SettingMenu.DoModal();
});
$(".changes-color").click(function () {
document.getElementById('color').click();
$(".change-color").change(function () {
var color = $(".change-color").val();
picture.LineColor = color;
picture.PointColor = color;
if (hqChart.ChartDrawStorage) hqChart.ChartDrawStorage.SaveDrawData(picture); //保存下
});
});
//成交量分布图设置
$(".vp-set").click(function()
{
if (!self.SettingPV) self.SettingPV=new ChartPictureVolProfileSettingMenu(frame.ChartBorder.UIElement.parentNode);
self.SettingPV.ChartPicture=picture;
self.SettingPV.HQChart=hqChart;
self.SettingPV.Position={Left:right + 80,Top:top + 20};
self.SettingPV.DoModal();
});
JSConsole.Chart.Log("[ChartPictureSettingMenu::DoModal]", {Top:top,Left:left, Right:right});
}
}
//画图工具 文本设置窗口
function ChartPictureTextSettingMenu(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.ChartPicture;
this.SettingDiv;
this.Position;
this.BackupData; //画图工具备份数据
this.Close=function()
{
if (this.SettingDiv) this.DivElement.removeChild(this.SettingDiv); //直接删除
}
this.DoModal=function()
{
var text=this.ChartPicture.Text; //显示的文本
var fontOption=this.ChartPicture.FontOption; //字体设置
var lineColor=this.ChartPicture.LineColor;
//数据备份, 点取消的时候把备份数据设置回去
this.BackupData=
{
Text:text,
LineColor:lineColor,
FontOption:{Family: fontOption.Family, Size: fontOption.Size, Weight: fontOption.Weight, Style: fontOption.Style }
};
JSConsole.Chart.Log('[ChartPictureTextSettingMenu::DoModal] picture info',this.BackupData);
var self=this;
var div=this.DivElement.getElementsByClassName('chartpicture-text-setting')[0];
if (!div)
{
div=document.createElement("div");
div.className='chartpicture-text-setting';
this.DivElement.appendChild(div);
this.SettingDiv=div;
}
else
{
this.SettingDiv=div;
}
var titleContainerStr = '<div class="titleWrap">'+
'<span class="titleName">样式设置</span>'+
'<i class="closeBtn iconfont icon-close"></i>'+
'</div>';
var fontSizeArray = [10,11,12,14,16,20,24,28,32,40];
var fontArray = ['微软雅黑','宋体','Arial','仿宋'];
var sizeListStr = "";
var fontListStr = "";
fontArray.forEach(function(item,index){
fontListStr += index !== 0 ? '<p>'+item+'</P>' : '<p class="active">'+item+'</P>';
});
fontSizeArray.forEach(function(item,index){
sizeListStr += index !== 5 ? '<p>'+item+'</P>' : '<p class="active">'+item+'</P>';
});
var contentContainerStr = '<div class="contentWrap">'+
'<div class="styleOptions">'+
'<span class="colorPicker"><input type="color" id="fontColor" value="#1e90ff"></span>'+
'<div class="likeSelect fontSelect"><span class="choicedText">微软雅黑</span><div class="selectList">'+fontListStr+'</div><i class="iconfont icon-xia"></i></div>'+
'<div class="likeSelect fontSizeSelect"><span class="choicedText">20</span><div class="selectList">'+sizeListStr+'</div><i class="iconfont icon-xia"></i></div>'+
'<span class="strongFont likeBtn"><i class="iconfont icon-jiacu"></i></span>'+
'<span class="italicsFont likeBtn"><i class="iconfont icon-qingxieL"></i></span>'+
'</div>'+
'<textarea class="tArea" id="tArea" placeholder="Text"></textarea>'+
'</div>';
var btnContainer = '<div class="btnsContainer">'+
'<span class="okBtn btn">确认</span>'+
'<span class="cancelBtn btn">取消</span>'+
'</div>';
var pixelTatio = GetDevicePixelRatio();
var DoModalStr = titleContainerStr+contentContainerStr+btnContainer;
this.SettingDiv.style.left = this.Position.Left/pixelTatio + "px";
this.SettingDiv.style.top = this.Position.Top/pixelTatio + "px";
this.SettingDiv.innerHTML=DoModalStr;
this.SettingDiv.style.position = "absolute";
this.SettingDiv.style.display = "block";
$(".chartpicture-text-setting .colorPicker").css({ //初始设置
"borderColor":self.ChartPicture.LineColor,
"background-color":self.ChartPicture.LineColor
});
var family = this.ChartPicture.FontOption.Family;
$('.chartpicture-text-setting .fontSelect .choicedText').html(family);
fontArray.forEach(function(item,index){
if(item == family){
$('.chartpicture-text-setting .fontSelect p').removeClass('active');
$('.chartpicture-text-setting .fontSelect p').eq(index).addClass('active');
}
});
var size = this.ChartPicture.FontOption.Size;
$('.chartpicture-text-setting .fontSizeSelect .choicedText').html(size);
fontSizeArray.forEach(function(item,index){
if(item == size){
$('.chartpicture-text-setting .fontSizeSelect p').removeClass('active');
$('.chartpicture-text-setting .fontSizeSelect p').eq(index).addClass('active');
}
});
var weight = this.ChartPicture.FontOption.Weight;
if( weight != null && weight == 'bold'){
$('.chartpicture-text-setting .strongFont').addClass('hot');
}
var style = this.ChartPicture.FontOption.Style;
if( style != null && style == 'italic'){
$('.chartpicture-text-setting .italicsFont').addClass('hot');
}
var text = this.ChartPicture.Text;
$('.chartpicture-text-setting .tArea').val(text); //结束初始设置
var defaultTextOption = { Family:'微软雅黑', Size:20, Weight:null, Style:null };
$(".chartpicture-text-setting #fontColor").change(
{
Picture:this.ChartPicture
},
function(event)
{ //颜色选择
var value = $(this).val();
$(this).parent().css({
"borderColor":value,
"background-color":value
});
var chart=event.data.Picture;
chart.LineColor = value;
if (chart.Update) chart.Update(); //更新界面
}
);
$(".chartpicture-text-setting .fontSelect,.chartpicture-text-setting .fontSizeSelect").click(function(){
$(this).find('.selectList').toggle();
$(this).toggleClass('hot');
});
$(".chartpicture-text-setting .fontSelect p").click(
{
Picture:this.ChartPicture
},
function(event){ //字体选择
var choicedText = $(this).closest(".fontSelect").find('.choicedText').html();
var currentSelect = event.currentTarget.innerHTML;
if(choicedText !== currentSelect){
$(this).closest(".fontSelect").find('.choicedText').html(currentSelect);
$(this).siblings().removeClass('active');
$(this).addClass('active');
var chart = event.data.Picture;
chart.FontOption.Family = currentSelect;
if (chart.Update) chart.Update(); //更新界面
}
});
$(".chartpicture-text-setting .fontSizeSelect p").click(
{
Picture:this.ChartPicture
},
function(event){ //字号选择
var choicedText = $(this).closest(".fontSizeSelect").find('.choicedText').html();
var currentSelect = event.currentTarget.innerHTML;
if(choicedText !== currentSelect){
$(this).closest(".fontSizeSelect").find('.choicedText').html(currentSelect);
$(this).siblings().removeClass('active');
$(this).addClass('active');
var chart = event.data.Picture;
chart.FontOption.Size = Number(currentSelect);
if (chart.Update) chart.Update(); //更新界面
}
});
$(".chartpicture-text-setting .strongFont").click(
{
Picture:this.ChartPicture
},
function(event){
$(this).toggleClass('hot');
var classnames = $(this).attr('class');
if(classnames.indexOf('hot') > 0){
var chart = event.data.Picture;
chart.FontOption.Weight = 'bold';
if (chart.Update) chart.Update(); //更新界面
}
});
$(".chartpicture-text-setting .italicsFont").click(
{
Picture:this.ChartPicture
},
function(event){
$(this).toggleClass('hot')
var classnames = $(this).attr('class');
if(classnames.indexOf('hot') > 0){
var chart = event.data.Picture;
chart.FontOption.Style = 'italic';
if (chart.Update) chart.Update(); //更新界面
}
});
$(".chartpicture-text-setting .titleWrap .closeBtn,.chartpicture-text-setting .btnsContainer .cancelBtn").click( //取消
{
Picture:this.ChartPicture
},
function(event){
var picture = event.data.Picture;
picture.Text = self.BackupData.Text;
picture.LineColor = self.BackupData.LineColor;
picture.FontOption = self.BackupData.FontOption;
if (picture.Update) picture.Update();
self.Close();
});
$(".chartpicture-text-setting .tArea").keyup( //文本内容
{
Picture:this.ChartPicture
},
function(event){
JSConsole.Chart.Log('[ChartPictureTextSettingMenu::DoModal] $(".chartpicture-text-setting .tArea").keyup()');
var content = $(this).val();
var chart = event.data.Picture;
chart.Text = content;
if (chart.Update) chart.Update(); //更新界面
});
//确定按钮
$(".chartpicture-text-setting .btnsContainer .okBtn").click(
function()
{
self.Close();
if (self.HQChart && self.HQChart.ChartDrawStorage) self.HQChart.ChartDrawStorage.SaveDrawData(self.ChartPicture); //保存下
}
);
}
}
function ChartPictureVolProfileSettingMenu(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.ChartPicture;
this.SettingDiv;
this.Position;
this.ID=Guid();
this.Close=function()
{
if (this.SettingDiv) this.DivElement.removeChild(this.SettingDiv); //直接删除
}
this.DoModal=function()
{
var valueAreaVol=this.ChartPicture.VAVol; //Value area volume
var barPosition=this.ChartPicture.BarPosition;
var self=this;
var div=document.getElementById(this.ID);
if (!div)
{
div=document.createElement("div");
div.className='jchart-modifyindex-box';
div.id=this.ID;
this.DivElement.appendChild(div);
this.SettingDiv=div;
}
else
{
this.SettingDiv=div;
}
div.innerHTML=
`<div class='parameter'>\
<div class='parameter-header'>\
<span>固定范围成交量分布设置</span>\
<strong id='close' class='icon iconfont icon-close'></strong>\
</div>\
<div class='parameter-content'>
<input class='row-line' value=${valueAreaVol} />VAVol <br>
<input class='row-line' value=${barPosition} />BarPosition
</div>\
<div class='parameter-footer'>\
<button class='submit' >确定</button>\
<button class='cancel' >取消</button>\
</div>\
</div>`;
var pixelTatio = GetDevicePixelRatio();
var frame=this.HQChart.Frame.SubFrame[0].Frame;
var top=frame.ChartBorder.Top + 40;
var right=frame.ChartBorder.Right;
var left=frame.ChartBorder.GetLeft();
this.SettingDiv.style.right = right/pixelTatio + "px";
this.SettingDiv.style.top = top/pixelTatio + "px";
this.SettingDiv.style.position = "absolute";
this.SettingDiv.style.display = "block";
var btnCancel=div.getElementsByClassName("cancel")[0];
btnCancel.onclick=function()
{
self.Close();
}
var btnClose=div.getElementsByClassName("icon iconfont icon-close")[0];
btnClose.onclick=function()
{
self.Close();
}
var btnSubmit=div.getElementsByClassName("submit")[0];
btnSubmit.onclick=function()
{
var value=div.getElementsByClassName("row-line")[0].value;
self.ChartPicture.VAVol=parseFloat(value);
var value=parseInt(div.getElementsByClassName("row-line")[1].value);
self.ChartPicture.BarPosition=value>0?1:0;
self.ChartPicture.RequestVolumeProfileData();
self.Close();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////
//
// 各个品种分钟走势图坐标信息
//
//////////////////////////////////////////////////////////////////////////////////////
var MARKET_SUFFIX_NAME=
{
SH:'.SH',
SZ:'.SZ',
SHSZ_C_Index:'.CI', //自定义指数
BJ:".BJ", //北交所 BeiJing stock exchange
SHO:'.SHO', //上海交易所 股票期权
SZO:".SZO", //深证交易所 股票期权
HK:'.HK', //港股
FHK:'.FHK', //港股期货
SHFE: '.SHF', //上期所 (Shanghai Futures Exchange) | 上期所-能源
SHFE2:'.SHFE', //上期所 (Shanghai Futures Exchange) | 上期所-能源
CFFEX: '.CFE', //中期所 (China Financial Futures Exchange)
CFFEX2:'.CFFEX', //中期所 (China Financial Futures Exchange)
CFFEX3:'.CF', //中期所 (China Financial Futures Exchange)
DCE: '.DCE', //大连商品交易所(Dalian Commodity Exchange)
CZCE: '.CZC', //郑州期货交易所
GZFE:".GZFE", //广州期货交易所
USA:'.USA', //美股
FTSE:'.FTSE', //富时中国
BIT:'.BIT', //数字货币 如比特币
BIZ:'.BIZ', //数字货币
FOREX:'.FOREX', //外汇 (Foreign Exchange)
NYMEX:'.NYMEX', //纽约商品期货交易所(New York Mercantile Exchange)
COMEX:".COMEX", //纽约商品期货交易所(New York Mercantile Exchange)
NYBOT:".NYBOT", //美國紐約商品交易所
CBOT:".CBOT", //芝商所
LME:".LME", //伦敦金属交易所
TOCOM:".TOCOM", //东京商品交易所(TOCOM)
IPE:".IPE", //美国洲际交易所 (ICE EUROPE)
TW:".TW", //台湾股票 9:00-13:30
JP:".JP", //日本股票 9:00-11:30, 12:30-15:00
//越南股市
HSX:".HSX", //HSX胡志明交易所
HNX:".HNX", //HNX河內交易所
UPCOM:".UPCOM", //UPCOM未上市公司交易所
ET:'.ET', //其他未知的品种
IsET:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.ET) > 0;
},
IsETShowAvPrice:function(upperSymbol) //是否显示均价
{
return false;
},
IsHSX:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.HSX)>0;
},
IsHNX:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.HNX)>0;
},
IsUPCOM:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.UPCOM)>0;
},
IsNYMEX:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.NYMEX)>0;
},
IsCOMEX:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.COMEX)>0;
},
IsNYBOT:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.NYBOT)>0;
},
IsCBOT:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.CBOT)>0;
},
IsLME:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.LME)>0;
},
IsTOCOM:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.TOCOM)>0;
},
IsIPE:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.IPE)>0;
},
IsForeignExchange(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.FOREX) > 0;
},
IsFTSE:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.FTSE) > 0;
},
IsFHK:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.FHK) > 0;
},
IsBIT:function(upperSymbol)
{
if (!upperSymbol) return false;
if (upperSymbol.indexOf(this.BIT) > 0) return true;
if (upperSymbol.indexOf(this.BIZ) > 0) return true;
return false;
},
IsUSA:function(upperSymbol) //是否是美股
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.USA) > 0;
},
IsSH: function (upperSymbol)
{
//需要精确匹配最后3位
var pos = upperSymbol.length-this.SH.length;
var find = upperSymbol.indexOf(this.SH);
return find == pos;
},
IsSZ: function (upperSymbol)
{
var pos = upperSymbol.length - this.SZ.length;
var find = upperSymbol.indexOf(this.SZ);
return find == pos;
},
IsBJ:function(upperSymbol)
{
var pos = upperSymbol.length - this.BJ.length;
var find = upperSymbol.indexOf(this.BJ);
return find == pos;
},
//自定义指数
IsSHSZCustomIndex:function(upperSymbol)
{
var pos = upperSymbol.length - this.SHSZ_C_Index.length;
var find = upperSymbol.indexOf(this.SHSZ_C_Index);
return find == pos;
},
IsSHO: function(upperSymbol)
{
if (this.IsSH(upperSymbol)) //10007211.sh
{
if (upperSymbol.length==11 && upperSymbol[0]=='1') return true;
}
var pos = upperSymbol.length - this.SHO.length;
var find = upperSymbol.indexOf(this.SHO);
return find == pos;
},
IsSZO: function(upperSymbol)
{
if (this.IsSZ(upperSymbol)) //90004047.sz
{
if (upperSymbol.length==11 && upperSymbol[0]=='9') return true;
}
var pos = upperSymbol.length - this.SZO.length;
var find = upperSymbol.indexOf(this.SZO);
return find == pos;
},
IsHK: function (upperSymbol)
{
var pos = upperSymbol.length - this.HK.length;
var find = upperSymbol.indexOf(this.HK);
return find == pos;
},
IsTW:function(upperSymbol)
{
var pos = upperSymbol.length - this.TW.length;
var find = upperSymbol.indexOf(this.TW);
return find == pos;
},
IsJP:function(upperSymbol)
{
var pos = upperSymbol.length - this.JP.length;
var find = upperSymbol.indexOf(this.JP);
return find == pos;
},
IsSHFE: function (upperSymbol)
{
if (!upperSymbol) return false;
if (upperSymbol.indexOf(this.SHFE) > 0) return true;
if (upperSymbol.indexOf(this.SHFE2) > 0) return true;
return false;
},
IsCFFEX: function (upperSymbol)
{
if (!upperSymbol) return false;
if (upperSymbol.indexOf(this.CFFEX) > 0) return true;
if (upperSymbol.indexOf(this.CFFEX2) > 0) return true;
var index=upperSymbol.indexOf(this.CFFEX3); //必须已.CF结尾
if (index > 0 && index+this.CFFEX3.length==upperSymbol.length) return true;
return false;
},
IsDCE: function (upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.DCE) > 0;
},
IsCZCE: function (upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.CZCE) > 0;
},
IsGZFE:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.GZFE) > 0;
},
IsChinaFutures:function(upperSymbol) //是否是国内期货 /期权
{
return this.IsSHO(upperSymbol) || this.IsSZO(upperSymbol) ||
this.IsGZFE(upperSymbol) ||
this.IsCFFEX(upperSymbol) || this.IsCZCE(upperSymbol) || this.IsDCE(upperSymbol) || this.IsSHFE(upperSymbol);
},
IsFutures:function(upperSymbol) //是否是期货 包含国外的
{
if (!upperSymbol) return false;
return this.IsChinaFutures(upperSymbol) ||
this.IsNYMEX(upperSymbol) || this.IsCOMEX(upperSymbol) || this.IsNYBOT(upperSymbol) || this.IsCBOT(upperSymbol) ||
this.IsLME(upperSymbol) || this.IsTOCOM(upperSymbol);
},
IsSHSZ:function(upperSymbol) //是否是沪深的股票
{
return this.IsSZ(upperSymbol)|| this.IsSH(upperSymbol) || this.IsSHSZCustomIndex(upperSymbol);
},
IsSHSZFund:function(upperSymbol) //是否是交易所基金
{
if (!upperSymbol) return false;
if (this.IsSH(upperSymbol)) //51XXXX.SH
{
if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true;
}
else if (this.IsSZ(upperSymbol)) //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz
{
if (upperSymbol.charAt(0)=='1' &&
(upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true;
}
return false;
},
IsSHSZIndex:function(symbol) //是否是沪深指数代码
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (this.IsSH(upperSymbol))
{
var temp=upperSymbol.replace('.SH','');
if (upperSymbol.charAt(0)=='0' && parseInt(temp)<=3000) return true;
}
else if (this.IsSZ(upperSymbol))
{
if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='9') return true;
}
else if (this.IsSHSZCustomIndex(upperSymbol)) //自定义指数
{
return true;
}
return false;
},
IsSHSZStockA:function(symbol) //是否是沪深A股
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (this.IsSH(upperSymbol))
{
var temp=upperSymbol.replace('.SH','');
if (upperSymbol.charAt(0)=='6') return true;
}
else if (this.IsSZ(upperSymbol))
{
if (upperSymbol.charAt(0)=='0')
{
if (upperSymbol.charAt(1)=='0' && upperSymbol.charAt(2)=='2') return true; //002 中小板
if (upperSymbol.charAt(1)!='7' && upperSymbol.charAt(1)!='8') return true;
}
else if (upperSymbol.charAt(0)=='3')
{
if (upperSymbol.charAt(1)=='0')
{
if (upperSymbol.charAt(2)=='0') return true; //创业板 300XXX.sz
if (upperSymbol.charAt(2)=='1') return true; //创业板 301XXX.sz
}
}
}
return false;
},
IsBJStock:function(symbol) //北交所股票
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (!this.IsBJ(upperSymbol)) return false;
var value=upperSymbol.charAt(0);
if (value=='4' || value=='8') return true;
return false;
},
IsSHStockSTAR:function(symbol) // 是否是科创板 Sci-Tech innovAtion boaRd (STAR Market)
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (!this.IsSH(upperSymbol)) return false;
if (upperSymbol.charAt(0)=='6' && upperSymbol.charAt(1)=='8' && upperSymbol.charAt(2)=='8')
return true;
return false;
},
IsSHGEM:function(symbol) //创业板(growth enterprise market) 30开头
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
if (!this.IsSH(upperSymbol)) return false;
if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='0')
return true;
return false;
},
GetMarketStatus:function(symbol) //获取市场状态 0=闭市 1=盘前 2=盘中 3=盘后
{
if (!symbol) return 0;
var upperSymbol=symbol.toUpperCase();
var nowDate= new Date();
var day = nowDate.getDay();
var time = nowDate.getHours() * 100 + nowDate.getMinutes();
if (this.IsUSA(upperSymbol))
{
var usaDate=GetLocalTime(-4);
var day = usaDate.getDay();
var time = usaDate.getHours() * 100 + usaDate.getMinutes();
if(day == 6 || day== 0) return 0; //周末
//9:30 - 16:00 考虑夏令时间时间增加1小时 9:30 - 17:00
if (time>1730) return 3;
if (time<930) return 1;
return 2;
}
else if (this.IsBIT(upperSymbol)) //数字货币24小时
{
return 2;
}
else if (this.IsForeignExchange(upperSymbol)) //外汇24小时
{
return 2;
}
else if (this.IsFTSE(upperSymbol)) //富时中国 9:00-16:30 17:00-04:45
{
if(day == 6 || day== 0) return 0; //周末
if (time>=830 && time<=2359) return 2;
if (time>=0 && time<=500) return 2;
return 0;
}
else if (this.IsFHK(upperSymbol)) //港股指数期货 9:15-12:00 13:00-16:30 17:15-01:00
{
if(day == 6 || day== 0) return 0; //周末
if (time>=900 && time<=2359) return 2;
if (time>=0 && time<=320) return 2;
return 0;
}
else if (this.IsET(upperSymbol))
{
return this.GetETMarketStatus(symbol);
}
else if (this.IsHK(upperSymbol)) //港股
{
if(day == 6 || day== 0) return 0; //周末
if(time>1630) return 3;
if(time<925) return 1;
return 2;
}
else if (this.IsTW(upperSymbol)) //台湾股票 上午9:00——下午1:30
{
if(day == 6 || day== 0) return 0; //周末
if(time>1410) return 3;
if(time<820) return 1;
return 2;
}
else if (this.IsJP(upperSymbol)) //日本股票 9:00-11:30 12:30-15:00
{
if(day == 6 || day== 0) return 0; //周末
if(time>1520) return 3;
if(time<830) return 1;
return 2;
}
else if (this.IsNYMEX(upperSymbol))
{
return this.GetNYMEXMarketStatus(upperSymbol);
}
else if (this.IsCOMEX(upperSymbol))
{
return this.GetCOMEXMarketStatus(upperSymbol);
}
else if (this.IsNYBOT(upperSymbol))
{
return this.GetNYBOTMarketStatus(upperSymbol);
}
else if (this.IsCBOT(upperSymbol))
{
return this.GetCBOTMarketStatus(upperSymbol);
}
else if (this.IsLME(upperSymbol))
{
return this.GetLMEMarketStatus(upperSymbol);
}
else if (this.IsTOCOM(upperSymbol))
{
return this.GetTOCOMMarketStatus(upperSymbol);
}
else if (this.IsChinaFutures(upperSymbol)) //国内期货
{
if(day == 6 || day== 0) return 0; //周末
if (this.IsCFFEX(upperSymbol)) //中金所期货 9:10-15:40
{
if(time>1540) return 3;
if(time<910) return 1;
return 2;
}
//21:00-2:30
if(time>=2100) return 2;
if (time<=240) return 2;
//8:55-11:30, 13:00-15:00
if(time>=830 && time<=1510) return 2;
return 1;
}
else //9:30 - 15:40 (默认9:10-15:40)
{
if(day == 6 || day== 0) return 0; //周末
if(time>1540) return 3;
if(time<910) return 1;
return 2;
}
},
GetLimitPriceRange:function(symbol, name) //涨停范围
{
if (!this.IsSHSZStockA(symbol)) return null;
if (this.IsSHStockSTAR(symbol)) return {Max:0.2 , Min:-0.2}; //科创板 [20% - -20%]
if (this.IsSHGEM(symbol)) return { Max:0.2 , Min:-0.2}; //创业板 [20% - -20%]
if (!name) return null;
if (name.indexOf('ST')>=0) return { Max:0.05, Min:-0.05 }; //ST 股票 [5% - -5%]
return {Max:0.1 , Min:-0.1}; //[10% - -10%]
},
GetDefaultDecimal:function(symbol) //默认小数位数
{
return 2;
},
GetSHDecimal:function(symbol)
{
return 2;
},
GetSZDecimal:function(symbol)
{
return 2;
},
GetFHKDecimal:function(symbol) //港股指数期货 小数位数
{
return 0;
},
GetFTSEDecimal:function(symbol) //富时中国A50期货 小数位数
{
return 0;
},
GetBITDecimal:function(symbol)
{
return 2;
},
GetSHODecimal:function(symbol)
{
return 4;
},
GetETDecimal:function(symbol)
{
return 2;
},
GetHKDecimal:function(symbol)
{
return 2;
},
GetTWDecimal:function(symbol)
{
return 2;
},
GetJPDecimal:function(symbol)
{
return 2;
},
GetHSXDecimal:function(symbol)
{
return 2;
},
GetHNXDecimal:function(symbol)
{
return 2;
},
GetUPCOMDecimal:function(symbol)
{
return 2;
},
GetForeignExchangeDecimal:function(symbol)
{
return 4;
},
GetNYMEXDecimal:function(symbol) //纽约期货交易所
{
return g_NYMEXTimeData.GetDecimal(symbol);
},
GetCOMEXDecimal:function(symbol)
{
return g_COMEXTimeData.GetDecimal(symbol);
},
GetNYBOTDecimal:function(symbol)
{
return g_NYBOTTimeData.GetDecimal(symbol);
},
GetCBOTDecimal:function(symbol)
{
return g_CBOTTimeData.GetDecimal(symbol);
},
GetLMEDecimal:function(symbol)
{
return g_LMETimeData.GetDecimal(symbol);
},
GetTOCOMDecimal:function(symbol)
{
return g_TOCOMTimeData.GetDecimal(symbol);
},
GetIPEDecimal:function(symbol)
{
return g_IPETimeData.GetDecimal(symbol);
},
GetETMarketStatus:function(symbol)
{
// 0=闭市 1=盘前 2=盘中 3=盘后
return 2;
},
GetNYMEXMarketStatus:function(symbol)
{
return g_NYMEXTimeData.GetMarketStatus(symbol);
},
GetCOMEXMarketStatus:function(symbol)
{
return g_COMEXTimeData.GetMarketStatus(symbol);
},
GetNYBOTMarketStatus:function(symbol)
{
return g_NYBOTTimeData.GetMarketStatus(symbol);
},
GetCBOTMarketStatus:function(symbol)
{
return g_CBOTTimeData.GetMarketStatus(symbol);
},
GetLMEMarketStatus:function(symbol)
{
return g_LMETimeData.GetMarketStatus(symbol);
},
GetTOCOMMarketStatus:function(symbol)
{
return g_TOCOMTimeData.GetMarketStatus(symbol);
},
GetIPEMarketStatus:function(symbol)
{
return g_IPETimeData.GetMarketStatus(symbol);
},
IsShowMinuteVolTitle:function(symbol) //是否画走势图成交量标题
{
if (!symbol) return false;
var upperSymbol=symbol.toUpperCase();
//if (this.IsChinaFutures(upperSymbol)) return true;
return false;
},
IsShowMinutePostionLine:function(upperSymbol) //分时图 成交量图中是否显示持仓线
{
if(MARKET_SUFFIX_NAME.IsFutures(upperSymbol) || MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol)) return true;
return false;
},
IsShowMinuteColorVolBar:function(symobl) //是否分时图成绩量柱子使用彩色柱
{
if (g_JSChartResource.Minute.VolBarColor) return true;
return false;
},
IsEnableRight:function(period, symbol, rightFormula) //是否支持复权
{
if (!MARKET_SUFFIX_NAME.IsSHSZStockA(symbol) && !MARKET_SUFFIX_NAME.IsBJStock(symbol)) return false;
if (ChartData.IsTickPeriod(period)) return false; //分笔没有复权
if (IFrameSplitOperator.IsPlusNumber(rightFormula)) return true; //复权因子复权
if (ChartData.IsMinutePeriod(period,true)) return false; //内置分钟K线不支持复权
return true;
}
}
//走势图分钟数据对应的时间
function MinuteTimeStringData()
{
this.SHSZ = null; //上海深证交易所时间
this.BJ=null;
this.SHO=null; //上海期权交易时间
this.SZO=null; //深证期权交易时间
this.HK = null; //香港交易所时间
this.Futures=new Map(); //期货交易时间 key=时间名称 Value=数据
this.USA = null; //美股交易时间
this.FTSE=null; //富时中国
this.FHK=null; //港股指数期货
this.ForeEx=null; //外汇
this.BIT=null; //数字货币
this.TW=null; //台湾股票
this.JP=null; //日本股票
this.HSX=null; //HSX胡志明交易所
this.HNX=null; //HNX河內交易所
this.UPCOM=null; //UPCOM未上市公司交易所
this.Initialize = function () //初始化 默认只初始化沪深的 其他市场动态生成
{
//this.SHSZ = this.CreateSHSZData();
//this.HK = this.CreateHKData();
}
this.GetET=function(upperSymbol) //当天所有的分钟
{
throw {Name:'MinuteTimeStringData::GetET', Error:'not implement'};
}
this.GetSHSZ=function(upperSymbol) //动态创建
{
if (!this.SHSZ) this.SHSZ=this.CreateSHSZData();
return this.SHSZ;
}
this.GetBJ=function(upperSymbol)
{
if (!this.BJ) this.BJ=this.CreateBJData();
return this.BJ;
}
this.GetSHO=function(upperSymbol)
{
if (!this.SHO) this.SHO=this.CreateSHOData();
return this.SHO;
}
this.GetSZO=function(upperSymbol)
{
if (!this.SZO) this.SZO=this.CreateSZOData();
return this.SZO;
}
this.GetHK=function(upperSymbol)
{
if (!this.HK) this.HK = this.CreateHKData();
return this.HK;
}
this.GetTW=function(upperSymbol)
{
if (this.TW) this.TW=this.CreateTWData();
return this.TW;
}
this.GetJP=function(upperSymbol)
{
if (this.JP) this.JP=this.CreateJPData();
return this.JP;
}
this.GetHSX=function(upperSymbol)
{
if (this.HSX) this.HSX=this.CreateHSXData();
return this.HSX;
}
this.GetHNX=function(upperSymbol)
{
if (this.HNX) this.HSX=this.CreateHNXData();
return this.HNX;
}
this.GetUPCOM=function(upperSymbol)
{
if (this.UPCOM) this.UPCOM=this.CreateUPCOMData();
return this.UPCOM;
}
this.GetFutures=function(splitData)
{
if (!this.Futures.has(splitData.Name))
{
var data = this.CreateTimeData(splitData.Data);
this.Futures.set(splitData.Name,data);
}
return this.Futures.get(splitData.Name);
}
// type=时间类型
this.GetUSA=function(upperSymbol)
{
if (!this.USA) this.USA=this.CreateUSAData(0);
return this.USA;
}
this.GetFTSE=function()
{
if (!this.FTSE) this.FTSE=this.CreateFTSEData();
return this.FTSE;
}
this.GetFHK=function()
{
if (!this.FHK) this.FHK=this.CreateFHKData();
return this.FHK;
}
this.GetForeignExchange=function(upperSymbol)
{
if (!this.ForeEx) this.ForeEx=this.CreateForeignExchangeData();
return this.ForeEx;
}
this.GetBIT=function(upperSymbol)
{
if (!this.BIT) this.BIT=this.CreateBITData();
return this.BIT;
}
this.CreateSHSZData = function ()
{
const TIME_SPLIT =
[
{ Start: 925, End: 925 },
{ Start: 930, End: 1130 },
{ Start: 1300, End: 1500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateBJData=function()
{
const TIME_SPLIT =
[
{ Start: 925, End: 925 },
{ Start: 930, End: 1130 },
{ Start: 1300, End: 1500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateSHOData=function()
{
const TIME_SPLIT =
[
{ Start: 930, End: 1129 },
{ Start: 1300, End: 1500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateSZOData=function()
{
const TIME_SPLIT =
[
{ Start: 930, End: 1129 },
{ Start: 1300, End: 1500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateHKData = function ()
{
const TIME_SPLIT =
[
{ Start: 930, End: 1200 },
{ Start: 1300, End: 1600 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateTWData=function()
{
const TIME_SPLIT =
[
{ Start: 900, End: 1330 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateJPData=function()
{
const TIME_SPLIT =
[
{ Start: 900, End: 1130 },
{ Start: 1230, End: 1500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateFTSEData=function()
{
const TIME_SPLIT=
[
{ Start:1700, End:2359 },
{ Start:0, End:445 },
{ Start:900, End:1630 }
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateFHKData=function()
{
//港股指数期货 9:15-12:00 13:00-16:30 17:15-03:00
const TIME_SPLIT=
[
{ Start:1715, End:2359 },
{ Start:0, End:300 },
{ Start:915, End:1200 },
{ Start:1300, End:1630 },
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateHSXData=function()
{
throw {Name:'MinuteTimeStringData::CreateHSXData', Error:'not implement'};
}
this.CreateHNXData=function()
{
throw {Name:'MinuteTimeStringData::CreateHNXData', Error:'not implement'};
}
this.CreateUPCOMData=function()
{
throw {Name:'MinuteTimeStringData::CreateUPCOMData', Error:'not implement'};
}
this.CreateUSAData=function(type)
{
if (type==1) //美国夏令时
{
const TIME_SPLIT =
[
{ Start: 2130, End: 2359 },
{ Start: 0, End: 400 }
];
return this.CreateTimeData(TIME_SPLIT);
}
else if (type==2) //非夏令时
{
const TIME_SPLIT =
[
{ Start: 2230, End: 2359 },
{ Start: 0, End: 500 }
];
return this.CreateTimeData(TIME_SPLIT);
}
else //使用美国本地时间
{
const TIME_SPLIT =
[
{ Start: 930, End: 1600 } //美国东部时间9:30到16:00
];
return this.CreateTimeData(TIME_SPLIT);
}
}
this.CreateForeignExchangeData=function()
{
//外汇 7:00 - 6:59
const TIME_SPLIT=
[
{ Start:600, End:2359 },
{ Start:0, End:559 },
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateBITData=function()
{
//数字货币 7:00 - 6:59
const TIME_SPLIT=
[
{ Start:600, End:2359 },
{ Start:0, End:559 },
];
return this.CreateTimeData(TIME_SPLIT);
}
this.CreateTimeData = function (timeSplit)
{
var data = [];
for (var i in timeSplit)
{
var item = timeSplit[i];
for (var j = item.Start; j <= item.End; ++j)
{
if (j % 100 >= 60) continue; //大于60分钟的数据去掉
data.push(j);
}
}
return data;
}
this.GetTimeData = function (symbol)
{
if (!symbol) return this.SHSZ;
var upperSymbol = symbol.toLocaleUpperCase(); //转成大写
if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol)) return this.GetSHO();
if (MARKET_SUFFIX_NAME.IsSZO(upperSymbol)) return this.GetSZO();
if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol)) return this.GetSHSZ(upperSymbol);
if (MARKET_SUFFIX_NAME.IsBJ(upperSymbol)) return this.GetBJ(upperSymbol);
if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) return this.GetHK(upperSymbol);
if (MARKET_SUFFIX_NAME.IsTW(upperSymbol)) return this.GetTW(upperSymbol);
if (MARKET_SUFFIX_NAME.IsJP(upperSymbol)) return this.GetJP(upperSymbol);
if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol)) return this.GetUSA(upperSymbol);
if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol) || MARKET_SUFFIX_NAME.IsGZFE(upperSymbol))
{
var splitData = g_FuturesTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol)) return this.GetFTSE();
if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol)) return this.GetFHK();
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) return this.GetForeignExchange(upperSymbol);
if (MARKET_SUFFIX_NAME.IsET(upperSymbol)) return this.GetET(upperSymbol);
if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) return this.GetBIT(upperSymbol);
//越南股市
if (MARKET_SUFFIX_NAME.IsHSX(upperSymbol)) return this.GetHSX(upperSymbol);
if (MARKET_SUFFIX_NAME.IsHNX(upperSymbol)) return this.GetHNX(upperSymbol);
if (MARKET_SUFFIX_NAME.IsUPCOM(upperSymbol)) return this.GetUPCOM(upperSymbol);
if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol)) //纽约期货交易所
{
var splitData = g_NYMEXTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol)) //纽约期货交易所
{
var splitData = g_COMEXTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol)) //纽约期货交易所
{
var splitData = g_NYBOTTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol)) //芝商所
{
var splitData = g_CBOTTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsLME(upperSymbol)) //伦敦LME
{
var splitData = g_LMETimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol)) //东京商品交易所(TOCOM)
{
var splitData = g_TOCOMTimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol)) //东京商品交易所(TOCOM)
{
var splitData = g_IPETimeData.GetSplitData(upperSymbol);
if (!splitData) return null;
return this.GetFutures(splitData);
}
}
}
//走势图刻度分钟线
function MinuteCoordinateData()
{
//沪深走势图时间刻度
const SHZE_MINUTE_X_COORDINATE =
{
Full: //完整模式
[
[0, 0, "rgb(200,200,200)", "09:30"], //[0]=索引 [1]=线段类型(预留) [2]=文字颜色(弃用) [3]=刻度文字 [4]=线段颜色 [5]=背景色
[31, 0, "RGB(200,200,200)", "10:00"],
[61, 0, "RGB(200,200,200)", "10:30"],
[91, 0, "RGB(200,200,200)", "11:00"],
[122, 1, "RGB(200,200,200)", "13:00"],
[152, 0, "RGB(200,200,200)", "13:30"],
[182, 0, "RGB(200,200,200)", "14:00"],
[212, 0, "RGB(200,200,200)", "14:30"],
[242, 1, "RGB(200,200,200)", "15:00"], // 15:00
],
Simple: //简洁模式
[
[0, 0, "rgb(200,200,200)", "09:30"],
[61, 0, "RGB(200,200,200)", "10:30"],
[122, 1, "RGB(200,200,200)", "13:00"],
[182, 0, "RGB(200,200,200)", "14:00"],
[242, 1, "RGB(200,200,200)", "15:00"]
],
Min: //最小模式
[
[0, 0, "rgb(200,200,200)", "09:30"],
[122, 1, "RGB(200,200,200)", "13:00"],
[242, 1, "RGB(200,200,200)", "15:00"]
],
Count: 243,
MiddleCount: 122,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 400) return this.Simple;
return this.Full;
}
};
//上海股票期权时间刻度
const SHO_MINUTE_X_COORDINATE =
{
Full: //完整模式
[
[0, 0, "rgb(200,200,200)", "09:30"],
[30, 0, "RGB(200,200,200)", "10:00"],
[60, 0, "RGB(200,200,200)", "10:30"],
[90, 0, "RGB(200,200,200)", "11:00"],
[120, 1, "RGB(200,200,200)", "13:00"],
[150, 0, "RGB(200,200,200)", "13:30"],
[180, 0, "RGB(200,200,200)", "14:00"],
[210, 0, "RGB(200,200,200)", "14:30"],
[240, 1, "RGB(200,200,200)", "15:00"], // 15:00
],
Simple: //简洁模式
[
[0, 0, "rgb(200,200,200)", "09:30"],
[60, 0, "RGB(200,200,200)", "10:30"],
[120, 1, "RGB(200,200,200)", "13:00"],
[180, 0, "RGB(200,200,200)", "14:00"],
[240, 1, "RGB(200,200,200)", "15:00"]
],
Min: //最小模式
[
[0, 0, "rgb(200,200,200)", "09:30"],
[120, 1, "RGB(200,200,200)", "13:00"],
[240, 1, "RGB(200,200,200)", "15:00"]
],
Count: 241,
MiddleCount: 120,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 400) return this.Simple;
return this.Full;
}
};
//港股走势图时间刻度
const HK_MINUTE_X_COORDINATE =
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "09:30"],
[30, 0, "RGB(200,200,200)", "10:00"],
[60, 1, "RGB(200,200,200)", "10:30"],
[90, 0, "RGB(200,200,200)", "11:00"],
[120, 1, "RGB(200,200,200)", "11:30"],
[151, 0, "RGB(200,200,200)", "13:00"],
[181, 1, "RGB(200,200,200)", "13:30"],
[211, 0, "RGB(200,200,200)", "14:00"],
[241, 1, "RGB(200,200,200)", "14:30"],
[271, 0, "RGB(200,200,200)", "15:00"],
[301, 1, "RGB(200,200,200)", "15:30"],
[331, 1, "RGB(200,200,200)", "16:00"]
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "09:30"],
[60, 1, "RGB(200,200,200)", "10:30"],
[120, 1, "RGB(200,200,200)", "11:30"],
[211, 0, "RGB(200,200,200)", "14:00"],
[271, 0, "RGB(200,200,200)", "15:00"],
[331, 1, "RGB(200,200,200)", "16:00"]
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "09:30"],
[151, 0, "RGB(200,200,200)", "13:00"],
[331, 1, "RGB(200,200,200)", "16:00"]
],
Count: 332,
MiddleCount: 151,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 450) return this.Simple;
return this.Full;
}
};
//美股走势图时间刻度
const USA_MINUTE_X_COORDINATE =
{
/*
Full: //完整模式
[
[0, 0, "rgb(200,200,200)", "21:30"],
[60, 0, "RGB(200,200,200)", "22:30"],
[120, 1, "RGB(200,200,200)", "23:30"],
[210, 0, "RGB(200,200,200)", "01:00"],
[270, 0, "RGB(200,200,200)", "02:00"],
[330, 0, "RGB(200,200,200)", "03:00"],
[390, 0, "RGB(200,200,200)", "04:00"],
],
Simple: //简洁模式
[
[0, 0, "rgb(200,200,200)", "21:30"],
[160, 1, "RGB(200,200,200)", "00:00"],
[270, 0, "RGB(200,200,200)", "02:00"],
[390, 0, "RGB(200,200,200)", "04:00"],
],
Min: //最小模式
[
[0, 0, "rgb(200,200,200)", "21:30"],
[160, 1, "RGB(200,200,200)", "00:00"],
[390, 0, "RGB(200,200,200)", "04:00"],
],
*/
//美国本地时间
Full: //完整模式
[
[0, 0, "rgb(200,200,200)", "9:30"],
[30, 0, "RGB(200,200,200)", "10:00"],
[90, 1, "RGB(200,200,200)", "11:00"],
[150, 0, "RGB(200,200,200)", "12:00"],
[210, 0, "RGB(200,200,200)", "13:00"],
[270, 0, "RGB(200,200,200)", "14:00"],
[330, 0, "RGB(200,200,200)", "15:00"],
[390, 0, "RGB(200,200,200)", "16:00"],
],
Simple: //简洁模式
[
[30, 0, "rgb(200,200,200)", "10:00"],
[150, 1, "RGB(200,200,200)", "12:00"],
[270, 0, "RGB(200,200,200)", "14:00"],
[390, 0, "RGB(200,200,200)", "16:00"],
],
Min: //最小模式
[
[30, 0, "rgb(200,200,200)", "10:00"],
[210, 1, "RGB(200,200,200)", "13:00"],
[390, 0, "RGB(200,200,200)", "16:00"],
],
Count: 391,
MiddleCount: 211,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 400) return this.Simple;
return this.Full;
}
};
//富时中国
const FTSE_MINUTE_X_COORDINATE=
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "17:00"],
//[60, 0, "RGB(200,200,200)", "18:00"],
[120, 1, "RGB(200,200,200)", "19:00"],
//[180, 0, "RGB(200,200,200)", "20:00"],
[240, 1, "RGB(200,200,200)", "21:00"],
//[300, 0, "RGB(200,200,200)", "22:00"],
[360, 1, "RGB(200,200,200)", "23:00"],
//[420, 0, "RGB(200,200,200)", "00:00"],
[480, 1, "RGB(200,200,200)", "01:00"],
//[540, 0, "RGB(200,200,200)", "02:00"],
[600, 1, "RGB(200,200,200)", "03:00"],
//[660, 1, "RGB(200,200,200)", "04:00"],
[706, 1, "RGB(200,200,200)", "09:00"],
//[766, 1, "RGB(200,200,200)", "10:00"],
[826, 1, "RGB(200,200,200)", "11:00"],
//[886, 1, "RGB(200,200,200)", "12:00"],
[946, 1, "RGB(200,200,200)", "13:00"],
//[1006, 1, "RGB(200,200,200)", "14:00"],
[1066, 1, "RGB(200,200,200)", "15:00"],
[1156, 1, "RGB(200,200,200)", "16:30"],
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "17:00"],
//[60, 0, "RGB(200,200,200)", "18:00"],
//[120, 1, "RGB(200,200,200)", "19:00"],
//[180, 0, "RGB(200,200,200)", "20:00"],
[240, 1, "RGB(200,200,200)", "21:00"],
//[300, 0, "RGB(200,200,200)", "22:00"],
//[360, 1, "RGB(200,200,200)", "23:30"],
//[420, 0, "RGB(200,200,200)", "00:00"],
[480, 1, "RGB(200,200,200)", "01:00"],
//[540, 0, "RGB(200,200,200)", "02:00"],
//[600, 1, "RGB(200,200,200)", "03:00"],
//[660, 1, "RGB(200,200,200)", "04:00"],
[706, 1, "RGB(200,200,200)", "09:00"],
//[766, 1, "RGB(200,200,200)", "10:00"],
//[826, 1, "RGB(200,200,200)", "11:00"],
//[886, 1, "RGB(200,200,200)", "12:00"],
[946, 1, "RGB(200,200,200)", "13:00"],
//[1006, 1, "RGB(200,200,200)", "14:00"],
//[1066, 1, "RGB(200,200,200)", "15:00"],
[1156, 1, "RGB(200,200,200)", "16:30"],
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "17:00"],
[706, 1, "RGB(200,200,200)", "09:00"],
[1156, 1, "RGB(200,200,200)", "16:30"],
],
Count: 1157,
MiddleCount: 707,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 450) return this.Simple;
return this.Full;
}
}
//港股指数期货
const FHK_MINUTE_X_COORDINATE=
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "17:15"],
[105, 1, "RGB(200,200,200)", "19:00"],
[225, 1, "RGB(200,200,200)", "21:00"],
[345, 1, "RGB(200,200,200)", "23:00"],
[586, 0, "RGB(200,200,200)", "09:15"],
[691, 1, "RGB(200,200,200)", "11:00"],
[812, 1, "RGB(200,200,200)", "14:00"],
[963, 1, "RGB(200,200,200)", "16:30"],
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "17:15"],
[225, 1, "RGB(200,200,200)", "21:00"],
[586, 0, "RGB(200,200,200)", "09:15"],
[752, 1, "RGB(200,200,200)", "13:00"],
[963, 1, "RGB(200,200,200)", "16:30"],
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "17:15"],
[586, 0, "RGB(200,200,200)", "09:15"],
[963, 1, "RGB(200,200,200)", "16:30"],
],
Count: 963,
MiddleCount: 526,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 450) return this.Simple;
return this.Full;
}
}
//外汇
const FOREX_MINUTE_X_COORDINATE=
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[120, 1, "RGB(200,200,200)", "08:00"],
[240, 1, "RGB(200,200,200)", "10:00"],
[360, 1, "RGB(200,200,200)", "12:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[600, 1, "RGB(200,200,200)", "16:00"],
[720, 1, "RGB(200,200,200)", "18:00"],
[840, 1, "RGB(200,200,200)", "20:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
[1080, 1, "RGB(200,200,200)", "0:00"],
[1200, 1, "RGB(200,200,200)", "02:00"],
[1320, 1, "RGB(200,200,200)", "04:00"],
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[240, 1, "RGB(200,200,200)", "10:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[720, 1, "RGB(200,200,200)", "18:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
[1200, 1, "RGB(200,200,200)", "02:00"],
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
],
Count: 1440,
MiddleCount: 600,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 450) return this.Simple;
return this.Full;
}
}
//台湾股票
const TW_MINUTE_X_COORDINATE=
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "09:00"],
[30, 0, "RGB(200,200,200)", "09:30"],
[60, 1, "RGB(200,200,200)", "10:00"],
[90, 0, "RGB(200,200,200)", "10:30"],
[120, 1, "RGB(200,200,200)", "11:00"],
[150, 0, "RGB(200,200,200)", "11:30"],
[180, 1, "RGB(200,200,200)", "12:00"],
[210, 0, "RGB(200,200,200)", "12:30"],
[240, 1, "RGB(200,200,200)", "13:00"],
[270, 0, "RGB(200,200,200)", "13:30"],
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "09:00"],
[60, 1, "RGB(200,200,200)", "10:00"],
[120, 1, "RGB(200,200,200)", "11:00"],
[180, 1, "RGB(200,200,200)", "12:00"],
[270, 0, "RGB(200,200,200)", "13:30"],
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "09:00"],
[60, 1, "RGB(200,200,200)", "11:00"],
[270, 0, "RGB(200,200,200)", "13:30"],
],
Count: 271,
MiddleCount: 151,
GetData: function (width)
{
if (width < 200) return this.Min;
else if (width < 450) return this.Simple;
return this.Full;
}
}
this.GetCoordinateData = function (symbol, width)
{
var data = null;
if (!symbol)
{
data = SHZE_MINUTE_X_COORDINATE; //默认沪深股票
}
else
{
var upperSymbol = symbol.toLocaleUpperCase(); //转成大写
if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol))
data=this.GetSHOData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsSZO(upperSymbol))
data=this.GetSZOData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol) || MARKET_SUFFIX_NAME.IsSHSZIndex(upperSymbol))
data = this.GetSHSZData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsBJ(upperSymbol))
data=this.GetBJData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsHK(upperSymbol))
data=this.GetHKData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsTW(upperSymbol))
data=this.GetTWData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsJP(upperSymbol))
data=this.GetJPData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol) || MARKET_SUFFIX_NAME.IsGZFE(upperSymbol))
return this.GetChinatFuturesData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol))
data = this.GetUSAData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol))
data=this.GetFTSEData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol))
data=this.GetFHKData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol))
data=this.GetForeignExchangeData(upperSymbol);
else if ((MARKET_SUFFIX_NAME.IsBIT(upperSymbol,width)))
data=this.GetBITData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol))
data=this.GetETData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol))
return data=this.GetNYMEXData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol))
return data=this.GetCOMEXData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol))
return data=this.GetNYBOTData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol))
return data=this.GetCBOTData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsLME(upperSymbol))
return data=this.GetLMEData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol))
return data=this.GetTOCOMData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol))
return data=this.GetIPEData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsHSX(upperSymbol))
return data=this.GetHSXData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsHNX(upperSymbol))
return data=this.GetHNXData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsUPCOM(upperSymbol))
return data=this.GetUPCOMData(upperSymbol,width);
}
//JSConsole.Chart.Log('[MiuteCoordinateData]', width);
var result = { Count: data.Count, MiddleCount: data.MiddleCount, Data: data.GetData(width) };
return result;
}
this.GetSHSZData=function(upperSymbol,width)
{
var result=SHZE_MINUTE_X_COORDINATE;
return result;
}
this.GetBJData=function(upperSymbol,width)
{
var result=SHZE_MINUTE_X_COORDINATE;
return result;
}
this.GetUSAData=function(upperSymbol,width)
{
var result=USA_MINUTE_X_COORDINATE;
return result;
}
this.GetHKData=function(upperSymbol,width)
{
var result=HK_MINUTE_X_COORDINATE;
return result;
}
this.GetTWData=function(upperSymbol,width)
{
return TW_MINUTE_X_COORDINATE;
}
this.GetSHOData=function(upperSymbol,width)
{
var result=SHO_MINUTE_X_COORDINATE;
return result;
}
this.GetSZOData=function(upperSymbol,width)
{
var result=SHO_MINUTE_X_COORDINATE;
return result;
}
this.GetFuturesData = function (upperSymbol,width,timeData)
{
var splitData = timeData.GetSplitData(upperSymbol);
if (!splitData) return null;
var stringData = g_MinuteTimeStringData.GetFutures(splitData);
if (!stringData) return null;
var result = { Count: stringData.length };
var coordinate=null;
var minWidth=200, simpleWidth=480;
/*
if (splitData.Name =='21:00-1:00,9:00-10:15,10:30-11:30,13:30-15:00')
{
minWidth=250;
simpleWidth=500;
}
*/
if (width < minWidth) coordinate = splitData.Coordinate.Min;
else if (width < simpleWidth) coordinate = splitData.Coordinate.Simple;
else coordinate = splitData.Coordinate.Full;
var data=[];
for(var i=0;i<stringData.length;++i)
{
var value = stringData[i];
for(var j=0;j<coordinate.length;++j)
{
var coordinateItem = coordinate[j];
if (value == coordinateItem.Value)
{
var item = [i, 0, 'RGB(200,200,200)', coordinateItem.Text];
data.push(item);
break;
}
}
}
result.Data = data;
return result;
}
this.GetChinatFuturesData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_FuturesTimeData);
}
this.GetNYMEXData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_NYMEXTimeData);
}
this.GetCOMEXData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_COMEXTimeData);
}
this.GetNYBOTData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_NYBOTTimeData);
}
this.GetCBOTData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_CBOTTimeData);
}
this.GetLMEData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_LMETimeData);
}
this.GetTOCOMData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_TOCOMTimeData);
}
this.GetIPEData=function(upperSymbol,width)
{
return this.GetFuturesData(upperSymbol,width, g_IPETimeData);
}
this.GetFTSEData=function(upperSymbol,width)
{
var result=FTSE_MINUTE_X_COORDINATE;
return result;
}
this.GetFHKData=function(upperSymbol,width)
{
var result=FHK_MINUTE_X_COORDINATE;
return result
}
this.GetForeignExchangeData=function(upperSymbol,width)
{
var result=FOREX_MINUTE_X_COORDINATE;
return result;
}
this.GetBITData=function(upperSymbol,width)
{
var result=FOREX_MINUTE_X_COORDINATE; //先用外汇的吧
return result;
}
this.GetETData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetETData', Error:'not implement'};
}
this.GetJPData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetJPData', Error:'not implement'};
}
this.GetHSXData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetHSXData', Error:'not implement'};
}
this.GetHNXData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetHNXData', Error:'not implement'};
}
this.GetUPCOMData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetUPCOMData', Error:'not implement'};
}
}
//国内期货不同品种 交易时间数据
function FuturesTimeData()
{
this.TIME_SPLIT=
[
//ID=0 9:00-10:15,10:31-11:30,13:31-15:00
{
Name:'9:00-10:15,10:31-11:30,13:31-15:00',
Data:
[
//9:00-10:15,10:30-11:30,13:30-15:00
{ Start: 900, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=1 9:30-11:30,13:01-15:15
{
Name:'9:30-11:30,13:01-15:15',
Data:
[
{ Start: 930, End: 1130 },
{ Start: 1301, End: 1515 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1515, Text: '15:15' },
],
Simple: //简洁模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1515, Text: '15:15' },
],
Min: //最小模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1515, Text: '15:15' },
]
}
},
//ID=2 '9:30-11:30,13:01-15:00'
{
Name:'9:30-11:30,13:00-15:00',
Data:
[
{ Start: 930, End: 1130 },
{ Start: 1301, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-23:30,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2330 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=4 21:00-1:00,9:01-10:15,10:31-11:30,13:31-15:00
{
Name:'21:00-1:00,9:01-10:15,10:31-11:30,13:31-15:00',
Data:
[
{ Start: 2100, End: 2359 },
{ Start: 0, End: 100 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=5 21:00-2:30,9:01-10:15,10:31-11:30,13:31-15:00
{
Name:'21:00-2:30,9:01-10:15,10:31-11:30,13:31-15:00',
Data:
[
{ Start: 2100, End: 2359 },
{ Start: 0, End: 230 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID:6 21:00-23:00,9:01-10:15,10:30-11:30,13:31-15:00
{
Name:'21:00-23:00,9:01-10:15,10:30-11:30,13:31-15:00',
Data:
[
{ Start: 2100, End: 2300 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'9:00-11:30,13:00-15:00',
Data:
[
{ Start: 900, End: 1130 },
{ Start: 1300, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-23:00,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2300 },
{ Start: 900, End: 1015 },
{ Start: 1030, End: 1130 },
{ Start: 1330, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=9 9:01-10:15,10:31-11:30,13:31-15:00
{
Name:'9:01-10:15,10:31-11:30,13:31-15:00',
Data:
[
//9:01-10:15,10:31-11:30,13:31-15:00
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 901, Text: '9:00' },
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 901, Text: '9:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 901, Text: '9:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=10 21:00-1:00,9:01-10:15,10:31-11:30,13:31-15:00
{
Name:'21:01-1:00,9:01-10:15,10:31-11:30,13:31-15:00',
Data:
[
{ Start: 2101, End: 2359 },
{ Start: 0, End: 100 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID:11 21:01-23:00,9:01-10:15,10:30-11:30,13:31-15:00
{
Name:'21:01-23:00,9:01-10:15,10:30-11:30,13:31-15:00',
Data:
[
{ Start: 2101, End: 2300 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=12 21:01-2:30,9:01-10:15,10:31-11:30,13:31-15:00
{
Name:'21:01-2:30,9:01-10:15,10:31-11:30,13:31-15:00',
Data:
[
{ Start: 2101, End: 2359 },
{ Start: 0, End: 230 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2101, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
//ID=13 9:31-11:30,13:01-15:15
{
Name:'9:30-11:30,13:01-15:15',
Data:
[
{ Start: 931, End: 1130 },
{ Start: 1301, End: 1515 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1301, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1515, Text: '15:15' },
],
Simple: //简洁模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1301, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1515, Text: '15:15' },
],
Min: //最小模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1301, Text: '13:00' },
{ Value: 1515, Text: '15:15' },
]
}
},
//ID=14 '9:31-11:30,13:01-15:00'
{
Name:'9:31-11:30,13:01-15:00',
Data:
[
{ Start: 931, End: 1130 },
{ Start: 1301, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1301, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1301, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 931, Text: '9:30' },
{ Value: 1301, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
];
this.MAP_TWOWORDS=new Map([
//大连商品交易所
[MARKET_SUFFIX_NAME.DCE + '-JD', {Time:0,Decimal:0,Name:"鸡蛋"}],
[MARKET_SUFFIX_NAME.DCE + '-FB', {Time:0,Decimal:2,Name:"纤板"}],
[MARKET_SUFFIX_NAME.DCE + '-BB', {Time:0,Decimal:2,Name:"胶板"}],
[MARKET_SUFFIX_NAME.DCE + '-PP', {Time:6,Decimal:0,Name:"丙烯"}],
[MARKET_SUFFIX_NAME.DCE + '-JM', {Time:6,Decimal:1,Name:'焦煤'}],
[MARKET_SUFFIX_NAME.DCE + '-EG', {Time:6,Decimal:0,Name:'乙二醇'}],
[MARKET_SUFFIX_NAME.DCE + '-EB', {Time:6,Decimal:0,Name:'苯乙烯'}],
[MARKET_SUFFIX_NAME.DCE + '-CS', {Time:6,Decimal:0,Name:'淀粉'}],
[MARKET_SUFFIX_NAME.DCE + '-PG', {Time:6,Decimal:0,Name:'液化气'}],
[MARKET_SUFFIX_NAME.DCE + '-RR', {Time:6,Decimal:0,Name:'梗米'}],
[MARKET_SUFFIX_NAME.DCE + '-LH', {Time:0,Decimal:0,Name:'生猪'}],
//上期所
[MARKET_SUFFIX_NAME.SHFE + '-CU', {Time:4,Decimal:0,Name:"铜"}],
[MARKET_SUFFIX_NAME.SHFE + '-AL', {Time:4,Decimal:0,Name:"铝"}],
[MARKET_SUFFIX_NAME.SHFE + '-NI', {Time:4,Decimal:0,Name:"镍"}],
[MARKET_SUFFIX_NAME.SHFE + '-SN', {Time:4,Decimal:0,Name:'沪锡'}],
[MARKET_SUFFIX_NAME.SHFE + '-ZN', {Time:4,Decimal:0,Name:"沪锌"}],
[MARKET_SUFFIX_NAME.SHFE + '-PB', {Time:4,Decimal:0,Name:'沪铅'}],
[MARKET_SUFFIX_NAME.SHFE + '-RU', {Time:6,Decimal:0,Name:"天然橡胶"}],
[MARKET_SUFFIX_NAME.SHFE + '-FU', {Time:6,Decimal:0,Name:"燃料油"}],
[MARKET_SUFFIX_NAME.SHFE + '-RB', {Time:6,Decimal:0,Name:"螺纹钢"}],
[MARKET_SUFFIX_NAME.SHFE + '-BU', {Time:6,Decimal:0,Name:'石油沥青'}],
[MARKET_SUFFIX_NAME.SHFE + '-HC', {Time:6,Decimal:0,Name:"热轧卷板"}],
[MARKET_SUFFIX_NAME.SHFE + '-SP', {Time:6,Decimal:0,Name:"纸浆"}],
[MARKET_SUFFIX_NAME.SHFE + '-WR', {Time:0,Decimal:0,Name:"线材"}],
[MARKET_SUFFIX_NAME.SHFE + '-AG', {Time:5,Decimal:0,Name:"白银"}],
[MARKET_SUFFIX_NAME.SHFE + '-AU', {Time:5,Decimal:2,Name:"黄金"}],
[MARKET_SUFFIX_NAME.SHFE + '-SS', {Time:4,Decimal:0,Name:'不锈钢'}],
[MARKET_SUFFIX_NAME.SHFE + '-AO', {Time:4,Decimal:0,Name:'氧化铝'}],
[MARKET_SUFFIX_NAME.SHFE + '-BR', {Time:6,Decimal:0,Name:'合成橡胶'}],
//上期所-能源
[MARKET_SUFFIX_NAME.SHFE + '-NR', {Time:6,Decimal:1,Name:'20号胶'}],
[MARKET_SUFFIX_NAME.SHFE + '-SC', {Time:5,Decimal:1,Name:'原油'}],
[MARKET_SUFFIX_NAME.SHFE + '-LU', {Time:6,Decimal:0,Name:'低硫燃油'}],
[MARKET_SUFFIX_NAME.SHFE + '-BC', {Time:4,Decimal:0,Name:'国际铜'}],
[MARKET_SUFFIX_NAME.SHFE + '-EC', {Time:0,Decimal:0,Name:'集运指数'}],
//郑州期货交易所
[MARKET_SUFFIX_NAME.CZCE + '-CF', {Time:6,Decimal:0,Name:"棉花"}],
[MARKET_SUFFIX_NAME.CZCE + '-SR', {Time:6,Decimal:0,Name:"白糖"}],
[MARKET_SUFFIX_NAME.CZCE + '-MA', {Time:6,Decimal:0,Name:"甲醇"}],
[MARKET_SUFFIX_NAME.CZCE + '-ZC', {Time:6,Decimal:1,Name:'动力煤'}],
[MARKET_SUFFIX_NAME.CZCE + '-TA', {Time:6,Decimal:0,Name:"精对苯二甲酸(PTA)"}],
[MARKET_SUFFIX_NAME.CZCE + '-RM', {Time:6,Decimal:0,Name:'菜籽粕'}],
[MARKET_SUFFIX_NAME.CZCE + '-OI', {Time:6,Decimal:0,Name:"菜籽油"}],
[MARKET_SUFFIX_NAME.CZCE + '-ME', {Time:3,Decimal:0,Name:"甲醇(老)"}],
[MARKET_SUFFIX_NAME.CZCE + '-FG', {Time:6,Decimal:0,Name:'平板玻璃'}],
[MARKET_SUFFIX_NAME.CZCE + '-WS', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-WT', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-GN', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RO', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RS', {Time:0,Decimal:0,Name:"菜籽"}],
[MARKET_SUFFIX_NAME.CZCE + '-ER', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RI', {Time:0,Decimal:0,Name:"早籼稻"}],
[MARKET_SUFFIX_NAME.CZCE + '-WH', {Time:0,Decimal:0,Name:"强麦"}],
[MARKET_SUFFIX_NAME.CZCE + '-AP', {Time:0,Decimal:0,Name:"苹果"}],
[MARKET_SUFFIX_NAME.CZCE + '-PM', {Time:0,Decimal:0,Name:"普麦"}],
[MARKET_SUFFIX_NAME.CZCE + '-QM', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-TC', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-JR', {Time:0,Decimal:0,Name:"粳稻"}],
[MARKET_SUFFIX_NAME.CZCE + '-LR', {Time:0,Decimal:0,Name:"晚籼稻"}],
[MARKET_SUFFIX_NAME.CZCE + '-SF', {Time:0,Decimal:0,Name:"硅铁"}],
[MARKET_SUFFIX_NAME.CZCE + '-SM', {Time:0,Decimal:0,Name:"锰硅"}],
[MARKET_SUFFIX_NAME.CZCE + '-CJ', {Time:0,Decimal:2, Name:"红枣"}],
[MARKET_SUFFIX_NAME.CZCE + '-CY', {Time:6,Decimal:0, Name:"棉纱"}],
[MARKET_SUFFIX_NAME.CZCE + '-UR', {Time:0,Decimal:0, Name:"尿素"}],
[MARKET_SUFFIX_NAME.CZCE + '-SA', {Time:6,Decimal:0, Name:"纯碱"}],
[MARKET_SUFFIX_NAME.CZCE + '-PF', {Time:6,Decimal:0, Name:"短纤"}],
[MARKET_SUFFIX_NAME.CZCE + '-PK', {Time:0,Decimal:0, Name:"花生"}],
[MARKET_SUFFIX_NAME.CZCE + '-PR', {Time:6,Decimal:0, Name:"瓶片"}],
//中期所
[MARKET_SUFFIX_NAME.CFFEX + '-TF', {Time:1,Decimal:3,Name:"二债"}],
[MARKET_SUFFIX_NAME.CFFEX + '-TS', {Time:1,Decimal:3,Name:"五债"}],
[MARKET_SUFFIX_NAME.CFFEX + '-IH', {Time:2,Decimal:1,Name:'上证股指期货'}],
[MARKET_SUFFIX_NAME.CFFEX + '-IC', {Time:2,Decimal:1,Name:'中证股指期货'}],
[MARKET_SUFFIX_NAME.CFFEX + '-IF', {Time:2,Decimal:1,Name:'沪深股指期货'}],
[MARKET_SUFFIX_NAME.CFFEX + '-IM', {Time:2,Decimal:1,Name:'中证1000股指期货'}],
[MARKET_SUFFIX_NAME.CFFEX + '-IO', {Time:2,Decimal:1,Name:'沪深300股指期权'}],
[MARKET_SUFFIX_NAME.CFFEX + '-MO', {Time:2,Decimal:1,Name:'中证1000股指期权'}],
[MARKET_SUFFIX_NAME.CFFEX + '-HO', {Time:2,Decimal:1,Name:'上证50股指期权'}],
//广州期货交易所
[MARKET_SUFFIX_NAME.GZFE+'-SI', {Time:0,Decimal:2,Name:"工业硅"}],
[MARKET_SUFFIX_NAME.GZFE+'-LC', {Time:0,Decimal:2,Name:"碳酸锂"}]
]);
this.MAP_ONEWORD=new Map([
//大连商品交易所
[MARKET_SUFFIX_NAME.DCE + '-C', {Time:6,Decimal:0,Name:"玉米"}],
[MARKET_SUFFIX_NAME.DCE + '-L', {Time:6,Decimal:0,Name:"乙烯"}],
[MARKET_SUFFIX_NAME.DCE + '-V', {Time:6,Decimal:0,Name:"PVC"}],
[MARKET_SUFFIX_NAME.DCE + '-A', {Time:6,Decimal:0,Name:"豆一"}],
[MARKET_SUFFIX_NAME.DCE + '-B', {Time:6,Decimal:0,Name:"豆二"}],
[MARKET_SUFFIX_NAME.DCE + '-M', {Time:6,Decimal:0,Name:"豆粕"}],
[MARKET_SUFFIX_NAME.DCE + '-Y', {Time:6,Decimal:0,Name:"豆油"}],
[MARKET_SUFFIX_NAME.DCE + '-P', {Time:6,Decimal:0,Name:"棕榈"}],
[MARKET_SUFFIX_NAME.DCE + '-J', {Time:6,Decimal:1,Name:'焦炭'}],
[MARKET_SUFFIX_NAME.DCE + '-I', {Time:6,Decimal:1,Name:"铁矿"}],
//中期所
[MARKET_SUFFIX_NAME.CFFEX + '-T', {Time:1,Decimal:3,Name:"十债"}],
]);
//添加新品种
this.AddNewFutures=function(obj) //{ Suffix:后缀, Symbol:品种代码, Time:交易时间段, Decimal:小数位数, Name:名字 }
{
if (!obj) return;
var key=obj.Suffix+'-'+obj.Symbol;
var item={ Time:obj.Time, Decimal:obj.Decimal, Name:obj.Name };
if (obj.Symbol.length==1)
{
this.MAP_ONEWORD.set(key, item);
}
else if (obj.Symbol.length==2)
{
this.MAP_TWOWORDS.set(key, item);
}
}
this.GetData=function(upperSymbol)
{
var oneWord = upperSymbol.charAt(0);
var twoWords = upperSymbol.substr(0,2);
var oneWordName = null, twoWordsName=null;
if (MARKET_SUFFIX_NAME.IsDCE(upperSymbol)) //大连商品交易所
{
oneWordName = MARKET_SUFFIX_NAME.DCE+'-'+oneWord;
twoWordsName = MARKET_SUFFIX_NAME.DCE + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) //上期所
{
oneWordName = MARKET_SUFFIX_NAME.SHFE + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.SHFE + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol)) //中期所
{
oneWordName = MARKET_SUFFIX_NAME.CFFEX + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.CFFEX + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsCZCE(upperSymbol)) //郑州期货交易所
{
oneWordName = MARKET_SUFFIX_NAME.CZCE + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.CZCE + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsGZFE(upperSymbol)) //广州期货交易所
{
oneWordName = MARKET_SUFFIX_NAME.GZFE + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.GZFE + '-' + twoWords;
}
if (this.MAP_TWOWORDS.has(twoWordsName))
{
return this.MAP_TWOWORDS.get(twoWordsName);
}
if (this.MAP_ONEWORD.has(oneWordName))
{
return this.MAP_ONEWORD.get(oneWordName);
}
return null;
}
this.GetSplitData = function (upperSymbol)
{
var data=this.GetData(upperSymbol);
if (!data) return null;
return this.TIME_SPLIT[data.Time];
}
this.GetDecimal=function(upperSymbol)
{
var data=this.GetData(upperSymbol);
if (!data) return 2;
return data.Decimal;
}
}
//纽约商业交易所 交易时间数据
function NYMEXTimeData()
{
//美国标准时间
this.TIME_SPLIT=
[
{
Name:'6:00-5:00',
Data:
[
//6:00 - 5:00
{ Start: 600, End: 2359 },
{ Start: 0, End: 500 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 600, Text: '6:00' },
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' },
{ Value: 400, Text: '4:00' },
],
Simple: //简洁模式
[
{ Value: 600, Text: '6:00' },
//{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
//{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
//{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
//{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
//{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
//{ Value: 400, Text: '4:00' },
],
Min: //最小模式
[
{ Value: 600, Text: '6:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 500, Text: '5:00' }
]
}
}
]
//美国夏时令
this.TIME_SPLIT2=
[
{
Name:'7:00-6:00',
Data:
[
//6:00 - 5:00
{ Start: 700, End: 2359 },
{ Start: 0, End: 600 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 700, Text: '7:00' },
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' },
{ Value: 500, Text: '5:00' }
],
Simple: //简洁模式
[
{ Value: 700, Text: '7:00' },
//{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
//{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
//{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
//{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
//{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
//{ Value: 500, Text: '5:00' }
],
Min: //最小模式
[
{ Value: 700, Text: '7:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 500, Text: '5:00' }
]
}
}
]
this.FUTURES_LIST=
[
{ Symbol:"CL", Decimal:2, Time:0, Name:"原油"}, //原油
{ Symbol:"NG", Decimal:3, Time:0, Name:"天然气" }, //天然气
{ Symbol:"RB", Decimal:4, Time:0, Name:"汽油" }, //汽油
{ Symbol:"PL", Decimal:1, Time:0, Name:"铂金" }, //铂金
{ Symbol:"PA", Decimal:2, Time:0, Name:"钯金" }, //钯金
{ Symbol:"HR", Decimal:0, Time:0, Name:"热轧钢卷" }, //热轧钢卷
{ Symbol:"QM", Decimal:3, Time:0, Name:"迷你原油" }, //迷你原油
{ Symbol:"HO", Decimal:4, Time:0, Name:"燃油"}, //燃油
]
this.MarketSuffix=".NYMEX";
this.TimeType=0; // 0=标准时间 1=夏令时间 2=美国时间
this.GetFuturesInfo=function(upperSymbol)
{
if (upperSymbol.indexOf(this.MarketSuffix)<=0) return null;
for(var i in this.FUTURES_LIST)
{
var item=this.FUTURES_LIST[i];
if (upperSymbol.indexOf(item.Symbol)==0)
{
return item;
}
}
return null;
}
this.GetSplitData=function(upperSymbol)
{
//夏令和标准时间切换
var timeSplit=this.TimeType==0 ? this.TIME_SPLIT : this.TIME_SPLIT2;
var find=this.GetFuturesInfo(upperSymbol);
if (find) return timeSplit[find.Time];
return timeSplit[0];
}
this.GetDecimal=function(upperSymbol)
{
var find=this.GetFuturesInfo(upperSymbol);
if (find) return find.Decimal;
return 3;
}
this.GetMarketStatus=function(upperSymbol) // 0=闭市 1=盘前 2=盘中 3=盘后
{
var usaDate=GetLocalTime(-4); //需要转成美国时间的 周6 周日
var nowDate= new Date();
var day = usaDate.getDay();
var time = nowDate.getHours() * 100 + nowDate.getMinutes();
if(day == 6 || day== 0) return 0; //周末
if(time>430 && time<730) return 1;
return 2;
}
this.AddNewFutures=function(obj) //{ Symbol:品种代码, Time:时间id, Decimal:小数位数, Name:名字 }
{
if (!obj) return;
var newItem={ Symbol:obj.Symbol, Time:obj.Time, Decimal:obj.Decimal, Name:obj.Name };
for(var i=0;i<this.FUTURES_LIST.length;++i)
{
var item=this.FUTURES_LIST[i];
if (item.Symbol==newItem.Symbol)
{
this.FUTURES_LIST[i]=newItem;
return;
}
}
this.FUTURES_LIST.push(newItem);
}
}
//纽约金属交易所(COMEX)
function COMEXTimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
this.FUTURES_LIST=
[
{ Symbol:"GC", Decimal:1, Time:0, Name:"COMEX黄金"}, //COMEX黄金
{ Symbol:"QO", Decimal:2, Time:0, Name:"迷你黄金" }, //迷你黄金
{ Symbol:"MG", Decimal:1, Time:0, Name:"微型黄金" }, //微型黄金
{ Symbol:"QI", Decimal:4, Time:0, Name:"迷你白银" }, //迷你白银
{ Symbol:"SI", Decimal:3, Time:0, Name:"COMEX白银" }, //COMEX白银
{ Symbol:"HG", Decimal:4, Time:0, Name:"COMEX铜" } //COMEX铜
]
this.MarketSuffix=".COMEX";
}
//纽约期货交易所(ICEUS-NYBOT)
function NYBOTTimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
//美国标准时间
this.TIME_SPLIT=
[
{
Name:'9:00-2:20',
Data:
[
//9:00-2:20
{ Start: 900, End: 2359 },
{ Start: 0, End: 220 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 100, Text: '1:00' }
]
}
},
{
Name:'15:30-1:00',
Data:
[
//9:00-2:20
{ Start: 1530, End: 2359 },
{ Start: 0, End: 100 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 1600, Text: '16:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 0, Text: '0:00' },
{ Value: 100, Text: '1:00' }
],
Simple: //简洁模式
[
{ Value: 1600, Text: '16:00' },
//{ Value: 1600, Text: '17:00' },
{ Value: 1800, Text: '18:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 0, Text: '0:00' },
//{ Value: 100, Text: '1:00' }
],
Min: //最小模式
[
{ Value: 1600, Text: '16:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 100, Text: '1:00' }
]
}
}
]
//美国夏时令
this.TIME_SPLIT2=
[
{
Name:'10:00-3:20',
Data:
[
//9:00-2:20
{ Start: 1000, End: 2359 },
{ Start: 0, End: 320 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 1000, Text: '10:00' },
//{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
//{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
//{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
//{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 1000, Text: '10:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
},
{
Name:'16:30-2:00',
Data:
[
{ Start: 1630, End: 2359 },
{ Start: 0, End: 200 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 1700, Text: '17:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 0, Text: '0:00' },
{ Value: 100, Text: '1:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 1700, Text: '17:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 1900, Text: '19:00' },
//{ Value: 2000, Text: '20:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
//{ Value: 0, Text: '0:00' },
{ Value: 100, Text: '1:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 1700, Text: '17:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 200, Text: '2:00' }
]
}
}
]
this.FUTURES_LIST=
[
{ Symbol:"SB", Decimal:2, Time:1 }, //11号白糖
{ Symbol:"CT", Decimal:2, Time:0 }, //棉花
//{ Symbol:"KC", Decimal:2, Time:0 }, //咖啡
//{ Symbol:"DX", Decimal:2, Time:0 }, //美元指数
//{ Symbol:"CC", Decimal:2, Time:0 } //可可
]
this.MarketSuffix=".NYBOT";
this.GetMarketStatus=function(upperSymbol) // 0=闭市 1=盘前 2=盘中 3=盘后
{
var usaDate=GetLocalTime(-4); //需要转成美国时间的 周6 周日
var day = usaDate.getDay();
var time = usaDate.getHours() * 100 + usaDate.getMinutes();
if(day == 6 || day== 0) return 0; //周末
var find=this.GetFuturesInfo(upperSymbol);
if (!find) return 2;
if (find.Symbol=="SB") //Sugar No. 11 Futures 03:30 - 13:00
{
if (time>300 && time<1400) return 2;
}
else if (find.Symbol=="CT") //美棉 21:00-14:20
{
if( (time>=0 && time<=1500 ) || (time>=2000 && time<=2359) ) return 2;
return 1;
}
return 0;
}
}
//芝加哥期货交易所
function CBOTTimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
//标准时间
this.TIME_SPLIT=
[
//ID=0 8:00-2:20
{
Name:'8:00-2:20',
Data:
[
//6:00 - 5:00
{ Start: 800, End: 2359 },
{ Start: 0, End: 220 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
//{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
//{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
},
//ID=1 8:00-2:45
{
Name:'8:00-2:45',
Data:
[
//6:00 - 5:00
{ Start: 800, End: 2359 },
{ Start: 0, End: 245 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
//{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
//{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
},
//ID=2 6:00-5:00
{
Name:'6:00-5:00',
Data:
[
//6:00 - 5:00
{ Start: 600, End: 2359 },
{ Start: 0, End: 500 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 600, Text: '6:00' },
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' },
{ Value: 400, Text: '4:00' },
],
Simple: //简洁模式
[
{ Value: 600, Text: '6:00' },
//{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
//{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
//{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
//{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
//{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
//{ Value: 400, Text: '4:00' },
],
Min: //最小模式
[
{ Value: 600, Text: '6:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 500, Text: '5:00' }
]
}
},
//ID=3 08:00-20:45 21:31-02:20
{
Name:'08:00-20:45 21:31-02:20',
Data:
[
{ Start: 800, End: 2045 },
{ Start: 2131, End: 2359 },
{ Start: 0, End: 220 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
//{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
//{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
},
//ID=4 8:00-20:45 21:31-2:45
{
Name:'8:00-2:45',
Data:
[
{ Start: 800, End: 2045 },
{ Start: 2131, End: 2359 },
{ Start: 0, End: 245 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
//{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
//{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
},
//ID=5 06:00-04:15 04:31-05:00
{
Name:'06:00-04:15 04:31-05:00',
Data:
[
{ Start: 600, End: 2359 },
{ Start: 0, End: 415 },
{ Start: 431, End: 500 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 600, Text: '6:00' },
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' },
{ Value: 400, Text: '4:00' },
],
Simple: //简洁模式
[
{ Value: 600, Text: '6:00' },
//{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
//{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
//{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
//{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
//{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
//{ Value: 400, Text: '4:00' },
],
Min: //最小模式
[
{ Value: 600, Text: '6:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 500, Text: '5:00' }
]
}
}
]
//夏令时间
this.TIME_SPLIT2=
[
//ID=0 9:00-3:20
{
Name:'9:00-3:20',
Data:
[
{ Start: 900, End: 2359 },
{ Start: 0, End: 320 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' }
//{ Value: 300, Text: '3:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 300, Text: '3:00' }
]
}
},
//ID=1 9:00-3:45
{
Name:'9:00-3:45',
Data:
[
{ Start: 900, End: 2359 },
{ Start: 0, End: 345 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' }
//{ Value: 300, Text: '3:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 300, Text: '3:00' }
]
}
},
//ID=2 7:00-6:00
{
Name:'7:00-6:00',
Data:
[
{ Start: 700, End: 2359 },
{ Start: 0, End: 600 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 700, Text: '7:00' },
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' },
{ Value: 500, Text: '5:00' }
],
Simple: //简洁模式
[
{ Value: 700, Text: '7:00' },
//{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
//{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
//{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
//{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
//{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
//{ Value: 500, Text: '5:00' }
],
Min: //最小模式
[
{ Value: 700, Text: '7:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 500, Text: '5:00' }
]
}
},
//ID=3 09:00-21:45 22:31-03:20
{
Name:'09:00-21:45 22:31-03:20',
Data:
[
{ Start: 900, End: 2145 },
{ Start: 2231, End: 2359 },
{ Start: 0, End: 320 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' }
//{ Value: 300, Text: '3:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 300, Text: '3:00' }
]
}
},
//ID=4 09:00-21:45 22:31-03:45
{
Name:'09:00-21:45 22:31-03:45',
Data:
[
{ Start: 900, End: 2145 },
{ Start: 2231, End: 2359 },
{ Start: 0, End: 345 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' }
//{ Value: 300, Text: '3:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 300, Text: '3:00' }
]
}
},
//ID=5 07:00-05:15 05:31-06:00
{
Name:'07:00-05:15 05:31-06:00',
Data:
[
{ Start: 700, End: 2359 },
{ Start: 0, End: 515 },
{ Start: 531, End: 600 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 700, Text: '7:00' },
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' },
{ Value: 500, Text: '5:00' }
],
Simple: //简洁模式
[
{ Value: 700, Text: '7:00' },
//{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
//{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
//{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
//{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
//{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' }
//{ Value: 500, Text: '5:00' }
],
Min: //最小模式
[
{ Value: 700, Text: '7:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 500, Text: '5:00' }
]
}
}
]
this.FUTURES_LIST=
[
{ Symbol:"ZC", Decimal:2, Time:0, Name:"玉米" }, //玉米
{ Symbol:"XC", Decimal:2, Time:1, Name:"迷你玉米" }, //迷你玉米
{ Symbol:"ZS", Decimal:2, Time:0, Name:'大豆' }, //大豆
{ Symbol:"XK", Decimal:2, Time:1, Name:"迷你大豆" }, //迷你大豆
{ Symbol:"ZL", Decimal:2, Time:0, Name:"豆油"}, //豆油
{ Symbol:"ZR", Decimal:2, Time:0, Name:"稻谷" }, //稻谷
{ Symbol:"ZO", Decimal:2, Time:0, Name:"燕麦" }, //燕麦
{ Symbol:"ZW", Decimal:2, Time:0, Name:'小麦'}, //小麦
{ Symbol:"XW", Decimal:2, Time:1, Name:"迷你小麦" }, //迷你小麦
{ Symbol:"ZM", Decimal:1, Time:0, Name:"豆粕" }, //豆粕
{ Symbol:"EH", Decimal:3, Time:2 }, //乙醇
{ Symbol:"YM", Decimal:0, Time:2, Name:"小型道指"}, //小型道指
{ Symbol:"ES", Decimal:2, Time:2, Name:"小型标普" }, //小型标普
{ Symbol:"NQ", Decimal:2, Time:2, Name:"小型纳指" }, //小型纳指
{ Symbol:"TY", Decimal:4, Time:2, Name:"10年美国债" }, //10年美国债
{ Symbol:"TU", Decimal:4, Time:2, Name:"2年美国债" }, //2年美国债
{ Symbol:"FV", Decimal:4, Time:2, Name:"5年美国债" }, //5年美国债
{ Symbol:"US", Decimal:4, Time:2, Name:"30年美国债" }, //30年美国债
{ Symbol:"UL", Decimal:4, Time:2, Name:"超国债" }, //超国债
]
this.MarketSuffix=".CBOT";
}
//伦敦金属交易所 LME
function LMETimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
//标准时间
this.TIME_SPLIT=
[
{
Name:'LME 9:00-3:00',
Data:
[
{ Start: 900, End: 2359 },
{ Start: 0, End: 300 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 300, Text: '3:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
//{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
//{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
//{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
//{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' }
// { Value: 300, Text: '3:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 300, Text: '3:00' }
]
}
}
]
//夏令
this.TIME_SPLIT=
[
{
Name:'LME 8:00-2:00',
Data:
[
{ Start: 800, End: 2359 },
{ Start: 0, End: 200 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' }
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
//{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
//{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
//{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
//{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' }
//{ Value: 200, Text: '2:00' }
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 200, Text: '2:00' }
]
}
}
]
this.FUTURES_LIST=
[
{ Symbol:"SN", Decimal:0, Time:0, Name:"LME锡" }, //综合锡03
{ Symbol:"AH", Decimal:2, Time:0, Name:"LME铝" }, //综合铝03
{ Symbol:"PB", Decimal:2, Time:0, Name:"LME铅" }, //综合铅03
{ Symbol:"ZS", Decimal:2, Time:0, Name:"LME锌" }, //综合锌03
{ Symbol:"CA", Decimal:2, Time:0, Name:"LME铜" }, //综合铜03
{ Symbol:"NI", Decimal:0, Time:0, Name:"LME镍" }, //综合镍03
]
this.MarketSuffix=".LME";
}
//东京商品交易所(TOCOM)
function TOCOMTimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
this.TimeType=0;
this.TIME_SPLIT=
[
//ID=0 15:30-04:30 07:46-14:15
{
Name:'15:30-04:30 07:46-14:15',
Data:
[
{ Start: 1530, End: 2359},
{ Start: 0, End: 430 },
{ Start: 746, End: 1415 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 1530, Text: '15:30' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 300, Text: '3:00' },
{ Value: 430, Text: '4:30' },
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1415, Text: '14:15' }
],
Simple: //简洁模式
[
{ Value: 1530, Text: '15:30' },
{ Value: 1900, Text: '19:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 430, Text: '4:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1415, Text: '14:15' }
],
Min: //最小模式
[
{ Value: 1530, Text: '15:30' },
{ Value: 100, Text: '1:00' },
{ Value: 1415, Text: '14:15' }
]
}
}
];
this.FUTURES_LIST=
[
{ Symbol:"JRV", Decimal:0, Time:0, Name:"东京TSR20橡胶" },
{ Symbol:"JPL", Decimal:0, Time:0, Name:"东京铂金" },
{ Symbol:"JAU", Decimal:0, Time:0, Name:"东京黄金" },
{ Symbol:"JCO", Decimal:0, Time:0, Name:"中东原油" },
{ Symbol:"JRU", Decimal:1, Time:0, Name:"东京RSS3橡胶橡胶" },
{ Symbol:"JAG", Decimal:1, Time:0, Name:"日白银" } ,
{ Symbol:"JPA", Decimal:1, Time:0, Name:"日钯金" }
]
this.MarketSuffix=".TOCOM";
}
//美国洲际交易所(ICE EUROPE)
function IPETimeData()
{
this.newMethod=NYMEXTimeData; //派生
this.newMethod();
delete this.newMethod;
this.MarketSuffix=".IPE";
//美国标准时间
this.TIME_SPLIT=
[
//ID=0 8:00-6:00
{
Name:'8:00-6:00',
Data:
[
{ Start: 800, End: 2359 },
{ Start: 0, End: 600 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 1800, Text: '18:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 0, Text: '0:00' },
{ Value: 200, Text: '2:00' },
{ Value: 400, Text: '4:00' },
{ Value: 600, Text: '6:00' },
],
Simple: //简洁模式
[
{ Value: 800, Text: '8:00' },
{ Value: 1200, Text: '12:00' },
{ Value: 1600, Text: '16:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 0, Text: '0:00' },
{ Value: 400, Text: '4:00' },
{ Value: 600, Text: '6:00' },
],
Min: //最小模式
[
{ Value: 800, Text: '8:00' },
{ Value: 2000, Text: '20:00' },
{ Value: 600, Text: '6:00' }
]
}
}
]
//美国夏时令
this.TIME_SPLIT2=
[
//ID=0 09:00-07:00
{
Name:'09:00-07:00',
Data:
[
{ Start: 900, End: 2359 },
{ Start: 0, End: 700 },
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 1900, Text: '19:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1, Text: '1:00' },
{ Value: 300, Text: '3:00' },
{ Value: 500, Text: '5:00' },
{ Value: 700, Text: '7:00' }
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1700, Text: '17:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 1, Text: '1:00' },
{ Value: 500, Text: '5:00' },
{ Value: 700, Text: '7:00' }
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 2100, Text: '21:00' },
{ Value: 700, Text: '7:00' }
]
}
}
]
this.FUTURES_LIST=
[
{ Symbol:"RC", Decimal:2, Time:0, Name:"罗布斯塔咖啡" },
{ Symbol:"W", Decimal:2, Time:0, Name:"白糖" },
{ Symbol:"C", Decimal:2, Time:0, Name:"伦敦可可" },
{ Symbol:"R", Decimal:2, Time:0, Name:"长期英国国债" },
{ Symbol:"L", Decimal:2, Time:0, Name:"3个月英镑利率" },
{ Symbol:"T", Decimal:2, Time:0, Name:"WTI原油" },
{ Symbol:"G", Decimal:2, Time:0, Name:"低硫柴油" },
{ Symbol:"B", Decimal:2, Time:0, Name:"布伦特原油" }
]
}
var g_MinuteTimeStringData = new MinuteTimeStringData();
var g_MinuteCoordinateData = new MinuteCoordinateData();
var g_FuturesTimeData = new FuturesTimeData();
var g_NYMEXTimeData=new NYMEXTimeData();
var g_COMEXTimeData=new COMEXTimeData();
var g_NYBOTTimeData=new NYBOTTimeData();
var g_CBOTTimeData=new CBOTTimeData();
var g_LMETimeData=new LMETimeData();
var g_TOCOMTimeData=new TOCOMTimeData();
var g_IPETimeData=new IPETimeData();
function GetfloatPrecision(symbol) //获取小数位数
{
var defaultfloatPrecision=2; //默认2位
if (!symbol) return defaultfloatPrecision;
var upperSymbol=symbol.toUpperCase();
//全部由外部控制
if (typeof(MARKET_SUFFIX_NAME.GetCustomDecimal)=='function') return MARKET_SUFFIX_NAME.GetCustomDecimal(upperSymbol);
if (MARKET_SUFFIX_NAME.IsSHSZFund(upperSymbol)) defaultfloatPrecision=3; //基金3位小数
else if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetSHODecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) defaultfloatPrecision=g_FuturesTimeData.GetDecimal(upperSymbol); //期货小数位数读配置
else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetFHKDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetFTSEDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetBITDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetETDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetForeignExchangeDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol)) defaultfloatPrecision=g_NYMEXTimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol)) defaultfloatPrecision=g_COMEXTimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol)) defaultfloatPrecision=g_NYBOTTimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol)) defaultfloatPrecision=g_CBOTTimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsLME(upperSymbol)) defaultfloatPrecision=g_LMETimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol)) defaultfloatPrecision=g_TOCOMTimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol)) defaultfloatPrecision=g_IPETimeData.GetDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetHKDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsTW(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetTWDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsJP(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetJPDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsHSX(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetHSXDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsHNX(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetHNXDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsUPCOM(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetUPCOMDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsSZ(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetSZDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsSH(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetSHDecimal(upperSymbol);
else defaultfloatPrecision=MARKET_SUFFIX_NAME.GetDefaultDecimal(upperSymbol);
return defaultfloatPrecision;
}
//把不连续的分时数据转成连续的分时数据
function GenerateMinuteStockJsonData(data)
{
var stock =
{
symbol:data.symbol, name:data.name,time:data.time, date:data.date,
price:data.price, open:data.open, yclose:data.yclose, high:data.high, low:data.low, vol:data.vol,amount:data.amount,
minute:[]
};
var mapMinute=new Map();
for(var i in data.minute)
{
var item=data.minute[i];
mapMinute.set(item.time,item);
}
var timeData=g_MinuteTimeStringData.GetTimeData(stock.symbol);
for(var i in timeData) //根据交易时间产生数据
{
var time=timeData[i];
var minuteItem={ time:time, vaild:false };
if (mapMinute.has(time))
{
var find=mapMinute.get(time);
minuteItem.vaild=true;
minuteItem.price=find.price;
minuteItem.open=find.open;
minuteItem.high=find.high;
minuteItem.low=find.low;
minuteItem.avprice=find.avprice;
minuteItem.vol=find.vol;
minuteItem.amount=find.amount;
if (IFrameSplitOperator.IsNumber(find.increase)) minuteItem.increase=find.increase;
if (IFrameSplitOperator.IsNumber(find.risefall)) minuteItem.risefall=find.risefall;
if (IFrameSplitOperator.IsNumber(find.position)) minuteItem.position=find.position;
}
stock.minute.push(minuteItem);
}
var vaildCount=0;
for(var i=stock.minute.length-1;i>=0;--i)
{
vaildCount=i+1;
var item=stock.minute[i];
if (item.vaild==true) break;
}
stock.minute=stock.minute.slice(0,vaildCount); //去掉最后无用的数据
return stock;
}
function GetLocalTime(i) //得到标准时区的时间的函数
{
if (typeof i !== 'number') return;
var d = new Date();
//得到1970年一月一日到现在的秒数
var len = d.getTime();
//本地时间与GMT时间的时间偏移差
var offset = d.getTimezoneOffset() * 60000;
//得到现在的格林尼治时间
var utcTime = len + offset;
return new Date(utcTime + 3600000 * i);
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
分析家语法编译执行器 (H5版本)
*/
//日志输出类
if (!JSConsole)
{
var JSConsole=
{
Chart:{ Log:console.log, Warn:console.warn }, //图形日志
Complier:{ Log:console.log, Warn:console.warn } //编译器日志
};
}
//API默认地址
var g_JSComplierResource=
{
Domain : "http://127.0.0.1:8080", //API域名
CacheDomain : "http://127.0.0.1:8087", //缓存域名
DrawIcon:
{
Family:'iconfont',
Data:new Map([
[1, { Text:'\ue660', Color:'rgb(243,28,15)'}], //向上箭头
[2, { Text:'\ue661', Color:'rgb(87,247,41)'}], //向下箭头
[3, { Text:'\ue662', Color:'rgb(237,153,0)'}],
[4, { Text:'\ue663', Color:'rgb(237,153,0)'}],
[5, { Text:'\ue664', Color:'rgb(237,153,0)'}],
[6, { Text:'\ue665', Color:'rgb(140,57,208)'}],
[7, { Text:'\ue666', Color:'rgb(246,135,37)'}],
[8, { Text:'\ue667', Color:'rgb(85,231,56)'}],
[9, { Text:'\ue668', Color:'rgb(227,61,41)'}],
[10, { Text:'\ue669', Color:'rgb(216,78,48)'}],
[11, { Text:'\ue66a', Color:'rgb(249,187,0)'}], //点赞
[12, { Text:'\ue66b', Color:'rgb(249,187,0)'}],
[13, { Text:'\ue66c', Color:'rgb(216,42,0)'}],
[14, { Text:'\ue66d', Color:'rgb(58,90,236)'}],
[15, { Text:'\ue66e', Color:'rgb(227,149,0)'}],
[16, { Text:'\ue66f', Color:'rgb(208,82,78)'}],
[17, { Text:'\ue670', Color:'rgb(234,114,26)'}],
[18, { Text:'\ue671', Color:'rgb(116,25,255)'}],
[19, { Text:'\ue672', Color:'rgb(102,9,11)'}],
[20, { Text:'\ue673', Color:'rgb(127,125,137)'}],
[21, { Text:'\ue674', Color:'rgb(110,188,255)'}],
[22, { Text:'\ue675', Color:'rgb(238,79,51)'}],
[23, { Text:'\ue676', Color:'rgb(244,71,0)'}],
[24, { Text:'\ue677', Color:'rgb(102,183,248)'}],
[25, { Text:'\ue678', Color:'rgb(234,88,231)'}],
[26, { Text:'\ue679', Color:'rgb(242,171,0)'}],
[27, { Text:'\ue67a', Color:'rgb(87,247,168)'}],
[28, { Text:'\ue67b', Color:'rgb(97,204,113)'}],
[29, { Text:'\ue67c', Color:'rgb(84,115,193)'}],
[30, { Text:'\ue67d', Color:'rgb(141,51,255)'}],
[31, { Text:'\ue67e', Color:'rgb(200,126,24)'}],
[32, { Text:'\ue67f', Color:'rgb(195,41,32)'}],
[33, { Text:'\ue68f', Color:'rgb(215,85,194)'}],
[34, { Text:'\ue690', Color:'rgb(250,222,105)'}],
[35, { Text:'\ue691', Color:'rgb(112,249,224)'}],
[36, { Text:'\ue692', Color:'rgb(217,107,98)'}],
[37, { Text:'\ue693', Color:'rgb(114,231,17)'}],
[38, { Text:'\ue694', Color:'rgb(238,31,25)'}],
[39, { Text:'\ue695', Color:'rgb(92,247,113)'}],
[40, { Text:'\ue696', Color:'rgb(175,175,175)'}],
[41, { Text:'\ue697', Color:'rgb(252,228,23)'}],
[42, { Text:'\ue698', Color:'rgb(88,195,235)'}],
[43, { Text:'\ue699', Color:'rgb(55,74,94)'}],
[44, { Text:'\ue69a', Color:'rgb(248,175,33)'}],
[45, { Text:'\ue69b', Color:'rgb(194,180,112)'}],
[46, { Text:'\ue69c', Color:'rgb(50,153,28)'}],
[47, { Text:'\ue69d', Color:'rgb(17,65,152)'}],
[48, { Text:'\ue69e', Color:'rgb(194,55,26)'}],
[49, { Text:'\ue69f', Color:'rgb(243,0,0)'}],
/*
[11,{ Text:'\ue624', Color:'rgb(245,159,40)'}],
[12,{ Text:'\ue600', Color:'rgb(245,159,40)'}],
[13,{Text:'\ue70f',Color:'rgb(209,37,35)'}, ], //B
[14,{Text:'\ue64c',Color:'rgb(127,209,59)'} ], //S
[9, {Text:'\ue626',Color:'rgb(245,159,40)'} ], //$
[36,{Text:'\ue68c',Color:'rgb(255,106,106)'} ], //关闭 红色
[37,{Text:'\ue68c',Color:'rgb(46,139,87)'} ], //关闭 绿色
[38,{Text:'\ue68d',Color:'rgb(238,44,44)'} ], //▲
[39,{Text:'\ue68e',Color:'rgb(0,139,69)'} ], //▼
[46,{Text:'\ue64d',Color:'rgb(51,51,51)'} ], //message
*/
])
},
CustomDrawIcon:
{
Data:new Map() //自定义图标 key=id
//value={ID:, Text:, Color, Family: } //svg
//value={ ID:1, Symbol:'↑', Color:'rgb(238,44,44)' } //文字
},
CustomFunction: //定制函数
{
Data:new Map() //自定义函数 key=函数名, Value:{ID:函数名, Callback: }
},
CustomVariant: //自定义变量
{
Data:new Map() //自定义函数 key=变量名, Value:{ Name:变量名, Description:描述信息 }
},
CustomDataFunction: //自定义数据函数
{
//自定义函数 key=变量名, Value:{ Name:变量名, Description:描述信息, ArgCount:参数个数 }
Data:new Map(
[
[
"L2_VOLNUM",
{
Name:"L2_VOLNUM",
Description:"单数分档,按: N(0--1):(超大+大)/(中+小),M(0--1):买/卖二类,沪深京品种的资金流向,仅日线以上周期,用于特定版本",
ArgCount:2
}
],
[
"L2_VOL",
{
Name:"L2_VOL",
Description:"成交量分档,按: N(0--3):超大/大/中/小四档处理,M(0--3):买入/卖出/主买/主卖四类,沪深京品种的资金流向,仅日线以上周期,用于特定版本",
ArgCount:2
}
],
[
"L2_AMO",
{
Name:"L2_AMO",
Description:"成交额分档,按: N(0--3):超大/大/中/小四档处理,M(0--3):买入/卖出/主买/主卖四类,沪深京品种的资金流向,仅日线以上周期,用于特定版本",
ArgCount:2
}
]
])
},
GetDrawIcon:function(id)
{
var icon;
if (g_JSComplierResource.CustomDrawIcon.Data.has(id))
{
const iconfont=g_JSComplierResource.CustomDrawIcon.Data.get(id);
if (iconfont.Symbol) //文字
icon={ Symbol:iconfont.Symbol, Color:iconfont.Color, IconFont:false, ID:id };
else //SVG图标
icon={ Symbol:iconfont.Text, Color:iconfont.Color, Family:iconfont.Family, IconFont:true, ID:id };
return icon;
}
if (g_JSComplierResource.DrawIcon.Data.has(id))
{
const iconfont=g_JSComplierResource.DrawIcon.Data.get(id);
icon={ Symbol:iconfont.Text, Color:iconfont.Color, Family:g_JSComplierResource.DrawIcon.Family, IconFont:true, ID:id };
return icon;
}
return null;
},
GetDrawTextIcon:function(id)
{
//图标对应的字符代码
let mapIcon=new Map([
[1,{Symbol:'↑',Color:'rgb(238,44,44)'} ],[2,{Symbol:'↓',Color:'rgb(0,139,69)'} ],
[3,{Symbol:'😧'} ],[4,{Symbol:'😨'} ],[5,{Symbol:'😁'} ],[6,{Symbol:'😱'} ],
[7,{Symbol:'B',Color:'rgb(238,44,44)'} ],[8,{Symbol:'S',Color:'rgb(0,139,69)'} ],
[9,{Symbol:'💰'} ],[10,{Symbol:'📪'} ],[11,{Symbol:'👆'} ],[12,{Symbol:'👇'} ],
[13,{Symbol:'B',Color:'rgb(178,34,34)'}, ],[14,{Symbol:'S',Color:'rgb(0,139,69)'} ],
[36,{Symbol:'Χ',Color:'rgb(238,44,44)'} ],[37,{Symbol:'X',Color:'rgb(0,139,69)'} ],
[38,{Symbol:'▲',Color:'rgb(238,44,44)'} ],[39,{Symbol:'▼',Color:'rgb(0,139,69)'} ],
[40,{Symbol:'◉',Color:'rgb(238,44,44)'}], [41,{Symbol:'◈',Color:'rgb(238,44,44)'}],
[42,{Symbol:'📌'}], [43,{Symbol:'💎'}], [44,{Symbol:'🥇'}],[45,{Symbol:'🥈'}],[46,{Symbol:'🥉'}],[47,{Symbol:'🏅'}]
]);
var icon=mapIcon.get(id);
return icon;
},
IsCustomFunction:function(name)
{
if (g_JSComplierResource.CustomFunction.Data.has(name)) return true;
return false;
},
IsCustomVariant:function(name)
{
if (g_JSComplierResource.CustomVariant.Data.has(name)) return true;
return false;
},
IsCustomDataFunction:function(name)
{
if (g_JSComplierResource.CustomDataFunction.Data.has(name)) return true;
return false;
}
}
var Messages = {
BadGetterArity: 'Getter must not have any formal parameters',
BadSetterArity: 'Setter must have exactly one formal parameter',
BadSetterRestParameter: 'Setter function argument must not be a rest parameter',
ConstructorIsAsync: 'Class constructor may not be an async method',
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
DeclarationMissingInitializer: 'Missing initializer in %0 declaration',
DefaultRestParameter: 'Unexpected token =',
DuplicateBinding: 'Duplicate binding %0',
DuplicateConstructor: 'A class may only have one constructor',
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
ForInOfLoopInitializer: '%0 loop variable declaration may not have an initializer',
GeneratorInLegacyContext: 'Generator declarations are not allowed in legacy contexts',
IllegalBreak: 'Illegal break statement',
IllegalContinue: 'Illegal continue statement',
IllegalExportDeclaration: 'Unexpected token',
IllegalImportDeclaration: 'Unexpected token',
IllegalLanguageModeDirective: 'Illegal \'use strict\' directive in function with non-simple parameter list',
IllegalReturn: 'Illegal return statement',
InvalidEscapedReservedWord: 'Keyword must not contain escaped characters',
InvalidHexEscapeSequence: 'Invalid hexadecimal escape sequence',
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
InvalidModuleSpecifier: 'Unexpected token',
InvalidRegExp: 'Invalid regular expression',
LetInLexicalBinding: 'let is disallowed as a lexically bound name',
MissingFromClause: 'Unexpected token',
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
NewlineAfterThrow: 'Illegal newline after throw',
NoAsAfterImportNamespace: 'Unexpected token',
NoCatchOrFinally: 'Missing catch or finally after try',
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
Redeclaration: '%0 \'%1\' has already been declared',
StaticPrototype: 'Classes may not have static property named prototype',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
StrictFunction: 'In strict mode code, functions can only be declared at top level or inside a block',
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
StrictModeWith: 'Strict mode code may not include a with statement',
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
StrictReservedWord: 'Use of future reserved word in strict mode',
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
UnexpectedEOS: 'Unexpected end of input',
UnexpectedIdentifier: 'Unexpected identifier',
UnexpectedNumber: 'Unexpected number',
UnexpectedReserved: 'Unexpected reserved word',
UnexpectedString: 'Unexpected string',
UnexpectedTemplate: 'Unexpected quasi %0',
UnexpectedToken: 'Unexpected token %0',
UnexpectedTokenIllegal: 'Unexpected token ILLEGAL',
UnknownLabel: 'Undefined label \'%0\'',
UnterminatedRegExp: 'Invalid regular expression: missing /'
};
var Regex = {
// Unicode v8.0.0 NonAsciiIdentifierStart:
NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,
// Unicode v8.0.0 NonAsciiIdentifierPart:
NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
}
var Character =
{
FromCodePoint: function (cp) {
return (cp < 0x10000) ? String.fromCharCode(cp) :
String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
},
//是否是空格 https://tc39.github.io/ecma262/#sec-white-space
IsWhiteSpace:function(cp)
{
return (cp === 0x20) || (cp === 0x09) || (cp === 0x0B) || (cp === 0x0C) || (cp === 0xA0) ||
(cp >= 0x1680 && [0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(cp) >= 0);
},
//是否换行 https://tc39.github.io/ecma262/#sec-line-terminators
IsLineTerminator:function(cp)
{
return (cp === 0x0A) || (cp === 0x0D) || (cp === 0x2028) || (cp === 0x2029);
},
// https://tc39.github.io/ecma262/#sec-names-and-keywords
IsIdentifierStart:function(cp)
{
return (cp === 0x24) || (cp === 0x5F) ||
(cp >= 0x41 && cp <= 0x5A) ||
(cp >= 0x61 && cp <= 0x7A) ||
(cp === 0x5C) ||
//【】▲▼
(cp===0x3010 || cp===0x3011 || cp===0x25B2 || cp===0x25BC) ||
((cp >= 0x80) && Regex.NonAsciiIdentifierStart.test(Character.FromCodePoint(cp)));
},
IsIdentifierPart: function (cp)
{
return (cp === 0x24) || (cp === 0x5F) ||
(cp >= 0x41 && cp <= 0x5A) ||
(cp >= 0x61 && cp <= 0x7A) ||
(cp >= 0x30 && cp <= 0x39) ||
(cp === 0x5C) || (cp===0x23) ||
//【】▲▼
(cp===0x3010 || cp===0x3011 || cp===0x25B2 || cp===0x25BC) ||
((cp >= 0x80) && Regex.NonAsciiIdentifierPart.test(Character.FromCodePoint(cp)));
},
// https://tc39.github.io/ecma262/#sec-literals-numeric-literals
IsDecimalDigit: function (cp)
{
return (cp >= 0x30 && cp <= 0x39); // 0..9
},
IsHexDigit: function (cp)
{
return (cp >= 0x30 && cp <= 0x39) || (cp >= 0x41 && cp <= 0x46) || (cp >= 0x61 && cp <= 0x66); // a..f
},
isOctalDigit: function (cp)
{
return (cp >= 0x30 && cp <= 0x37); // 0..7
}
}
var TOKEN_NAME={};
TOKEN_NAME[1 /* BooleanLiteral */] = 'Boolean';
TOKEN_NAME[2 /* EOF */] = '<end>';
TOKEN_NAME[3 /* Identifier */] = 'Identifier';
TOKEN_NAME[4 /* Keyword */] = 'Keyword';
TOKEN_NAME[5 /* NullLiteral */] = 'Null';
TOKEN_NAME[6 /* NumericLiteral */] = 'Numeric';
TOKEN_NAME[7 /* Punctuator */] = 'Punctuator';
TOKEN_NAME[8 /* StringLiteral */] = 'String';
TOKEN_NAME[9 /* RegularExpression */] = 'RegularExpression';
TOKEN_NAME[10 /* Template */] = 'Template';
//公共方法
function JSComplierHelper()
{
}
JSComplierHelper.GetPeriodInfo=function(obj)
{
const PERIOD_LIST=
[
{Name:'MIN1', Period:4, Order:1},
{Name:'MIN5', Period:5, Order:2},
{Name:'MIN15', Period:6, Order:3},
{Name:'MIN30', Period:7, Order:4},
{Name:'MIN60', Period:8, Order:5},
{Name:'DAY', Period:0, Order:1000},
{Name:'MULTIDAY', Period:40002, Order:1002},
{Name:'DAY2', Period:40002, Order:1002},
{Name:'DAY3', Period:40003, Order:1003},
{Name:'DAY4', Period:40004, Order:1004},
{Name:'DAY5', Period:40005, Order:1005},
{Name:'WEEK', Period:1, Order:1005},
{Name:'DAY6', Period:40006, Order:1006},
{Name:'DAY7', Period:40007, Order:1007},
{Name:'DAY8', Period:40008, Order:1008},
{Name:'DAY9', Period:40009, Order:1009},
{Name:'DAY10', Period:40009, Order:1010},
{Name:"WEEK2", Period:21, Order:1010},
{Name:'DAY11', Period:40011, Order:1011},
{Name:'DAY12', Period:40012, Order:1012},
{Name:'DAY13', Period:40013, Order:1013},
{Name:'DAY14', Period:40014, Order:1014},
{Name:'MONTH', Period:2, Order:1030},
{Name:"SEASON", Period:9, Order:1090},
{Name:"HALFYEAR", Period:22, Order:1180},
{Name:"YEAR", Period:3, Order:1365}
];
if (obj.Name)
{
for(var i in PERIOD_LIST)
{
if (obj.Name && PERIOD_LIST[i].Name==obj.Name)
return PERIOD_LIST[i];
}
return null;
}
if (IFrameSplitOperator.IsNumber(obj.PeriodID))
{
for(var i in PERIOD_LIST)
{
if (PERIOD_LIST[i].Period==obj.PeriodID)
return PERIOD_LIST[i];
}
return null;
}
return null;
}
JSComplierHelper.GetConvertValueName=function(funcName)
{
var valueName;
if (funcName=='COVER_C') valueName='CLOSE';
else if (funcName=='COVER_O') valueName="OPEN";
else if (funcName=='COVER_H') valueName="HIGH";
else if (funcName=='COVER_L') valueName="LOW";
else if (funcName=='COVER_A') valueName="AMOUNT";
else if (funcName=='COVER_V') valueName="VOL";
return valueName;
}
//编译异常, 错误类
function ErrorHandler()
{
this.Error=[];
this.RecordError=function(error)
{
this.Error.push(error);
}
this.ConstructError=function(msg,column)
{
let error=new Error(msg);
//通过自己抛异常并自己截获 来获取调用堆栈信息
try
{
throw error;
}
catch(base)
{
if (Object.create && Object.defineProperties)
{
error=Object.create(base);
error.Column=column;
}
}
return error;
}
this.CreateError=function(index, line, col, description, word)
{
let msg='Line ' + line + ': ' + description;
let error=this.ConstructError(msg,col);
error.Index=index;
error.LineNumber=line;
error.Description=description;
error.Word=word; //错误单词
return error;
}
this.ThrowError=function(index, line, col, description, word)
{
let error=this.CreateError(index,line,col,description,word);
throw error;
}
//重新下载数据
this.ThrowDownloadJob=function(index, line, col, description,job)
{
let error=this.CreateError(index,line,col,description);
error.Job=job;
throw error;
}
}
//扫描类
function Scanner(code, ErrorHandler)
{
this.Source=code;
this.ErrorHandler=ErrorHandler;
this.Length=code.length;
this.Index=0;
this.LineNumber=(code.length>0)?1:0;
this.LineStart=0;
this.CurlyStack=[];
this.SaveState=function() //保存当前扫描状态
{
return { Index:this.Index, LineNumber:this.LineNumber, LineStart:this.LineStart };
}
this.RestoreState=function(state) //还原扫描状态
{
this.Index=state.Index;
this.LineNumber=state.LineNumber;
this.LineStart=state.LineStart;
}
this.IsEOF=function() //否是已经结束
{
return this.Index>=this.Length;
}
this.IsKeyword=function(id)
{
return false;
}
this.CodePointAt = function (i)
{
let cp = this.Source.charCodeAt(i);
if (cp >= 0xD800 && cp <= 0xDBFF)
{
let second = this.Source.charCodeAt(i + 1);
if (second >= 0xDC00 && second <= 0xDFFF) {
var first = cp;
cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
}
}
return cp;
}
this.Lex=function()
{
if (this.IsEOF()) return { Type:2/*EOF*/, Value:'', LineNumber:this.LineNumber, LineStart:this.LineStart, Start:this.Index, End:this.Index };
let cp=this.Source.charCodeAt(this.Index);
//变量名 或 关键字
if (Character.IsIdentifierStart(cp)) return this.ScanIdentifier();
//( ) ; 开头 操作符扫描
if (cp === 0x28 || cp === 0x29 || cp === 0x3B) return this.ScanPunctuator();
//' " 开头 字符串扫描
if (cp === 0x27 || cp === 0x22) return this.ScanStringLiteral();
//. 开头 浮点型
if (cp==0x2E)
{
if (Character.IsDecimalDigit(this.Source.charCodeAt(this.Index + 1)))
return this.ScanNumericLiteral();
return this.ScanPunctuator();
}
//数字
if (Character.IsDecimalDigit(cp)) return this.ScanNumericLiteral();
if (cp >= 0xD800 && cp < 0xDFFF)
{
if (Character.IsIdentifierStart(this.CodePointAt(this.Index))) return this.ScanIdentifier();
}
return this.ScanPunctuator();
}
//关键字 变量名 https://tc39.github.io/ecma262/#sec-names-and-keywords
this.ScanIdentifier=function()
{
let type;
let start=this.Index;
//0x5C 反斜杠
let id=(this.Source.charCodeAt(start)=== 0x5C) ? this.GetComplexIdentifier() : this.GetIdentifier();
if (id.length) type=3; //Identifier
else if (this.IsKeyword(id)) type=4; //Keyword
else if (id==null) type=5; //NullLiteral
else if (id=='true' || id=='false') type=1; //BooleanLiteral
else type=3; //Identifier
if (type!=3 && (start+id.length!=this.Index))
{
let restore=this.Index;
this.Index=start;
throw Messages.InvalidEscapedReservedWord;
this.Index=restore;
}
if (id=='AND' || id=='OR') type=7 /*Punctuator*/;
return { Type:type, Value:id, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index};
}
this.GetIdentifier=function()
{
let start=this.Index++; //start 保存进来的位置
while(!this.IsEOF())
{
let ch=this.Source.charCodeAt(this.Index);
if (ch==0x5C)
{
this.Index=start;
return this.GetComplexIdentifier();
}
else if (ch >= 0xD800 && ch < 0xDFFF)
{
this.Index=start;
return this.GetComplexIdentifier();
}
if (Character.IsIdentifierPart(ch)) ++this.Index;
else break;
}
return this.Source.slice(start,this.Index);
}
//操作符 https://tc39.github.io/ecma262/#sec-punctuators
this.ScanPunctuator=function()
{
let start=this.Index;
let str=this.Source[this.Index];
switch(str)
{
case '(':
++this.Index;
break;
case ')':
case ';':
case ',':
++this.Index;
break;
case '.':
++this.Index;
/*if (this.Source[this.Index] === '.' && this.Source[this.Index + 1] === '.')
{
//Spread operator: ...
this.Index += 2;
str = '...';
}
*/
break;
default:
str=this.Source.substr(this.Index,3);
if (str=='AND')
{
this.Index+=3;
}
else
{
str = this.Source.substr(this.Index, 2);
if (str === '&&' || str === '||' || str === '==' || str === '!=' || str === '<=' || str === '>=' || str === '=>' || str==':=' || str=='OR' || str=='<>')
{
this.Index += 2;
}
else
{
str=this.Source[this.Index];
if ('<>=!+-*%&|^/:'.indexOf(str) >= 0) ++this.Index;
}
}
}
if (this.Index==start)
this.ThrowUnecpectedToken();
return { Type:7/*Punctuator*/, Value:str, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index };
}
//字符串 https://tc39.github.io/ecma262/#sec-literals-string-literals
this.ScanStringLiteral=function()
{
let start=this.Index;
let quote=this.Source[this.Index];
++this.Index;
var octal=false;
let str='';
while(!this.IsEOF())
{
let ch=this.Source[this.Index++];
if (ch==quote)
{
quote='';
break;
}
else if (ch=='\\') //字符串转义
{
throw "not complete";
}
else if (Character.IsLineTerminator(ch.charCodeAt(0)))
{
break;
}
else
{
str+=ch;
}
}
if (quote!='')
{
this.Index=start;
this.ThrowUnecpectedToken();
}
return {Type:8/*StringLiteral*/, Value:str, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index};
}
this.ScanNumericLiteral=function()
{
let start=this.Index;
let ch=this.Source[this.Index];
let num='';
if (ch!='.')
{
num=this.Source[this.Index++];
ch=this.Source[this.Index];
// Hex number starts with '0x'. 16进制
if (num=='0')
{
if (ch=='x' || ch=='X')
{
++this.Index;
return this.ScanHexLiteral(start);
}
}
while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index)))
{
num+=this.Source[this.Index++];
}
ch=this.Source[this.Index];
}
if (ch=='.')
{
num+=this.Source[this.Index++];
while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index)))
{
num+=this.Source[this.Index++];
}
ch=this.Source[this.Index];
}
//科学计数法
if (ch=='e' || ch=='E')
{
num+=this.Source[this.Index++];
ch=this.Source[this.Index];
if (ch=='+' || ch=='-') num+=this.Source[this.Index];
if (Character.IsDecimalDigit(this.Source.charCodeAt(this.Index)))
{
while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index)))
{
num+=this.Source[this.Index++];
}
}
else
{
this.ThrowUnecpectedToken();
}
}
if (Character.IsIdentifierStart(this.Source.charCodeAt(this.Index)))
{
this.ThrowUnecpectedToken();
}
return { Type:6/*NumericLiteral*/, Value:parseFloat(num), LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index };
}
//空格 或 注释
this.ScanComments=function()
{
let comments;
let start=(this.Index==0);
while(!this.IsEOF())
{
let ch=this.Source.charCodeAt(this.Index);
if (Character.IsWhiteSpace(ch)) //过滤掉空格
{
++this.Index;
}
else if (Character.IsLineTerminator(ch))
{
++this.Index;
if (ch==0x0D && this.Source.charCodeAt(this.Index)==0x0A) ++this.Index; //回车+换行
++this.LineNumber;
this.LineStart=this.Index;
start=true;
}
else if (ch==0x2F) // //注释
{
ch=this.Source.charCodeAt(this.Index+1);
if (ch==0x2F)
{
this.Index+=2;
let comment=this.SkipSingleLineComment(2);
start=true;
}
else
{
break;
}
}
else if (ch==0x7B) //{ } 注释
{
this.Index+=1;
let comment = this.SkipMultiLineComment();
}
else
{
break;
}
}
return comments;
}
this.SkipMultiLineComment=function()
{
var comments = [];
while(!this.IsEOF())
{
var ch=this.Source.charCodeAt(this.Index);
if (Character.IsLineTerminator(ch))
{
++this.LineNumber;
++this.Index;
this.LineStart=this.Index;
}
else if (ch==0x7D)
{
this.Index+=1;
return comments;
}
else
{
++this.Index;
}
}
return comments;
}
//单行注释 https://tc39.github.io/ecma262/#sec-comments
this.SkipSingleLineComment=function(offset)
{
let comments=[];
while(!this.IsEOF())
{
let ch=this.Source.charCodeAt(this.Index);
++this.Index;
if (Character.IsLineTerminator(ch))
{
if (ch === 13 && this.Source.charCodeAt(this.Index) === 10)
++this.Index;
++this.LineNumber;
this.LineStart=this.Index;
return comments;
}
}
return comments;
}
this.ThrowUnecpectedToken=function(message,word)
{
if (!message) message = Messages.UnexpectedTokenIllegal;
return this.ErrorHandler.ThrowError(this.Index, this.LineNumber, this.Index - this.LineStart + 1, message, word);
}
}
function Tokenizer(code)
{
this.ErrorHandler=new ErrorHandler(); //错误信息处理类
this.Scanner=new Scanner(code,this.ErrorHandler);
this.Buffer=[];
this.GetNextToken=function()
{
if (this.Buffer.length==0)
{
let comments=this.Scanner.ScanComments();
if (!this.Scanner.IsEOF())
{
let token=this.Scanner.Lex();
let entry={ Type:TOKEN_NAME[token.Type], Value:this.Scanner.Source.slice(token.Start, token.End)};
this.Buffer.push(entry);
}
}
return this.Buffer.shift();
}
}
var Syntax = {
AssignmentExpression: 'AssignmentExpression',
AssignmentPattern: 'AssignmentPattern',
ArrayExpression: 'ArrayExpression',
ArrayPattern: 'ArrayPattern',
ArrowFunctionExpression: 'ArrowFunctionExpression',
AwaitExpression: 'AwaitExpression',
BlockStatement: 'BlockStatement',
BinaryExpression: 'BinaryExpression',
BreakStatement: 'BreakStatement',
CallExpression: 'CallExpression',
CatchClause: 'CatchClause',
ClassBody: 'ClassBody',
ClassDeclaration: 'ClassDeclaration',
ClassExpression: 'ClassExpression',
ConditionalExpression: 'ConditionalExpression',
ContinueStatement: 'ContinueStatement',
DoWhileStatement: 'DoWhileStatement',
DebuggerStatement: 'DebuggerStatement',
EmptyStatement: 'EmptyStatement',
ExportAllDeclaration: 'ExportAllDeclaration',
ExportDefaultDeclaration: 'ExportDefaultDeclaration',
ExportNamedDeclaration: 'ExportNamedDeclaration',
ExportSpecifier: 'ExportSpecifier',
ExpressionStatement: 'ExpressionStatement',
ForStatement: 'ForStatement',
ForOfStatement: 'ForOfStatement',
ForInStatement: 'ForInStatement',
FunctionDeclaration: 'FunctionDeclaration',
FunctionExpression: 'FunctionExpression',
Identifier: 'Identifier',
IfStatement: 'IfStatement',
ImportDeclaration: 'ImportDeclaration',
ImportDefaultSpecifier: 'ImportDefaultSpecifier',
ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
ImportSpecifier: 'ImportSpecifier',
Literal: 'Literal',
LabeledStatement: 'LabeledStatement',
LogicalExpression: 'LogicalExpression',
MemberExpression: 'MemberExpression',
MetaProperty: 'MetaProperty',
MethodDefinition: 'MethodDefinition',
NewExpression: 'NewExpression',
ObjectExpression: 'ObjectExpression',
ObjectPattern: 'ObjectPattern',
Program: 'Program',
Property: 'Property',
RestElement: 'RestElement',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SpreadElement: 'SpreadElement',
Super: 'Super',
SwitchCase: 'SwitchCase',
SwitchStatement: 'SwitchStatement',
TaggedTemplateExpression: 'TaggedTemplateExpression',
TemplateElement: 'TemplateElement',
TemplateLiteral: 'TemplateLiteral',
ThisExpression: 'ThisExpression',
ThrowStatement: 'ThrowStatement',
TryStatement: 'TryStatement',
UnaryExpression: 'UnaryExpression',
UpdateExpression: 'UpdateExpression',
VariableDeclaration: 'VariableDeclaration',
VariableDeclarator: 'VariableDeclarator',
WhileStatement: 'WhileStatement',
WithStatement: 'WithStatement',
YieldExpression: 'YieldExpression'
};
function Node(ErrorHandler)
{
this.IsNeedIndexData=false; //是否需要大盘数据
this.IsNeedLatestIndexData=false; //是否需要下载最新大盘数据
this.IsNeedSymbolData=false; //是否需要下载股票数据
this.IsNeedMarginData=new Set();
this.IsNeedNewsAnalysisData=new Set(); //新闻统计数据
this.NeedBlockIncreaseData=[]; //是否需要市场涨跌股票数据统计
this.IsNeedSymbolExData=new Set(); //下载股票行情的其他数据
this.NeedHK2SHSZData=[]; //下载北上资金数据
this.IsNeedSectionFinance=new Map(); //下载截面财务数据 { key= 报告期 , Set() 字段}
this.FunctionData=[]; //{ID:, Args:, FunctionName: }
//FINVALUE(ID),FINONE(ID,Y,MMDD)
this.Dynainfo=[]; //最新的个股行情数据 {ID:, Args:, FunctionName: }
this.IsAPIData=[] //加载API数据
this.ExecuteIndex=[]; //执行调用指标
this.OtherSymbolData=[]; //其他股票数据 key=股票代码(小写)
this.PeriodSymbolData=[]; //跨周期数据 { Period:, VarName: }
this.ErrorHandler=ErrorHandler;
this.GetDataJobList=function() //下载数据任务列表
{
let jobs=[];
if (this.IsNeedSymbolData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA});
if (this.IsNeedIndexData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_DATA});
if (this.IsNeedLatestIndexData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_LATEST_INDEX_DATA});
//最新的个股行情数据
for(var i=0;i<this.Dynainfo.length;++i)
{
var item=this.Dynainfo[i];
jobs.push(item);
}
//涨跌停家数统计
for(var i in this.NeedBlockIncreaseData)
{
jobs.push(this.NeedBlockIncreaseData[i]);
}
//加载融资融券
for(var jobID of this.IsNeedMarginData)
{
jobs.push({ID:jobID});
}
//加载北上资金
for(var i in this.NeedHK2SHSZData)
{
jobs.push(this.NeedHK2SHSZData[i]);
}
//加载新闻统计
for(var jobID of this.IsNeedNewsAnalysisData)
{
jobs.push({ID:jobID});
}
//行情其他数据
for(var jobID of this.IsNeedSymbolExData)
{
jobs.push({ID:jobID});
}
//获取截面数据下载任务
for(var item of this.IsNeedSectionFinance)
{
jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF, SF:item});
}
for(var i in this.IsAPIData)
{
var item=this.IsAPIData[i];
jobs.push(item);
}
for(var i in this.ExecuteIndex)
{
var item=this.ExecuteIndex[i];
jobs.push(item);
}
for(var i in this.OtherSymbolData)
{
var item=this.OtherSymbolData[i];
jobs.push(item);
}
for(var i in this.PeriodSymbolData)
{
var item=this.PeriodSymbolData[i];
jobs.push(item);
}
for(var i in this.FunctionData)
{
var item=this.FunctionData[i];
jobs.push(item);
}
return jobs;
}
this.VerifySymbolVariable=function(varName, token)
{
let setIndexName=new Set(['INDEXA','INDEXC','INDEXH','INDEXL',"INDEXO","INDEXV",'INDEXDEC','INDEXADV']);
if (setIndexName.has(varName))
{
this.IsNeedIndexData=true;
return;
}
let setSymbolDataName=new Set(['CLOSE','C','VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
if (setSymbolDataName.has(varName))
{
this.IsNeedSymbolData=true;
return;
}
if (varName==='VOLR')
{
if (!this.IsNeedSymbolExData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA))
this.IsNeedSymbolExData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA);
}
//CAPITAL流通股本(手), EXCHANGE 换手率, TOTALCAPITAL 总股本(手)
let setVariantName=new Set(
[
"CAPITAL","TOTALCAPITAL","EXCHANGE",
"HYBLOCK","DYBLOCK","GNBLOCK","FGBLOCK","ZSBLOCK","ZHBLOCK","ZDBLOCK","HYZSCODE",
"GNBLOCKNUM","FGBLOCKNUM","ZSBLOCKNUM","ZHBLOCKNUM","ZDBLOCKNUM",
"HYSYL","HYSJL","FROMOPEN",
//资金流向
"LARGEINTRDVOL","LARGEOUTTRDVOL",
"TRADENUM","TRADEINNUM","TRADEOUTNUM",
"LARGETRDINNUM","LARGETRDOUTNUM",
"CUR_BUYORDER","CUR_SELLORDER",
"ACTINVOL","ACTOUTVOL",
"BIDORDERVOL","BIDCANCELVOL","AVGBIDPX",
"OFFERORDERVOL","OFFERCANCELVOL","AVGOFFERPX",
]);
if (setVariantName.has(varName))
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:varName };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
if (varName=='ADVANCE' || varName=="DECLINE")
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA, IsSelfSymbol:true, FunctionName:varName };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.NeedBlockIncreaseData.push(item);
return;
}
if (varName.indexOf('#')>0)
{
var aryWrods = varName.split('#');
if (aryWrods.length!=2)
{
var errorMessage=`${varName}, 跨周期语法错误, 变量名#周期`;
this.ThrowUnexpectedToken(token,errorMessage);
}
else
{
const VAR_NAME=["C", "CLOSE", "O","OPEN", "H","HIGH", "L", "LOW", "AMOUNT", "AMO", "VOL", "V" , "VOLINSTK"];
if (VAR_NAME.indexOf(aryWrods[0])<0)
{
var errorMessage=`${varName}, 跨周期语法错误, 数据只支持'OPEN,HIGH,LOW,CLOSE,VOL,AMOUNT,VOLINSTK'`;
this.ThrowUnexpectedToken(token,errorMessage);
}
const VAR_PERIOD_NAME=
[
"MIN1","MIN5","MIN15","MIN30","MIN60","MIN120","MIN240","DAY","WEEK","MONTH","SEASON","YEAR","HALFYEAR","WEEK2",
"MULTIDAY","DAY2","DAY3","DAY4","DAY5","DAY6","DAY7","DAY8","DAY9","DAY10",
"DAY11","DAY12","DAY13","DAY14","DAY15"
];
if (VAR_PERIOD_NAME.indexOf(aryWrods[1])<0)
{
var errorMessage=`${varName}, 跨周期语法错误, 周期只支持'MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR'`;
this.ThrowUnexpectedToken(token,errorMessage);
}
var item={ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_PERIOD_DATA, VarName:varName, ValueName:aryWrods[0], PeriodName:aryWrods[1] };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.PeriodSymbolData.push(item);
}
return;
}
if (g_JSComplierResource.IsCustomVariant(varName)) //自定义函数
{
var item={ VariantName:varName, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
}
this.VerifySymbolLiteral=function(value,token)
{
if (IFrameSplitOperator.IsString(value))
{
if (value.indexOf('$')>0)
{
var aryValue=value.split('$');
if (aryValue.length!=2) return;
var item= { Literal:value, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.OtherSymbolData.push(item);
}
}
}
this.VerifySymbolFunction=function(callee,args, token)
{
//自定义函数 可以覆盖系统内置函数
if (g_JSComplierResource.IsCustomFunction(callee.Name))
{
var item={FunctionName:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA, Args:args}
if (token) item.Token={ Index:token.Start, Line:token.LineNumber};
this.FunctionData.push(item);
return;
}
//自定义数据函数
if (g_JSComplierResource.IsCustomDataFunction(callee.Name))
{
var item={FunctionName:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_DATA_FUNCTION, Args:args}
if (token) item.Token={ Index:token.Start, Line:token.LineNumber};
this.FunctionData.push(item);
return;
}
if (callee.Name=='DYNAINFO')
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_LATEST_DATA, Args:args, FunctionName:callee.Name };
this.Dynainfo.push(item);
return;
}
//财务函数
if (callee.Name=='FINANCE')
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
if (callee.Name=="FINVALUE")
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
if (callee.Name=="FINONE")
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
//专业财务数据
for(var i=0;i<JS_ARRAY_PROFESSIONAL_FINANCE.length;++i)
{
var financeItem=JS_ARRAY_PROFESSIONAL_FINANCE[i];
if (financeItem.Name==callee.Name)
{
var item={ ID:financeItem.JobID, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
}
if (callee.Name==='MARGIN')
{
let jobID=JS_EXECUTE_JOB_ID.GetMarginJobID(args[0].Value);
if (jobID && !this.IsNeedMarginData.has(jobID)) this.IsNeedMarginData.add(jobID);
return;
}
if (callee.Name==='NEWS')
{
let jobID=JS_EXECUTE_JOB_ID.GetNewsAnalysisID(args[0].Value);
if (jobID && !this.IsNeedNewsAnalysisData.has(jobID)) this.IsNeedNewsAnalysisData.add(jobID);
return;
}
if (callee.Name==='HK2SHSZ') //北上资金
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SHSZ, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.NeedHK2SHSZData.push(item);
return;
}
if (callee.Name=='COST' || callee.Name=='WINNER' || callee.Name=='PPART' || callee.Name=='COSTEX' ||
callee.Name=='LWINNER' || callee.Name=='PWINNER') //需要流通股
{
//下载流通股
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:[7], FunctionName:"FINANCE", FunctionName2:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
if (callee.Name=="INBLOCK")
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:"INBLOCK" }; //下载所有板块
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.FunctionData.push(item);
return;
}
if (callee.Name==='BETA') //beta需要下载上证指数
{
this.IsNeedIndexData=true;
return;
}
if (callee.Name=='UPCOUNT' || callee.Name=='DOWNCOUNT') //上涨下跌个数
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.NeedBlockIncreaseData.push(item);
return;
}
if (callee.Name=='STKINDI' || callee.Name=='CALCSTOCKINDEX') //指标调用
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX, Args:args, FunctionName:callee.Name };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.ExecuteIndex.push(item);
return;
}
//"MA.MA1"(10,5,5)"
if (callee.Type==Syntax.Literal)
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX, Args:args, FunctionName:callee.Value, DynamicName:callee.Value };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.ExecuteIndex.push(item);
return;
}
if (callee.Name=='COVER_C' || callee.Name=='COVER_O' || callee.Name=='COVER_H' || callee.Name=='COVER_L' || callee.Name=='COVER_A' || callee.Name=='COVER_V') //跨周期函数
{
var periodName=args[0].Value;
const VAR_PERIOD_NAME=["MIN1","MIN5","MIN15","MIN30","MIN60","DAY","WEEK","MONTH","SEASON","YEAR"];
if (VAR_PERIOD_NAME.indexOf(periodName)<0)
{
var errorMessage=`${callee.Name}, 跨周期函数错误, 周期只支持'MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR'`;
this.ThrowUnexpectedToken(token,errorMessage);
}
var valueName=JSComplierHelper.GetConvertValueName(callee.Name);
var item={ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_PERIOD_DATA, FunctionName:callee.Name, ValueName:valueName, PeriodName:periodName };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.PeriodSymbolData.push(item);
return;
}
if (callee.Name=='SF') //Section finance
{
let period=JS_EXECUTE_JOB_ID.GetSectionReportPeriod(args[0].Value,args[1].Value); //报告期
if (!period) return;
let jobID=JS_EXECUTE_JOB_ID.GetSectionFinanceID(args[2].Value);
if (!jobID) return;
var sfkey=period.Year+ '-' + period.Quarter;
if (!this.IsNeedSectionFinance.has(sfkey))
{
var finacne={ Period:period, Fields:new Set([jobID]) };
this.IsNeedSectionFinance.set(sfkey, finacne);
}
else
{
var finacne=this.IsNeedSectionFinance.get(sfkey);
if (!finacne.Fields.has(jobID)) finacne.Fields.add(jobID);
}
return;
}
if (callee.Name=="LOADAPIDATA") //加载API数据
{
var item= { Name:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA,Args:args };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber};
this.IsAPIData.push(item);
return;
}
let setStockDataName=new Set(['CLOSE',"C",'VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
if (setStockDataName.has(callee.Name))
{
var item= { Name:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA,Args:args };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber};
this.OtherSymbolData.push(item);
return;
}
}
this.VerifyMemberVariable=function(object,property,token)
{
var item={ ID:JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX, Member:{Object:object, Property:property} };
if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
this.ExecuteIndex.push(item);
return;
}
this.ExpressionStatement=function(expression)
{
return { Type:Syntax.ExpressionStatement, Expression:expression };
}
this.Script=function(body)
{
return {Type:Syntax.Program, Body:body, SourceType:'通达信脚本' };
}
this.SequenceExpression=function(expression)
{
return {Type:Syntax.SequenceExpression, Expression:expression };
}
this.BinaryExpression=function(operator, left, right)
{
let logical = (operator === '||' || operator === '&&' || operator=='AND' || operator=='OR');
let type = logical ? Syntax.LogicalExpression : Syntax.BinaryExpression;
return { Type:type, Operator:operator, Left:left, Right:right };
}
this.Literal=function(value,raw,token)
{
this.VerifySymbolLiteral(value, token);
return { Type:Syntax.Literal, Value:value, Raw:raw };
}
this.Identifier=function(name, token)
{
this.VerifySymbolVariable(name, token);
return { Type:Syntax.Identifier, Name:name};
}
//成员变量, 不需要检测
this.MemberIdentifier=function(name, token)
{
return { Type:Syntax.Identifier, Name:name};
}
this.AssignmentExpression=function (operator, left, right)
{
return { Type:Syntax.AssignmentExpression, Operator:operator, Left:left, Right:right };
}
this.UnaryExpression=function(operator, argument)
{
return { Type:Syntax.UnaryExpression, Operator:operator, Argument:argument, Prefix:true };
}
this.EmptyStatement=function()
{
return { Type:Syntax.EmptyStatement };
}
this.CallExpression=function(callee, args, token)
{
this.VerifySymbolFunction(callee, args, token);
return { Type:Syntax.CallExpression, Callee:callee, Arguments:args };
}
this.StaticMemberExpression=function(object, property,token)
{
this.VerifyMemberVariable(object,property, token);
return { Type:Syntax.MemberExpression, Computed:false, Object:object, Property:property };
}
this. Directive=function(expression, directive)
{
return { Type:Syntax.ExpressionStatement, Expression : expression, Directive: directive };
}
////////////////////////////////////////////////////////////////
this.ThrowUnexpectedToken=function(token,message)
{
throw this.UnexpectedTokenError(token,message);
}
this.UnexpectedTokenError=function(token,message)
{
let msg=message || Messages.UnexpectedToken;
let value='ILLEGAL';
if (token)
{
if (!message) { }
value=token.Value;
}
msg=msg.replace("%0",value);
if (token && typeof(token.LineNumber)=='number')
{
let index=token.Start;
let line=token.LineNumber;
let column=-1
return this.ErrorHandler.CreateError(index,line,column,msg);
}
}
}
function JSParser(code)
{
this.ErrorHandler=new ErrorHandler();
this.Scanner=new Scanner(code, this.ErrorHandler);
this.Node=new Node(this.ErrorHandler); //节点创建
this.LookAhead={Type:2, Value:'', LineNumber:this.Scanner.LineNumber, LineStart:0, Start:0, End:0 };
this.HasLineTerminator=false;
this.Context = {
IsModule: false,
await: false,
allowIn: true,
allowStrictDirective: true,
allowYield: true,
FirstCoverInitializedNameError: null,
IsAssignmentTarget: false,
IsBindingElement: false,
InFunctionBody: false,
inIteration: false,
inSwitch: false,
labelSet: {},
Strict: false
};
this.PeratorPrecedence =
{
')': 0,
';': 0,
',': 0,
']': 0,
'||': 1,
'OR':1,
'&&': 2,
'AND':2,
'|': 3,
'^': 4,
'&': 5,
'==': 6,
'=': 6,
'!=': 6,
'<>':6,
'===': 6,
'!==': 6,
'<': 7,
'>': 7,
'<=': 7,
'>=': 7,
'<<': 8,
'>>': 8,
'>>>': 8,
'+': 9,
'-': 9,
'*': 11,
'/': 11,
'%': 11
};
this.StartMarker={Index:0, Line: this.Scanner.LineNumber, Column:0 };
this.LastMarker={Index:0, Line: this.Scanner.LineNumber, Column:0 };
this.Initialize=function()
{
this.NextToken();
this.LastMarker={ Index:this.Scanner.Index, Line:this.Scanner.LineNumber, Column:this.Scanner.Index-this.Scanner.LineStart };
}
this.CreateNode=function()
{
return { Index:this.StartMarker.Index, Line:this.StartMarker.Line, Column:this.StartMarker.Column };
}
this.StartNode=function(token, lastLineStart)
{
if (lastLineStart==void 0) { lastLineStart=0; }
let column = token.Start - token.LineStart;
let line = token.LineNumber;
if (column < 0)
{
column += lastLineStart;
line--;
}
return { Index: token.Start, Line: line, Column: column };
}
this.Match=function(value)
{
return this.LookAhead.Type==7 /*Punctuator*/ && this.LookAhead.Value==value;
}
this.Expect=function(value, message)
{
let token=this.NextToken();
if (token.Type!=7 /*Punctuator*/ || token.Value!=value)
this.ThrowUnexpectedToken(token, message);
}
//是否是赋值操作符
this.MatchAssign=function()
{
if (this.LookAhead.Type!=7 /*Punctuator*/) return false;
let op=this.LookAhead.Value;
return op==':' || op==':=';
}
this.GetTokenRaw=function(token)
{
return this.Scanner.Source.slice(token.Start, token.End);
}
this.NextToken=function()
{
let token=this.LookAhead;
this.LastMarker.Index=this.Scanner.Index;
this.LastMarker.Line=this.Scanner.LineNumber;
this.LastMarker.Column=this.Scanner.Index-this.Scanner.LineStart;
this.CollectComments(); //过滤注释 空格
if (this.Scanner.Index !== this.StartMarker.Index)
{
this.StartMarker.Index = this.Scanner.Index;
this.StartMarker.Line = this.Scanner.LineNumber;
this.StartMarker.Column = this.Scanner.Index - this.Scanner.LineStart;
}
let next=this.Scanner.Lex();
this.HasLineTerminator=(token.LineNumber!=next.LineNumber);
if (next && this.Context.Strict && next.Type==3/*Identifier */)
{
//TODO:
}
this.LookAhead=next;
return token;
}
this.CollectComments=function()
{
this.Scanner.ScanComments();
}
this.ParseScript=function()
{
let node=this.CreateNode();
let body=this.ParseDirectivePrologues();
while(this.LookAhead.Type!=2 /*EOF*/)
{
body.push(this.ParseStatementListItem())
}
return this.Finalize(node,this.Node.Script(body));
}
//https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive
this.ParseDirective=function()
{
let token=this.LookAhead;
let node=this.CreateNode();
let expr=this.ParseExpression();
let directive = (expr.Type === Syntax.Literal) ? this.GetTokenRaw(token).slice(1, -1) : null;
this.ConsumeSemicolon();
return this.Finalize(node, directive ? this.Node.Directive(expr, directive) : this.Node.ExpressionStatement(expr));
}
this.ParseDirectivePrologues=function()
{
let firstRestricted=null;
let body=[];
while(true)
{
let token=this.LookAhead;
if (token.Type!=8 /*StringLiteral*/) break;
let statement=this.ParseDirective();
body.push(statement);
}
return body;
}
// https://tc39.github.io/ecma262/#sec-block
this.ParseStatementListItem=function()
{
let statement;
this.Context.IsAssignmentTarget=true;
this.Context.IsBindingElement=true;
if (this.LookAhead.Type==4 /*Keyword*/)
{
}
else
{
statement=this.ParseStatement();
}
return statement;
}
// https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations
this.ParseStatement=function()
{
let statement;
switch(this.LookAhead.Type)
{
case 1 /* BooleanLiteral */:
case 5 /* NullLiteral */:
case 6 /* NumericLiteral */:
case 8 /* StringLiteral */:
case 10 /* Template */:
case 9 /* RegularExpression */:
statement = this.ParseExpressionStatement();
break;
case 7 /* Punctuator */:
let value = this.LookAhead.Value;
if (value === '(') statement = this.ParseExpressionStatement();
else if (value === ';') statement = this.ParseEmptyStatement();
else statement = this.ParseExpressionStatement();
break;
case 3 /* Identifier */:
statement = this.ParseLabelledStatement();
break;
case 4 /* Keyword */:
break;
default:
statement="error";
}
return statement;
}
// https://tc39.github.io/ecma262/#sec-empty-statement
this.ParseEmptyStatement=function()
{
let node=this.CreateNode();
this.Expect(';');
return this.Finalize(node, this.Node.EmptyStatement());
}
//https://tc39.github.io/ecma262/#sec-labelled-statements
this.ParseLabelledStatement=function()
{
let node=this.CreateNode();
let expr=this.ParseExpression();
this.ConsumeSemicolon();
let statement = new this.Node.ExpressionStatement(expr);
return this.Finalize(node, statement);
}
// https://tc39.github.io/ecma262/#sec-comma-operator
this.ParseExpression=function()
{
let startToken=this.LookAhead;
let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
if (this.Match(','))
{
let expressions=[];
expressions.push(expr);
while(this.LookAhead.Type!=2 /*EOF*/)
{
if (!this.Match(',')) break;
this.NextToken();
expressions.push(this.IsolateCoverGrammar(this.ParseAssignmentExpression));
}
expr=this.Finalize(this.StartNode(startToken),this.Node.SequenceExpression(expressions));
}
return expr;
}
this.ParseAssignmentExpression=function()
{
let expr;
let startToken=this.LookAhead;
let token=startToken;
expr=this.ParseConditionalExpression();
if (this.MatchAssign())
{
if (!this.Context.IsAssignmentTarget)
{
let marker=expr.Marker;
this.ThrowUnexpectedError(marker.Index,marker.Line,marker.Column,Messages.InvalidLHSInAssignment);
}
if (!this.Match('=') && !this.Match(':'))
{
this.Context.IsAssignmentTarget=false;
this.Context.IsBindingElement=false;
}
else
{
this.ReinterpretExpressionAsPattern(expr);
}
token=this.NextToken();
let operator=token.Value;
let right=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
expr=this.Finalize(this.StartNode(startToken), this.Node.AssignmentExpression(operator, expr, right));
this.Context.FirstCoverInitializedNameError=null;
}
return expr;
}
this.ParseConditionalExpression=function()
{
let startToken=this.LookAhead;
let expr=this.InheritCoverGrammar(this.ParseBinaryExpression);
return expr;
}
this.ParseBinaryExpression=function()
{
let startToken=this.LookAhead;
let expr=this.InheritCoverGrammar(this.ParseExponentiationExpression);
let token=this.LookAhead;
var prec=this.BinaryPrecedence(token);
if (prec>0)
{
this.NextToken();
this.Context.IsAssignmentTarget=false;
this.Context.IsBindingElement=false;
let markers=[startToken,this.LookAhead];
let left=expr;
let right=this.IsolateCoverGrammar(this.ParseExponentiationExpression);
let stack=[left,token.Value,right];
let precedences = [prec];
while(true)
{
prec=this.BinaryPrecedence(this.LookAhead);
if (prec<=0) break;
while(stack.length>2 && prec<=precedences[precedences.length-1])
{
right=stack.pop();
let operator=stack.pop();
precedences.pop();
left=stack.pop();
markers.pop();
let node=this.StartNode(markers[markers.length - 1]);
stack.push(this.Finalize(node, this.Node.BinaryExpression(operator, left, right)));
}
//Shift
stack.push(this.NextToken().Value);
precedences.push(prec);
markers.push(this.LookAhead);
stack.push(this.IsolateCoverGrammar(this.ParseExponentiationExpression));
}
let i=stack.length-1;
expr=stack[i];
let lastMarker=markers.pop();
while(i>1)
{
let marker=markers.pop();
let lastLineStart=lastMarker && lastMarker.LineStart;
let node=this.StartNode(marker, lastLineStart);
let operator=stack[i-1];
expr=this.Finalize(node, this.Node.BinaryExpression(operator, stack[i - 2], expr));
i-=2;
lastMarker=marker;
}
}
return expr;
}
this.ParseExponentiationExpression=function()
{
let startToken=this.LookAhead;
let expr=this.InheritCoverGrammar(this.ParseUnaryExpression);
return expr;
}
this.ParseUnaryExpression=function()
{
let expr;
if (this.Match('+') || this.Match('-'))
{
let node=this.StartNode(this.LookAhead);
let token=this.NextToken();
expr=this.InheritCoverGrammar(this.ParseUnaryExpression);
expr=this.Finalize(node, this.Node.UnaryExpression(token.Value, expr));
this.Context.IsAssignmentTarget=false;
this.Context.IsBindingElement=false;
}
else
{
expr=this.ParseUpdateExpression();
}
return expr;
}
// https://tc39.github.io/ecma262/#sec-update-expressions
this.ParseUpdateExpression=function()
{
let expr;
let startToken=this.LookAhead;
expr=this.InheritCoverGrammar(this.ParseLeftHandSideExpressionAllowCall);
return expr;
}
this.ParseLeftHandSideExpressionAllowCall=function()
{
let startToken=this.LookAhead;
let expr;
expr=this.InheritCoverGrammar(this.ParsePrimaryExpression);
while(true)
{
if (this.Match('.'))
{
this.Context.IsBindingElement = false;
this.Context.IsAssignmentTarget = true;
this.Expect('.');
const property = this.ParseMemberIdentifierName();
expr = this.Finalize(this.StartNode(startToken), this.Node.StaticMemberExpression(expr, property,startToken));
}
else if (this.Match('('))
{
this.Context.IsBindingElement=false;
this.Context.IsAssignmentTarget=false;
var args=this.ParseArguments(); //解析 调用参数
expr=this.Finalize(this.StartNode(startToken), this.Node.CallExpression(expr,args,startToken));
}
else
{
break;
}
}
return expr;
}
/*
BooleanLiteral = 1,
EOF=2,
Identifier=3,
Keyword=4,
NullLiteral=5,
NumericLiteral=6,
Punctuator=7,
StringLiteral=9,
RegularExpression=9,
Template=10
*/
this.IsIdentifierName=function(token)
{
return token.Type === 3 //Identifier
|| token.Type === 4 //Keyword
|| token.Type === 1 //BooleanLiteral
|| token.Type === 5 ;//NullLiteral;
}
this.ParseIdentifierName=function()
{
const node = this.CreateNode();
const token = this.NextToken();
if (!this.IsIdentifierName(token))
{
this.ThrowUnexpectedToken(token);
}
return this.Finalize(node, this.Node.Identifier(token.Value, token));
}
this.ParseMemberIdentifierName=function()
{
const node = this.CreateNode();
const token = this.NextToken();
if (!this.IsIdentifierName(token))
{
this.ThrowUnexpectedToken(token);
}
return this.Finalize(node, this.Node.MemberIdentifier(token.Value, token));
}
// https://tc39.github.io/ecma262/#sec-left-hand-side-expressions
this.ParseArguments=function()
{
this.Expect('(');
var args=[];
if (!this.Match(')'))
{
while(true)
{
let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
args.push(expr);
if (this.Match(')')) break;
this.ExpectCommaSeparator();
if (this.Match(')')) break;
}
}
this.Expect(')');
return args;
}
// Quietly expect a comma when in tolerant mode, otherwise delegates to expect().
this.ExpectCommaSeparator=function()
{
this.Expect(',',"函数参数格式错误");
}
// https://tc39.github.io/ecma262/#sec-primary-expression
this.ParsePrimaryExpression=function()
{
let node=this.CreateNode();
let expr;
var token, raw;
switch(this.LookAhead.Type)
{
case 3:/* Identifier */
token=this.NextToken();
expr=this.Finalize(node, this.Node.Identifier(token.Value, token));
break;
case 6:/* NumericLiteral */
case 8:/* StringLiteral */
this.Context.IsAssignmentTarget=false;
this.Context.IsBindingElement=false;
token=this.NextToken();
raw=this.GetTokenRaw(token);
expr=this.Finalize(node, this.Node.Literal(token.Value,raw,token));
break;
case 7:/* Punctuator */
switch(this.LookAhead.Value)
{
case '(':
this.Context.IsBindingElement=false;
expr=this.InheritCoverGrammar(this.ParseGroupExpression);
break;
default:
expr=this.ThrowUnexpectedToken(this.NextToken())
}
break;
default:
expr = this.ThrowUnexpectedToken(this.NextToken());
}
return expr;
}
this.ParseGroupExpression=function()
{
let expr;
this.Expect('(');
if (this.Match(')'))
{
this.NextToken();
}
else
{
let startToken=this.LookAhead;
let params=[];
let arrow=false;
this.Context.IsBindingElement=true;
expr=this.InheritCoverGrammar(this.ParseAssignmentExpression);
if (this.Match(','))
{
let expressions=[];
this.Context.IsAssignmentTarget=false;
expressions.push(expr);
while(this.LookAhead.Type!=2 /* EOF */)
{
if (!this.Match(',')) break;
this.NextToken();
if (this.Match(')'))
{
}
}
}
if (!arrow)
{
this.Expect(')');
this.Context.IsBindingElement=false;
}
}
return expr;
}
// https://tc39.github.io/ecma262/#sec-expression-statement
this.ParseExpressionStatement=function()
{
let node=this.CreateNode();
let expr=this.ParseExpression();
this.ConsumeSemicolon();
return this.Finalize(node,this.Node.ExpressionStatement(expr));
}
this.ConsumeSemicolon=function()
{
if (this.Match(';'))
{
this.NextToken();
}
else if (!this.HasLineTerminator)
{
//if (this.LookAhead.Type!=2/*EOF*/ && !this.Match('}'))
this.LastMarker.Index=this.StartMarker.Index;
this.LastMarker.Line=this.StartMarker.Line;
this.LastMarker.Column=this.StartMarker.Column;
}
}
this.ReinterpretExpressionAsPattern=function(expr)
{
switch(expr.Type)
{
case Syntax.Identifier:
case Syntax.MemberExpression:
case Syntax.AssignmentExpression:
break;
default:
break;
}
}
this.Finalize=function(marker,node)
{
node.Marker={ Line:marker.Line, Column:marker.Column, Index:marker.Index };
return node;
}
this.BinaryPrecedence = function (token)
{
let op = token.Value;
let precedence;
if (token.Type === 7 /* Punctuator */) precedence = this.PeratorPrecedence[op] || 0;
else precedence = 0;
return precedence;
};
this.IsolateCoverGrammar=function(parseFunction)
{
let previousIsBindingElement=this.Context.IsBindingElement;
let previousIsAssignmentTarget=this.Context.IsAssignmentTarget;
let previousFirstCoverInitializedNameError=this.Context.FirstCoverInitializedNameError;
this.Context.IsBindingElement=true;
this.Context.IsAssignmentTarget=true;
this.Context.FirstCoverInitializedNameError=null;
let result=parseFunction.call(this);
if (this.Context.FirstCoverInitializedNameError!=null)
{
//错误 this.throwUnexpectedToken(this.context.firstCoverInitializedNameError);
}
this.Context.IsBindingElement=previousIsBindingElement;
this.Context.IsAssignmentTarget=previousIsAssignmentTarget;
this.Context.FirstCoverInitializedNameError=previousFirstCoverInitializedNameError;
return result;
}
this.InheritCoverGrammar = function (parseFunction)
{
let previousIsBindingElement = this.Context.IsBindingElement;
let previousIsAssignmentTarget = this.Context.IsAssignmentTarget;
let previousFirstCoverInitializedNameError = this.Context.FirstCoverInitializedNameError;
this.Context.IsBindingElement = true;
this.Context.IsAssignmentTarget = true;
this.Context.FirstCoverInitializedNameError = null;
let result = parseFunction.call(this);
this.Context.IsBindingElement = this.Context.IsBindingElement && previousIsBindingElement;
this.Context.IsAssignmentTarget = this.Context.IsAssignmentTarget && previousIsAssignmentTarget;
this.Context.FirstCoverInitializedNameError = previousFirstCoverInitializedNameError || this.Context.FirstCoverInitializedNameError;
return result;
};
this.ThrowUnexpectedToken=function(token,message)
{
throw this.UnexpectedTokenError(token,message);
}
this.ThrowUnexpectedError=function(index,line,column,message)
{
let msg=message || "执行异常";
return this.ErrorHandler.ThrowError(index,line,column,msg);
}
this.UnexpectedTokenError=function(token,message)
{
let msg=message || Messages.UnexpectedToken;
let value='ILLEGAL';
if (token)
{
if (!message)
{
}
value=token.Value;
}
msg=msg.replace("%0",value);
if (token && typeof(token.LineNumber)=='number')
{
let index=token.Start;
let line=token.LineNumber;
let lastMarkerLineStart=this.LastMarker.Index-this.LastMarker.Column;
let column=token.Start-lastMarkerLineStart+1;
return this.ErrorHandler.CreateError(index,line,column,msg);
}
else
{
let index=this.LastMarker.Index;
let line=this.LastMarker.Line;
let column=this.LastMarker.Column+1;
return this.ErrorHandler.CreateError(index,line,column,msg);
}
}
}
/*
算法类
*/
function JSAlgorithm(errorHandler,symbolData)
{
this.ErrorHandler=errorHandler;
this.SymbolData=symbolData; //股票数据
//相加
this.Add=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值相加
if (isNumber && isNumber2) return data+data2;
//都是数组相加
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]+data2[i];
}
}
return result;
}
//单数据和数组相加
let value;
let aryData;
if (isNumber)
{
value=data;
aryData=data2;
}
else
{
value=data2;
aryData=data;
}
for(let i in aryData)
{
result[i]=null;
if (this.IsNumber(aryData[i]) && this.IsNumber(value)) result[i]=value+aryData[i];
}
return result;
}
//相减
this.Subtract=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值相减
if (isNumber && isNumber2) return data-data2;
//都是数组相减
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]-data2[i];
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (this.IsNumber(data) && this.IsNumber(data2[i])) result[i]=data-data2[i];
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (this.IsNumber(data[i]) && this.IsNumber(data2)) result[i]=data[i]-data2;
}
}
return result;
}
//相乘
this.Multiply=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值相乘
if (isNumber && isNumber2) return data*data2;
//都是数组相乘
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]*data2[i];
}
}
return result;
}
//单数据和数组相乘
let value;
let aryData;
if (isNumber)
{
value=data;
aryData=data2;
}
else
{
value=data2;
aryData=data;
}
for(let i in aryData)
{
result[i]=null;
if (this.IsNumber(aryData[i]) && this.IsNumber(value)) result[i]=value*aryData[i];
}
return result;
}
//相除
this.Divide=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值相除
if (isNumber && isNumber2)
{
if (data2==0) return null; //除0判断
return data/data2;
}
//都是数组相除
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsDivideNumber(data2[i]) ) result[i]=data[i]/data2[i];
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( this.IsNumber(data) && this.IsDivideNumber(data2[i]) ) result[i]=data/data2[i];
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( this.IsNumber(data[i]) && this.IsDivideNumber(data2) ) result[i]=data[i]/data2;
}
}
return result;
}
//大于
this.GT=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data>data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[i]>data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data)) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data>data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2)) continue;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i]>data2 ? 1 : 0);
}
}
return result;
}
//大于等于
this.GTE=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data>=data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data[i]>=data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data)) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data>=data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2)) continue;
result[i]=(data[i]>=data2 ? 1 : 0);
}
}
return result;
}
//小于
this.LT=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data<data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data[i]<data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data)) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data<data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2)) continue;
result[i]=(data[i]<data2 ? 1 : 0);
}
}
return result;
}
//小于等于
this.LTE=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data>=data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data[i]<=data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data)) continue;
if (!IFrameSplitOperator.IsVaild(data2[i])) continue;
result[i]=(data<=data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (!IFrameSplitOperator.IsVaild(data[i])) continue;
if (!IFrameSplitOperator.IsVaild(data2)) continue;
result[i]=(data[i]<=data2 ? 1 : 0);
}
}
return result;
}
//等于
this.EQ=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data==data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[i]==data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data==data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i]==data2 ? 1 : 0);
}
}
return result;
}
//不等于
this.NEQ=function(data,data2)
{
let isNumber=IFrameSplitOperator.IsNumber(data);
let isNumber2=IFrameSplitOperator.IsNumber(data2);
//单数值比较
if (isNumber && isNumber2) return (data!=data2 ? 1 : 0);
//都是数组比较
let result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[i]!=data2[i] ? 1:0);
}
}
return result;
}
if (isNumber && Array.isArray(data2)) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data!=data2[i] ? 1 : 0);
}
}
else if (isNumber2 && Array.isArray(data)) //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i]!=data2 ? 1 : 0);
}
}
return result;
}
//AND &&
this.And=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值 &&
if (isNumber && isNumber2) return (data && data2 ? 1 : 0);
//都是数组 &&
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[i] && data2[i] ? 1:0);
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data && data2[i] ? 1 : 0);
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i] && data2 ? 1 : 0);
}
}
return result;
}
//OR ||
this.Or=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值 &&
if (isNumber && isNumber2) return (data || data2 ? 1 : 0);
//都是数组 &&
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[i] || data2[i] ? 1:0);
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data || data2[i] ? 1 : 0);
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i] || data2 ? 1 : 0);
}
}
return result;
}
this.IF=function(data,trueData,falseData)
{
let isNumber=this.IsNumber(data);
let isNumber2=this.IsNumber(trueData);
let isNumber3=this.IsNumber(falseData);
var isArray2=Array.isArray(trueData);
var isArray3=Array.isArray(falseData);
//单数值
if (isNumber)
{
if (isNumber2 && isNumber3) return data?trueData:falseData;
return data? trueData:falseData;
}
//都是数组
let result=[];
for(let i in data)
{
if (data[i])
{
if (isNumber2) result[i]=trueData;
else if (isArray2) result[i]=trueData[i];
else result[i]=null;
}
else
{
if (isNumber3) result[i]=falseData;
else if (isArray3) result[i]=falseData[i];
else result[i]=null;
}
}
return result;
}
/*
根据条件求不同的值,同IF判断相反.
用法: IFN(X,A,B)若X不为0则返回B,否则返回A
例如: IFN(CLOSE>OPEN,HIGH,LOW)表示该周期收阴则返回最高值,否则返回最低值
*/
this.IFN=function(data,trueData,falseData)
{
return this.IF(data,falseData,trueData);
}
//指标函数 函数名全部大写
//引用若干周期前的数据(平滑处理).
//用法: REF(X,A),引用A周期前的X值.A可以是变量.
//平滑处理:当引用不到数据时进行的操作.此函数中,平滑时使用上一个周期的引用值.
//例如: REF(CLOSE,BARSCOUNT(C)-1)表示第二根K线的收盘价.
this.REF=function(data,n)
{
let result=[];
if (typeof(n)=='number')
{
if (IFrameSplitOperator.IsNumber(data)) //单数值
{
if (n<0) return result;
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var count=kData.length;
for(var i=n;i<count;++i)
{
result[i]=data;
}
}
else
{
if (data.length<=0) return result;
if (n>=data.length) return result;
result=data.slice(0,data.length-n);
//平滑处理
var firstData=data[0];
for(let i=0;i<n;++i)
result.unshift(firstData);
}
}
else //n 为数组的情况
{
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var value=n[i];
if (value>=0 && value<=i) result[i]=data[i-value];
else if (i) result[i]=result[i-1];
else result[i]=data[i];
}
}
return result;
}
//引用若干周期前的数据(未作平滑处理).
//用法: REFV(X,A),引用A周期前的X值.A可以是变量.
//平滑处理:当引用不到数据时进行的操作.
//例如: REFV(CLOSE,BARSCOUNT(C)-1)表示第二根K线的收盘价.
this.REFV=function(data,n)
{
let result=[];
if (typeof(n)=='number')
{
if (data.length<=0) return result;
if (n>=data.length) return result;
result=data.slice(0,data.length-n);
for(let i=0;i<n;++i) //不作平滑处理
result.unshift(null);
}
else //n 为数组的情况
{
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var value=n[i];
if (value>=0 && value<=i) result[i]=data[i-value];
}
}
return result;
}
//属于未来函数,引用若干周期后的数据(平滑处理).
//用法: REFX(X,A),引用A周期后的X值.A可以是变量.
//平滑处理:当引用不到数据时进行的操作.此函数中,平滑时使用上一个周期的引用值.
//例如: TT:=IF(C>O,1,2);
// REFX(CLOSE,TT);表示阳线引用下一周期的收盘价,阴线引用日后第二周期的收盘价.
this.REFX=function(data,n)
{
let result=[];
if (typeof(n)=='number')
{
if (data.length<=0) return result;
if (n>=data.length)
{
if (data.length>0) return data[data.length-1]; //取最后一个数据
return result;
}
result=data.slice(n,data.length);
//平滑处理
var lastData=data[data.length-1];
for(let i=0;i<n;++i)
result.push(lastData);
}
else //n 为数组的情况
{
var dataCount=data.length;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var value=n[i];
if (value>=0 && value+i<dataCount) result[i]=data[i+value];
else if (i) result[i]=result[i-1];
else result[i]=data[i];
}
}
return result;
}
//属于未来函数,引用若干周期后的数据(未作平滑处理).
//用法:REFXV(X,A),引用A周期后的X值.A可以是变量.
//平滑处理:当引用不到数据时进行的操作.
//例如: REFXV(CLOSE,1)表示下一周期的收盘价,在日线上就是明天收盘价
this.REFXV=function(data,n)
{
let result=[];
if (typeof(n)=='number')
{
if (data.length<=0) return result;
if (n>=data.length) return result;
result=data.slice(n,data.length);
//平滑处理
for(let i=0;i<n;++i)
result.push(null);
}
else //n 为数组的情况
{
var dataCount=data.length;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var value=n[i];
if (value>=0 && value+i<dataCount) result[i]=data[i+value];
}
}
return result;
}
//求最大值.
//用法:MAX(A,B,C,D ..... ) 返回A,B,C,D ..... 中的较大值
//例如: MAX(CLOSE-OPEN,0)表示若收盘价大于开盘价返回它们的差值,否则返回0
this.MAX=function(args, node)
{
if (args.length==0) this.ThrowUnexpectedNode(node,'MAX() Error: 参数个数不能为0');
if (args.length==1) return args[0];
var aryData=[], aryNumber=[];
for(var i in args)
{
var item=args[i];
if (IFrameSplitOperator.IsNumber(item)) aryNumber.push(item);
else if (Array.isArray(item)) aryData.push(item);
}
var maxNumber=null;
if (aryNumber.length>0)
{
maxNumber=aryNumber[0];
for(var i=1; i<aryNumber.length; ++i)
{
maxNumber=Math.max(maxNumber,aryNumber[i]);
}
}
var maxAryData=null;
if (aryData.length>0)
{
maxAryData=aryData[0].slice(0);
for(var i=1;i<aryData.length;++i)
{
var dataItem=aryData[i];
for(var j in dataItem)
{
var maxItem=maxAryData[j];
var item=dataItem[j];
if (!IFrameSplitOperator.IsNumber(maxItem)) continue;
if (!IFrameSplitOperator.IsNumber(item))
{
maxAryData[j]=null;
continue;
}
maxAryData[j]=Math.max(maxItem,item);
}
}
}
if (maxAryData==null && maxNumber!=null) return maxNumber;
if (maxAryData && maxNumber==null) return maxAryData;
for(var i in maxAryData)
{
if (!IFrameSplitOperator.IsNumber(maxAryData[i])) continue;
maxAryData[i]=Math.max(maxAryData[i],maxNumber);
}
return maxAryData;
}
//求最小值.
//用法:MIN(A,B, C, D .....)返回A,B, C ,D ......中的较小值
//例如:MIN(CLOSE,OPEN)返回开盘价和收盘价中的较小值
this.MIN=function(args, node)
{
if (args.length==0) this.ThrowUnexpectedNode(node,'MIN() Error: 参数个数不能为0');
if (args.length==1) return args[0];
var aryData=[], aryNumber=[];
for(var i in args)
{
var item=args[i];
if (IFrameSplitOperator.IsNumber(item)) aryNumber.push(item);
else if (Array.isArray(item)) aryData.push(item);
}
var minNumber=null;
if (aryNumber.length>0)
{
minNumber=aryNumber[0];
for(var i=1; i<aryNumber.length; ++i)
{
minNumber=Math.min(minNumber,aryNumber[i]);
}
}
var minAryData=null;
if (aryData.length>0)
{
minAryData=aryData[0].slice(0);
for(var i=1;i<aryData.length;++i)
{
var dataItem=aryData[i];
for(var j in dataItem)
{
var minItem=minAryData[j];
var item=dataItem[j];
if (!IFrameSplitOperator.IsNumber(minItem)) continue;
if (!IFrameSplitOperator.IsNumber(item))
{
minAryData[j]=null;
continue;
}
minAryData[j]=Math.min(minItem,item);
}
}
}
if (minAryData==null && minNumber!=null) return minNumber;
if (minAryData && minNumber==null) return minAryData;
for(var i in minAryData)
{
if (!IFrameSplitOperator.IsNumber(minAryData[i])) continue;
minAryData[i]=Math.min(minAryData[i],minNumber);
}
return minAryData;
}
//取正数
this.ABS=function(data)
{
let result=[];
for(let i in data)
{
result[i]=null;
if (!isNaN(data[i])) result[i]=Math.abs(data[i]);
}
return result;
}
this.MA=function(data,dayCount)
{
let result=[];
if (dayCount<=0) return result;
if (!Array.isArray(dayCount))
{
dayCount=parseInt(dayCount); //转整形
if (dayCount<=0) dayCount=1;
if (!data || !data.length) return result;
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
var data=data.slice(0); //复制一份数据出来
for(var days=0;i<data.length;++i,++days)
{
if (days<dayCount-1)
{
result[i]=null;
continue;
}
let preValue=data[i-(dayCount-1)];
let sum=0;
for(let j=dayCount-1;j>=0;--j)
{
var value=data[i-j];
if (!this.IsNumber(value))
{
value=preValue; //空数据就取上一个数据
data[i-j]=value;
}
else
{
preValue=value;
}
sum+=value;
}
result[i]=sum/dayCount;
}
}
else
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (i>=dayCount.length) continue;
var sumCount=dayCount[i];
if (!this.IsNumber(sumCount)) continue;
if (sumCount<=0) continue;
var sum=0;
var count=0;
for(var j=i, k=0;j>=0 && k<sumCount;--j,++k)
{
sum+=data[j];
++count;
}
if (count>0) result[i]=sum/count;
}
}
return result;
}
//指数平均数指标 EMA(close,10)
//N 支持周期数组
this.EMA=function(data,dayCount)
{
var result = [];
if (data.length<=0) return result;
if (Array.isArray(dayCount))
{
for(var i=0;i<dayCount.length;++i)
{
var period=dayCount[i];
if (!this.IsNumber(period)) continue;
period=parseInt(period); //周期用整数
if (period<=0) continue;
if (period>i+1) period=i+1;
//EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'为前一天的ema
var EMAFactor=[ 2/ (period + 1), (period - 1) / (period + 1)];
var ema=null;
var lastEMA=null;
for(var j=0;j<period;++j)
{
var index=i-(period-j-1);
var value=data[index];
if (!this.IsNumber(value)) coninue;
if (lastEMA==null)
{
ema=value; //第一个EMA为第一个数据的价格
lastEMA=ema;
}
else
{
ema = EMAFactor[0] * value + EMAFactor[1] * lastEMA;
lastEMA=ema;
}
}
result[i]=ema;
}
}
else
{
dayCount=parseInt(dayCount); //转整形
if (dayCount<=0) return result;
var offset=0;
//取首个有效数据
for(;offset<data.length;++offset)
{
if (data[offset]!=null && !isNaN(data[offset]))
break;
}
var p1Index=offset;
var p2Index=offset+1;
result[p1Index]=data[p1Index];
for(var i=offset+1;i<data.length;++i,++p1Index,++p2Index)
{
result[p2Index]=((2*data[p2Index]+(dayCount-1)*result[p1Index]))/(dayCount+1);
}
}
return result;
}
this.XMA=function(data,n)
{
var result=[];
var offset=0;
for(;offset<data.length;++offset)
{
if (this.IsNumber(data[offset])) break;
}
var p = parseInt((n - 2) / 2);
var sum = 0;
var count = 0, start=0, end = 0;
for(var i=offset, j=0; i<data.length; ++i)
{
start = i - p - 1;
end = i + (n - p) - 1;
for (j = start; j < end; ++j)
{
if (j >= 0 && j<data.length)
{
if (this.IsNumber(data[j]))
{
sum += data[j];
++count;
}
}
}
if (count!=0) result[i]=(sum / count);
else result[i]=null;
sum = 0;
count = 0;
}
return result;
}
/*
SMA 移动平均
返回移动平均。
用法: SMA(X,N,M) X的N日移动平均,M为权重,如Y=(X*M+Y'*(N-M))/N
*/
this.SMA=function(data,n,m)
{
var result = [];
if (Array.isArray(n))
{
for( var i=0;i<n.length;++i)
{
var period=n[i];
if (!this.IsNumber(period)) continue;
period=parseInt(period);
if (period<=0) continue;
if (period>i+1) period=i+1;
var lastSMA=null;
var sma=null;
for(var j=0;j<period;++j)
{
var index=i-(period-j-1);
var item=data[index];
if (!this.IsNumber(item)) continue;
if (lastSMA==null)
{
lastSMA=item;
sma=item;
}
else
{
sma=(m*item+(period-m)*lastSMA)/period;
lastSMA=sma;
}
}
result[i]=sma;
}
}
else
{
var i=n;
var lastData=null;
for(;i<data.length; ++i)
{
if (data[i]==null || isNaN(data[i])) continue;
lastData=data[i];
result[i]=lastData; //第一天的数据
break;
}
for(++i;i<data.length;++i)
{
result[i]=(m*data[i]+(n-m)*lastData)/n;
lastData=result[i];
}
}
return result;
}
/*
求动态移动平均.
用法: DMA(X,A),求X的动态移动平均.
算法: 若Y=DMA(X,A)则 Y=A*X+(1-A)*Y',其中Y'表示上一周期Y值,A必须小于1.
例如:DMA(CLOSE,VOL/CAPITAL)表示求以换手率作平滑因子的平均价
*/
this.DMA=function(data,data2)
{
var result = [];
if (data.length<0 || data.length!=data2.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]) && data2[index]!=null && !isNaN(data2[index]))
{
result[index]=data[index];
break;
}
}
for(index=index+1;index<data.length;++index)
{
if (data[index]==null || data2[index]==null)
result[index]=null;
else
{
if (data2[index]<1)
result[index]=(data2[index]*data[index])+(1-data2[index])*result[index-1];
else
result[index]= data[index];
}
}
return result;
}
/*
返回加权移动平均
用法:WMA(X,N):X的N日加权移动平均.
算法:Yn=(1*X1+2*X2+...+n*Xn)/(1+2+...+n)
*/
this.WMA=function(data, dayCount)
{
let result=[];
if (!data || !data.length) return result;
if (Array.isArray(dayCount))
{
for(i=0;i<dayCount.length && i<data.length;++i)
{
result[i]=null;
var period=dayCount[i];
if (period<=0) continue;
var start=0,value=0, index=0, preValue=0;
for(var j=0;j<period;++j)
{
index=i-(period-j-1);
value=data[index];
start=j;
if (this.IsNumber(value))
{
preValue=value;
break;
}
}
if (start>=period) continue;
var sum=0, count=0;
for(var j=start, k=1;j<period; ++j, ++k)
{
index=i-(period-j-1);
value=data[index];
if (this.IsNumber(value))
preValue=value;
else
value=preValue;
count += k;
sum += value * k;
}
result[i] = sum / count;
}
return result;
}
else
{
if (dayCount<=0) return [];
var i = 0;
for(i = 0; i < data.length && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
var data = data.slice(0);
for(var days=0; i < data.length; ++i,++days)
{
if (days < dayCount-1)
{
result[i] = null;
continue;
}
var preValue = data[i - (dayCount-1)];
var sum = 0;
var count = 0;
for (var j = dayCount-1; j >= 0; --j)
{
var value = data[i-j];
if (!this.IsNumber(value))
{
value = preValue;
data[i-j] = value;
}
else
preValue = value;
count += dayCount - j;
sum += value * (dayCount - j);
}
result[i] = sum / count;
}
return result;
}
}
/*
返回平滑移动平均
用法:MEMA(X,N):X的N日平滑移动平均,如Y=(X+Y'*(N-1))/N
MEMA(X,N)相当于SMA(X,N,1)
*/
this.MEMA=function(data, dayCount)
{
let result=[];
if (!data || !data.length) return result;
var i = 0, j = 0;
for (j = 0; j < data.length && !this.IsNumber(data[j]); ++j)
{
result[j] = null;
}
i = j;
if (dayCount < 1 || i+dayCount >= data.length) return result;
var sum = 0;
var data = data.slice(0);
for (; i < j+dayCount; ++i)
{
result[i] = null;
if (!this.IsNumber(data[i]) && i-1 >= 0)
data[i] = data[i-1];
sum += data[i];
}
result[i-1] = sum / dayCount;
for (; i < data.length; ++i)
{
if (this.IsNumber(result[i-1]) && this.IsNumber(data[i]))
result[i] = (data[i]+result[i-1]*(dayCount-1)) / dayCount;
else if (i-1 > -1 && this.IsNumber(result[i-1]))
result[i] = result[i-1];
else
result[i] = null;
}
return result;
}
/*
加权移动平均
返回加权移动平均
用法:EXPMA(X,M):X的M日加权移动平均
EXPMA[i]=buffer[i]*para+(1-para)*EXPMA[i-1] para=2/(1+__para)
*/
this.EXPMA=function(data,dayCount)
{
let result=[];
if (dayCount>=data.length) return result;
let i=dayCount;
for(;i<data.length;++i) //获取第1个有效数据
{
if (data[i]!=null)
{
result[i]=data[i];
break;
}
}
for (i=i+1; i < data.length; ++i)
{
if (result[i-1]!=null && data[i]!=null)
result[i]=(2*data[i]+(dayCount-1)*result[i-1])/(dayCount+1);
else if (result[i-1]!=null)
result[i]=result[i-1];
}
return result;
}
//加权平滑平均,MEMA[i]=SMA[i]*para+(1-para)*SMA[i-1] para=2/(1+__para)
this.EXPMEMA=function(data,dayCount)
{
var result=[];
if (dayCount>=data.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index] && !isNaN(data[index])) break;
}
var sum=0;
for(var i=0; index<data.length && i<dayCount;++i, ++index)
{
if (data[index] && !isNaN(data[index]))
sum+=data[index];
else
sum+=data[index-1];
}
result[index-1]=sum/dayCount;
for(;index<data.length;++index)
{
if(result[index-1]!=null && data[index]!=null)
result[index]=(2*data[index]+(dayCount-1)*result[index-1])/(dayCount+1);
else if(result[index-1]!=null)
result[index] = result[index-1];
}
return result;
}
/*
向前累加到指定值到现在的周期数.
用法:SUMBARS(X,A):将X向前累加直到大于等于A,返回这个区间的周期数
例如:SUMBARS(VOL,CAPITAL)求完全换手到现在的周期数
*/
this.SUMBARS=function(data, data2)
{
var result = [];
if (!data || !data.length || !data2 || !data2.length) return result;
var start = 0, i = 0, j = 0;
for(; start < data.length && !this.IsNumber(data[start]); ++start)
{
result[start] = null;
}
for (i = data.length-1; i >= start; --i)
{
var total = 0;
for (j = i, total = 0; j >= start && total < data2[i]; --j)
total += data[j];
if (j < start) result[i] = null;
else result[i] = i - j;
}
for(i = start+1; i < data.length; ++i)
{
if (result[i]==null)
result[i] = result[i-1];
}
return result;
}
/*
求相反数.
用法:REVERSE(X)返回-X.
例如:REVERSE(CLOSE)返回-CLOSE
*/
this.REVERSE=function(data)
{
if (this.IsNumber(data))
{
return 0-data;
}
var result = [];
var i = 0;
for (; i<data.length && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
for (; i < data.length; ++i)
{
if (!this.IsNumber(data[i]))
result[i] = null;
else
result[i] = 0-data[i];
}
return result;
}
/*
统计满足条件的周期数.
用法:COUNT(X, N), 统计N周期中满足X条件的周期数, 若N<0则从第一个有效值开始.
例如 :COUNT(CLOSE>OPEN, 20)表示统计20周期内收阳的周期数
N 支持数组
*/
this.COUNT=function(data,n)
{
if (Array.isArray(n))
{
var start=null;
var dataCount=data.length;
for(var i=0;i<dataCount;++i)
{
if (this.IsNumber(data[i]))
{
start=i;
break;
}
}
if (start==null) return [];
var result=[];
var count=0;
for(var i=0;i<n.length;++i)
{
var period=n[i];
if (period==0)
{
result[i]=0;
continue;
}
if (!IFrameSplitOperator.IsNumber(period) ) period=i+1; //无效周期 第一个有效值开始.
else if (period<0) period=i+1;
count=0;
for(var j=i, k=0 ;j>=0 && k<period ;--j,++k) //当前往前period天 统计
{
if (data[j]) ++count;
}
result[i]=count;
}
return result;
}
else
{
var period=n;
var dataCount=data.length;
var period=period<1?dataCount:period;
var i=0,j=0;
for(;i<dataCount;++i) // 取第1个有效数据
{
if (this.IsNumber(data[i])) break;
}
var result=[];
var days=0;
for(;i<dataCount && j<period; ++i,++j)
{
days=data[i]?days+1:days;
result[i]=days;
}
for(;i<dataCount;++i)
{
if (data[i-period] && days) days--;
days=data[i] ? days+1 : days;
result[i]=days;
}
return result;
}
}
/*
HHV 最高值
求最高值。
用法: HHV(X,N) 求N周期内X最高值,N=0则从第一个有效值开始。
例如: HHV(HIGH,30) 表示求30日最高价。
*/
this.HHV=function(data,n)
{
let result = [];
if (Array.isArray(n))
{
var max=null;
for(var i=0,j=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
max=null;
var count=n[i];
if (count>0 && count<=i)
{
for(j=i-count;j<=i;++j)
{
if (max==null || max<data[j]) max=data[j];
}
}
else
{
count=i;
for(j=0;j<=i;++j)
{
if (max==null || max<data[j]) max=data[j];
}
}
result[i]=max;
}
}
else
{
if (!IFrameSplitOperator.IsNonEmptyArray(data)) return result;
n=parseInt(n);
if (n<=0) n=data.length;
else if (n>data.length) n=data.length;
var nStart=this.GetFirstVaildIndex(data);
if (nStart>=data.length) return result;
var nMax=nStart;
if (nMax<data.length) result[nMax]=data[nMax];
for(var i=nMax+1,j=2;i<data.length && j<n;++i,++j)
{
if (data[i]>=data[nMax]) nMax=i;
result[i]=data[nMax];
}
for(;i<data.length;++i)
{
if (i-nMax<n)
{
nMax=data[i]<data[nMax]?nMax:i;
}
else
{
for(j=nMax=(i-n+1);j<=i;++j)
{
nMax=data[j]<data[nMax]?nMax:j;
}
}
result[i]=data[nMax];
}
}
return result;
}
/*
HV(X,N):求X在N个周期内(不包含当前k线)的最高值。
注:
1、若N为0则从第一个有效值开始算起(不包含当前K线);
2、当N为有效值,但当前的k线数不足N根,按照实际的根数计算,第一根k线返回空值;
3、N为空值时,返回空值。
4、N可以是变量。
例1:
HH:HV(H,10);//求前10根k线的最高点。
例2:
N:=BARSLAST(DATE<>REF(DATE,1))+1;
ZH:VALUEWHEN(DATE<>REF(DATE,1),HV(H,N));//在分钟周期上,求昨天最高价。
例3:
HV(H,5) 和 REF(HHV(H,5),1) 的结果是一样的,用HV编写更加方便。
*/
this.HV=function(data,n)
{
var result=this.HHV(data,n);
return this.REF(result,1);
}
/*
LLV 最低值
求最低值。
用法: LLV(X,N) 求N周期内X最低值,N=0则从第一个有效值开始。
例如: LLV(LOW,0) 表示求历史最低价。
*/
this.LLV=function(data,n)
{
var result = [];
if (Array.isArray(n))
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var min=null;
var count=n[i];
if (count>0 && count<=i)
{
for(var j=i-count;j<=i;++j)
{
if (min==null || min>data[j]) min=data[j];
}
}
else
{
count=i;
for(var j=0;j<=i;++j)
{
if (min==null || min>data[j]) min=data[j];
}
}
result[i]=min;
}
}
else
{
if (!IFrameSplitOperator.IsNonEmptyArray(data)) return result;
n=parseInt(n);
if (n<=0) n=data.length;
else if (n>data.length) n=data.length;
var nStart=this.GetFirstVaildIndex(data);
if (nStart>=data.length) return result;
var nMin=nStart;
if (nMin<data.length) result[nMin]=data[nMin];
for(var i=nMin+1,j=2;i<data.length && j<n;++i,++j)
{
if (data[i]<=data[nMin]) nMin=i;
result[i]=data[nMin];
}
for(;i<data.length;++i)
{
if (i-nMin<n)
{
nMin=data[i]>data[nMin]?nMin:i;
}
else
{
for(j=nMin=(i-n+1);j<=i;++j)
{
nMin=data[j]>data[nMin]?nMin:j;
}
}
result[i]=data[nMin];
}
}
return result;
}
/*
LV(X,N) 求X在N个周期内的最小值(不包含当前k线)
注:
1、若N为0则从第一个有效值开始算起;
2、当N为有效值,但当前的k线数不足N根,按照实际的根数计算;
3、N为空值时,返回空值。
4、N可以是变量。
例1:
LL:LV(L,10);//求前面10根k线的最低点。(不包含当前k线)
例2:
N:=BARSLAST(DATE<>REF(DATE,1))+1;//分钟周期,日内k线根数
ZL:VALUEWHEN(DATE<>REF(DATE,1),LV(L,N));//在分钟周期上,求昨天最低价。
例3:
LV(L,5) 和 REF(LLV(L,5),1) 的结果是一样的,用LV编写更加方便。
*/
this.LV=function(data,n)
{
var result=this.LLV(data,n);
return this.REF(result,1);
}
this.STD=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
var nStart=this.GetFirstVaildIndex(data);
if (!IFrameSplitOperator.IsNumber(n)) return result;
if(nStart+n>data.length || n<1) return result;
var i=nStart, j=0, bFirst=true, dTotal=0, dAvg=0;
for(i+=n-1;i<data.length;++i)
{
dTotal = 0;
if(bFirst)
{
bFirst = false;
for(j=i-n+1;j<=i;++j)
{
dAvg += data[j];
}
dAvg /= n;
}
else
{
dAvg += (data[i]-data[i-n])/n;
}
for(j=i-n+1;j<=i;++j)
{
dTotal += (data[j]-dAvg)*(data[j]-dAvg);
}
result[i] = Math.sqrt(dTotal/(n-1));
}
return result;
}
//STDDEV(X,N) 返回标准偏差
//将标准差除以样本大小N的平方根即可得出标准误差。标准误差 = σ/sqrt(n)
this.STDDEV=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
var nStart=this.GetFirstVaildIndex(data);
if (!IFrameSplitOperator.IsNumber(n)) return result;
if(nStart+n>data.length || n<1) return result;
var i=nStart, j=0, bFirst=true, dTotal=0, dAvg=0;
for(i+=n-1;i<data.length;++i)
{
dTotal = 0;
if(bFirst)
{
bFirst = false;
for(j=i-n+1;j<=i;++j)
{
dAvg += data[j];
}
dAvg /= n;
}
else
{
dAvg += (data[i]-data[i-n])/n;
}
for(j=i-n+1;j<=i;++j)
{
dTotal += (data[j]-dAvg)*(data[j]-dAvg);
}
result[i] = Math.sqrt(dTotal/(n-1))/Math.sqrt(n);
}
return result;
}
//平均绝对方差
this.AVEDEV=function(data,n)
{
var result=[];
var total=0;
var averageData=[]; //平均值
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=data[i-j];
}
averageData[i]=total/n;
}
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=Math.abs(data[i-j]-averageData[i]);
}
result[i]=total/n;
}
return result;
}
//上穿
this.CROSS=function(data,data2)
{
var result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
if (data.length!=data2.length) return result=[];
var index=0;
for(;index<data.length;++index)
{
if (this.IsNumber(data[index]) && this.IsNumber(data2[index]))
break;
}
for(++index;index<data.length;++index)
{
result[index]= (data[index]>data2[index] && data[index-1]<data2[index-1]) ? 1:0;
}
}
else if (Array.isArray(data) && typeof(data2)=='number')
{
var index=0;
for(;index<data.length;++index)
{
if (this.IsNumber(data[index])) break;
}
for(++index;index<data.length;++index)
{
result[index]= (data[index]>data2 && data[index-1]<data2) ? 1:0;
}
}
else if (typeof(data)=='number' && Array.isArray(data2))
{
var index=0;
for(;index<data2.length;++index)
{
if (this.IsNumber(data2[index])) break;
}
for(++index;index<data2.length;++index)
{
result[index]= (data2[index]<data && data2[index-1]>data) ? 1:0;
}
}
return result;
}
/*
CROSSDOWN(A,B):表示当A从上方向下穿B,成立返回1(Yes),否则返回0(No)
注:1、CROSSDOWN(A,B)等同于CROSS(B,A),CROSSDOWN(A,B)编写更利于理解
例1:
MA5:=MA(C,5);
MA10:=MA(C,10);
CROSSDOWN(MA5,MA10)//MA5下穿MA10
*/
this.CROSSDOWN=function(data,data2)
{
return this.CROSS(data2,data);
}
/*
CROSSUP(A,B) 表当A从下方向上穿过B,成立返回1(Yes),否则返回0(No)
注:
1、CROSSUP(A,B)等同于CROSS(A,B),CROSSUP(A,B)编写更利于理解。
例1:
MA5:=MA(C,5);
MA10:=MA(C,10);
CROSSUP(MA5,MA10),ICON(1,'ICO4');//MA5上穿MA10,标注红箭头。
//CROSSUP(MA5,MA10),ICON(1,'ICO4'); 与 CROSSUP(MA5,MA10)=1,ICON(1,'ICO4');表达同等意义
*/
this.CROSSUP=function(data,data2)
{
return this.CROSS(data,data2);
}
//累乘
this.MULAR=function(data,n)
{
var result=[];
if (!Array.isArray(n))
{
if(data.length<n) return result;
if (n==0)
{
var index=n;
for(;index<data.length;++index)
{
if (this.IsNumber(data[index]))
{
result[index]=data[index];
break;
}
}
for(++index;index<data.length;++index)
{
result[index]=result[index-1]*data[index];
}
}
else
{
for(var i=n-1,j=0;i<data.length;++i,++j)
{
for(var k=0;k<n;++k)
{
if (k==0) result[i]=data[k+j];
else result[i]*=data[k+j];
}
}
}
}
else
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var totalCount=n[i];
if (!this.IsNumber(totalCount)) continue;
totalCount=parseInt(totalCount);
if (totalCount<0) continue;
for(var j=i, k=0 ;j>=0 && k<totalCount ;--j,++k)
{
if (k==0) result[i]=data[j];
else result[i]*=data[j];
}
}
}
return result;
}
this.SUM=function(data,n)
{
var result=[];
if (!Array.isArray(n))
{
if (n<=0)
{
var start=-1;
for(var i=0; i<data.length; ++i) //取第1个有效数
{
if (IFrameSplitOperator.IsNumber(data[i]))
{
start=i;
break;
}
}
if (start<0) return result;
result[start]=data[start];
for (var i=start+1; i<data.length; ++i)
{
result[i] = result[i-1]+data[i];
}
}
else
{
result[0]=data[0];
for(var i=1;i<n && i<data.length;++i) //前面小于N周期的累加
{
result[i] = result[i-1]+data[i];
}
for(var i=n-1,j=0;i<data.length;++i,++j)
{
for(var k=0;k<n;++k)
{
if (k==0) result[i]=data[k+j];
else result[i]+=data[k+j];
}
}
}
}
else
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var totalCount=n[i];
if (!(totalCount>0)) continue;
for(var j=i, k=0 ;j>=0 && k<totalCount ;--j,++k)
{
if (k==0) result[i]=data[j];
else result[i]+=data[j];
}
}
}
return result;
}
/*
BARSCOUNT 有效数据周期数
求总的周期数。
用法: BARSCOUNT(X) 第一个有效数据到当前的天数。
例如: BARSCOUNT(CLOSE) 对于日线数据取得上市以来总交易日数,对于分笔成交取得当日成交笔数,对于1分钟线取得当日交易分钟数。
*/
this.BARSCOUNT=function(data)
{
let result=[];
let days=null;
for(let i in data)
{
result[i]=0;
if (days==null)
{
if (!this.IsNumber(data[i])) continue;
days=0;
}
result[i]=days;
++days;
}
return result;
}
//DEVSQ 数据偏差平方和
//DEVSQ(X,N)  返回数据偏差平方和。
this.DEVSQ=function(data,n)
{
if (this.IsNumber(data) && this.IsNumber(n))
return 0;
var result=[];
if (Array.isArray(data))
{
var num = null;
if (Array.isArray(n)) //取最后一个有效数
{
for(var i=n.length-1;i>=0;--i)
{
if (this.IsNumber(n[i]))
{
num = parseInt(n[i]);
break;
}
}
}
else
{
num = parseInt(n);
}
if (!this.IsNumber(num)) return result;
var datanum = data.length;
var i = 0, j = 0, k = 0;
var E = 0, DEV = 0;
for(i = 0; i < datanum && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
if (num < 1 || i+num>datanum) return result;
for(E=0; i < datanum && j < num; ++i,++j)
E += data[i]/num;
if (j == num)
{
DEV = 0;
for(i--; k < num; k++)
DEV += (data[i-k]-E) * (data[i-k]-E);
result[i] = DEV;
i++;
}
for(; i < datanum; ++i)
{
E += (data[i] - data[i-num]) / num;
for(DEV=0, k = 0; k < num; ++k)
DEV += (data[i-k]-E) * (data[i-k]-E);
result[i] = DEV;
}
}
return result;
}
//NOT 取反
//求逻辑非。
//用法: NOT(X) 返回非X,即当X=0时返回1,否则返回0。
//例如: NOT(ISUP) 表示平盘或收阴。
this.NOT=function(data)
{
let isNumber=typeof(data)=='number';
if (isNumber) return data? 0:1;
let result=[];
for(let i in data)
{
result[i]=null;
if (this.IsNumber(data[i])) result[i]=data[i]?0:1;
}
return result;
}
//FORCAST 线性回归预测值
//FORCAST(X,N)  返回线性回归预测值。
this.FORCAST=function(data,n)
{
var result=[];
if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
var num = n;
var datanum = data.length;
if (num < 1 || num >= datanum)
return result;
var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope;
var i, j,x;
for(j = 0; j < datanum && !this.IsNumber(data[j]); ++j)
{
result[j] = null;
}
for(i = j+num-1; i < datanum; ++i)
{
Ex = Ey = Sxy = Sxx = 0;
for(j = 0, x=num; j < num && j <= i; ++j, --x)
{
Ex += x;
Ey += data[i - j];
}
Ex /= num;
Ey /= num;
for(j = 0, x=num; j < num && j <= i; ++j,--x)
{
Sxy += (x-Ex)*(data[i-j]-Ey);
Sxx += (x-Ex)*(x-Ex);
}
Slope = Sxy / Sxx;
Const = Ey - Ex*Slope;
result[i] = Slope * num + Const;
}
return result;
}
//TSMA(X,N):求X在N个周期内的时间序列三角移动平均
//TSMA(a,n) 算法如下:
//ysum=a[i]+a[i-1]+...+a[i-n+1]
//xsum=i+i-1+..+i-n+1
//xxsum=i*i+(i-1)*(i-1)+...+(i-n+1)*(i-n+1)
//xysum=i*a[i]+(i-1)*a[i-1]+...+(i-n+1)*a[i-n+1]
//k=(xysum -(ysum/n)*xsum)/(xxsum- xsum/n * xsum) //斜率
//b= ysum/n - k*xsum/n
//forcast[i]=k*i+b //线性回归
//tsma[i] = forcast[i]+k //线性回归+斜率
this.TSMA=function(data,n)
{
var result=[];
if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
var num = n;
var datanum = data.length;
if (num < 1 || num >= datanum)
return result;
var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope;
var i, j,x;
for(j = 0; j < datanum && !this.IsNumber(data[j]); ++j)
{
result[j] = null;
}
for(i = j+num-1; i < datanum; ++i)
{
Ex = Ey = Sxy = Sxx = 0;
for(j = 0, x=num; j < num && j <= i; ++j, --x)
{
Ex += x;
Ey += data[i - j];
}
Ex /= num;
Ey /= num;
for(j = 0, x=num; j < num && j <= i; ++j,--x)
{
Sxy += (x-Ex)*(data[i-j]-Ey);
Sxx += (x-Ex)*(x-Ex);
}
Slope = Sxy / Sxx;
Const = Ey - Ex*Slope;
result[i] = (Slope * num + Const) + Slope;
}
return result;
}
//SLOPE 线性回归斜率
//SLOPE(X,N)  返回线性回归斜率。
this.SLOPE=function(data,n)
{
let result=[];
if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
if (n<1 || !data.length) return result;
if (n>=data.length) return result;
let start=0;
for(let i=0;i<data.length;++i,++start)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
let x,y,xy,xx;
for(let i=start+n-1;i<data.length;++i)
{
result[i]=null;
x=y=xy=xx=0;
for(var j=0;j<n && j<=i; ++j)
{
x+=(i-j); //数据索引相加
y+=data[i-j]; //数据相加
}
x=x/n; y=y/n;
for(j=0;j<n && j<=i; ++j)
{
xy+=(i-j-x)*(data[i-j]-y);
xx+=(i-j-x)*(i-j-x);
}
if (xx) result[i]= xy/xx;
else if (i) result[i]=result[i-1];
}
return result;
}
//STDP 总体标准差
//STDP(X,N)  返回总体标准差。
this.STDP=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
var nStart=this.GetFirstVaildIndex(data);
if (!IFrameSplitOperator.IsNumber(n)) return result;
if(nStart+n>data.length || n<1) return result;
var i=nStart, j=0, bFirst=true, dTotal=0, dAvg=0;
for(i+=n-1;i<data.length;++i)
{
dTotal = 0;
if(bFirst)
{
bFirst = false;
for(j=i-n+1;j<=i;++j)
{
dAvg += data[j];
}
dAvg /= n;
}
else
{
dAvg += (data[i]-data[i-n])/n;
}
for(j=i-n+1;j<=i;++j)
{
dTotal += (data[j]-dAvg)*(data[j]-dAvg);
}
result[i] = Math.sqrt(dTotal/n);
}
return result;
}
//VAR 估算样本方差
//VAR(X,N)  返回估算样本方差。
this.VAR=function(data,n)
{
if (this.IsNumber(data) && this.IsNumber(n)) return 0;
var result=[];
if (Array.isArray(data) && this.IsNumber(n))
{
var num = parseInt(n);
var datanum = data.length;
if (num <= 0 || num >= datanum) return result;
var i, j;
for(i = 0; i < datanum && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
var SigmaPowerX, SigmaX;
for (j = 0, i = i+num-1; i < datanum; ++i)
{
SigmaPowerX = SigmaX = 0;
for(j=0; j < num && j <= i; ++j)
{
SigmaPowerX += data[i-j] * data[i-j];
SigmaX += data[i-j];
}
result[i] = (num*SigmaPowerX - SigmaX*SigmaX) / num * (num -1);
}
}
else if (Array.isArray(data) && Array.isArray(n))
{
var start=this.GetFirstVaildIndex(data);
for(var i=start; i<data.length; ++i)
{
var SigmaPowerX = SigmaX = 0;
if (!this.IsNumber(n[i])) continue;
var num=parseInt(n[i]);
if (num <= 0 || i-(num-1)<0) continue;
for (var j = 0; j<num; ++j)
{
SigmaPowerX += data[i-j] * data[i-j];
SigmaX += data[i-j];
}
result[i] = (num*SigmaPowerX - SigmaX*SigmaX) / num * (num -1);
}
}
return result;
}
//VARP 总体样本方差
//VARP(X,N)  返回总体样本方差 。
this.VARP=function(data,n)
{
var result=[];
if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
var num = n;
var datanum = data.length;
if (num < 1 || num >= datanum)
return result;
var i = 0, j = 0;
for(i = 0; i < datanum && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
var SigmaPowerX = 0, SigmaX = 0;
for (; i < datanum && j < num; ++i, ++j)
{
SigmaPowerX += data[i] * data[i];
SigmaX += data[i];
}
if (j == num)
result[i-1] = (num*SigmaPowerX - SigmaX*SigmaX) / (num*num);
for(; i < datanum; ++i)
{
SigmaPowerX += data[i]*data[i] - data[i-num]*data[i-num];
SigmaX += data[i] - data[i-num];
result[i] = (num*SigmaPowerX - SigmaX*SigmaX) / (num*num);
}
return result;
}
//RANGE(A,B,C)表示A>B AND A<C;
this.RANGE=function(data,range,range2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(range)=='number';
let isNumber3=typeof(range2)=='number';
if (isNumber && isNumber2 && isNumber3)
{
if (data>Math.min(range,range2) && data<Math.max(range,range2)) return 1;
else return 0;
}
let result=[];
let value, rangeValue,rangValue2;
for(let i=0; i<data.length; ++i)
{
result[i]=null;
value=data[i];
if (!this.IsNumber(value)) continue;
if (!isNumber2)
{
if (i>=range.length) continue;
rangeValue=range[i];
}
else
{
rangeValue=range;
}
if (!this.IsNumber(rangeValue)) continue;
if (!isNumber3)
{
if (i>=range2.length) continue;
rangeValue2=range2[i];
}
else
{
rangeValue2=range2;
}
if (!this.IsNumber(rangeValue2)) continue;
result[i]= (value>Math.min(rangeValue,rangeValue2) && value<Math.max(rangeValue,rangeValue2)) ? 1:0;
}
return result;
}
/*
是否存在.
例如: EXIST(CLOSE>OPEN,10)
表示10日内存在着阳线
*/
this.EXIST=function(data,n)
{
if (typeof(data)=='number') return 0;
if (Array.isArray(n))
{
var result=[];
if (data.length<=0) return result;
for( var i in data) //初始化
{
result[i]=0;
}
for(var i=0;i<n.length && i<data.length;++i)
{
var period=n[i];
if (!this.IsNumber(period)) continue;
period=parseInt(period);
if (period<=0) continue;
if (period>i+1) period=i+1;
var bExist=false;
var index=0, value=0;
for(var j=0;j<period;++j)
{
index=i-(period-j-1);
value=data[i];
if (this.IsNumber(value) && value>0)
{
bExist=true;
break;
}
}
result[i]=bExist?1:0;
}
return result;
}
else
{
n=parseInt(n);
var latestID=null; //最新满足条件的数据索引
var result=[];
var value;
for(let i=0;i<data.length;++i)
{
result[i]=null;
value=data[i];
if (this.IsNumber(value) && value>0) latestID=i;
if (latestID!=null && i-latestID<n) result[i]=1;
else result[i]=0;
}
return result;
}
}
/*
过滤连续出现的信号.
用法:TFILTER(买入条件,卖出条件,N);过滤掉买入(卖出)信号发出后,下一个反向信号发出前的所有买入(卖出)信号.
N=1表示仅对买入信号过滤;
N=2表示仅对卖出信号过滤;
N=0表示对买入和卖出信号都过滤,返回1,2表示买入或卖出条件成立;
同一K线上只能有一个信号;
例如:
ENTERLONG:TFILTER(买入,卖出,1);
EXITLONG:TFILTER(买入,卖出,2);
TFILTER(D,K,1) 等价于 D AND COUNT(D, BARSLAST(K)) == 1
TFILTER(D,K,2) 等价于 K AND COUNT(K, BARSLAST(D)) == 1
TFILTER(D,K,0) 需要做个判断,如果满足 D AND COUNT(D, BARSLAST(K)) == 1 则返回1,如果满足 K AND COUNT(K, BARSLAST(D)) == 1 则返回2
*/
this.TFILTER=function(data,data2,n)
{
if (!this.IsNumber(n)) return [];
if (n==1)
{
return this.And(data,this.EQ(this.COUNT(data,this.BARSLAST(data2)),1));
}
else if (n==2)
{
return this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
}
else if (n==0)
{
var result=this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
var value=this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
for(var i=0; i<result.length; ++i)
{
var item=value[i];
if (item>0) result[i]=2;
}
return result;
}
return [];
}
/*
过滤连续出现的信号.
用法:FILTER(X,N):X满足条件后,将其后N周期内的数据置为0,N为常量.
例如:
FILTER(CLOSE>OPEN,5)查找阳线,5天内再次出现的阳线不被记录在内
*/
this.FILTER=function(data,n)
{
var result=[];
for(let i=0,j=0; i<data.length; ++i)
{
if (data[i])
{
result[i]=1;
for(j=0;j<n && j+i+1<data.length;++j)
{
result[j+i+1]=0;
}
i+=n;
}
else
{
result[i]=0;
}
}
return result;
}
//反向过滤连续出现的信号.
//用法:FILTERX(X,N):X满足条件后,将其前N周期内的数据置为0,N为常量.
//例如:FILTERX(CLOSE>OPEN,5)查找阳线,前5天内出现过的阳线不被记录在内
this.FILTERX=function(data, n, node)
{
var result=[];
for(let i=0,j=0; i<data.length; ++i)
{
if (data[i])
{
result[i]=1;
for(j=0;j<n && i-j-1>=0;++j)
{
result[i-j-1]=0;
}
i+=n;
}
else
{
result[i]=0;
}
}
return result;
}
//上一次条件成立到当前的周期数.
//用法:BARSLAST(X):上一次X不为0到现在的周期数
//例如:BARSLAST(CLOSE/REF(CLOSE,1)>=1.1)表示上一个涨停板到当前的周期数
this.BARSLAST=function(data)
{
var result=[];
if (!data) return result;
let day=null;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (data[i]>0) day=0;
else if (day!=null) ++day;
if (day!=null) result[i]=day;
}
return result;
}
//倒数第N次成立时距今的周期数.
//用法:BARSLASTS(X,N):X倒数第N满足到现在的周期数,N支持变量
this.BARSLASTS=function(data, n, node)
{
var result=[];
if (!data) return result;
if (n<=0) n=data.length;
var day=null;
var SingleValue=0; //单词数
var periodCount=0;
for(let i=0;i<data.length;++i)
{
result[i]=null;
var value=data[i];
if (value>0)
{
if (day==null)
{
day=0;
++periodCount;
}
else
{
++periodCount;
if (periodCount>n) day-=SingleValue;
}
SingleValue=0;
}
else
{
if (day!=null)
{
++day;
++SingleValue;
}
}
if (day!=null) result[i]=day;
}
return result;
}
/*
N周期内第一个条件成立到当前的周期数.
用法:
BARSSINCEN(X,N):N周期内第一次X不为0到现在的天数,N为常量
例如:
BARSSINCEN(HIGH>10,10)表示10个周期内股价超过10元时到当前的周期数
*/
this.BARSSINCEN=function(data,n)
{
var result=[];
if (this.IsNumber(n) && Array.isArray(data))
{
var nPeriod=n;
if (nPeriod<1) nPeriod=data.length;
var i=this.GetFirstVaildIndex(data);
if (i>=data.length) return result;
var j=0;
if (i <= nPeriod - 1) j = nPeriod - 1;
else j = i;
result[j] = j - i;
for (; j < data.length; ++j)
{
if (this.IsNumber(result[j - 1]))
{
if (result[j - 1] + 1 < nPeriod)
{
result[j] = result[j - 1] + 1;
}
else
{
for (var k = j - nPeriod+1; k <= j; ++k)
{
if (!(Math.abs(data[k]) < 0.000001))
{
result[j] = j - k;
break;
}
}
}
}
else
{
if (!(Math.abs(data[j]) < 0.000001))
result[j] = 0;
}
}
}
return result;
}
/*
第一个条件成立到当前的周期数.
用法:
BARSSINCE(X):第一次X不为0到现在的天数
例如:
BARSSINCE(HIGH>10)表示股价超过10元时到当前的周期数
*/
this.BARSSINCE=function(data)
{
var result=[];
var day=null;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (day==null)
{
if (data[i]) day=0;
}
else
{
++day;
}
if (day) result[i]=day;
}
return result;
}
/*三角函数调用 func 三角函数
反正切值. 用法: ATAN(X)返回X的反正切值
余弦值. 用法: COS(X)返回X的余弦值
正弦值. 用法: SIN(X)返回X的正弦值
正切值. 用法: TAN(X)返回X的正切值
求自然对数. 用法: LN(X)以e为底的对数 例如: LN(CLOSE)求收盘价的对数
求10为底的对数. 用法: LOG(X)取得X的对数 例如: LOG(100)等于2
指数. 用法: EXP(X)为e的X次幂 例如: EXP(CLOSE)返回e的CLOSE次幂
开平方. 用法: SQRT(X)为X的平方根 例如: SQRT(CLOSE)收盘价的平方根
*/
this.Trigonometric=function(data,func)
{
if (!Array.isArray(data))
{
if (this.IsNumber(data)) return func(data);
return null;
}
else
{
var result=[];
for(let i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=func(item);
else result[i]=null;
}
return result;
}
}
//反正弦值. 用法: ASIN(X)返回X的反正弦值
this.ASIN=function(data)
{
if (!Array.isArray(data))
{
if (this.IsNumber(data)) return Math.acos(data);
return null;
}
else
{
var result=[];
for(let i in data)
{
var item=data[i];
result[i]=null;
if (this.IsNumber(item))
{
if (item>=-1 && item<=1)
{
result[i]=Math.asin(item);
}
else if (i-1>=0)
{
var preItem=result[i-1];
if (this.IsNumber(preItem)) result[i]=preItem;
}
}
}
return result;
}
}
//反余弦值. 用法: ACOS(X)返回X的反余弦值
this.ACOS=function(data)
{
if (!Array.isArray(data))
{
if (this.IsNumber(data)) return Math.acos(data);
return null;
}
else
{
var result=[];
for(let i in data)
{
var item=data[i];
result[i]=null;
if (this.IsNumber(item))
{
if (item>=-1 && item<=1)
{
result[i]=Math.acos(item);
}
else if (i-1>=0)
{
var preItem=result[i-1];
if (this.IsNumber(preItem)) result[i]=preItem;
}
}
}
return result;
}
}
/*
LAST(X,A,B):持续存在.
用法:
LAST(CLOSE>OPEN,10,5)
表示从前10日到前5日内一直阳线
若A为0,表示从第一天开始,B为0,表示到最后日止
*/
this.LAST=function(data,n,n2)
{
if (!Array.isArray(data)) return [];
var result=[];
var lCount=data.length;
var nStart = n;
var nEnd = n2, k = 0, i = 0, j = 0, t = 0;
for (; k < lCount; ++k)
{
if (data[k]) break;
}
for (i = k, t = k - nEnd + 1; i<lCount; ++i, ++t)
{
j = (nStart == 0) ? k : Math.max(k, i - nStart);
for (; j < t; ++j)
{
if (data[j]<=0)
{
break;
}
}
result[i]=(j<t ? 0 : 1);
}
return result;
}
/*
属于未来函数,之字转向.
用法: ZIG(K,N),当价格变化量超过N%时转向,K表示0:开盘价,1:最高价,2:最低价,3:收盘价,其余:数组信息
例如: ZIG(3,5)表示收盘价的5%的ZIG转向
*/
this.ZIG=function(data,n)
{
var hisData=this.SymbolData.Data;
var result=[];
if (typeof(data)=='number')
{
switch(data)
{
case 0:
data=hisData.GetOpen();
break;
case 1:
data=hisData.GetHigh();
break;
case 2:
data=hisData.GetLow();
break;
case 3:
data=hisData.GetClose();
break;
default:
return result;
}
}
return this.ZIG_Calculate(data,n);
}
this.GetFirstVaildIndex=function(data)
{
for (var i = 0; i <data.length; ++i)
{
if (this.IsNumber(data[i]))
return i;
}
return data.length;
}
this.ZIG_Calculate=function(data,dRate)
{
var dest=[];
var nDataCount=data.length;
var m=this.GetFirstVaildIndex(data);
var i = 0, lLastPos = 0, lState = 0, j = 0;
var dif = 0;
for (i = m + 1, lLastPos = lState = m; i<nDataCount - 1 && lState == m; ++i)
{
lState = Math.abs(data[i] - data[m]) * 100 >= dRate*data[m] ? (data[i]>data[m] ? i : -i) : m;
}
for (; i<nDataCount - 1; ++i)
{
if (data[i] >= data[i - 1] && data[i] >= data[i + 1])
{
if (lState<0)
{
if ((data[i] - data[-lState]) * 100<dRate*data[-lState]) continue;
else
{
dif = (data[lLastPos] - data[j = -lState]) / (-lState - lLastPos);
dest[j--]=data[-lState];
for (; j >= lLastPos; j--)
dest[j]=data[-lState] + (-lState - j)*dif;
lLastPos = -lState;
lState = i;
}
}
else if (data[i]>data[lState]) lState = i;
}
else if (data[i] <= data[i - 1] && data[i] <= data[i + 1])
{
if (lState>0)
{
if ((data[lState] - data[i]) * 100<dRate*data[lState]) continue;
else
{
dif = (data[lState] - data[j = lLastPos]) / (lState - lLastPos);
dest[j++]=data[lLastPos];
for (; j <= lState; ++j)
dest[j]=data[lLastPos] + (j - lLastPos)*dif;
lLastPos = lState;
lState = -i;
}
}
else if (data[i]<data[-lState]) lState = -i;
}
}
if (Math.abs(lState) >= nDataCount - 2)
{
if (lState>0 && data[nDataCount - 1] >= data[lState]) lState = nDataCount - 1;
if (lState<0 && data[nDataCount - 1] <= data[-lState]) lState = 1 - nDataCount;
}
if (lState>0)
{
dif = (data[lState] - data[j = lLastPos]) / (lState - lLastPos );
dest[j++]=data[lLastPos];
for (; j <= lState; ++j)
dest[j]=data[lLastPos] + (j - lLastPos)*dif;
}
else
{
dif = (data[lLastPos] - data[j = -lState]) / (-lState - lLastPos);
dest[j--]=data[-lState];
for (; j >= lLastPos; j--)
dest[j]=(data[-lState] + (-lState - j)*dif);
}
if ((lState = Math.abs(lState))<nDataCount - 1)
{
if (data[nDataCount - 1] >= data[lState])
{
dif = (data[nDataCount - 1] - data[j = lState]) / (nDataCount - lState);
dest[j++]=(data[lState]);
for (; j<nDataCount; ++j)
dest[j]=(data[lState] + (j - lState)*dif);
}
else
{
dif = (data[lState] - data[j = nDataCount - 1]) / (nDataCount - lState);
dest[j--]=(data[nDataCount - 1]);
for (; j >= lState; j--)
dest[j]=(data[nDataCount - 1] + (nDataCount - j)*dif);
}
}
return dest;
}
this.JSDraw=null;
this.CalculateZIGLine=function(firstData,secondData,thridData,data,result)
{
if (this.JSDraw==null) this.JSDraw=new JSDraw(this.ErrorHandler);
var isUp=secondData.Up;
var findData=firstData;
if (isUp)
{
for(var i=firstData.ID+1;i<thridData.ID;++i) //查找最高点
{
var subItem=data[i];
if (!this.IsNumber(subItem)) continue;
if (findData.Value<subItem) findData={ID:i, Value:subItem};
}
}
else
{
for(var i=firstData.ID+1;i<thridData.ID;++i) //查找最低点
{
var subItem=data[i];
if (!this.IsNumber(subItem)) continue;
if (findData.Value>subItem) findData={ID:i, Value:subItem};
}
}
secondData.Value=findData.Value;
secondData.ID=findData.ID;
var lineCache={ Start:{ID:firstData.ID, Value:firstData.Value}, End:{ID:secondData.ID,Value:secondData.Value}};
var lineData=this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值
for(var i in lineData)
{
var lineItem=lineData[i];
result[lineItem.ID]=lineItem.Value;
}
if (thridData.ID==data.length-1) //最后一组数据
{
//最后2个点的数据连成线
lineCache={ Start:{ID:secondData.ID, Value:secondData.Value}, End:{ID:thridData.ID,Value:thridData.Value} };
lineData=this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值
for(var i in lineData)
{
var lineItem=lineData[i];
result[lineItem.ID]=lineItem.Value;
}
}
else
{
firstData.ID=secondData.ID;
firstData.Value=secondData.Value;
secondData.ID=thridData.ID;
secondData.Value=thridData.Value;
secondData.Up=firstData.Value < secondData.Value;
}
}
/*
属于未来函数,前M个ZIG转向波谷到当前距离.
用法:
TROUGHBARS(K,N,M)表示之字转向ZIG(K,N)的前M个波谷到当前的周期数,M必须大于等于1
例如:
TROUGHBARS(2,5,2)表示%5最低价ZIG转向的前2个波谷到当前的周期数
*/
this.TROUGHBARS=function(data,n,n2)
{
var zigData=this.ZIG(data,n); //计算ZIG
var dest=[];
var lEnd =n2;
if (lEnd<1) return dest;
var nDataCount = zigData.length;
var trough = [];
for(var i=0;i<lEnd;++i) trough[i]=0;
var lFlag = 0;
var i = this.GetFirstVaildIndex(zigData) + 1;
for (lEnd--; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);
for (; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);
for (trough[0] = --i; i<nDataCount - 1; ++i)
{
if (zigData[i]<zigData[i + 1])
{
if (lFlag)
{
if (lEnd)
{
var tempTrough=trough.slice(0);
for(var j=0;j<lEnd;++j)
{
trough[j+1]=tempTrough[j];
}
}
trough[lFlag = 0] = i;
}
}
else lFlag = 1;
if (trough[lEnd]) dest[i]=(i - trough[lEnd]);
}
if (trough[lEnd]) dest[i]=(i - trough[lEnd]);
return dest;
}
this.TROUGH=function(data,n,n2)
{
var zigData=this.ZIG(data,n); //计算ZIG
var dest=[];
var End=n2;
if(End<1) return dest;
var nDataCount = zigData.length;
var trough=[];
for(var i=0;i<End;++i) trough[i]=0;
var i=1,Flag=0;
var i = this.GetFirstVaildIndex(zigData) + 1;
for(End--; i<nDataCount && zigData[i]>zigData[i-1]; ++i);
for(; i<nDataCount && zigData[i]<zigData[i-1]; ++i);
for(trough[0]=--i;i<nDataCount-1;++i)
{
if(zigData[i]<zigData[i+1])
{
if(Flag)
{
if(End)
{
var tempTrough=trough.slice(0);
for(var j=0;j<End;++j)
{
trough[j+1]=tempTrough[j];
}
}
trough[Flag=0]=i;
}
}
else Flag=1;
if(trough[End]) dest[i]=zigData[trough[End]];
}
if(trough[End]) dest[i]=zigData[trough[End]];
return dest;
}
/*
属于未来函数,前M个ZIG转向波峰到当前距离.
用法:
PEAKBARS(K,N,M)表示之字转向ZIG(K,N)的前M个波峰到当前的周期数,M必须大于等于1
例如:
PEAKBARS(0,5,1)表示%5开盘价ZIG转向的上一个波峰到当前的周期数
*/
this.PEAKBARS=function(data,n,n2)
{
var zigData=this.ZIG(data,n); //计算ZIG
var dest=[];
var nDataCount = zigData.length;
var lEnd = n2;
if (lEnd < 1) return dest;
var peak = [];
for(var i=0;i<lEnd;++i) peak[i]=0;
var lFlag = 0;
var i = this.GetFirstVaildIndex(zigData) + 1;
for (lEnd--; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);
for (; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);
for (peak[0] = --i; i<nDataCount - 1; ++i)
{
if (zigData[i]>zigData[i + 1])
{
if (lFlag)
{
if (lEnd)
{
var tempPeak=peak.slice(0);
for(var j=0;j<lEnd;++j)
{
peak[j+1]=tempPeak[j];
}
}
peak[lFlag = 0] = i;
}
}
else lFlag = 1;
if (peak[lEnd]) dest[i]=(i - peak[lEnd]);
}
if (peak[lEnd])dest[i]=(i - peak[lEnd]);
return dest;
}
this.PEAK=function(data,n,n2)
{
var zigData=this.ZIG(data,n); //计算ZIG
var dest=[];
var nDataCount = zigData.length;
var lEnd = n2;
if (lEnd < 1) return dest;
var lFlag = 0;
var peak = [];
for(var i=0;i<lEnd;++i) peak[i]=0;
var i = this.GetFirstVaildIndex(zigData) + 1;
for (lEnd--; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);
for (; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);
for (peak[0] = --i; i<nDataCount - 1; ++i)
{
if (zigData[i]>zigData[i + 1])
{
if (lFlag)
{
if (lEnd)
{
var tempPeak=peak.slice(0);
for(var j=0;j<lEnd;++j)
{
peak[j+1]=tempPeak[j];
}
}
peak[lFlag = 0] = i;
}
}
else lFlag = 1;
if (peak[lEnd]) dest[i]=(zigData[peak[lEnd]]);
}
if (peak[lEnd]) dest[i]=(zigData[peak[lEnd]]);
return dest;
}
/*
一直存在.
例如:
EVERY(CLOSE>OPEN,N)
表示N日内一直阳线(N应大于0,小于总周期数,N支持变量)
*/
this.EVERY=function(data,n)
{
var result=[];
if (n<1) return result;
if (IFrameSplitOperator.IsNumber(n))
{
n=parseInt(n);
var i=0;
for(;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
var flag=0;
for(;i<data.length;++i)
{
if (data[i]) flag+=1;
else flag=0;
if (flag==n)
{
result[i]=1;
--flag;
}
else
{
result[i]=0;
}
}
}
else if (Array.isArray(n))
{
for(var i=0;i<n.length;++i)
{
var value=n[i];
result[i]=null;
if (!IFrameSplitOperator.IsPlusNumber(value)) continue;
value=parseInt(value);
var flag=0;
for(var j=i, k=0; j>=0 && k<value; --j, ++k)
{
if (data[j]) ++flag;
}
result[i]=(flag==value?1:0);
}
}
return result;
}
/*
成本分布情况.
用法:
COST(10),表示10%获利盘的价格是多少,即有10%的持仓量在该价格以下,其余90%在该价格以上,为套牢盘
该函数仅对日线分析周期有效
*/
this.COST=function(data, node)
{
var result=[];
var rate=data/100;
if(rate<0.000001 || rate>1) return result;
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
for(var i=0;i<kData.length;++i)
{
var item=kData[i];
dMinPrice = Math.min(dMinPrice,item.Low);
dMaxPrice = Math.max(dMaxPrice,item.High);
}
if (dMinPrice > 2000 || dMinPrice < 0 || dMaxPrice>2000 || dMinPrice < 0)
this.ThrowUnexpectedNode(node,'COST() 历史K线最大最小值错误, 超出(0,1000)范围');
var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
var lMinPrice = parseInt(dMinPrice * 100 - 1);
var lLow = 0, lHigh = 0, lClose = 0;
//去掉小数
dMaxPrice = lMaxPrice / 100.0;
dMinPrice = lMinPrice / 100.0;
var lSpeed = lMaxPrice - lMinPrice + 1;
if (lSpeed < 1) return result;
var aryVolPrice=[],aryPerVol=[];
for(var i=0;i<lSpeed;++i)
{
aryVolPrice[i]=0;
aryPerVol[i]=0;
}
var dHSL = 0, dTotalVol = 0, dVol = 0, dCost=0;
for(var i=0;i<kData.length;++i)
{
if (i >= aryCapital.length) continue;
if (aryCapital[i]>1)
{
var kItem=kData[i]
dHSL = kItem.Vol/aryCapital[i];
for( var j=0;j<lSpeed;j++)
aryVolPrice[j]*=(1-dHSL);
lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;
for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;
var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
if (lHalf == lHigh || lHalf == lLow)
{
aryPerVol[lHalf] += kItem.Vol;
}
else
{
var dVH = kItem.Vol / (lHalf - lLow);
for (var k = lLow; k<lHalf; ++k)
{
aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
}
for (k; k <= lHigh; ++k)
{
aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
}
}
var dTotalVol = 0;
for (var j = lLow; j <= lHigh; j++)
{
aryVolPrice[j] += aryPerVol[j];
}
for (var j = 0; j < lSpeed; j++)
{
dTotalVol += aryVolPrice[j];
}
for(j=0,dCost=dVol=0;j<lSpeed;++j)
{
dVol+=aryVolPrice[j];
if(dVol>=dTotalVol*rate)
{
dCost=(dMaxPrice-dMinPrice)*j/lSpeed+dMinPrice;
break;
}
}
}
result[i]=dCost;
}
return result;
}
/*
this.COST=function(data)
{
var result=[];
var exchangeID=201;
var exchangeData=this.SymbolData.GetFinanceCacheData(exchangeID); //换手率
if (!exchangeData) return result;
var isNumber=Array.isArray(data)?false:true;
var singleData=null;
if (isNumber) singleData=parseFloat(data);
var compareData=null;
for(let i=this.SymbolData.Data.Data.length-1, j=0,k=0 ; i>=0; --i)
{
result[i]=null;
var chipData=this.CalculateChip(i,exchangeData,this.SymbolData.Data.Data,1);
if (chipData.Max==null || chipData.Min==null || chipData.Max<=0 || chipData.Min<=0) continue;
var max=parseInt(chipData.Max*100);
var min=parseInt(chipData.Min*100);
if (singleData!=null)
{
compareData=singleData;
}
else
{
if (i>=data.length) continue;
compareData=data[i];
}
var totalVol=0,vol=0;
var aryMap=new Map();
for(j=i; j>=0; --j)
{
var item=chipData.Data[j];
var start=parseInt(item.Low*100);
var end=parseInt(item.High*100);
if ((end-start+1)<=0) continue;
var iAverageVolume=item.Vol;
iAverageVolume=iAverageVolume/(end-start+1);
if (iAverageVolume<=0) continue;
for(k=start;k<=end && k<=max;++k)
{
if (aryMap.has(k))
{
vol=aryMap.get(k);
aryMap.set(k,vol+iAverageVolume);
}
else
{
aryMap.set(k,iAverageVolume);
}
}
totalVol+=item.Vol;
}
//计算获利盘
vol=0;
for(var priceData of aryMap)
{
vol+=priceData[1];
result[i]=priceData[0]/100;
if (vol/totalVol*100>compareData)
break;
}
}
return result;
}
*/
/*
获利盘比例.
用法:
WINNER(CLOSE),表示以当前收市价卖出的获利盘比例,例如返回0.1表示10%获利盘;WINNER(10.5)表示10.5元价格的获利盘比例
该函数仅对日线分析周期有效
*/
this.WINNER=function(data, node)
{
var result=[];
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
for(var i=0;i<kData.length;++i)
{
var item=kData[i];
dMinPrice = Math.min(dMinPrice,item.Low);
dMaxPrice = Math.max(dMaxPrice,item.High);
}
if (dMinPrice > 5000 || dMinPrice < 0 || dMaxPrice>5000 || dMinPrice < 0)
this.ThrowUnexpectedNode(node,'WINNER() 历史K线最大最小值错误, 超出(0,5000)范围');
var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
var lMinPrice = parseInt(dMinPrice * 100 - 1);
var lLow = 0, lHigh = 0, lClose = 0;
//去掉小数
dMaxPrice = lMaxPrice / 100.0;
dMinPrice = lMinPrice / 100.0;
var lSpeed = lMaxPrice - lMinPrice + 1;
if (lSpeed < 1) return result;
var aryVolPrice=[],aryPerVol=[];
for(var i=0;i<lSpeed;++i)
{
aryVolPrice[i]=0;
aryPerVol[i]=0;
}
var dHSL = 0, dTotalVol = 0, dVol = 0;
for(var i=0;i<kData.length;++i)
{
if (i >= aryCapital.length) continue;
if (!(aryCapital[i]>1)) continue;
var kItem=kData[i]
dHSL = kItem.Vol/aryCapital[i];
for( var j=0;j<lSpeed;j++)
aryVolPrice[j]*=(1-dHSL);
lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;
for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;
var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
if (lHalf == lHigh || lHalf == lLow)
{
aryPerVol[lHalf] += kItem.Vol;
}
else
{
var dVH = kItem.Vol / (lHalf - lLow);
for (var k = lLow; k<lHalf; ++k)
{
aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
}
for (k; k <= lHigh; ++k)
{
aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
}
}
var dTotalVol = 0;
for (var j = lLow; j <= lHigh; j++)
{
aryVolPrice[j] += aryPerVol[j];
}
for (var j = 0; j < lSpeed; j++)
{
dTotalVol += aryVolPrice[j];
}
if (Array.isArray(data))
lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
else
lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));
for (var j = 0, dVol = 0; j <= lHigh; j++)
{
dVol += aryVolPrice[j];
}
if (dTotalVol > 0) result[i]=dVol / dTotalVol;
else if (i - 1 >= 0) result[i] = result[i - 1];
}
return result;
}
/*
this.WINNER=function(data)
{
var result=[];
var exchangeID=201;
var exchangeData=this.SymbolData.GetFinanceCacheData(exchangeID); //换手率
if (!exchangeData) return result;
var isNumber=Array.isArray(data)?false:true;
var singleData=null;
if (isNumber) singleData=parseInt(parseFloat(data)*100);
var compareData=null;
for(let i=this.SymbolData.Data.Data.length-1, j=0,k=0 ; i>=0; --i)
{
result[i]=null;
var chipData=this.CalculateChip(i,exchangeData,this.SymbolData.Data.Data,1);
if (chipData.Max==null || chipData.Min==null || chipData.Max<=0 || chipData.Min<=0) continue;
var max=parseInt(chipData.Max*100);
var min=parseInt(chipData.Min*100);
if (singleData!=null)
{
compareData=singleData;
}
else
{
if (i>=data.length) continue;
compareData=parseInt(data[i]*100);
}
var totalVol=0,vol=0;
for(j=i; j>=0; --j)
{
var item=chipData.Data[j];
var start=parseInt(item.Low*100);
var end=parseInt(item.High*100);
if ((end-start+1)<=0) continue;
var iAverageVolume=item.Vol;
iAverageVolume=iAverageVolume/(end-start+1);
if (iAverageVolume<=0) continue;
var profitVol=0; //获利的成交量
if (compareData>end) profitVol=item.Vol;
else if (compareData<start) profitVol=0;
else profitVol=item.Vol*(compareData-start+1)/(end-start+1);
vol+=profitVol;
totalVol+=item.Vol;
}
if (totalVol>0) result[i]=vol/totalVol;
}
return result;
}
*/
/*
区间成本.
用法:
例如COSTEX(CLOSE,REF(CLOSE,1)),表示近两日收盘价格间筹码的成本
该函数仅对日线分析周期有效
*/
this.COSTEX=function(data, data2, node)
{
var result=[];
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
for(var i=0;i<kData.length;++i)
{
var item=kData[i];
dMinPrice = Math.min(dMinPrice,item.Low);
dMaxPrice = Math.max(dMaxPrice,item.High);
}
if (dMinPrice > 5000 || dMinPrice < 0 || dMaxPrice>5000 || dMinPrice < 0)
this.ThrowUnexpectedNode(node,'COSTEX() 历史K线最大最小值错误, 超出(0,5000)范围');
var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
var lMinPrice = parseInt(dMinPrice * 100 - 1);
var lLow = 0, lHigh = 0, lClose = 0;
//去掉小数
dMaxPrice = lMaxPrice / 100.0;
dMinPrice = lMinPrice / 100.0;
var lSpeed = lMaxPrice - lMinPrice + 1;
if (lSpeed < 1) return result;
var aryVolPrice=[],aryPerVol=[];
for(var i=0;i<lSpeed;++i)
{
aryVolPrice[i]=0;
aryPerVol[i]=0;
}
var dHSL = 0, dTotalVol = 0, dVol = 0, dVola=0, dPerVola=0, dVolb=0, dPerVolb=0;
for(var i=0, j=0;i<kData.length;++i)
{
if (i >= aryCapital.length) continue;
if (aryCapital[i]>1)
{
var kItem=kData[i]
dHSL = kItem.Vol/aryCapital[i];
for( var j=0;j<lSpeed;j++)
aryVolPrice[j]*=(1-dHSL);
lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;
for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;
var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
if (lHalf == lHigh || lHalf == lLow)
{
aryPerVol[lHalf] += kItem.Vol;
}
else
{
var dVH = kItem.Vol / (lHalf - lLow);
for (var k = lLow; k<lHalf; ++k)
{
aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
}
for (k; k <= lHigh; ++k)
{
aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
}
}
dTotalVol = 0;
for (var j = lLow; j <= lHigh; j++)
{
aryVolPrice[j] += aryPerVol[j];
}
for (var j = 0; j < lSpeed; j++)
{
dTotalVol += aryVolPrice[j];
}
if (Array.isArray(data)) lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
else lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));
for (j = 0, dVola = 0, dPerVola = 0; j <= lHigh; j++)
{
dVola += aryVolPrice[j];
dPerVola += (0.01*(j + lMinPrice))*aryVolPrice[j];
}
if (Array.isArray(data2)) lHigh = parseInt(Math.min((data2[i] * 100) - lMinPrice, lSpeed - 1));
else lHigh = parseInt(Math.min((data2 * 100) - lMinPrice, lSpeed - 1));
for (j = 0, dVolb = 0, dPerVolb = 0; j <= lHigh; j++)
{
dVolb += aryVolPrice[j];
dPerVolb += (0.01*(j + lMinPrice))*aryVolPrice[j];
}
dVol = dVola - dVolb;
dPerVolRange = dPerVola - dPerVolb;
if (Math.abs(dPerVolRange) > 0.001 && dVol!=0 ) result[i]=dPerVolRange / dVol;
else if (i-1>=0) result[i] = result[i - 1];
}
}
return result;
}
/*
远期成本分布比例.
用法:
PPART(10),表示10前的成本占总成本的比例,0.2表示20%
*/
this.PPART=function(n,node)
{
var result=[];
var startDay=n;
if (startDay<0) return result;
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
for (var i = startDay, j = 0; i < kData.length; ++i)
{
var start = i - startDay;
if (start < 0) continue;
var partVol = 0;
for (j = 0; j < startDay; ++j) //前n日成交量和
{
var kItem=kData[j + start];
partVol += kItem.Vol;
}
if (i < aryCapital.length)
{
if (aryCapital[i]>0)
{
var value=1 - (partVol / aryCapital[i]);
result[i]=value;
}
}
}
return result;
}
/*
近期获利盘比例.
用法: LWINNER(5,CLOSE),表示最近5天的那部分成本以当前收市价卖出的获利盘比例
例如: 返回0.1表示10%获利盘
*/
this.LWINNER=function(n, data, node)
{
var startDay =n;
if (startDay<=0) this.ThrowUnexpectedNode(node,'LWINNER() 第1个参数错误');
var result=[];
var kData=this.SymbolData.Data.Data;
if (!kData || kData.length<=0) return result;
var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
var dTotalVol=0,dVol=0;
for (var i = startDay-1, j=0, k=0 ; i < kData.length; ++i)
{
var index = i - startDay + 1;
var dMaxPrice=kData[index].High,dMinPrice=kData[index].Low;
for(var j=0;j<startDay;++j)
{
var item=kData[index+j];
dMinPrice = Math.min(dMinPrice,item.Low);
dMaxPrice = Math.max(dMaxPrice,item.High);
}
if (dMinPrice > 5000 || dMinPrice < 0 || dMaxPrice>5000 || dMinPrice < 0)
this.ThrowUnexpectedNode(node,'LWINNER() 历史K线最大最小值错误, 超出(0,5000)范围');
var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
var lMinPrice = parseInt(dMinPrice * 100 - 1);
var lLow = 0, lHigh = 0, lClose = 0;
dMaxPrice = lMaxPrice / 100.0;
dMinPrice = lMinPrice / 100.0;
var lSpeed = lMaxPrice - lMinPrice + 1;
if (lSpeed < 1) return result;
var aryVolPrice=[],aryPerVol=[];
for(var j=0;j<lSpeed;++j)
{
aryVolPrice[j]=0;
aryPerVol[j]=0;
}
for (j = 0; j<startDay; ++j)
{
var capital=aryCapital[index + j];
if (capital<1) continue;
var kItem=kData[index + j];
var dHSL = kItem.Vol / capital;
for (k = 0; k < lSpeed; k++)
{
aryVolPrice[k] *= (1 - dHSL);
}
lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;
for(var k=0;k<lSpeed;++k) aryPerVol[k]=0;
var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
if (lHalf == lHigh || lHalf == lLow)
{
aryPerVol[lHalf] += kItem.Vol;
}
else
{
var dVH = kItem.Vol / (lHalf - lLow);
for (let k = lLow; k<lHalf; ++k)
{
aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
}
for (let k; k <= lHigh; ++k)
{
aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
}
}
dTotalVol = 0;
for (var k = lLow; k <= lHigh; k++)
{
aryVolPrice[k] += aryPerVol[k];
}
}
for (var j = 0; j < lSpeed; j++)
{
dTotalVol += aryVolPrice[j];
}
if (Array.isArray(data))
lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
else
lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));
dVol = 0;
for (k = 0 ; k <= lHigh; k++)
{
dVol += aryVolPrice[k];
}
if (dTotalVol > 0 && dVol > 0 && dVol <= dTotalVol) result[i]=dVol / dTotalVol;
else if (i - 1 >= 0) result[i] = result[i - 1];
}
return result;
}
this.PWINNER=function(n, data, node)
{
var result=[];
return result;
}
//计算截至到某一天的历史所有筹码
this.CalculateChip=function(index,exchangeData,hisData,dRate)
{
var result={Min:null,Max:null,Data:[]};
var seed=1;//筹码历史衰减换手系数
var max=null, min=null;
for(let i=index; i>=0; --i)
{
let item={}; //Vol:量 High:最高 Low:最低
var kData=hisData[i];
if (i==index) item.Vol=kData.Vol*exchangeData[i];
else item.Vol=kData.Vol*seed;
item.Date=kData.Date;
item.High=kData.High;
item.Low=kData.Low;
if (max==null) max=item.High;
else if (max<item.High) max=item.High;
if (min==null) min=item.Low;
else if (min<item.Low) min=item.Low;
result.Data[i]=item;
seed*=(1-(exchangeData[i]/100)*dRate); //换手率累乘
}
result.Max=max;
result.Min=min;
return result;
}
/*
返回是否连涨周期数.
用法:
UPNDAY(CLOSE,M)
表示连涨M个周期,M为常量
*/
this.UPNDAY=function(data,n)
{
var result=[];
if (n<1) return result;
if (data==null || n>data.length) return result;
var days=0;
for(let i=0;i<data.length;++i)
{
result[i]=0;
if (i-1<0) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data[i-1])) //无效数都不算连涨
{
days=0;
continue;
}
if (data[i]>data[i-1]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
return result;
}
/*
返回是否连跌周期.
用法:
DOWNNDAY(CLOSE,M)
表示连跌M个周期,M为常量
*/
this.DOWNNDAY=function(data,n)
{
var result=[];
if (n<1) return result;
if (data==null || n>data.length) return result;
var days=0;
for(let i=0;i<data.length;++i)
{
result[i]=0;
if (i-1<0) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data[i-1])) //无效数都不算连涨
{
days=0;
continue;
}
if (data[i]<data[i-1]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
return result;
}
/*
返回是否持续存在X>Y
用法:
NDAY(CLOSE,OPEN,3)
表示连续3日收阳线
*/
this.NDAY=function(data,data2,n)
{
var result=[];
if (n<1) return result;
if (!Array.isArray(data) && !Array.isArray(data2)) return result;
if (data==null || data2==null ) return result;
if (Array.isArray(data) && Array.isArray(data2))
{
if (n>=data.length || n>=data2.length) return result;
var count=Math.max(data.length,data2.length);
var days=0;
for(let i=0;i<count;++i)
{
result[i]=0;
if (i>=data.length || i>=data2.length) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i]))
{
days=0;
continue;
}
if (data[i]>data2[i]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
else if (Array.isArray(data) && !Array.isArray(data2))
{
if (n>=data.length || !this.IsNumber(data2)) return;
var days=0;
for(let i in data)
{
result[i]=0;
if (!this.IsNumber(data[i]))
{
days=0;
continue;
}
if (data[i]>data2) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
else if (!Array.isArray(data) && Array.isArray(data2))
{
if (n>=data2.length || !this.IsNumber(data)) return;
var days=0;
for(let i in data2)
{
result[i]=0;
if (!this.IsNumber(data2[i]))
{
days=0;
continue;
}
if (data>data2[i]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
return result;
}
/*
两条线维持一定周期后交叉.
用法:LONGCROSS(A,B,N)表示A在N周期内都小于B,本周期从下方向上穿过B时返回1,否则返回0
*/
this.LONGCROSS=function(data,data2,n)
{
var result=[];
var count=Math.max(data.length,data2.length);
for(let i=0;i<count;++i)
{
result[i]=0;
if (i-1<0) continue;
if (i>=data.length || i>=data2.length) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i]) || !this.IsNumber(data[i-1]) || !this.IsNumber(data2[i-1])) continue;
if (data[i]>data2[i] && data[i-1]<data2[i-1]) result[i]=1;
}
for(let i=0,j=0;i<count;++i)
{
if (!result[i]) continue;
for(j=1;j<=n && i-j>=0;++j)
{
if (data[i-j]>=data2[i-j])
{
result[i]=0;
break;
}
}
}
return result;
}
this.ISVALID=function(data)
{
if (Array.isArray(data))
{
var result=[];
for(var i=0;i<data.length;++i)
{
var item=data[i];
if (item) result[i]=1;
else result[i]=0;
}
return result;
}
else
{
if (data) return 1;
else return 0;
}
}
/*
EXISTR(X,A,B):是否存在(前几日到前几日间).
例如: EXISTR(CLOSE>OPEN,10,5)
表示从前10日内到前5日内存在着阳线
若A为0,表示从第一天开始,B为0,表示到最后日止
*/
this.EXISTR=function(data,n,n2)
{
var result=[];
if (!Array.isArray(data)) return result;
n=parseInt(n);
n2=parseInt(n2);
if (n<=0) n=data.length;
if (n2<=0) n2=1;
if (n2>n) return result;
var result=[];
var value;
for(let i=0,j=0;i<data.length;++i)
{
result[i]=null;
if (i-n<0 || i-n2<0) continue;
result[i]=0;
for(j=n;j>=n2;--j)
{
var value=data[i-j];
if (this.IsNumber(value) && value)
{
result[i]=1;
break;
}
}
}
return result;
}
/*
RELATE(X,Y,N) 返回X和Y的N周期的相关系数
RELATE(X,Y,N)=(∑[(Xi-Avg(X))(Yi-Avg(y))])/N ÷ √((∑(Xi-Avg(X))^2)/N * (∑(Yi-Avg(Y))^2)/N)
其中 avg(x)表示x的N周期均值: avg(X) = (∑Xi)/N
√(...)表示开平方
*/
this.RELATE=function(data,data2,n)
{
var result=[];
if (n<1) n=1;
if (!Array.isArray(data)|| !Array.isArray(data2)) return result;
var dataAverage=this.CalculateAverage(data,n);
var data2Average=this.CalculateAverage(data2,n);
var count=Math.max(data.length,data2.length);
for(let i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=data.length || i>=data2.length || i>=dataAverage.length || i>=data2Average.length) continue;
var average=dataAverage[i];
var average2=data2Average[i];
var total=0,total2=0,total3=0;
for(j=i-n+1;j<=i;++j)
{
total+=(data[j]-average)*(data2[j]-average2); //∑[(Xi-Avg(X))(Yi-Avg(y))])
total2+=Math.pow(data[j]-average,2); //∑(Xi-Avg(X))^2
total3+=Math.pow(data2[j]-average2,2); //∑(Yi-Avg(Y))^2)
}
result[i]=(total/n)/(Math.sqrt(total2/n)*Math.sqrt(total3/n));
}
return result;
}
//计算数组n周期内的均值
this.CalculateAverage=function(data,n)
{
var result=[];
if (n<1) return result;
var total=0;
for(var i=0;i<data.length;++i) //去掉开始的无效数
{
if (this.IsNumber(data[i])) break;
}
for(;i<data.length && i<n;++i) //计算第1个周期的数据
{
result[i]=null;
var value=data[i];
if (!this.IsNumber(value)) continue;
total+=value;
}
result[i-1]=total/n;
for(;i<data.length;++i) //计算后面的周期数据
{
var value=data[i];
var preValue=data[i-n]; //上一个周期的第1个数据
if (!this.IsNumber(value)) value=0;
if (!this.IsNumber(preValue)) preValue=0;
total=total-preValue+value; //当前周期的数据 等于上一个周期数据 去掉上一个周期的第1个数据 加上这个周期的最后1个数据
result[i]=total/n;
}
return result;
}
/*
COVAR(X,Y,N) 返回X和Y的N周期的协方差
*/
this.COVAR=function(data,data2,n)
{
if (this.IsNumber(data) || this.IsNumber(data2)) return 0;
var result=[];
if (n<1) n=1;
if (!Array.isArray(data)|| !Array.isArray(data2)) return result;
var dataAverage=this.CalculateAverage(data,n);
var data2Average=this.CalculateAverage(data2,n);
var count=Math.max(data.length,data2.length);
var count=Math.max(data.length,data2.length);
for(let i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=data.length || i>=data2.length || i>=dataAverage.length || i>=data2Average.length) continue;
var average=dataAverage[i];
var average2=data2Average[i];
var total=0;
for(j=i-n+1;j<=i;++j)
{
total+=(data[j]-average)*(data2[j]-average2);
}
result[i]=(total/n);
}
return result;
}
/*
求上一高点到当前的周期数.
用法:
HHVBARS(X,N):求N周期内X最高值到当前周期数,N=0表示从第一个有效值开始统计
例如:
HHVBARS(HIGH,0)求得历史新高到到当前的周期数
*/
this.HHVBARS=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
if (Array.isArray(n))
{
for(var i=0;i<n.length;++i)
{
result[i]=null;
var period=n[i];
if (!this.IsNumber(period)) continue;
var start=i-period;
if (start<0) start=0;
var nMax=null;
var j=start;
for(; j<data.length;++j)
{
if (this.IsNumber(data[j]))
{
nMax=j;
break;
}
}
for(var k=0; j<data.length && k<period;++k, ++j)
{
if (data[j]>=data[nMax]) nMax=j;
}
if (nMax!=null)
result[i]=(i-nMax);
}
}
else
{
if (n<1) n=data.length;
var nMax=null; //最大值索引
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i]))
{
nMax=i;
break;
}
}
var j=0;
for(i=nMax+1;i<data.length && j<n ;++i,++j) //求第1个最大值
{
if (data[i]>=data[nMax]) nMax=i;
if(n==data.length) result[i]=(i-nMax);
}
for(;i<data.length;++i)
{
if (i-nMax<n)
{
if (data[i]>=data[nMax]) nMax=i;
}
else
{
nMax=i-n+1;
for(j=nMax;j<=i;++j) //计算区间最大值
{
if (data[j]>=data[nMax]) nMax=j;
}
}
result[i]=i-nMax;
}
}
return result;
}
/*
求上一低点到当前的周期数.
用法: LLVBARS(X,N):求N周期内X最低值到当前周期数,N=0表示从第一个有效值开始统计
例如: LLVBARS(HIGH,20)求得20日最低点到当前的周期数
*/
this.LLVBARS=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
if (Array.isArray(n))
{
for(var i=0;i<n.length;++i)
{
result[i]=null;
var period=n[i];
if (!this.IsNumber(period)) continue;
var start=i-period;
if (start<0) start=0;
var nMin=null;
var j=start;
for(; j<data.length;++j)
{
if (this.IsNumber(data[j]))
{
nMin=j;
break;
}
}
for(var k=0; j<data.length && k<period;++k, ++j)
{
if (data[j]<=data[nMin]) nMin=j;
}
if (nMin!=null)
result[i]=(i-nMin);
}
}
else
{
if (n<1) n=data.length;
var nMin=null; //最小值索引
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i]))
{
nMin=i;
break;
}
}
var j=0;
for(i=nMin+1;i<data.length && j<n ;++i,++j) //求第1个最大值
{
if (data[i]<=data[nMin]) nMin=i;
if(n==data.length) result[i]=(i-nMin);
}
for(;i<data.length;++i)
{
if (i-nMin<n)
{
if (data[i]<=data[nMin]) nMin=i;
}
else
{
nMin=i-n+1;
for(j=nMin;j<=i;++j) //计算区间最小值
{
if (data[j]<=data[nMin]) nMin=j;
}
}
result[i]=i-nMin;
}
}
return result;
}
/*
β(Beta)系数
BETA(N) 返回当前证券N周期收益与对应大盘指数收益相比的贝塔系数
需要下载上证指数历史数据
涨幅(X)=(现价-上一个交易日收盘价)/上一个交易日收盘价
公式=股票和指数协方差/指数方差
*/
this.BETA=function(n)
{
var result=[];
var stockData= this.SymbolData.Data;
var indexData=this.SymbolData.IndexData;
if (n<=0) n=1;
var stockProfit=[]; //股票涨幅
var indexProfit=[]; //指数涨幅
for(let i=0;i<stockData.Data.length;++i)
{
stockProfit[i]=0;
indexProfit[i]=0;
var stockItem=stockData.Data[i];
var indexItem=indexData.Data[i];
if (stockItem.Close>0 && stockItem.YClose>0) stockProfit[i]=(stockItem.Close-stockItem.YClose)/stockItem.YClose;
if (indexItem.Close>0 && indexItem.YClose>0) indexProfit[i]=(indexItem.Close-indexItem.YClose)/indexItem.YClose;
}
//计算均值数组
var averageStockProfit=this.CalculateAverage(stockProfit,n);
var averageIndexProfit=this.CalculateAverage(indexProfit,n);
for(var i=0,j=0;i<stockData.Data.length;++i)
{
result[i]=null;
if (i>=stockProfit.length || i>=indexProfit.length || i>=averageStockProfit.length || i>=averageIndexProfit.length) continue;
var averageStock=averageStockProfit[i];
var averageIndex=averageIndexProfit[i];
var covariance=0; //协方差
var variance=0; //方差
for(j=i-n+1;j<=i;++j)
{
var value=(indexProfit[j]-averageIndex);
var value2=(stockProfit[j]-averageStock);
covariance+=value*value2;
variance+=value*value;
}
if (this.IsDivideNumber(variance) && this.IsNumber(covariance))
result[i]=covariance/variance; //(covariance/n)/(variance/n)=covariance/variance;
}
return result;
}
/*
用法:BETA2(X,Y,N)为X与Y的N周期相关放大系数,表示Y变化1%,则X将变化N%
例如:BETA2(CLOSE,INDEXC,10)表示收盘价与大盘指数之间的10周期相关放大率
*/
this.BETA2=function(x,y,n)
{
var result=[];
if (n<=0) n=1;
var xProfit=[null]; //x数据的涨幅
var yProfit=[null]; //y数据的涨幅
var count=Math.max(x.length,y.length);
var lastItem={X:x[0], Y:y[0]};
for(var i=1;i<count;++i)
{
xProfit[i]=0;
yProfit[i]=0;
var xItem=x[i];
var yItem=y[i];
if (lastItem.X>0) xProfit[i]=(xItem-lastItem.X)/lastItem.X;
if (lastItem.Y>0) yProfit[i]=(yItem-lastItem.Y)/lastItem.Y;
lastItem={X:xItem, Y:yItem};
}
//计算均值数组
var averageXProfit=this.CalculateAverage(xProfit,n);
var averageYProfit=this.CalculateAverage(yProfit,n);
for(var i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=xProfit.length || i>=yProfit.length || i>=averageXProfit.length || i>=averageYProfit.length) continue;
var averageX=averageXProfit[i];
var averageY=averageYProfit[i];
var covariance=0; //协方差
var variance=0; //方差
for(j=i-n+1;j<=i;++j)
{
var value=(xProfit[j]-averageX);
var value2=(yProfit[j]-averageY);
covariance+=value*value2;
variance+=value*value;
}
if (this.IsDivideNumber(variance) && this.IsNumber(covariance))
result[i]=covariance/variance; //(covariance/n)/(variance/n)=covariance/variance;
}
return result;
}
/*
抛物转向.
用法:
SAR(N,S,M),N为计算周期,S为步长,M为极值
例如:
SAR(10,2,20)表示计算10日抛物转向,步长为2%,极限值为20%
*/
this.SAR=function(n,step,exValue)
{
var result=[];
var stockData= this.SymbolData.Data;
if (n>=stockData.Data.length) return result;
var high=null,low=null;
for(var i=0;i<n;++i)
{
var item=stockData.Data[i];
if (high==null) high=item.High;
else if (high<item.High) high=item.High;
if (low==null) low=item.Low;
else if (low>item.Low) low=item.Low;
}
const SAR_LONG=0, SAR_SHORT=1;
var position=SAR_LONG;
result[n-1]=low;
var nextSar=low, sip=stockData.Data[0].High,af=step/100;
for(var i=n;i<stockData.Data.length;++i)
{
var ysip=sip;
var item=stockData.Data[i];
var yitem=stockData.Data[i-1];
if (position==SAR_LONG)
{
if (item.Low<result[i-1])
{
position=SAR_SHORT;
sip=item.Low;
af=step/100;
nextSar =Math.max(item.High,yitem.High);
nextSar =Math.max(nextSar,ysip+af*(sip-ysip));
}
else
{
position = SAR_LONG;
if(item.High>ysip)
{
sip=item.High;
af=Math.min(af+step/100,exValue/100);
}
nextSar=Math.min(item.Low,yitem.Low);
nextSar=Math.min(nextSar,result[i-1]+af*(sip-result[i-1]));
}
}
else if (position==SAR_SHORT)
{
if(item.High>result[i-1])
{
position=SAR_LONG;
sip=item.High;
af=step/100;
nextSar =Math.min(item.Low,yitem.Low);
nextSar =Math.min(nextSar,result[i-1]+af*(sip-ysip));
}
else
{
position = SAR_SHORT;
if(item.Low<ysip)
{
sip=item.Low;
af=Math.min(af+step/100,exValue/100);
}
nextSar=Math.max(item.High,yitem.High);
nextSar=Math.max(nextSar,result[i-1]+af*(sip-result[i-1]));
}
}
result[i]=nextSar;
}
return result;
}
/*
抛物转向点.
用法:
SARTURN(N,S,M),N为计算周期,S为步长,M为极值,若发生向上转向则返回1,若发生向下转向则返回-1,否则为0
其用法与SAR函数相同
*/
this.SARTURN=function(n,step,exValue)
{
var result=[];
var sar=this.SAR(n,step,exValue);
var stockData= this.SymbolData.Data;
var index=0;
for(index=0;index<sar.length;++index)
{
if (this.IsNumber(sar[index])) break;
}
var flag=0;
if (index<stockData.Data.length) flag=stockData.Data[index].Close>sar[index];
for(var i=index+1;i<stockData.Data.length;++i)
{
var item=stockData.Data[i];
if (item.Close<sar[i] && flag) result[i]=-1;
else result[i]= (item.Close>sar[i] && !flag)? 1:0;
flag=item.Close>sar[i];
}
return result;
}
/*
属于未来函数,将当前位置到若干周期前的数据设为1.
用法:
BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1.
例如:
BACKSET(CLOSE>OPEN,2)若收阳则将该周期及前一周期数值设为1,否则为0
*/
this.BACKSET=function(condition,n)
{
var result=[];
if (!condition) return result;
var dataCount=condition.length;
if (!this.IsNumber(dataCount) || dataCount<=0) return result;
if (Array.isArray(n))
{
for(var i=0;i<dataCount;++i) //初始化0
{
result[i]=0;
}
for(var i=0;i<dataCount;++i)
{
var value=condition[i];
var period=n[i];
if (this.IsNumber(value) && value && this.IsNumber(period))
{
for(var j=i,k=0; j>=0 && k<period; --j,++k)
{
result[j]=1;
}
}
}
}
else
{
for(var i=0;i<dataCount;++i) //初始化0
{
result[i]=0;
}
for(var pos=0;pos<dataCount;++pos)
{
if (this.IsNumber(condition[pos])) break;
}
if (pos==dataCount) return result;
var num=Math.min(dataCount-pos,Math.max(n,1));
for(var i=dataCount-1,j=0;i>=0;--i)
{
var value=condition[i];
if (this.IsNumber(value) && value)
{
for(j=i;j>i-num;--j)
{
result[j]=1;
}
}
}
if (condition[i])
{
for(j=i;j>=pos;--j) result[j]=1;
}
}
return result;
}
//用法:BETWEEN(A,B,C)表示A处于B和C之间时返回1,否则返回0
//例如:BETWEEN(CLOSE,MA(CLOSE,20),MA(CLOSE,10))表示收盘价介于10日均线和20日均线之间
this.BETWEEN=function(condition, data, data2)
{
var result=[];
var isNumber=typeof(condition)=='number';
var isNumber2=typeof(data)=='number';
var isNumber3=typeof(data2)=='number';
if (isNumber && isNumber2 && isNumber3) //单数值
{
return (condition>=data && condition<=data2) ? 1 : 0;
}
for(var i in condition)
{
result[i]=0;
var item=condition[i];
var left=null, right=null;
if (isNumber2) left=data;
else if (i<data.length-1) left=data[i];
if (isNumber3) right=data2;
else if (i<data2.length-1) right=data2[i];
if (left==null || right==null) continue;
if (left>right)
{
if (item>=right && item<=left)
result[i]=1;
}
else
{
if (item<=right && item>=left)
result[i]=1;
}
}
return result;
}
//STRCAT(A,B):将两个字符串A,B(非序列化)相加成一个字符串C.
//用法: STRCAT('多头','开仓')将两个字符串'多头','开仓'相加成一个字符串'多头开仓'
this.STRCAT=function(str1, str2)
{
var result=[];
if (IFrameSplitOperator.IsString(str1) && IFrameSplitOperator.IsString(str2))
result=str1+str2;
return result;
}
//VARCAT(A,B):将两个字符串A,B相加成一个字符串C.
//用法: DRAWTEXT(CLOSE>OPEN,LOW,VARCAT('多头',VAR2STR(C,2))) 将两个字符串相加成一个字符串并按条件显示出来
this.VARCAT=function(data,data2)
{
var result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
var nCount=Math.max(data.length, data2.length);
var strValue="";
for(var i=0;i<nCount;++i)
{
result[i]=null;
strValue="";
if (i<data.length)
{
var item=data[i];
if (IFrameSplitOperator.IsString(item))
strValue+=item;
}
if (i<data2.length)
{
var item=data2[i];
if (IFrameSplitOperator.IsString(item))
strValue+=item;
}
if (strValue!="")
result[i]=strValue;
}
}
else if (IFrameSplitOperator.IsString(data) && Array.isArray(data2))
{
for(var i=0;i<data2.length;++i)
{
result[i]=null;
var item=data2[i];
if (IFrameSplitOperator.IsString(item))
{
result[i]=data+item;
}
}
}
else if (Array.isArray(data) && IFrameSplitOperator.IsString(data2))
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var item=data[i];
if (IFrameSplitOperator.IsString(item))
{
result[i]=item+data2;
}
}
}
else if (IFrameSplitOperator.IsString(data) && IFrameSplitOperator.IsString(data2))
{
result=data+data2;
}
return result;
}
//FINDSTR(A,B):在字符串A中查找字符串B,如果找到返回1,否则返回0.
//用法: FINDSTR('多头开仓','开仓')在字符串'多头开仓'中查找字符串'开仓',返回1
this.FINDSTR=function(data, data2)
{
var result=[];
var str, str2;
if (IFrameSplitOperator.IsNumber(data)) str=data.toString();
else str=data;
if (IFrameSplitOperator.IsNumber(data2)) str2=data2.toString();
else str2=data2;
if (IFrameSplitOperator.IsString(str) && IFrameSplitOperator.IsString(str2))
{
if (str.indexOf(str2)>=0) return 1;
else return 0;
}
else if (Array.isArray(data) && IFrameSplitOperator.IsString(str2))
{
for(var i=0;i<data.length;++i)
{
var item=data[i];
if (IFrameSplitOperator.IsString(item))
{
result[i]=item.indexOf(str2)>=0?1:0;
}
else if (IFrameSplitOperator.IsNumber(item))
{
str=item.toString();
result[i]=str.indexOf(str2)>=0?1:0;
}
else
{
result[i]=0;
}
}
}
return result;
}
this.STRLEN=function(data)
{
if (IFrameSplitOperator.IsString(data)) return data.length;
if (Array.isArray(data))
{
var result=[];
for(var i=0;i<data.length;++i)
{
var item=data[i];
if (IFrameSplitOperator.IsString(item)) result[i]=item.length;
else result[i]=null;
}
return result;
}
return null;
}
this.STRCMP=function(data, data2)
{
if (IFrameSplitOperator.IsString(data) && IFrameSplitOperator.IsString(data2))
{
return data==data2? 1:0;
}
return null;
}
//STRSPACE(A):字符串附带一空格
this.STRSPACE=function(data)
{
var result=[];
if (Array.isArray(data))
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var item=data[i];
if (IFrameSplitOperator.IsString(item))
result[i]=item+' ';
}
}
else
{
if (IFrameSplitOperator.IsString(data))
result=data+" ";
}
return result;
}
//CON2STR(A,N):取A最后的值(非序列值)转为字符串,小数位数N.
//用法: CON2STR(FINANCE(20),3)表示取营业收入,以3位小数转为字符串
this.CON2STR=function(data,n)
{
var result=[];
if (Array.isArray(data))
{
for(var i=data.length-1 ; i>=0; --i)
{
var item=data[i];
if (this.IsNumber(item))
{
result=item.toFixed(n);
return result;
}
}
}
else
{
if (this.IsNumber(data))
result=data.toFixed(n);
}
return result;
}
//VAR2STR(A,N):取A的每一个值转为字符串,小数位数N.
//用法: VAR2STR(C,3)表示取收盘价,以3位小数转为字符串
this.VAR2STR=function(data,n)
{
var result=[];
if (Array.isArray(data))
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var item=data[i];
if (this.IsNumber(item))
result[i]=item.toFixed(n);
}
}
else
{
if (this.IsNumber(data))
result=data.toFixed(n);
}
return result;
}
this.MOD=function(data, data2)
{
var result=[];
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值
if (isNumber && isNumber2)
{
return JSAlgorithm.MOD(data,data2);
}
else if (!isNumber && !isNumber2) //都是数组相加
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=JSAlgorithm.MOD(data[i],data2[i]);
}
}
return result;
}
else if (isNumber && !isNumber2) //单数字 数组
{
for(var i in data2)
{
result[i]=null;
if (this.IsNumber(data) && this.IsNumber(data2[i])) result[i]=JSAlgorithm.MOD(data,data2[i]);
}
return result;
}
else if (!isNumber && isNumber2) //数组 单数字
{
for(var i in data)
{
result[i]=null;
if (this.IsNumber(data[i]) && this.IsNumber(data2)) result[i]=JSAlgorithm.MOD(data[i],data2);
}
return result;
}
return result;
}
this.POW=function(data, n)
{
var result=[];
if (Array.isArray(data) && Array.isArray(n))
{
for(var i=0;i<data.length;++i)
{
var value=data[i];
var value2=n[i];
if (this.IsNumber(value) && this.IsNumber(value2)) result[i]=Math.pow(value,value2);
else result[i]=null;
}
}
else if (IFrameSplitOperator.IsNumber(data) && Array.isArray(n))
{
for(var i=0;i<n.length;++i)
{
var item=n[i];
if (this.IsNumber(item)) result[i]=Math.pow(data,item);
else result[i]=null;
}
}
else if (IFrameSplitOperator.IsNumber(data) && IFrameSplitOperator.IsNumber(n))
{
return Math.pow(data,n);
}
else if (Array.isArray(data) && IFrameSplitOperator.IsNumber(n))
{
for(var i=0; i<data.length;++i)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=Math.pow(item,n);
else result[i]=null;
}
}
return result;
}
this.CEILING=function(data)
{
let isNumber=typeof(data)=='number';
if (isNumber) return parseInt(data);
var result=[];
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=parseInt(item);
else result[i]=null;
}
return result;
}
this.FLOOR=function(data)
{
let isNumber=typeof(data)=='number';
if (isNumber) return parseInt((data-1));
var result=[];
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=parseInt((item-1));
else result[i]=null;
}
return result;
}
this.ZTPRICE=function(data, rate)
{
if (!this.IsNumber(rate)) return null;
if (Array.isArray(data))
{
var result=[];
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=(1+rate)*item;
else result[i]=null;
}
return result;
}
else if (this.IsNumber(data))
{
var result=(1+rate)*data;
return result;
}
}
this.DTPRICE=function(data, rate)
{
if (!this.IsNumber(rate)) return null;
if (Array.isArray(data))
{
var result=[];
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=(1-rate)*item;
else result[i]=null;
}
return result;
}
else if (this.IsNumber(data))
{
var result=(1-rate)*data;
return result;
}
}
/*
FRACPART(A) 取得小数部分
含义:FRACPART(A)返回数值的小数部分
阐释:例如FRACPART(12.3)求得0.3,FRACPART(-3.5)求得-0.5
*/
this.FRACPART=function(data)
{
if (Array.isArray(data))
{
var result=[];
var integer=0;
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item))
{
integer=parseInt(item);
result[i]=item-integer;
}
else result[i]=null;
}
return result;
}
else if (this.IsNumber(data))
{
integer=parseInt(data);
var result=data-integer;
return result;
}
}
/*
取符号.
用法:
SIGN(X),返回X的符号.当X>0,X=0,X<0分别返回1,0,-1
*/
this.SIGN=function(data)
{
if (Array.isArray(data))
{
var result=[];
for(var i=0;i<data.length;++i)
{
var item=data[i];
result[i]=null;
if (!IFrameSplitOperator.IsNumber(item)) continue;
if (item>0) result[i]=1;
else if (item==0) result[i]=0;
else result[i]=-1;
}
return result;
}
else
{
if (data>0) return 1;
else if (data==0) return 0;
else return -1;
}
}
/*
统计连续满足条件的周期数.
用法: BARSLASTCOUNT(X),统计连续满足X条件的周期数.
例如: BARSLASTCOUNT(CLOSE>OPEN)表示统计连续收阳的周期数
*/
this.BARSLASTCOUNT=function(data)
{
var result=null;
if (Array.isArray(data))
{
result=[];
if (data.length>0)
{
var count=0;
for(var i=data.length-1;i>=0;--i)
{
count=0;
for(var j=i;j>=0;--j)
{
if (data[j]) ++count;
else break;
}
result[i]=count;
}
}
}
else
{
if (data) result=1;
else result=0;
}
return result;
}
//取整.
//用法: INTPART(A)返回沿A绝对值减小方向最接近的整数
//例如:INTPART(12.3)求得12,INTPART(-3.5)求得-3
this.INTPART=function(data)
{
var result=null;
if (Array.isArray(data))
{
result=[];
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=parseInt(item);
else result[i]=null;
}
}
else if (this.IsNumber(data))
{
result=parseInt(data);
}
return result;
}
//用法:CONST(A),取A最后的值为常量.
//例如:CONST(INDEXC),表示取大盘现价
this.CONST=function(data)
{
if (Array.isArray(data))
{
var count=data.length;
if (count>0)
return data[count-1];
return null;
}
else
{
return data;
}
}
//当前值是近多少周期内的最大值.
//用法: TOPRANGE(X):X是近多少周期内X的最大值
//例如: TOPRANGE(HIGH)表示当前最高价是近多少周期内最高价的最大值
this.TOPRANGE=function(data)
{
if (this.IsNumber(data)) return 0;
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1; i>=0;--i)
{
result[i]=0;
var item=data[i];
if (!this.IsNumber(item)) continue;
var value=0;
for(var j=i-1;j>=0;--j)
{
if (data[j]>item)
{
break;
}
++value;
}
result[i]=value;
}
}
return result;
}
//当前值是近多少周期内的最小值.
//用法:LOWRANGE(X):X是近多少周期内X的最小值
//例如:LOWRANGE(LOW)表示当前最低价是近多少周期内最低价的最小值
this.LOWRANGE=function(data)
{
if (this.IsNumber(data)) return 0;
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1; i>=0;--i)
{
result[i]=0;
var item=data[i];
if (!this.IsNumber(item)) continue;
var value=0;
for(var j=i-1;j>=0;--j)
{
if (data[j]<item)
{
break;
}
++value;
}
result[i]=value;
}
}
return result;
}
//N周期前的M周期内的第T个最小值.
//用法:FINDLOW(VAR,N,M,T):VAR在N日前的M天内第T个最低价
this.FINDLOW=function(data,n,m,t)
{
if (this.IsNumber(data)) return data;
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
result[i]=null;
var aryValue=[];
for(var j=n;j<m;++j)
{
var index=i-j;
if (index<0) break;
var item=data[index];
if (this.IsNumber(item)) aryValue.push(item);
}
if (aryValue.length>0)
{
aryValue.sort(function(a,b) { return a-b;});
var index=t-1;
if (index<0) index=0;
else if (index>=aryValue.length) index=aryValue.length-1;
result[i]=aryValue[index];
}
}
}
return result;
}
//N周期前的M周期内的第T个最大值.
//用法:FINDHIGH(VAR,N,M,T):VAR在N日前的M天内第T个最高价
this.FINDHIGH=function(data,n,m,t)
{
if (this.IsNumber(data)) return data;
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
result[i]=null;
var aryValue=[];
for(var j=n;j<m;++j)
{
var index=i-j;
if (index<0) break;
var item=data[index];
if (this.IsNumber(item)) aryValue.push(item);
}
if (aryValue.length>0)
{
aryValue.sort(function(a,b) { return b-a;});
var index=t-1;
if (index<0) index=0;
else if (index>=aryValue.length) index=aryValue.length-1;
result[i]=aryValue[index];
}
}
}
return result;
}
//N周期前的M周期内的第T个最大值到当前周期的周期数.
//用法:FINDHIGHBARS(VAR,N,M,T):VAR在N日前的M天内第T个最高价到当前周期的周期数
this.FINDHIGHBARS=function(data, n, m, t)
{
if (this.IsNumber(data)) return (m-n-t);
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
result[i]=null;
var aryValue=[];
for(var j=n;j<m;++j)
{
var index=i-j;
if (index<0) break;
var item=data[index];
if (this.IsNumber(item)) aryValue.push({ Value:item, Period:j });
}
if (aryValue.length>0)
{
aryValue.sort(function(a,b) { return b.Value-a.Value;});
var index=t-1;
if (index<0) index=0;
else if (index>=aryValue.length) index=aryValue.length-1;
result[i]=aryValue[index].Period;
}
}
}
return result;
}
//N周期前的M周期内的第T个最小值到当前周期的周期数.
//用法:FINDLOWBARS(VAR,N,M,T):VAR在N日前的M天内第T个最低价到当前周期的周期数.
this.FINDLOWBARS=function(data, n, m, t)
{
if (this.IsNumber(data)) return (m-n-t);
var result=[];
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
result[i]=null;
var aryValue=[];
for(var j=n;j<m;++j)
{
var index=i-j;
if (index<0) break;
var item=data[index];
if (this.IsNumber(item)) aryValue.push({ Value:item, Period:j });
}
if (aryValue.length>0)
{
aryValue.sort(function(a,b) { return a.Value-b.Value;});
var index=t-1;
if (index<0) index=0;
else if (index>=aryValue.length) index=aryValue.length-1;
result[i]=aryValue[index].Period;
}
}
}
return result;
}
//求高值名次.
//用法:HOD(X,N):求当前X数据是N周期内的第几个高值,N=0则从第一个有效值开始.
//例如:HOD(HIGH,20)返回是20日的第几个高价
this.HOD=function(data, n)
{
var result=[];
if (IFrameSplitOperator.IsNumber(data)) return 1;
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
var value=data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (Array.isArray(n)) var subCount=parseInt(n[i]);
else var subCount=parseInt(n);
if (n<=0) subCount=i;
var index=1;
for(var j=i-1, k=1; j>=0 && k<subCount; --j, ++k)
{
var item=data[j];
if (IFrameSplitOperator.IsNumber(item) && item>value) ++index;
}
result[i]=index;
}
}
return result;
}
//求低值名次.
//用法:LOD(X,N):求当前X数据是N周期内的第几个低值,N=0则从第一个有效值开始.
//例如:LOD(LOW,20)返回是20日的第几个低价
this.LOD=function(data, n)
{
var result=[];
if (IFrameSplitOperator.IsNumber(data)) return 1;
if (Array.isArray(data))
{
var count=data.length;
for(var i=count-1;i>=0;--i)
{
var value=data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (Array.isArray(n)) var subCount=parseInt(n[i]);
else var subCount=parseInt(n);
if (n<=0) subCount=i;
var index=1;
for(var j=i-1, k=1; j>=0 && k<subCount; --j, ++k)
{
var item=data[j];
if (IFrameSplitOperator.IsNumber(item) && item<value) ++index;
}
result[i]=index;
}
}
return result;
}
//属于未来函数,下一次条件成立到当前的周期数.
//用法:BARSNEXT(X):下一次X不为0到现在的天数
//例如:BARSNEXT(CLOSE/REF(CLOSE,1)>=1.1)表示下一个涨停板到当前的周期数
this.BARSNEXT=function(data)
{
if (!Array.isArray(data)) return 0;
var result=[];
for(var i=0;i<data.length;++i)
{
result[i]=0;
for(var j=i, k=0;j<data.length;++j, ++k)
{
var item=data[j];
if (item>0)
{
result[i]=k;
break;
}
}
}
return result;
}
//取随机数.
//用法:RAND(N),返回一个范围在1-N的随机整数
this.RAND=function(n)
{
if (Array.isArray(n))
{
var result=[];
for(var i in n)
{
result[i]=null;
var item=n[i];
var value=parseInt(item);
if (value<=0) continue;
result[i]=Math.ceil(Math.random()*value);
}
return result;
}
else
{
var value=parseInt(n);
if (value<=0) return null;
var stockData= this.SymbolData.Data;
var count=stockData.Data.length;
var result=[];
for(var i=0;i<count;++i)
{
result[i]=Math.ceil(Math.random()*value);
}
return result;
}
}
//求自适应均线值.
//用法:AMA(X,A),A为自适应系数,必须小于1.
//算法:Y=Y'+A*(X-Y').初值为X
this.AMA=function(data,n)
{
var result=[];
var period;
if (Array.isArray(n))
{
//取最新的一个数据做为自适应系数
for(var i=data.length-1;i>=0;--i)
{
if (this.IsNumber(n[i]))
{
period=n[i];
break;
}
}
}
else
{
period=n;
}
if (this.IsNumber(period))
{
if (period>1) return result;
var index=0;
var value=0;
for(index;index<data.length;++index)
{
result[index]=null;
if (this.IsNumber(data[index]))
{
value=data[index];
result[index]=value;
break;
}
}
for(var i=index+1;i<data.length;++i)
{
var item=data[i];
result[i]=result[i-1]+period*(item-result[i-1]);
}
}
return result;
}
//返回移动平均
//用法:TMA(X,A,B),A和B必须小于1,算法 Y=(A*Y'+B*X),其中Y'表示上一周期Y值.初值为X
this.TMA=function(data, a, b)
{
var result=[];
if (this.IsNumber(a) && a<=1 && this.IsNumber(b) && b<1)
{
var bFirstFind=false;
var proValue; //上一个值
for(var i in data)
{
result[i]=null;
if (bFirstFind==false)
{
var item=data[i];
if (this.IsNumber(item))
{
result[i]=item;
proValue=result[i];
bFirstFind=true;
}
}
else
{
var item=data[i];
if (!this.IsNumber(item)) continue;
result[i]=a*result[i-1]+b*item;
proValue=result[i];
}
}
}
return result;
}
this.ROUND=function(data)
{
if (this.IsNumber(data))
{
return Math.round(data);
}
var result=[];
if (Array.isArray(data))
{
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item))
result[i]=Math.round(item);
else
result[i]=null;
}
}
return result;
}
this.ROUND2=function(data,n)
{
var ROUND2_SEED=
[
1,10,100,1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000
];
var decimal=0;
if (this.IsNumber(n)) decimal=parseInt(n);
if (n<0) decimal=0;
else if (n>=ROUND2_SEED.length) decimal=ROUND2_SEED.length-1;
if (this.IsNumber(data))
{
return Math.round(data*ROUND2_SEED[decimal])/ROUND2_SEED[decimal];
}
var result=[];
if (Array.isArray(data))
{
for(var i in data)
{
var item=data[i];
if (this.IsNumber(item))
{
result[i]=Math.round(item*ROUND2_SEED[decimal])/ROUND2_SEED[decimal];
}
else
{
result[i]=null;
}
}
}
return result;
}
/* 文华
TRMA(X,N): 求X在N个周期的三角移动平均值。
算法:三角移动平均线公式,是采用算数移动平均,并且对第一个移动平均线再一次应用算数移动平均。
TRMA(X,N) 算法如下
ma_half= MA(X,N/2)
trma=MA(ma_half,N/2)
注:
1、N包含当前k线。
2、当N为有效值,但当前的k线数不足N根,函数返回空值。
3、N为0或空值的情况下,函数返回空值。
例1:
TRMA5:TRMA(CLOSE,5);//计算5个周期内收盘价的三角移动平均。(N不能被2整除)
//TRMA(CLOSE,5)=MA(MA(CLOSE,(5+1)/2)),(5+1)/2);
例2:
TRMA10:TRMA(CLOSE,10);// 计算10个周期内收盘价的三角移动平均。(N能被2整除)
TRMA(CLOSE,10)=MA(MA(CLOSE,10/2),(10/2)+1));
*/
this.TRMA=function(data,n)
{
if (!this.IsNumber(n) || n<=0) return [];
n=parseInt(n);
var nFalf=0,nFalf2=0;
if (n%2==0)
{
nFalf=parseInt(n/2);
nFalf2=nFalf+1;
}
else
{
nFalf=parseInt((n+1)/2);
nFalf2=nFalf;
}
var maFalf=this.MA(data,nFalf);
var result=this.MA(maFalf,nFalf2);
return result;
}
//VALUEWHEN(COND,X)
//当COND条件成立时,取X的当前值,否则取VALUEWHEN的上个值.
this.VALUEWHEN=function(cond,data)
{
if (Array.isArray(cond))
{
var result=[];
if (Array.isArray(data))
{
var preValue=null;
for(var i in cond)
{
if (i>=data.length)
{
result[i]=preValue;
continue;
}
var item=data[i];
if (cond[i])
{
result[i]=item;
preValue=item;
}
else
{
result[i]=preValue;
}
}
}
else
{
var preValue=null;
for(var i in cond)
{
if (cond[i])
{
result[i]=data;
preValue=data;
}
else
{
result[i]=preValue;
}
}
}
return result;
}
else
{
return cond? 1:0;
}
}
/*
HARMEAN(X,N) 求X在N个周期内的调和平均值。
算法举例:HARMEAN(X,5)=1/[(1/X1+1/X2+1/X3+1/X4+1/X5)/5]
注:
1、N包含当前k线。
2、调和平均值与倒数的简单平均值互为倒数。
3、当N为有效值,但当前的k线数不足N根,函数返回空值。
4、N为0或空值的情况下,函数返回空值。
5、X为0或空值的情况下,函数返回空值。
6、N可以为变量。
例:HM5:=HARMEAN(C,5);//求5周期收盘价的调和平均值。
*/
this.HARMEAN=function(data, n)
{
var result=[];
if (Array.isArray(data))
{
if (Array.isArray(n))
{
for(var i=0;i<data.length;++i)
{
if (i>=n.length)
{
result[i]=null;
continue;
}
var count=parseInt(n[i]);
if (count<=0 || count>i)
{
result[i]=null;
continue;
}
var sum=0;
for(var j=0;j<count;++j)
{
var item=data[i-j];
if (!this.IsNumber(item) || item==0)
{
sum=null;
break;
}
sum+=1/item;
}
if (sum==null)
{
result[i]=null;
}
else
{
result[i]=1/(sum/count);
}
}
}
else if (this.IsNumber(n))
{
n=parseInt(n);
if (n<=0) return result;
for(var i=0;i<data.length;++i)
{
if (n>i)
{
result[i]=null;
continue;
}
var sum=0;
for(var j=0;j<n;++j)
{
var item=data[i-j];
if (!this.IsNumber(item) || item==0)
{
sum=null;
break;
}
sum+=1/item;
}
if (sum==null)
{
result[i]=null;
}
else
{
result[i]=1/(sum/n);
}
}
}
}
return result;
}
//指定日期到1990.12.19的天数.
//用法: DATETODAY(date)
//DATETODAY(date).返回date到1990.12.19的天数.有效日期为(901219-1341231)
//例如: DATETODAY(901219)返回0.
this.DATETODAY=function(data)
{
var result=[];
var startDate=new Date('1990-12-19')
var startValue=19901219;
var ONE_DAY=1000 * 60 * 60 * 24
if (Array.isArray(data))
{
for(var i in data)
{
result[i]=null;
var item=data[i];
if (!this.IsNumber(item)) continue;
var value=item+19000000;
if (value<startValue) continue;
var year=parseInt(value/10000);
var month=parseInt((value%10000)/100);
var day=parseInt(value%100);
var dateItem=new Date(`${year}-${month}-${day}`);
result[i]=Math.round((dateItem-startDate)/ONE_DAY);
}
}
else if (this.IsNumber(data))
{
var value=data+19000000;
if (value>=startValue)
{
var year=parseInt(value/10000);
var month=parseInt((value%10000)/100);
var day=parseInt(value%100);
var dateItem=new Date(`${year}-${month}-${day}`);
return Math.round((dateItem-dateItem)/ONE_DAY);
}
}
return result;
}
//求1990.12.19后第若干天的日期.
//用法:DAYTODATE(N)
//DAYTODATE(N).返回1990.12.19后第N天的日期.有效天数为(0-20000)
//例如:DAYTODATE(0)返回901219.
this.DAYTODATE=function(data)
{
var startDate=new Date('1990-12-19')
var result=[];
if (Array.isArray(data))
{
for(var i in data)
{
result[i]=null;
var item=data[i];
if (!this.IsNumber(item)) continue;
startDate.setDate(startDate.getDate()+item);
var value=startDate.getFullYear()*10000+(startDate.getMonth()+1)*100+startDate.getDate();
value-=19000000;
result[i]=value;
startDate.setDate(startDate.getDate()-item);
}
}
else if (this.IsNumber(data))
{
startDate.setDate(startDate.getDate()+data);
var value=startDate.getFullYear()*10000+(startDate.getMonth()+1)*100+startDate.getDate();
value-=19000000;
return value;
}
return result;
}
/*
求指定时刻距0时有多长时间.
用法:
TIMETOSEC(time)
TIMETOSEC(time).返回time时刻距0时有多长时间,单位为秒.有效时间为(0-235959)
例如:
TIMETOSEC(93000)返回34200.
*/
this.TIMETOSEC=function(time)
{
var hour=parseInt(time/10000);
var minute=parseInt((time%10000)/100);
var sec=time%100;
var value=hour*60*60+minute*60+sec;
return value;
}
/*
求0时后若干秒是什么时间.
用法:
SECTOTIME(N)
SECTOTIME(N).返回0时后N秒是什么时间.有效秒数为(0-86399)
例如:
SECTOTIME(34200)返回93000.
*/
this.SECTOTIME=function(data)
{
var daySec = 24 * 60 * 60;
var hourSec= 60 * 60;
var minuteSec=60;
var dd = Math.floor(data / daySec);
var hh = Math.floor((data % daySec) / hourSec);
var mm = Math.floor((data % hourSec) / minuteSec);
var ss=data%minuteSec;
var value=hh*10000+mm*100+ss;
return value;
}
//用法:ANY(CLOSE>OPEN,10),表示前10日内存在着阳线
this.ANY=function(data, n)
{
if (n<=0) n=1;
var result=[];
if (Array.isArray(data))
{
if (n>=data.length) return 0;
for(var i=n, j=0;i<data.length;++i)
{
var value=0;
for(j=0;j<n;++j)
{
var item=data[i-j];
if (item>0)
{
value=1;
break;
}
}
result[i]=value;
}
return result;
}
else if (IFrameSplitOperator.IsNumber(data))
{
if (data<=0) return 0;
if (n>=this.SymbolData.Data.Data.length) return 0;
for(var i=n; i<this.SymbolData.Data.Data.length; ++i)
{
result[i]=1;
}
return result;
}
else
{
return 0;
}
}
//用法:ALL(CLOSE>OPEN,10),表示前10日内一直阳线
this.ALL=function(data, n)
{
if (n<=0) n=1;
var result=[];
if (Array.isArray(data))
{
if (n>=data.length) return 0;
for(var i=n, j=0;i<data.length;++i)
{
var value=1;
for(j=0;j<n;++j)
{
var item=data[i-j];
if (!(item>0))
{
value=0;
break;
}
}
result[i]=value;
}
return result;
}
else if (IFrameSplitOperator.IsNumber(data))
{
if (data<=0) return 0;
if (n>=this.SymbolData.Data.Data.length) return 0;
for(var i=n; i<this.SymbolData.Data.Data.length; ++i)
{
result[i]=1;
}
return result;
}
else
{
return 0;
}
}
/*
TESTSKIP(A):满足A则直接返回.
用法:
TESTSKIP(A)
表示如果满足条件A则该公式直接返回,不再计算接下来的表达式 注意:A为非序列数据,只取最后一个数据
*/
this.TESTSKIP=function(data, node)
{
if (Array.isArray(data))
{
if (data.length<=0) return false;
var item=data[data.length-1];
if (!item) return false;
return true;
}
else if (IFrameSplitOperator.IsNumber(data))
{
if (data<=0) return false;
return true;
}
else
{
if (!data) return false;
return true;
}
}
/*根据条件执行不同的语句,可中止(根据序列的最后一个数值来判断).
用法:
IFC(X,A,B)若X不为0则执行A,否则执行B.IFC与IF函数的区别:根据X的值来选择性执行A、B表达式.
例如:
IFC(CLOSE>OPEN,HIGH,TESTSKIP(1));L;表示当日收阳则返回最高值,并执行下一句"L;",否则退出公式计算
*/
this.IFC=function(data)
{
if (Array.isArray(data))
{
var item=data[data.length-1];
if (IFrameSplitOperator.IsNumber(item)) return item>0;
return false;
}
else if (IFrameSplitOperator.IsNumber(data))
{
return data>0;
}
else
{
return false;
}
}
/*
有效数据右对齐.
用法:
ALIGNRIGHT(X)有效数据向右移动,左边空出来的周期填充无效值
例如:TC:=IF(CURRBARSCOUNT=2 || CURRBARSCOUNT=5,DRAWNULL,C);XC:ALIGNRIGHT(TC);删除了两天的收盘价,并将剩余数据右移
*/
this.ALIGNRIGHT=function(data)
{
if (Array.isArray(data))
{
var result=[];
var index=data.length-1;
for(var i=data.length-1;i>=0;--i)
{
var item=data[i];
if (IFrameSplitOperator.IsNumber(item) || IFrameSplitOperator.IsString(item))
{
result[index]=item;
--index;
}
}
for(var i=index;i>=0;--i)
{
result[i]=null;
}
return result;
}
else
{
return data;
}
}
/*
向前累加到指定值到现在的周期数.
用法:
SUMBARS(X,A):将X向前累加直到大于等于A,返回这个区间的周期数,若所有的数据都累加后还不能达到A,则返回此时前面的总周期数.
例如:SUMBARS(VOL,CAPITAL)求完全换手到现在的周期数
*/
this.SUMBARS=function(data, data2)
{
var isArray=Array.isArray(data);
var isArray2=Array.isArray(data2);
var isNumber=IFrameSplitOperator.IsNumber(data);
var isNumber2=IFrameSplitOperator.IsNumber(data2);
var result=[];
if (isArray && isNumber2)
{
for(var i=0, n=0;i<data.length;++i)
{
var sum=0;
var n=0;
for(var j=i-1; j>=0; --j, ++n)
{
var item=data[i];
if (!IFrameSplitOperator.IsNumber(item)) continue;
sum+=data[j];
if (sum>data2)
{
break;
}
}
result[i]=n;
}
}
else if (isArray && isArray2)
{
var count=Math.max(data.length, data2.length);
for(var i=0;i<count;++i)
{
result[i]=null;
var sum=0;
var n=0;
var value=data2[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
for(var j=i-1; j>=0; --j,++n)
{
var item=data[i];
if (!IFrameSplitOperator.IsNumber(item)) continue;
sum+=data[j];
if (sum>value)
{
break;
}
}
result[i]=n;
}
}
else if (isNumber && isArray2)
{
for(var i=0;i<data2.length;++i)
{
result[i]=null;
var sum=0;
var n=0;
var value=data2[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
for(var j=i-1; j>=0; --j, ++n)
{
sum+=data;
if (sum>value)
{
break;
}
}
result[i]=n;
}
}
else if (isNumber && isNumber2)
{
//TODO: 后面再写吧
}
return result;
}
//格式化字符串 "{0}-{1}", C, O; 小数位数 {0:0.00}
this.STRFORMAT=function(strFormat,args,node)
{
var aryParam=strFormat.match(/{[0-9.:]+}/g);
if (!IFrameSplitOperator.IsNonEmptyArray(aryParam)) return null;
var mapParam=new Map(); //key=index, value={Text}
var maxIndex=-1;
for(var i=0;i<aryParam.length;++i)
{
var item=aryParam[i];
if (item.length<3) continue;
var value=item.slice(1, item.length-1);
var index=-1,decimal=-1;
if (value.indexOf(":")>0)
{
var aryTemp=value.split(":");
if (aryTemp)
{
if (aryTemp[0])
index=parseInt(aryTemp[0]);
if (aryTemp[1])
{
if (aryTemp[1].indexOf(".")>=0)
{
var zeroCount=0;
var strTemp=aryTemp[1];
for(var j=strTemp.length-1; j>=0; --j)
{
if (strTemp[j]=="0") ++zeroCount;
else break;
}
if (zeroCount>0) decimal=zeroCount;
}
else if (aryTemp[1]=="0")
{
decimal=0;
}
}
}
}
else
{
index=parseInt(value);
}
if (index<0) continue;
var paramItem={ Src:item, Index:index, Text:null, Decimal:null };
if (decimal>=0) paramItem.Decimal=decimal;
if (maxIndex<index) maxIndex=index;
mapParam.set(index, paramItem);
}
var isArray=false; //是否输出数组字符串
var maxCount=0;
for(var i=1;i<args.length;++i)
{
var item=args[i];
if (Array.isArray(item))
{
isArray=true;
if (maxCount<item.length) maxCount=item.length;
}
}
if (isArray)
{
var result=[];
for(var i=0;i<maxCount;++i)
{
var strItem=strFormat;
for(var item of mapParam)
{
var paramInfo=item[1];
var paramItem=args[paramInfo.Index+1];
var text="null";
if (paramItem)
{
if (Array.isArray(paramItem))
{
var value=paramItem[i];
if (value)
{
if (IFrameSplitOperator.IsNumber(paramInfo.Decimal))
text=`${value.toFixed(paramInfo.Decimal)}`;
else
text=`${value}`;
}
}
else
{
text=`${paramItem}`;
}
}
strItem=strItem.replace(paramInfo.Src, text);
}
result[i]=strItem;
}
return result;
}
else
{
var result=strFormat;
for(var item of mapParam)
{
var paramInfo=item[1];
var paramItem=args[paramInfo.Index+1];
var text="null";
if (paramItem)
{
text=`${paramItem}`;
}
result=result.replace(paramInfo.Src, text);
}
return result;
}
}
//函数调用
this.CallFunction=function(name,args,node,symbolData)
{
switch(name)
{
case 'MAX':
case "MAX6":
return this.MAX(args,node);
case 'MIN':
case "MIN6":
return this.MIN(args,node);
case 'REF':
return this.REF(args[0], args[1]);
case "REFV":
return this.REFV(args[0], args[1]);
case 'REFX':
return this.REFX(args[0], args[1]);
case "REFXV":
return this.REFXV(args[0], args[1]);
case "REFX1": //文华函数
return this.REFX(args[0], args[1]);
case 'ABS':
return this.ABS(args[0]);
case 'MA':
return this.MA(args[0], args[1]);
case "EMA":
return this.EMA(args[0], args[1]);
case "SMA":
return this.SMA(args[0], args[1],args[2]);
case "DMA":
return this.DMA(args[0], args[1]);
case "XMA":
return this.XMA(args[0], args[1]);
case 'EXPMA':
return this.EXPMA(args[0], args[1]);
case 'EXPMEMA':
return this.EXPMEMA(args[0], args[1]);
case 'COUNT':
return this.COUNT(args[0], args[1]);
case 'LLV':
return this.LLV(args[0], args[1]);
case "LV":
return this.LV(args[0], args[1]);
case 'LLVBARS':
return this.LLVBARS(args[0], args[1]);
case 'HHV':
return this.HHV(args[0], args[1]);
case 'HV':
return this.HV(args[0], args[1]);
case 'HHVBARS':
return this.HHVBARS(args[0], args[1]);
case 'MULAR':
return this.MULAR(args[0], args[1]);
case 'CROSS':
return this.CROSS(args[0], args[1]);
case 'LONGCROSS':
return this.LONGCROSS(args[0], args[1], args[2]);
case "ISVALID":
return this.ISVALID(args[0]);
case "CROSSDOWN":
return this.CROSSDOWN(args[0], args[1]);
case "CROSSUP":
return this.CROSSUP(args[0], args[1]);
case 'AVEDEV':
return this.AVEDEV(args[0], args[1]);
case 'STD':
return this.STD(args[0], args[1]);
case "STDDEV":
return this.STDDEV(args[0], args[1]);
case 'IF':
case 'IFF':
case "IFELSE":
return this.IF(args[0], args[1], args[2]);
case 'IFN':
return this.IFN(args[0], args[1], args[2]);
case 'NOT':
return this.NOT(args[0]);
case 'SUM':
return this.SUM(args[0], args[1]);
case 'RANGE':
return this.RANGE(args[0],args[1],args[2]);
case 'EXIST':
return this.EXIST(args[0],args[1]);
case 'EXISTR':
return this.EXISTR(args[0],args[1],args[2]);
case 'FILTER':
return this.FILTER(args[0],args[1]);
case 'TFILTER':
return this.TFILTER(args[0],args[1],args[2]);
case "FILTERX":
return this.FILTERX(args[0],args[1],node);
case 'SLOPE':
return this.SLOPE(args[0],args[1]);
case 'BARSLAST':
return this.BARSLAST(args[0]);
case "BARSLASTS":
//this.ThrowUnexpectedNode(node,`函数'BARSLASTS'还在开发中`, name);
return this.BARSLASTS(args[0],args[1],node);
case 'BARSCOUNT':
return this.BARSCOUNT(args[0]);
case 'BARSSINCEN':
return this.BARSSINCEN(args[0],args[1]);
case 'BARSSINCE':
return this.BARSSINCE(args[0]);
case 'LAST':
return this.LAST(args[0],args[1],args[2]);
case 'EVERY':
return this.EVERY(args[0],args[1]);
case 'DEVSQ':
return this.DEVSQ(args[0], args[1]);
case 'ZIG':
return this.ZIG(args[0],args[1]);
case 'TROUGHBARS':
return this.TROUGHBARS(args[0],args[1],args[2]);
case "TROUGH":
return this.TROUGH(args[0],args[1],args[2]);
case 'PEAKBARS':
return this.PEAKBARS(args[0],args[1],args[2]);
case 'PEAK':
return this.PEAK(args[0],args[1],args[2]);
case 'COST':
return this.COST(args[0]);
case 'WINNER':
return this.WINNER(args[0],node);
case 'PPART':
return this.PPART(args[0],node);
case "COSTEX":
return this.COSTEX(args[0],args[1],node);
case "LWINNER":
return this.LWINNER(args[0],args[1],node);
case "PWINNER":
return this.PWINNER(args[0],args[1],node);
case 'FORCAST':
return this.FORCAST(args[0], args[1]);
case "TSMA":
return this.TSMA(args[0], args[1]);
case 'STDP':
return this.STDP(args[0], args[1]);
case 'VAR':
return this.VAR(args[0], args[1]);
case 'VARP':
return this.VARP(args[0], args[1]);
case 'UPNDAY':
return this.UPNDAY(args[0],args[1]);
case 'DOWNNDAY':
return this.DOWNNDAY(args[0],args[1]);
case 'NDAY':
return this.NDAY(args[0],args[1],args[2]);
case 'RELATE':
return this.RELATE(args[0],args[1],args[2]);
case 'COVAR':
return this.COVAR(args[0],args[1],args[2]);
case 'BETA':
return this.BETA(args[0]);
case 'BETA2':
return this.BETA2(args[0],args[1],args[2]);
case 'WMA':
return this.WMA(args[0], args[1]);
case 'MEMA':
return this.MEMA(args[0], args[1]);
case 'SUMBARS':
return this.SUMBARS(args[0], args[1]);
case 'REVERSE':
return this.REVERSE(args[0]);
case 'SAR':
return this.SAR(args[0], args[1], args[2]);
case 'SARTURN':
return this.SARTURN(args[0], args[1], args[2]);
case 'BACKSET':
return this.BACKSET(args[0], args[1]);
case 'BETWEEN':
return this.BETWEEN(args[0], args[1], args[2]);
case 'STRCAT':
return this.STRCAT(args[0], args[1]);
case 'CON2STR':
return this.CON2STR(args[0], args[1]);
case "VAR2STR":
return this.VAR2STR(args[0], args[1]);
case "VARCAT":
return this.VARCAT(args[0], args[1]);
case "STRSPACE":
return this.STRSPACE(args[0]);
case "FINDSTR":
return this.FINDSTR(args[0], args[1]);
case "STRCMP":
return this.STRCMP(args[0], args[1]);
case "STRLEN":
return this.STRLEN(args[0]);
case "STRFORMAT":
return this.STRFORMAT(args[0], args, node);
case 'DTPRICE':
return this.DTPRICE(args[0], args[1]);
case 'ZTPRICE':
return this.ZTPRICE(args[0], args[1]);
case 'MOD':
return this.MOD(args[0],args[1]);
case 'POW':
return this.POW(args[0],args[1]);
case 'CEILING':
return this.CEILING(args[0]);
case 'FLOOR':
return this.FLOOR(args[0]);
case 'FRACPART':
return this.FRACPART(args[0]);
case "SIGN":
return this.SIGN(args[0]);
case 'BARSLASTCOUNT':
return this.BARSLASTCOUNT(args[0]);
case 'INTPART':
return this.INTPART(args[0]);
case "CONST":
return this.CONST(args[0]);
case "TOPRANGE":
return this.TOPRANGE(args[0]);
case "LOWRANGE":
return this.LOWRANGE(args[0]);
case "FINDLOW":
return this.FINDLOW(args[0],args[1],args[2],args[3]);
case "FINDLOWBARS":
return this.FINDLOWBARS(args[0],args[1],args[2],args[3]);
case "FINDHIGH":
return this.FINDHIGH(args[0],args[1],args[2],args[3]);
case "FINDHIGHBARS":
return this.FINDHIGHBARS(args[0],args[1],args[2],args[3]);
case "BARSNEXT":
return this.BARSNEXT(args[0]);
case "HOD":
return this.HOD(args[0], args[1]);
case "LOD":
return this.LOD(args[0], args[1]);
case "AMA":
return this.AMA(args[0], args[1]);
case "TMA":
return this.TMA(args[0],args[1],args[2]);
case "ROUND":
return this.ROUND(args[0]);
case "ROUND2":
return this.ROUND2(args[0],args[1]);
case "TRMA":
return this.TRMA(args[0],args[1]);
case "VALUEWHEN":
return this.VALUEWHEN(args[0],args[1]);
case "HARMEAN":
return this.HARMEAN(args[0],args[1]);
case "DATETODAY":
return this.DATETODAY(args[0]);
case "DAYTODATE":
return this.DAYTODATE(args[0]);
case "TIMETOSEC":
return this.TIMETOSEC(args[0]);
case "SECTOTIME":
return this.SECTOTIME(args[0]);
case "ANY":
return this.ANY(args[0],args[1]);
case "ALL":
return this.ALL(args[0],args[1]);
case "TESTSKIP":
return this.TESTSKIP(args[0],node);
case "SUMBARS":
return this.SUMBARS(args[0],args[1]);
case "ALIGNRIGHT":
return this.ALIGNRIGHT(args[0]);
//三角函数
case 'ATAN':
return this.Trigonometric(args[0],Math.atan);
case 'ACOS':
return this.ACOS(args[0]);
case 'ASIN':
return this.ASIN(args[0]);
case 'COS':
return this.Trigonometric(args[0],Math.cos);
case 'SIN':
return this.Trigonometric(args[0],Math.sin);
case 'TAN':
return this.Trigonometric(args[0],Math.tan);
case 'LN':
return this.Trigonometric(args[0],Math.log);
case 'LOG':
return this.Trigonometric(args[0],Math.log10);
case 'EXP':
return this.Trigonometric(args[0],Math.exp);
case 'SQRT':
return this.Trigonometric(args[0],Math.sqrt);
case "RAND":
return this.RAND(args[0]);
default:
this.ThrowUnexpectedNode(node,'函数'+name+'不存在', name);
}
}
//调用自定义函数 返回数据格式{Out:输出数据, Draw:绘图数据(可选)}
this.CallCustomFunction=function(name, args, symbolData, node)
{
var functionInfo=g_JSComplierResource.CustomFunction.Data.get(name);
var dwonloadData=symbolData.GetStockCacheData({ CustomName:name, Node:node });
if (!functionInfo.Invoke)
return { Out: dwonloadData }
JSConsole.Complier.Log('[JSAlgorithm::CallCustomFunction] call custom function functionInfo=',functionInfo);
var self=this;
var obj=
{
Name:name,
Args:args,
Symbol:symbolData.Symbol, Period:symbolData.Period, Right:symbolData.Right,
KData:symbolData.Data, //K线数据
DownloadData:dwonloadData,
ThrowError:function(error)
{
self.ThrowUnexpectedNode(node, error);
}
};
return functionInfo.Invoke(obj);
}
this.ThrowUnexpectedNode=function(node,message,word)
{
let marker=node.Marker;
let msg=message || "执行异常";
return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg,word);
}
}
//是否有是有效的数字
JSAlgorithm.prototype.IsNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return true;
}
//是否有是有效的除数
JSAlgorithm.prototype.IsDivideNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
if (value==0) return false;
return true;
}
//取模
JSAlgorithm.MOD=function(number,divisor)
{
if( (number < 0 && divisor < 0) || (number >=0 && divisor >= 0)) //同号
{
if(parseInt(number) == number && parseInt(divisor) == divisor) //全为整数
{
return number%divisor;
}
else //被除数-(整商×除数)之后在第一位小数位进行四舍五入
{
var value = parseFloat((number - (Math.floor(number/divisor) * divisor)).toFixed(1));
return value;
}
}
else //异号
{
var absNumber = Math.abs(number); //绝对值
var absDivisor = Math.abs(divisor); //绝对值
var value = Math.abs(Math.abs(divisor) * (Math.floor(absNumber/absDivisor) + 1) - Math.abs(number));
if(divisor < 0) value = -value
return value;
}
}
/*
绘图函数
*/
function JSDraw(errorHandler,symbolData)
{
this.ErrorHandler=errorHandler;
this.SymbolData=symbolData;
this.DRAWTEXT=function(condition,price,text)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWTEXT',Text:text};
if (Array.isArray(condition))
{
if (condition.length<=0) return result;
var IsNumber=this.IsNumber(price);
var isFixedPosition=false;
if (price==="TOP"|| price==="BOTTOM")
{
result.FixedPosition=price;
isFixedPosition=true;
}
for(var i in condition)
{
drawData[i]=null;
if (isNaN(condition[i]) || !condition[i]) continue;
if (IsNumber || isFixedPosition)
{
drawData[i]=price;
}
else
{
if (this.IsNumber(price[i])) drawData[i]=price[i];
}
}
}
else if (this.IsNumber(condition) && condition)
{
var IsNumber=this.IsNumber(price);
var isFixedPosition=false;
if (price==="TOP"|| price==="BOTTOM")
{
result.FixedPosition=price;
isFixedPosition=true;
}
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
if (IsNumber || isFixedPosition)
{
drawData[i]=price;
}
else
{
if (this.IsNumber(price[i])) drawData[i]=price[i];
}
}
}
return result;
}
this.DRAWTEXT_FIX=function(condition,x,y,type,text)
{
var drawData={ Value:[], Text:[] };
var result={DrawData:drawData, DrawType:'DRAWTEXT_FIX', Text:null, Position:{ X:x, Y:y, Type:type } };
if (condition.length<=0) return result;
if (Array.isArray(condition))
{
for(var i in condition)
{
drawData.Text[i]=null;
drawData.Value[i]=0;
if (isNaN(condition[i]) || !condition[i]) continue;
drawData.Value[i]=1;
drawData.Text[i]=text;
}
}
else
{
if(condition)
{
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData.Text[i]=text;
drawData.Value[i]=1;
}
}
}
return result;
}
//direction 文字Y轴位置 0=middle 1=价格的顶部 2=价格的底部
//offset 文字Y轴偏移
this.SUPERDRAWTEXT=function(condition,price,text,direction,offset)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'SUPERDRAWTEXT',Text:text,YOffset:offset,Direction:direction,TextAlign:'center'};
if (condition.length<=0) return result;
var IsNumber=typeof(price)=="number";
for(var i in condition)
{
drawData[i]=null;
if (isNaN(condition[i]) || !condition[i]) continue;
if (IsNumber)
{
drawData[i]=price;
}
else
{
if (this.IsNumber(price[i])) drawData[i]=price[i];
}
}
return result;
}
/*
STICKLINE 绘制柱线
在图形上绘制柱线。
用法: STICKLINE(COND,PRICE1,PRICE2,WIDTH,EMPTY),当COND条件满足时,在PRICE1和PRICE2位置之间画柱状线,宽度为WIDTH(10为标准间距),EMPTH不为0则画空心柱。
例如: STICKLINE(CLOSE>OPEN,CLOSE,OPEN,0.8,1)表示画K线中阳线的空心柱体部分。
*/
this.STICKLINE=function(condition,data,data2,width,type)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'STICKLINE',Width:width, Type:type};
if (result.Width<0) result.Width=3; //<0的宽度 使用K线宽度
var IsNumber=typeof(data)=="number";
var IsNumber2=typeof(data2)=="number";
if (Array.isArray(condition)) //数组
{
if(condition.length<=0) return result;
for(var i in condition)
{
drawData[i]=null;
if (isNaN(condition[i]) || !condition[i]) continue;
if (IsNumber && IsNumber2)
{
drawData[i]={Value:data,Value2:data2};
}
else if (IsNumber && !IsNumber2)
{
if (isNaN(data2[i])) continue;
drawData[i]={Value:data,Value2:data2[i]};
}
else if (!IsNumber && IsNumber2)
{
if (isNaN(data[i])) continue;
drawData[i]={Value:data[i],Value2:data2};
}
else
{
if (isNaN(data[i]) || isNaN(data2[i])) continue;
drawData[i]={Value:data[i],Value2:data2[i]};
}
}
}
else //单值
{
if(!condition) return result;
for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
{
drawData[i]=null;
if (IsNumber && IsNumber2)
{
drawData[i]={Value:data,Value2:data2};
}
else if (IsNumber && !IsNumber2)
{
if (!IFrameSplitOperator.IsNumber(data2[i])) continue;
drawData[i]={Value:data,Value2:data2[i]};
}
else if (!IsNumber && IsNumber2)
{
if (!IFrameSplitOperator.IsNumber(data[i])) continue;
drawData[i]={Value:data[i],Value2:data2};
}
else
{
if (!IFrameSplitOperator.IsNumber(data[i]) || !IFrameSplitOperator.IsNumber(data2[i])) continue;
drawData[i]={Value:data[i],Value2:data2[i]};
}
}
}
return result;
}
/*
DRAWLINE 绘制直线段
在图形上绘制直线段。
用法: DRAWLINE(COND1,PRICE1,COND2,PRICE2,EXPAND)
当COND1条件满足时,在PRICE1位置画直线起点,当COND2条件满足时,在PRICE2位置画直线终点,EXPAND为延长类型。
例如: DRAWLINE(HIGH>=HHV(HIGH,20),HIGH,LOW<=LLV(LOW,20),LOW,1) 表示在创20天新高与创20天新低之间画直线并且向右延长。
*/
this.DRAWLINE=function(condition,data,condition2,data2,expand)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWLINE', Expand:expand};
if(condition.length<=0) return result;
let count=Math.max(condition.length,condition2.length);
let bFirstPoint=false;
let bSecondPont=false;
let lineCache={Start:{ },End:{ }, List:new Array()};
for(let i=0;i<count;++i)
{
drawData[i]=null;
if (i<condition.length && i<condition2.length)
{
if (bFirstPoint==false && bSecondPont==false)
{
if (condition[i]==null || !condition[i]) continue;
bFirstPoint=true;
lineCache.Start={ID:i, Value:data[i]}; //第1个点
}
else if (bFirstPoint==true && bSecondPont==false)
{
var bCondition2=(condition2[i]!=null && condition2[i]); //条件2
if (!bCondition2)
{
if (condition[i] ) //条件1满足
lineCache.Start={ID:i, Value:data[i]}; //移动第1个点
continue;
}
if (bCondition2)
{
bSecondPont=true;
lineCache.End={ID:i, Value:data2[i]}; //第2个点
}
}
else if (bFirstPoint==true && bSecondPont==true)
{
var bCondition2=(condition2[i]!=null && condition2[i]); //条件2
if (bCondition2) //条件2满足
{
lineCache.End={ID:i, Value:data2[i]}; //移动第2个点
}
else if (condition[i]) //条件1满足
{
let lineData=this.CalculateDrawLine(lineCache); //计算2个点的线上 其他点的数值
for(let j in lineData)
{
let item=lineData[j];
drawData[item.ID]=item.Value;
}
if (expand==1) this.CalculateDrawDataExtendLine(drawData, lineCache.Start.ID-2);//右延长线
bFirstPoint=bSecondPont=false;
lineCache={Start:{ },End:{ }};
bFirstPoint=true;
bSecondPont=false;
lineCache.Start={ID:i, Value:data[i]}; //第1个点
}
}
}
//最后一组线
if (bFirstPoint==true && bSecondPont==true)
{
let lineData=this.CalculateDrawLine(lineCache);
for(let j in lineData)
{
let item=lineData[j];
drawData[item.ID]=item.Value;
}
}
}
if (expand==1) this.CalculateDrawDataExtendLine(drawData);//右延长线
return result;
}
/*
画出带状线.
用法: DRAWBAND(VAL1,COLOR1,VAL2,COLOR2),当VAL1>VAL2时,在VAL1和VAL2之间填充COLOR1;当VAL1<VAL2时,填充COLOR2,这里的颜色均使用RGB函数计算得到.
例如: DRAWBAND(OPEN,RGB(0,224,224),CLOSE,RGB(255,96,96));
*/
this.DRAWBAND=function(data,color,data2,color2)
{
if (IFrameSplitOperator.IsNumber(color)) color=`rgb(${color},0,0)`;
if (IFrameSplitOperator.IsNumber(color2)) color2=`rgb(${color2},0,0)`;
var drawData=[];
var result={DrawData:drawData, DrawType:'DRAWBAND', Color:[null, null]}; //颜色使用小写字符串
if (color) result.Color[0]=color.toLowerCase();
if (color2) result.Color[1]=color2.toLowerCase();
var isNumber=IFrameSplitOperator.IsNumber(data);
var isNumber2=IFrameSplitOperator.IsNumber(data2);
if (!isNumber && !isNumber2)
{
var count=Math.max(data.length, data2.length);
for(var i=0;i<count;++i)
{
var item={Value:null, Value2:null};
if (i<data.length) item.Value=data[i];
if (i<data2.length) item.Value2=data2[i];
drawData.push(item);
}
}
else if (isNumber && !isNumber2)
{
var count=data2.length;
for(var i=0;i<count;++i)
{
var item={Value:data, Value2:null};
if (i<data2.length) item.Value2=data2[i];
drawData.push(item);
}
}
else if (!isNumber && isNumber2)
{
var count=data.length;
for(var i=0;i<count;++i)
{
var item={Value:null, Value2:data2};
if (i<data.length) item.Value=data[i];
drawData.push(item);
}
}
else if (isNumber && isNumber2)
{
var count=this.SymbolData.Data.Data.length;
for(var i=0;i<count;++i)
{
var item={Value:data, Value2:data2};
drawData.push(item);
}
}
return result;
}
this.GetDataByIndex=function(data, index)
{
var result={Result:false , Data:null };
if (this.IsNumber(data))
{
result.Result=true;
result.Data=data;
}
else
{
if (index<data.length)
{
result.Result=true;
result.Data=data[index];
}
else
{
result.Result=false;
}
}
return result;
}
/*
FILLRGN(MA1>MA2, MA1,MA2),colorred
表示MA1>MA2时以红色填充MA1和MA2之间的区域
*/
this.FILLRGN=function(condition, data,data2)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'FILLRGN'};
var isNumber=this.IsNumber(data);
var isNumber2=this.IsNumber(data2);
if (Array.isArray(condition)) //数组
{
for(var i in condition)
{
drawData[i]=null;
var condItem=condition[i];
if (!condItem) continue;
var value=this.GetDataByIndex(data, i);
if (!value.Result) continue;
var value2=this.GetDataByIndex(data2, i);
if (!value2.Result) continue;
var item={ Value:value.Data, Value2:value2.Data };
drawData[i]=item;
}
}
else
{
if (condition)
{
for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
{
drawData[i]=null;
var value=this.GetDataByIndex(data, i);
if (!value.Result) continue;
var value2=this.GetDataByIndex(data2, i);
if (!value2.Result) continue;
var item={ Value:value.Data, Value2:value2.Data };
drawData[i]=item;
}
}
}
return result;
}
//DRAWKLINE(HIGH,OPEN,LOW,CLOSE).
//用法:以HIGH为最高价,OPEN为开盘价,LOW为最低,CLOSE收盘画K线
this.DRAWKLINE=function(high,open,low,close)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWKLINE'};
let count=Math.max(high.length, open.length,low.length,close.length);
for(let i=0;i<count;++i)
{
let item={Open:null,High:null, Low:null, Close:null};
if (i<high.length && i<open.length && i<low.length && i<close.length)
{
item.Open=open[i];
item.High=high[i];
item.Low=low[i];
item.Close=close[i];
}
drawData[i]=item;
}
return result;
}
//满足条件画一根K线
this.DRAWKLINE_IF=function(condition,high,open,low,close)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWKLINE_IF'};
let count=Math.max(condition.length,high.length, open.length,low.length,close.length);
for(let i=0;i<count;++i)
{
let item={Open:null,High:null, Low:null, Close:null};
if (i<high.length && i<open.length && i<low.length && i<close.length && i<condition.length)
{
if (condition[i])
{
item.Open=open[i];
item.High=high[i];
item.Low=low[i];
item.Close=close[i];
}
}
drawData[i]=item;
}
return result;
}
//叠加一个K线
this.DRAWOVERLAYKLINE=function(open, high, low, close)
{
var drawData=[];
var result={DrawData:drawData, DrawType:'DRAWOVERLAYKLINE'};
var count=Math.max(high.length, open.length,low.length,close.length);
var kData=this.SymbolData.Data.Data;
for(var i=0;i<count;++i)
{
var item={Open:null,High:null, Low:null, Close:null};
var kItem=kData[i];
if (i<high.length && i<open.length && i<low.length && i<close.length &&
IFrameSplitOperator.IsNumber(open[i]) && IFrameSplitOperator.IsNumber(high[i]) && IFrameSplitOperator.IsNumber(low[i]) && IFrameSplitOperator.IsNumber(low[i]))
{
item.Open=open[i];
item.High=high[i];
item.Low=low[i];
item.Close=close[i];
item.Date=kItem.Date;
if (IFrameSplitOperator.IsNumber(kItem.Time)) item.Time=kItem.Time;
}
drawData[i]=item;
}
return result;
}
/*
DRAWCOLORKLINE 绘制K线
用法:
DRAWCOLORKLINE(Cond,Color,Empty);
满足Cond条件时,按照Color颜色绘制K线,根据Empty标志判断是空心还是实心。COLOR代表颜色,Empty非0为空心。
注:
不支持将该函数定义为变量,即不支持下面的写法:
A:DRAWCOLORKLINE(Cond,Color,Empty);
例:
DRAWCOLORKLINE(C>O,COLORBLUE,0);//收盘价大于开盘价,用蓝色绘制实心K线
*/
this.DRAWCOLORKLINE=function(condition, color, empty)
{
let drawData=[];
let result={ DrawData:drawData, DrawType:'DRAWCOLORKLINE', IsEmptyBar:!(empty==0), Color:color };
if (Array.isArray(condition)) //数组
{
for(var i=0; i<condition.length && i<this.SymbolData.Data.Data.length; ++i)
{
drawData[i]=null;
var condItem=condition[i];
if (!condItem) continue;
var kItem=this.SymbolData.Data.Data[i];
if (!kItem) continue;
drawData[i]={Open:kItem.Open,High:kItem.High, Low:kItem.Low, Close:kItem.Close};
}
}
else
{
if (condition)
{
for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
{
drawData[i]=null;
var kItem=this.SymbolData.Data.Data[i];
if (!kItem) continue;
drawData[i]={Open:kItem.Open,High:kItem.High, Low:kItem.Low, Close:kItem.Close };
}
}
}
return result;
}
/*
PLOYLINE 折线段
在图形上绘制折线段。
用法: PLOYLINE(COND,PRICE),当COND条件满足时,以PRICE位置为顶点画折线连接。
例如: PLOYLINE(HIGH>=HHV(HIGH,20),HIGH)表示在创20天新高点之间画折线。
*/
this.POLYLINE=function(condition,data)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'POLYLINE'};
let isNumber=IFrameSplitOperator.IsNumber(data);
let bFirstPoint=false;
let bSecondPont=false;
if (isNumber)
{
if (this.IsNumber(condition))
{
if (condition)
{
var count=this.SymbolData.Data.Data.length;
for(var i=0;i<count;++i )
{
drawData[i]=data;
}
}
}
else if (Array.isArray(condition))
{
var bFind=false;
for(var i=0; i<condition.length; ++i)
{
drawData[i]=null;
if (bFind)
{
drawData[i]=data;
}
else
{
if (!condition[i]) continue;
bFind=true;
drawData[i]=data;
}
}
}
}
else
{
if (IFrameSplitOperator.IsNumber(condition))
{
if (!condition) return result;
let lineCache={Start:{ },End:{ }, List:[]};
for(var i=0;i<data.length;++i)
{
drawData[i]=null;
if (bFirstPoint==false && bSecondPont==false)
{
if (!this.IsNumber(data[i])) continue;
bFirstPoint=true;
lineCache.Start={ID:parseInt(i), Value:data[i]}; //第1个点
}
else if (bFirstPoint==true && bSecondPont==false)
{
if (!this.IsNumber(data[i])) continue;
lineCache.End={ID:parseInt(i), Value:data[i]}; //第2个点
//根据起始点和结束点 计算中间各个点的数据
let lineData=this.CalculateDrawLine(lineCache); //计算2个点的线上 其他点的数值
for(let j in lineData)
{
let item=lineData[j];
drawData[item.ID]=item.Value;
}
let start={ ID:lineCache.End.ID,Value:lineCache.End.Value };
lineCache={Start:start,End:{ } };
}
}
this.CalculateDrawDataExtendLine(drawData);
}
else
{
let lineCache={Start:{ },End:{ }, List:[]};
for(let i in condition)
{
drawData[i]=null;
if (bFirstPoint==false && bSecondPont==false)
{
if (condition[i]==null || !condition[i]) continue;
if (i>=data.length || !this.IsNumber(data[i])) continue;
bFirstPoint=true;
lineCache.Start={ID:parseInt(i), Value:data[i]}; //第1个点
}
else if (bFirstPoint==true && bSecondPont==false)
{
if (condition[i]==null || !condition[i]) continue;
if (i>=data.length || !this.IsNumber(data[i])) continue;
lineCache.End={ID:parseInt(i), Value:data[i]}; //第2个点
//根据起始点和结束点 计算中间各个点的数据
let lineData=this.CalculateDrawLine(lineCache); //计算2个点的线上 其他点的数值
for(let j in lineData)
{
let item=lineData[j];
drawData[item.ID]=item.Value;
}
let start={ ID:lineCache.End.ID,Value:lineCache.End.Value };
lineCache={Start:start,End:{ } };
}
}
this.CalculateDrawDataExtendLine(drawData);
}
}
return result
}
this.CalculateDrawDataExtendLine=function(drawData, maxCount)
{
if (maxCount<0) return;
var x2=null;
var count=drawData.length;
if (this.IsNumber(maxCount) && maxCount<count) count=maxCount;
for(var i=count-1;i>=0;--i)
{
if (this.IsNumber(drawData[i]))
{
x2=i;
break;
}
}
//y3=(y1-y2)*(x3-x1)/(x2-x1)
if (x2!=null && x2-1>=0)
{
var x1=x2-1;
for(var i=x2+1;i<count;++i)
{
var y1=drawData[x1];
var y2=drawData[x2];
var y3=(y1-y2)*(i-x1)/(x2-x1);
if (y1-y3<0) break;
drawData[i]=y1-y3;
}
}
}
/*
画出数字.
用法:
DRAWNUMBER(COND,PRICE,NUMBER),当COND条件满足时,在PRICE位置书写数字NUMBER.
例如:
DRAWNUMBER(CLOSE/OPEN>1.08,LOW,C)表示当日实体阳线大于8%时在最低价位置显示收盘价.
decimal=小数位数 默认2
*/
this.DRAWNUMBER=function(condition,data,data2,decimal)
{
let drawData={ Value:[], Text:[] };
let result={ DrawData:drawData, DrawType:'DRAWNUMBER' };
var dec=2; //小数位数
if (IFrameSplitOperator.IsNumber(decimal)) dec=decimal;
var priceData={ DataType:0, SingleValue:null, ArrayValue:null }; //SingleValue=单值 ArrayValue=数组
if (Array.isArray(data))
{
priceData.ArrayValue=data;
priceData.DataType=2;
}
else
{
if (data==="TOP"|| data==="BOTTOM") result.FixedPosition=data;
priceData.SingleValue=data;
priceData.DataType=1;
}
var numberData={ DataType:0, SingleValue:null,ArrayValue:null };
if (Array.isArray(data2))
{
numberData.ArrayValue=data2;
numberData.DataType=2;
}
else
{ //单值
numberData.SingleValue=data2;
numberData.DataType=1;
if (IFrameSplitOperator.IsNumber(data2))
{
if (IFrameSplitOperator.IsInteger(data2)) numberData.SingleValue=data2.toString();
else text=data2.toFixed(dec);
}
}
if (Array.isArray(condition))
{
for(var i=0; i<condition.length; ++i)
{
drawData.Value[i]=null;
if (!condition[i]) continue;
drawData.Value[i]=this.DRAWNUMBER_Temp_PriceItem(i,priceData);
drawData.Text[i]=this.DRAWNUMBER_Temp_NumberItem(i,numberData,dec);
}
}
else if (this.IsNumber(condition) && condition)
{
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData.Value[i]=this.DRAWNUMBER_Temp_PriceItem(i,priceData);
drawData.Text[i]=this.DRAWNUMBER_Temp_NumberItem(i,numberData,dec);
}
}
return result;
}
this.DRAWNUMBER_Temp_PriceItem=function(index, priceData)
{
if (!priceData) return null;
if (priceData.DataType==1) return priceData.SingleValue;
if (!IFrameSplitOperator.IsNonEmptyArray(priceData.ArrayValue)) return null;
return priceData.ArrayValue[index];
}
this.DRAWNUMBER_Temp_NumberItem=function(index,numberData,decimal)
{
if (!numberData) return null;
if (numberData.DataType==1) return numberData.SingleValue;
if (!IFrameSplitOperator.IsNonEmptyArray(numberData.ArrayValue)) return null;
var value=numberData.ArrayValue[index];
if (this.IsNumber(value))
{
if (IFrameSplitOperator.IsInteger(value)) return value.toString();
else return value.toFixed(decimal);
}
return value.toString();
}
/*
固定位置显示数字.
用法: DRAWNUMBER_FIX(COND,X,Y,TYPE,NUMBER),当COND条件满足时,在当前指标窗口内(X,Y)位置书写数字NUMBER,X,Y为书写点在窗口中相对于左上角的百分比,TYPE:0为左对齐,1为右对齐.
例如: DRAWNUMBER_FIX(CURRBARSCOUNT=1 AND CLOSE/OPEN>1.08,0.5,0.5,0,C)表示最后一个交易日实体阳线大于8%时在窗口中间位置显示收盘价.
*/
this.DRAWNUMBER_FIX=function(condition,x,y,align,data)
{
var drawData={ Value:[], Text:[], };
var result={ DrawData:drawData, DrawType:'DRAWNUMBER_FIX', Position:{ X:x, Y:y, Type:align } };
var isNumber=IFrameSplitOperator.IsNumber(data);
if (Array.isArray(condition))
{
for(var i in condition)
{
drawData.Text[i]=null;
drawData.Value[i]=null;
if (!condition[i]) continue;
if (isNumber)
{
drawData.Text[i]=this.RemoveZero(data.toFixed(2));
drawData.Value[i]=data;
}
else
{
if (i>=data.length || !IFrameSplitOperator.IsNumber(data[i])) continue;
var item=data[i];
drawData.Text[i]=this.RemoveZero(item.toFixed(2));
drawData.Value[i]=item;
}
}
}
else
{
if(!condition)
{
}
else
{
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
if (isNumber)
{
drawData.Text[i]=this.RemoveZero(data.toFixed(2));
drawData.Value[i]=data;
}
else
{
if (i>=data.length || !IFrameSplitOperator.IsNumber(data[i])) continue;
var item=data[i];
drawData.Text[i]=this.RemoveZero(item.toFixed(2));
drawData.Value[i]=item;
}
}
}
}
return result;
}
/*
通达信语法:
在图形上绘制小图标.
用法:
DRAWICON(COND,PRICE,TYPE),当COND条件满足时,在PRICE位置画TYPE号图标(TYPE为1--41).
例如:
DRAWICON(CLOSE>OPEN,LOW,1)表示当收阳时在最低价位置画1号图标.
文华语法:
DRAWICON:绘制小图标。
用法:
DRAWICON(COND,PRICE,ICON);
当COND条件满足时,在PRICE位置画图标ICON。
注:
1、该函数可以指定位置PRICE标注图标ICON
2、ICON位置可以写成'ICON'的形式,也可以写为数字的形式,即DRAWICON(COND,PRICE,'ICO1');等价于DRAWICON(COND,PRICE,1);
3、不支持将该函数定义为变量,即不支持下面的写法:
A:DRAWICON(COND,PRICE,ICON);
4、该函数可以用ALIGN,VALIGN设置图标的对齐方式。
例1:
DRAWICON(CLOSE<OPEN,LOW,'ICO1');//在阴线的最低价上画出图标ICON1。
写完“DRAWICON(CLOSE<OPEN,LOW,” 以后,点击插入图标按钮,再单击选中的图标插入到函数中,图标用'ICO1'~'ICO105'(或1~105)表示。
例2:
MA5:=MA(C,5);
DRAWICON(C>MA5,MA5,2);//表示在收盘价大于5周期均线的k线对应的MA5数值位置上画出图标ICON2。
写完“DRAWICON(C>MA5,MA5,” 以后,点击插入图标按钮,再单击选中的图标插入到函数中,图标用ICO1~ICO105(或1~105)表示。
*/
this.DRAWICON=function(condition,data,type)
{
if (IFrameSplitOperator.IsString(type)) //把ICO1=>1
{
var value=type.replace('ICO',"");
type=parseInt(value);
}
var icon=g_JSComplierResource.GetDrawIcon(type);
if (!icon) g_JSComplierResource.GetDrawTextIcon(type);
if (!icon) icon={Symbol:'🚩'};
let drawData=[];
let result={ DrawData:drawData, DrawType:'DRAWICON',Icon:icon, IconType:type };
if (condition.length<=0) return result;
var IsNumber=typeof(data)=="number";
if (typeof(condition)=='number')
{
if (!condition) return result;
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (i<data.length && this.IsNumber(data[i])) drawData[i]=data[i];
else drawData[i]=null;
}
}
return result;
}
for(var i in condition)
{
drawData[i]=null;
if (!condition[i]) continue;
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (this.IsNumber(data[i])) drawData[i]=data[i];
}
}
return result;
}
/*
ICON:在k线图上,显示小图标。
用法:ICON(TYPE,ICON);
当TYPE为1,则在K线最高价位置显示图标ICON,当TYPE为0,则在最低价位置显示
图标ICON。
注:
1、该函数与判断条件连用,如:COND,ICON(TYPE,ICON);
2、该函数支持在函数后设置垂直对齐方式:VALIGN0(上对齐)、VALIGN1(中对齐)、VALIGN2(下对齐)
即可以写为如下格式:
CLOSE<OPEN,ICON(1,'阴'),VALIGN0;
例1:
CLOSE>OPEN,ICON(1,'ICO1');//表示K线收盘大于开盘时,在最高价上显示图标1。
写完“ICON(1,” 以后,点击插入图标按钮,再单击选中的图标插入到函数中,图标用
'ICO1'~'ICO105'表示
*/
this.ICON=function(position, type)
{
if (IFrameSplitOperator.IsString(type)) //把ICO1=>1
{
var value=type.replace('ICO',"");
type=parseInt(value);
}
var icon=g_JSComplierResource.GetDrawIcon(type);
if (!icon) g_JSComplierResource.GetDrawTextIcon(type);
if (!icon) icon={Symbol:'🚩'};
let drawData=[];
let result={DrawData:drawData, DrawType:'ICON',Icon:icon};
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
var kItem=this.SymbolData.Data.Data[i];
if (!kItem) continue;
if (position==0) drawData[i]=kItem.Low;
else if (position==1) drawData[i]=kItem.High;
}
return result;
}
/*
含义:在图形上显示图标,鼠标移近时显示文字。
用法:
TIPICON(COND,PRICE,TYPE, TEXT),当COND条件满足时,在PRICE位置显示图标(TYPE) 若PRICE="TOP", "BOTTOM" 顶部或底部输出图标
*/
this.TIPICON=function(condition, data, type, text)
{
if (IFrameSplitOperator.IsString(type)) //把ICO1=>1
{
var value=type.replace('ICO',"");
type=parseInt(value);
}
var icon=g_JSComplierResource.GetDrawIcon(type);
let drawData=[];
let result={ DrawData:drawData, DrawType:'TIPICON',Icon:icon, IconType:type, Text:text };
if (condition.length<=0) return result;
var IsNumber=typeof(data)=="number";
if (IFrameSplitOperator.IsNumber(condition))
{
if (!condition) return result;
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (i<data.length && IFrameSplitOperator.IsNumber(data[i])) drawData[i]=data[i];
else drawData[i]=null;
}
}
}
else if (Array.isArray(condition))
{
for(var i=0; i<condition.length; ++i)
{
drawData[i]=null;
if (!condition[i]) continue;
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (IFrameSplitOperator.IsNumber(data[i])) drawData[i]=data[i];
}
}
}
return result;
}
/*
绘制通道
condition:条件
data,data2:通道顶部和底部
borderColor: 通道顶部和底部线段颜色RGB(24,30,40) 不填就不画
borderWidth: 通道顶部和底部线段宽度
areaColor: 通道面积颜色 RGB(200,30,44) 不填使用默认颜色
dotted: 通道顶部和底部虚线设置 '3,4' , 不填默认 3,3
*/
this.DRAWCHANNEL=function(condition, data, data2, borderColor, borderWidth, dotted, areaColor)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWCHANNEL', Border:{ }};
if (condition.length<=0) return result;
if (borderColor) result.Border.Color=borderColor;
if (areaColor) result.AreaColor=areaColor;
if (borderWidth>0) result.Border.Width=borderWidth;
if (dotted)
{
if (dotted=='0')
{
result.Border.Dotted=[];
}
else
{
let ary=dotted.split(',');
result.Border.Dotted=[];
for(var i in ary)
{
var item=ary[i];
if (!item) continue;
var value=parseInt(ary[i]);
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (value<=0) continue;
result.Border.Dotted.push(value);
}
if (result.Border.Dotted.length<=0) result.Border.Dotted=null;
}
}
var IsNumber=typeof(data)=="number";
var IsNumber2=typeof(data2)=="number";
if (typeof(condition)=='number')
{
if (!condition) return result; //条件是否
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
if (IsNumber && IsNumber2)
{
drawData[i]={Value:data,Value2:data2};
}
else if (IsNumber && !IsNumber2)
{
if (isNaN(data2[i])) continue;
drawData[i]={Value:data,Value2:data2[i]};
}
else if (!IsNumber && IsNumber2)
{
if (isNaN(data[i])) continue;
drawData[i]={Value:data[i],Value2:data2};
}
else
{
if (isNaN(data[i]) || isNaN(data2[i])) continue;
drawData[i]={Value:data[i],Value2:data2[i]};
}
}
}
else
{
for(var i=0;i<condition.length;++i)
{
drawData[i]=null;
if (isNaN(condition[i]) || !condition[i]) continue;
if (IsNumber && IsNumber2)
{
drawData[i]={Value:data,Value2:data2};
}
else if (IsNumber && !IsNumber2)
{
if (isNaN(data2[i])) continue;
drawData[i]={Value:data,Value2:data2[i]};
}
else if (!IsNumber && IsNumber2)
{
if (isNaN(data[i])) continue;
drawData[i]={Value:data[i],Value2:data2};
}
else
{
if (isNaN(data[i]) || isNaN(data2[i])) continue;
drawData[i]={Value:data[i],Value2:data2[i]};
}
}
}
return result;
}
this.RGB=function(r,g,b)
{
var rgb=`RGB(${r},${g},${b})`;
return rgb;
}
this.RGBA=function(r,g,b,a)
{
var rgba=`RGB(${r},${g},${b},${a})`;
return rgba;
}
this.UPCOLOR=function(color)
{
return color;
}
this.DOWNCOLOR=function(color)
{
return color;
}
this.STICKTYPE=function(value)
{
return value;
}
//数据左右偏移
this.XMOVE=function(offset)
{
return offset;
}
//数据上下偏移
this.YMOVE=function(offset)
{
return offset;
}
this.LINEDASH=function(aryData)
{
if (IFrameSplitOperator.IsNonEmptyArray(aryData)) return aryData.slice();
return [];
}
this.KLINETYPE=function(type)
{
return type;
}
this.FIRSTDRAW=function(value)
{
return value;
}
/*
SOUND 播放声音。用法:SOUND(NAME),播放NAME
注:
1、点击设置声音按钮,在弹出来的界面中设置声音,声音用字符'A'~'J'表示。
2、自定义声音可以在设置菜单的设置声音文件中设置
3、条件如果一直满足,则只播放一次,不重复播放。
4、历史数据不触发该函数
例:
CLOSE>OPEN,SOUND('A');//表示K线收盘大于开盘时,播放声音"A"
*/
this.SOUND=function(value)
{
return { Name:"SOUND", Value: value };
}
/*
PLAYSOUND 条件满足时,播放指定声音。用法:PLAYSOUND(COND, 'N') 当条件满足时,播放声音'N'
注:
1、点击设置声音按钮,在弹出来的界面中设置声音,声音用字符'A'~'J'表示。
2、自定义声音可以在设置菜单的设置声音文件中设置
3、条件如果一直满足,则只播放一次,不重复播放。
4、历史数据不触发该函数
例:
PLAYSOUND(CLOSE>OPEN,'A');//表示CLOSE>OPEN时播放自定义声音'A'。
*/
this.PLAYSOUND=function(cond, value)
{
return null;
}
//用法:PARTLINE(PRICE,COND1,COLOR1,COND2,COLOR2...),
//绘制PRICE线,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不绘制,从COLOR1之后的参数均可以省略,最多可以有10组条件
//例如:PARTLINE(CLOSE,CLOSE>OPEN,RGB(255,0,0),CLOSE<OPEN,RGB(0,255,0),1,RGB(0,0,255))
//表示画收盘价线,阳线时用红色,阴线时用绿色,平盘用蓝色.注意最后一个条件为1,表示前面都不满足时必然满足这个条件
this.PARTLINE=function(args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'PARTLINE'};
if (args.length<3) return result;
var data=args[0];
var condition=[];
for(var i=1;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], RGB:args[i+1]});
}
for(var i in data)
{
var drawItem={Value:null, RGB:null};
drawData[i]=drawItem;
var value=data[i];
if (!this.IsNumber(value)) continue;
var rgb=null;
for(var j in condition)
{
var item=condition[j];
if (Array.isArray(item.Cond))
{
if (i<item.Cond.length && item.Cond[i])
{
rgb=item.RGB;
break;
}
}
else
{
if (this.IsNumber(item.Cond) && item.Cond) //单数值条件
{
rgb=item.RGB;
break;
}
}
}
if (rgb)
{
drawItem.Value=value;
drawItem.RGB=rgb;
}
}
return result;
}
//函数:FILLRGN,根据条件用RGN颜色填充区域
//用法:FILLRGN(PRICE1,PRICE2,COND1,COLOR1,COND2,COLOR2...),填充PRICE1到PRICE2之间的区域,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不填充,从COLOR1之后的参数均可以省略,最多可以有15组条件。
//例如:FILLRGN(CLOSE,OPEN,CLOSE>OPEN,RGB(255,0,0),CLOSE<OPEN,RGB(0,255,0))表示填充开盘价和收盘价之间的区域,阳线时用红色,阴线时用绿色,平盘不绘制。
this.FILLRGN2=function(args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'FILLRGN2'};
if (args.length<4) return result;
var price=args[0];
var price2=args[1];
var condition=[];
for(var i=2;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], Color:args[i+1]});
}
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
var drawItem={ Value:null, Value2:null, Color:null };
for(var j in condition)
{
var item=condition[j];
if (Array.isArray(item.Cond))
{
if (i<item.Cond.length && item.Cond[i])
{
drawItem.Color=item.Color;
break;
}
}
else
{
if (this.IsNumber(item.Cond) && item.Cond) //单数值条件
{
drawItem.Color=item.Color;
break;
}
}
}
if (!drawItem.Color) continue;
if (Array.isArray(price))
{
if (i>=price.length) continue;
if (!this.IsNumber(price[i])) continue;
drawItem.Value=price[i];
}
else if (this.IsNumber(price))
{
drawItem.Value=price;
}
else
{
continue;
}
if (Array.isArray(price2))
{
if (i>=price2.length) continue;
if (!this.IsNumber(price2[i])) continue;
drawItem.Value2=price2[i];
}
else if (this.IsNumber(price2))
{
drawItem.Value2=price2;
}
else
{
continue;
}
drawData[i]=drawItem;
}
return result;
}
//用法:FLOATRGN(PRICE,WIDTH,COND1,COLOR1,COND2,COLOR2...),以PRICE为基础填充宽度为WIDTH像素的区域,WIDTH为负则向下填充,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不填充,从COND1之后的参数均可以省略,最多可以有10组条件
//例如:FLOATRGN(CLOSE,VOL/HHV(VOL,10)*15,CLOSE>OPEN,RGB(255,0,0),1,RGB(0,255,0))表示沿收盘价填充宽度为成交量的区域,区域最大宽度为15像素,阳线时用红色,阴线时用绿色。
this.FLOATRGN=function(args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'FLOATRGN'};
if (args.length<4) return result;
var price=args[0];
var width=args[1];
var condition=[];
for(var i=2;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], Color:args[i+1]});
}
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
var drawItem={ Value:null, Value2:null, Color:null };
for(var j in condition)
{
var item=condition[j];
if (Array.isArray(item.Cond))
{
if (i<item.Cond.length && item.Cond[i])
{
drawItem.Color=item.Color;
break;
}
}
else
{
if (this.IsNumber(item.Cond) && item.Cond) //单数值条件
{
drawItem.Color=item.Color;
break;
}
}
}
if (!drawItem.Color) continue;
if (Array.isArray(price))
{
if (i>=price.length) continue;
if (!this.IsNumber(price[i])) continue;
drawItem.Value=price[i];
}
else if (this.IsNumber(price))
{
drawItem.Value=price;
}
else
{
continue;
}
if (Array.isArray(width))
{
if (i>=width.length) continue;
if (!this.IsNumber(width[i])) continue;
drawItem.Value2=width[i];
}
else if (this.IsNumber(width))
{
drawItem.Value2=width;
}
else
{
continue;
}
drawData[i]=drawItem;
}
return result;
}
//函数:FILLTOPRGN / FILLBOTTOMRGN 根据条件填充顶部或底部区域
//用法 FILLTOPRGN(PRICE, COND1, COLOR, COND2, COLOR2)
this.FILLBGRGN=function(type,args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:(type==1 ?'FILLTOPRGN':"FILLBOTTOMRGN")};
if (args.length<3) return result;
var price=args[0];
var condition=[];
for(var i=1;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], Color:args[i+1]});
}
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
var drawItem={ Value:null, Color:null };
for(var j in condition)
{
var item=condition[j];
if (Array.isArray(item.Cond))
{
if (i<item.Cond.length && item.Cond[i])
{
drawItem.Color=item.Color;
break;
}
}
else
{
if (this.IsNumber(item.Cond) && item.Cond) //单数值条件
{
drawItem.Color=item.Color;
break;
}
}
}
if (!drawItem.Color) continue;
if (Array.isArray(price))
{
if (i>=price.length) continue;
if (!this.IsNumber(price[i])) continue;
drawItem.Value=price[i];
}
else if (this.IsNumber(price))
{
drawItem.Value=price;
}
else
{
continue;
}
drawData[i]=drawItem;
}
return result;
}
//函数:FILLVERTICALRGN 根据条件填充顶部到底部区域
//用法 FILLVERTICALRGN(COND1, COLOR, COND2, COLOR2)
this.FILLVERTICALRGN=function(args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:"FILLVERTICALRGN"};
if (args.length<2) return result;
var condition=[];
for(var i=0;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], Color:args[i+1]});
}
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
var drawItem={ Color:null };
for(var j in condition)
{
var item=condition[j];
if (Array.isArray(item.Cond))
{
if (i<item.Cond.length && item.Cond[i])
{
drawItem.Color=item.Color;
break;
}
}
else
{
if (this.IsNumber(item.Cond) && item.Cond) //单数值条件
{
drawItem.Color=item.Color;
break;
}
}
}
if (!drawItem.Color) continue;
drawData[i]=drawItem;
}
return result;
}
//填充背景.
//用法: DRAWGBK(COND,COLOR1,COLOR2,colorAngle) colorAngle=渐近色角度
//例如: DRAWGBK(O>C,RGB(0,255,0),RGB(255,0,0),0);
this.DRAWGBK=function(condition, color, color2, colorAngle)
{
let drawData={ Color:[], Angle:colorAngle };
if (color) drawData.Color.push(color);
if (color2) drawData.Color.push(color2);
let result={DrawData:null, DrawType:'DRAWGBK'};
if (Array.isArray(condition))
{
for(var i in condition)
{
var item=condition[i];
if (item)
{
result.DrawData=drawData;
break;
}
}
}
else
{
if (condition) result.DrawData=drawData;
}
return result;
}
this.DRAWGBK2=function(condition, color, color2, colorAngle)
{
let drawData={ Color:[], Angle:colorAngle };
if (color) drawData.Color.push(color);
if (color2) drawData.Color.push(color2);
let result={DrawData:null, DrawType:'DRAWGBK2'};
if (Array.isArray(condition))
{
drawData.Data=[];
for(var i in condition)
{
var item=condition[i];
drawData.Data[i]=item ? 1:0;
}
result.DrawData=drawData;
}
else
{
if (condition)
{
result.DrawData=drawData;
result.DrawType="DRAWGBK";
}
}
return result;
}
//填充部分背景.
//用法:
//DRAWGBK_DIV(COND,COLOR1,COLOR2,填色方式,填充范围),填充满足COND条件的背景区域
//填色方式:0是上下渐进 1是左右渐进 2是用COLOR1画框线 3是用COLOR1画框线, 用COLOR2填充
//填充范围:0为整个区域 1为最高最低区 2为开盘收盘区
//例如:
//DRAWGBK_DIV(C>O,RGB(0,255,0),RGB(255,0,0),0,0);
this.DRAWGBK_DIV=function(condition, color, color2, colorType, fillType)
{
var drawData={ AryColor:[color, color2], ColorType:colorType, FillType:fillType, Data:[] };
var result={ DrawData:drawData, DrawType:'DRAWGBK_DIV' };
if (!this.SymbolData || !this.SymbolData.Data || !IFrameSplitOperator.IsNonEmptyArray(this.SymbolData.Data.Data)) return result;
var aryKData=this.SymbolData.Data.Data;
if (Array.isArray(condition))
{
for(var i=0; i<aryKData.length; ++i)
{
var condItem=condition[i];
var item=null;
if (condItem)
{
var kItem=aryKData[i];
if (fillType==1) item={ AryValue:[kItem.High, kItem.Low] }
else if (fillType==2) item={ AryValue:[kItem.Open, kItem.Close] }
else item={ AryValue:null };
}
drawData.Data[i]=item;
}
}
else
{
if (condition)
{
for(var i=0; i<aryKData.length; ++i)
{
var kItem=aryKData[i];
var item=null;
if (fillType==1) item={ AryValue:[kItem.High, kItem.Low] }
else if (fillType==2) item={ AryValue:[kItem.Open, kItem.Close] }
else item={ AryValue:null };
drawData.Data[i]=item;
}
}
}
return result;
}
//画文字 及线段
this.DRAWTEXT_LINE=function(condition, price, text, textcolor, fontSize, linetype, linecolor)
{
let drawData={ Text:{ Title:text, Color:textcolor }, Line:{ Type:linetype, Color:linecolor } };
if (fontSize<=0) fontSize=12;
drawData.Text.Font=fontSize*GetDevicePixelRatio()+'px 微软雅黑';
let result={DrawData:null, DrawType:'DRAWTEXT_LINE'};
if (Array.isArray(condition))
{
var item=null;
if (IFrameSplitOperator.IsNonEmptyArray(condition))
item=condition[condition.length-1]; //取最后一个数值
if (item)
{
if (Array.isArray(price)) drawData.Price=price[condition.length-1];
else drawData.Price=price;
result.DrawData=drawData;
}
}
else
{
if (condition)
{
if (Array.isArray(price))
{
var value=null;
if (price.length>0) value=price[price.length-1];
drawData.Price=value;
}
else
{
drawData.Price=price;
}
result.DrawData=drawData;
}
}
return result;
}
// 相对位置上画矩形.
//用法: DRAWRECTREL(LEFT,TOP,RIGHT,BOTTOM,COLOR),以图形窗口(LEFT,TOP)为左上角,(RIGHT,BOTTOM)为右下角绘制矩形,坐标单位是窗口沿水平和垂直方向的1/1000,取值范围是0—999,超出范围则可能显示在图形窗口外,矩形中间填充颜色COLOR,COLOR为0表示不填充.
//例如: DRAWRECTREL(0,0,500,500,RGB(255,255,0))表示在图形最左上部1/4位置用黄色绘制矩形
this.DRAWRECTREL=function(left, top, right,bottom, color)
{
let drawData={ Rect:{Left:Math.min(left,right), Top:Math.min(top,bottom), Right:Math.max(right,left), Bottom:Math.max(bottom,top) }, Color:color };
if (color==0) drawData.Color=null;
let result={DrawData:drawData, DrawType:'DRAWRECTREL'};
return result;
}
//DRAWTEXTREL(X,Y,TEXT),在图形窗口(X,Y)坐标位置书写文字TEXT,坐标单位是窗口沿水平和垂直方向的1/1000,X、Y取值范围是0—999,超出范围则可能显示在图形窗口外。
//例如:DRAWTEXTREL(500,500,'注意')表示在图形中间位置显示'注意'字样。
this.DRAWTEXTREL=function(x, y, text)
{
let drawData={ Point:{X:x, Y:y} };
if (IFrameSplitOperator.IsString(text))
drawData.Text=text;
else if (IFrameSplitOperator.IsNonEmptyArray(text))
drawData.Text=text[0];
let result={DrawData:drawData, DrawType:'DRAWTEXTREL'};
return result;
}
//DRAWTEXTABS(X,Y,TEXT),在图形窗口(X,Y)坐标位置书写文字TEXT,坐标单位是像素,图形窗口左上角坐标为(0,0)。
//例如:DRAWTEXTABS(0,0,'注意')表示在图形最左上角位置显示'注意'字样。
this.DRAWTEXTABS=function(x, y, text)
{
let drawData={ Point:{X:x, Y:y} };
if (IFrameSplitOperator.IsString(text))
drawData.Text=text;
else if (IFrameSplitOperator.IsNonEmptyArray(text))
drawData.Text=text[0];
let result={DrawData:drawData, DrawType:'DRAWTEXTABS'};
return result;
}
//画百分比叠加线
this.DRAWOVERLAYLINE=function(data, mainData, title)
{
let drawData={ Data:data, MainData:mainData };
if (title && typeof(title)=='string') drawData.Title=title;
let result={ DrawData:drawData, DrawType:'DRAWOVERLAYLINE' };
return result;
}
//绘制斜线.
//用法:DRAWSL(COND,PRICE,SLOPE,LEN,DIRECT),当COND条件满足时,在PRICE位置画斜线,SLOPE为斜率,LEN为长度,DIRECT为0向右延伸,1向左延伸,2双向延伸.
//注意:
//1.K线间的纵向高度差为SLOPE;
//2.SLOPE为0时,为水平线;
//3.SLOPE为10000时,为垂直线,LEN为向上的像素高度,DIRECT表示向上或向下延伸;
//4.SLOPE和LEN支持变量;
this.DRAWSL=function(condition, data, slope, len, direct)
{
let drawData={ Data:[], Option:[] };
let result={ DrawData:drawData, DrawType:'DRAWSL' };
var isNumber=this.IsNumber(data);
if (Array.isArray(condition))
{
for(var i in condition)
{
drawData.Data[i]=null;
if (!condition[i]) continue;
if (isNumber)
{
drawData.Data[i]=data;
drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
}
else
{
if (i<data.length && this.IsNumber(data[i]))
{
drawData.Data[i]=data[i];
drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
}
}
}
}
else
{
if (condition)
{
var count=this.SymbolData.Data.Data.length;
for(var i=0; i<count; ++i)
{
drawData.Data[i]=null;
if (isNumber)
{
drawData.Data[i]=data;
drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
}
else
{
if (i<data.length && this.IsNumber(data[i]))
{
drawData.Data[i]= data[i];
drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
}
}
}
}
}
return result;
}
//含义:在图形上绘制垂直线。
//用法:
//VERTLINE(COND,TYPE),当COND条件满足时,沿垂直方向绘制TYPE类型的线段,TYPE=0表示实线,1表示虚线'---',2表示点线'...',3表示点划线'-.-.-',4表示点点划线'-..-..-'。
//例如:VERTLINE(HIGH>=HHV(HIGH,20),1)表示在创20天新高画垂直虚线。
this.VERTLINE=function(condition, type)
{
let drawData={ Data:[], LineType:type };
let result={ DrawData:drawData, DrawType:'VERTLINE' };
if (Array.isArray(condition))
{
for(var i=0;i<condition.length;++i)
{
var item=condition[i];
if (item) drawData.Data[i]=1;
else drawData.Data[i]=0;
}
}
else
{
}
return result;
}
//含义:在图形上绘制水平线。
//用法:
//HORLINE(COND,PRICE,TYPE,EXTEND),当COND条件满足时,在PRICE位置沿水平方向绘制TYPE类型的线段,TYPE=0表示实线,1表示虚线'---',2表示点线'...',3表示点划线'-.-.-',4表示点点划线'-..-..-'。EXTEND=1 表示向左延长,=2表示向右延长,=3表示左右延长。
//例如:HORLINE(HIGH>=HHV(HIGH,20),HIGH,1,2)表示在创20天新高时画水平虚线向右延伸。
this.HORLINE=function(condition, data, type, extend)
{
let drawData={ Data:[], LineType:type, Extend:extend };
let result={ DrawData:drawData, DrawType:'HORLINE' };
if (Array.isArray(condition) && Array.isArray(data))
{
for(var i=0;i<condition.length;++i)
{
var item=condition[i];
drawData.Data[i]=null;
if (!item) continue;
if (i>=data.length) continue;
var value=data[i];
if (IFrameSplitOperator.IsNumber(value)) drawData.Data[i]=value;
}
}
else if (Array.isArray(condition) && IFrameSplitOperator.IsNumber(data))
{
for(var i=0;i<condition.length;++i)
{
var item=condition[i];
drawData.Data[i]=null;
if (!item) continue;
drawData.Data[i]=data;
}
}
else if (IFrameSplitOperator.IsNumber(condition) && condition)
{
if (this.SymbolData && this.SymbolData.Data && this.SymbolData.Data.Data)
{
if (Array.isArray(data))
{
var count=this.SymbolData.Data.Data.length;
for(var i=0; i<count; ++i)
{
drawData.Data[i]=null;
if (i>=data.length) continue;
var value=data[i];
if (IFrameSplitOperator.IsNumber(value)) drawData.Data[i]=value;
}
}
else if (IFrameSplitOperator.IsNumber(data))
{
var count=this.SymbolData.Data.Data.length;
for(var i=0; i<count; ++i)
{
drawData.Data[i]=data;
}
}
}
}
return result;
}
//该函数和DRAWTEXT连用
//{ Color:背景色, Border:边框颜色, Margin=[上,下,左, 右] }
this.BACKGROUND=function(color, borderColor, left, right, top, bottom)
{
var bg={ Margin:[0,1,1,1] };
if (color) bg.Color=color;
if (borderColor) bg.Border=borderColor;
if (IFrameSplitOperator.IsNumber(left)) bg.Margin[2]=left;
if (IFrameSplitOperator.IsNumber(right)) bg.Margin[3]=right;
if (IFrameSplitOperator.IsNumber(top)) bg.Margin[0]=top;
if (IFrameSplitOperator.IsNumber(bottom)) bg.Margin[1]=bottom;
return bg;
}
//该函数和DRAWTEXT, DRAWICON连用
//{ color:线段颜色, lineWidth:宽度 lineType:线段样式0=直线 1=虚线}
this.CKLINE=function(color, lineWidth, lineType, lineDotted)
{
var drawData={ Color:color, LineWidth: 1, LineType:0, LineDot:[3,3] };
if (IFrameSplitOperator.IsPlusNumber(lineWidth)) drawData.LineWidth=lineWidth;
if (IFrameSplitOperator.IsPlusNumber(lineType)) drawData.LineType=lineType;
if (lineDotted)
{
let ary=lineDotted.split(',');
var dotted=[];
for(var i in ary)
{
var item=ary[i];
if (!item) continue;
var value=parseInt(ary[i]);
if (value<=0) continue;
dotted.push(value);
}
if (dotted.length>0) drawData.LineDotted=dotted;
}
drawData.Data=[];
for(var i=0;i<this.SymbolData.Data.Data.length;++i)
{
var item=this.SymbolData.Data.Data[i];
drawData.Data[i]={ High:item.High, Low:item.Low };
}
return drawData;
}
//多头建仓(买入开仓).
//参数1为触发条件,参数2为标记放置位置.此函数只适用于特定版本交易模式下.
//例如: BUY(CROSS(A,B),LOW),当A上穿B时,在LOW处画标记,同时突出提示或直接下单,如果LOW改为DRAWNULL,就不画标记.(分时图上不支持)
this.BUY=function(condition, data, iconSymbol, color)
{
var iconInfo={ Color:"rgb(0,255,0)", Type:"SVG", Icon:'\ue660' };
if (IFrameSplitOperator.IsString(iconSymbol)) iconInfo.Icon=iconSymbol;
if (color) iconInfo.Color=color;
var result=this.CalculateTradeData(condition, data, iconInfo);
result.DrawType='BUY';
return result;
}
this.BUYSHORT=function(condition, data, iconSymbol, color)
{
var iconInfo={ Color:"rgb(0,255,0)", Type:"SVG", Icon:'\ue660' };
if (IFrameSplitOperator.IsString(iconSymbol)) iconInfo.Icon=iconSymbol;
if (color) iconInfo.Color=color;
var result=this.CalculateTradeData(condition, data, iconInfo);
result.DrawType='BUYSHORT';
return result;
}
//多头平仓(卖出平仓).
//参数1为触发条件,参数2为标记放置位置.此函数只适用于特定版本交易模式下.
//例如: SELL(CROSS(A,B),HIGH),当A上穿B时,在HIGH处画标记,同时突出提示或直接下单,如果HIGH改为DRAWNULL,就不画标记.(分时图上不支持)
this.SELL=function(condition, data, iconSymbol,color)
{
var iconInfo={ Color:"rgb(255,0,0)", Type:"SVG", Icon:'\ue661' };
if (IFrameSplitOperator.IsString(iconSymbol)) iconInfo.Icon=iconSymbol;
if (color) iconInfo.Color=color;
var result=this.CalculateTradeData(condition, data, iconInfo);
result.DrawType='SELL';
return result;
}
this.SELLSHORT=function(condition, data, iconSymbol,color)
{
var iconInfo={ Color:"rgb(255,0,0)", Type:"SVG", Icon:'\ue661' };
if (IFrameSplitOperator.IsString(iconSymbol)) iconInfo.Icon=iconSymbol;
if (color) iconInfo.Color=color;
var result=this.CalculateTradeData(condition, data, iconInfo);
result.DrawType='SELLSHORT';
return result;
}
this.CalculateTradeData=function(condition, data, IconInfo)
{
var aryData=[];
var aryIcon=[];
var result={ DrawData:{ Data:aryData, Icons:aryIcon } };
if (Array.isArray(condition))
{
var isAryPosition=Array.isArray(data);
for(var i=0;i<condition.length;++i)
{
aryData[i]=0;
aryIcon[i]=null
if (!condition[i]) continue;
aryData[i]=1;
if (isAryPosition) aryIcon[i]={ Value:data[i], Type:IconInfo.Type, Color:IconInfo.Color, Icon:IconInfo.Icon };
else aryIcon[i]={ Value:data, Type:IconInfo.Type, Color:IconInfo.Color, Icon:IconInfo.Icon };
}
}
else if (IFrameSplitOperator.IsNumber(condition) && condition>0)
{
}
return result;
}
}
JSDraw.prototype.CalculateDrawLine=function(lineCache)
{
lineCache.List=[];
for(let i=lineCache.Start.ID; i<=lineCache.End.ID; ++i) lineCache.List.push(i);
let height=Math.abs(lineCache.Start.Value-lineCache.End.Value);
let width=lineCache.List.length-1;
var result=[];
result.push({ID:lineCache.Start.ID, Value:lineCache.Start.Value}); //第1个点
if (lineCache.Start.Value>lineCache.End.Value)
{
for(let i=1;i<lineCache.List.length-1;++i)
{
var value=height*(lineCache.List.length-1-i)/width+lineCache.End.Value;
result.push({ID:lineCache.List[i], Value:value});
}
}
else
{
for(let i=1;i<lineCache.List.length-1;++i)
{
var value=height*i/width+lineCache.Start.Value;
result.push({ID:lineCache.List[i], Value:value});
}
}
result.push({ID:lineCache.End.ID, Value:lineCache.End.Value}); //最后一个点
return result;
}
//是否有是有效的数字
JSDraw.prototype.IsNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return true;
}
JSDraw.prototype.IsDrawFunction=function(name)
{
let setFunctionName=new Set(
[
"STICKLINE","DRAWTEXT",'SUPERDRAWTEXT','DRAWLINE','DRAWBAND','DRAWKLINE',"DRAWKLINE1",'DRAWKLINE_IF',"DRAWCOLORKLINE",'PLOYLINE',"DRAWOVERLAYKLINE",
'POLYLINE','DRAWNUMBER',"DRAWNUMBER_FIX",'DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL',"DRAWTEXTABS","DRAWTEXTREL",
'DRAWOVERLAYLINE',"FILLRGN", "FILLRGN2","FILLTOPRGN", "FILLBOTTOMRGN", "FILLVERTICALRGN","FLOATRGN","DRAWSL", "DRAWGBK2","DRAWGBK_DIV",
"VERTLINE","HORLINE","TIPICON",
"BUY","SELL","SELLSHORT","BUYSHORT",
]);
if (setFunctionName.has(name)) return true;
return false;
}
JSDraw.prototype.RemoveZero = function (strValue)
{
while(strValue.length>0)
{
var index=strValue.length-1;
var ch=strValue[index];
if (ch=="0")
{
strValue=strValue.substr(0,index);
}
else if (ch==".")
{
strValue=strValue.substr(0,index);
break;
}
else
{
break;
}
}
return strValue;
}
//http://www.newone.com.cn/helpcontroller/index?code=zszy_pc
var DYNAINFO_ARGUMENT_ID=
{
YCLOSE:3,
OPEN:4,
HIGH:5,
LOW:6,
CLOSE:7,
VOL:8,
AMOUNT:10,
AMPLITUDE:13, //振幅
INCREASE:14, //涨幅
EXCHANGERATE:37, //换手率
};
function JSSymbolData(ast,option,jsExecute)
{
this.AST=ast; //语法树
this.Execute=jsExecute;
this.Symbol='600000.sh';
this.Name;
this.Data=null; //个股数据
this.PeriodData=new Map(); //跨周期数据 {Key=period, value=[histroydata]}
this.IsApiPeriod=false; //是否是后台api周期数据
this.SourceData=null; //不复权的个股数据
this.MarketValue=null; //总市值
this.Period=0; //周期
this.Right=0; //复权
this.DataType=0; //默认K线数据 2=分钟走势图数据 3=多日分钟走势图
this.IsBeforeData=false; //当日走势图数据是否包含开盘前数据
this.DayCount; //多日分时图天数
this.Arguments=[]; //指标参数
this.KLineApiUrl= g_JSComplierResource.Domain+"/API/KLine2"; //日线
this.MinuteKLineApiUrl= g_JSComplierResource.Domain+'/API/KLine3'; //分钟K线
this.RealtimeApiUrl= g_JSComplierResource.Domain+'/API/stock'; //实时行情
this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData'; //历史分钟数据(多日分时图)
this.StockHistoryDayApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay'; //历史财务数据
this.StockHistoryDay3ApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay3'; //历史财务数据
this.StockHistoryDay2ApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay2'; //历史财务数据
this.StockNewsAnalysisApiUrl= g_JSComplierResource.CacheDomain+'/cache/newsanalyze'; //新闻分析数据
this.HKToSHSZApiUrl= //北上资金 !!顺序不要变 后面都是写死的
[
g_JSComplierResource.CacheDomain+'/cache/historyday/all/hk2shsz.json', //日线数据
g_JSComplierResource.CacheDomain+'/cache/analyze/hk2shsz/hk2shsz.json', //最新分钟
g_JSComplierResource.Domain+'/API/HKToSHSZMinuteData', //多日分时分钟
g_JSComplierResource.CacheDomain+'/cache/analyze/hk2szshanalyze' //个股的北上
] ;
this.MaxRequestDataCount=1000;
this.MaxRequestMinuteDayCount=5;
this.KLineDateTimeRange; //请求的K线日期范围
this.LatestData=new Map(); //最新行情 key=id value=数据
this.IndexData; //大盘指数
this.LatestIndexData; //最新大盘数据
this.MarginData=new Map(); //融资融券
this.HKToSHSZData=new Map(); //北上资金
this.NewsAnalysisData=new Map(); //新闻统计
this.ExtendData=new Map(); //其他的扩展数据
this.UserData=new Map(); //用户数据
this.CustomAPIData=new Map(); //自定义API数据
this.ScriptIndexOutData=new Map(); //调用脚本执行返回的数据
this.OtherSymbolData=new Map(); //其他股票信息 key=symbol value=[historydata]
//股票数据缓存 key=函数名(参数) { Data: value=拟合的数据 , Error: }
//FinValue(id)
this.StockData=new Map();
this.SectionFinanceData=new Map(); //截面报告数据
this.ThrowSFPeirod=new Set(); //重新获取数据
this.NetworkFilter; //网络请求回调 function(data, callback);
this.DrawInfo;
//使用option初始化
if (option)
{
if (option.HQDataType) this.DataType=option.HQDataType;
if (option.Data)
{
this.Data=option.Data;
if (this.DataType!=HQ_DATA_TYPE.MINUTE_ID && this.DataType!=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID && this.DataType!=HQ_DATA_TYPE.HISTORY_MINUTE_ID) //分钟走势图数据 没有周期和复权
{
this.Period=option.Data.Period; //周期
this.Right=option.Data.Right; //复权
}
//this.Data=null;
}
if (option.SourceData) this.SourceData=option.SourceData;
if (option.Symbol) this.Symbol=option.Symbol;
if (option.Name) this.Name=option.Name;
if (option.MaxRequestDataCount>0) this.MaxRequestDataCount=option.MaxRequestDataCount;
if (option.MaxRequestMinuteDayCount>0) this.MaxRequestMinuteDayCount=option.MaxRequestMinuteDayCount;
if (option.KLineApiUrl) this.KLineApiUrl=option.KLineApiUrl;
if (option.Right) this.Right=option.Right;
if (option.Period) this.Period=option.Period;
if (option.IsBeforeData===true) this.IsBeforeData=option.IsBeforeData;
if (option.NetworkFilter) this.NetworkFilter=option.NetworkFilter;
if (option.DayCount>0) this.DayCount=option.DayCount;
if (option.Arguments) this.Arguments=option.Arguments;
if (option.KLineRange) this.KLineDateTimeRange=option.KLineRange;
if (option.IsApiPeriod) this.IsApiPeriod=option.IsApiPeriod;
if (option.DrawInfo) this.DrawInfo=option.DrawInfo;
}
this.RecvError=function(request)
{
JSConsole.Complier.Log('[JSSymbolData::RecvError] ajax error.',request.status);
throw {FunctionName:'RecvError', Request:request};
}
this.GetLatestDataKey=function(key)
{
var key=`DYNAINFO-${key}`;
return key;
}
//最新行情
this.GetLatestData=function(jobItem)
{
var aryArgs=this.JobArgumentsToArray(jobItem, 1);
var lID=aryArgs[0];
var key=this.GetLatestDataKey(lID);
if (this.LatestData.has(key)) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetLatestData', //类名::
Explain:'DYNAINFO()',
Args:aryArgs,
Request:{ Url:self.RealtimeApiUrl, Type:'POST' ,
Data: { symbol:[this.Symbol], field: ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","exchangerate","amplitude"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvLatestData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","exchangerate","amplitude"],
"symbol": [this.Symbol]
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvLatestData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvLatestData=function(data)
{
if (data.ver==2.0)
{
this.RecvLatestDataVer2(data);
return;
}
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
if (!stock) return;
if (IFrameSplitOperator.IsNumber(stock.yclose)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.YCLOSE,stock.yclose);
if (IFrameSplitOperator.IsNumber(stock.open)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.OPEN,stock.open);
if (IFrameSplitOperator.IsNumber(stock.high)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.HIGH,stock.high);
if (IFrameSplitOperator.IsNumber(stock.low)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.LOW,stock.low);
if (IFrameSplitOperator.IsNumber(stock.price)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.CLOSE,stock.price);
if (IFrameSplitOperator.IsNumber(stock.vol)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.VOL,stock.vol);
if (IFrameSplitOperator.IsNumber(stock.amount)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.AMOUNT,stock.amount);
if (IFrameSplitOperator.IsNumber(stock.increase)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.INCREASE,stock.increase);
if (IFrameSplitOperator.IsNumber(stock.exchangerate)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.EXCHANGERATE,stock.exchangerate);
if (IFrameSplitOperator.IsNumber(stock.amplitude)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.AMPLITUDE,stock.amplitude);
/*
this.LatestData={ Symbol:stock.symbol, Name:stock.name, Date:stock.date, Time:stock.time,
YClose:stock.yclose,Price:stock.price, Open:stock.open, High:stock.high, Low:stock.low, Vol:stock.vol, Amount:stock.amount,
Increase:stock.increase, Exchangerate:stock.exchangerate, Amplitude:stock.amplitude};
*/
JSConsole.Complier.Log('[JSSymbolData::RecvLatestData] symbol, LatestData', stock.symbol, this.LatestData);
}
//data:[{ id:, value: }]
this.RecvLatestDataVer2=function(data)
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return;
var symbol=data.symbol;
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
if (!item) continue;
if (!IFrameSplitOperator.IsNumber(item.id)) continue;
if (IFrameSplitOperator.IsNumber(item.value) || IFrameSplitOperator.IsString(item.value))
{
JSConsole.Complier.Log(`[JSSymbolData::RecvLatestDataVer2] symbol=${symbol} DYNAINFO(${item.id})=${item.value}.`);
this.LatestData.set(item.id, item.value);
}
}
JSConsole.Complier.Log('[JSSymbolData::RecvLatestDataVer2]', this.LatestData);
}
this.GetLatestCacheData=function(dataname)
{
if (this.LatestData.has(dataname)) return this.LatestData.get(dataname);
return null;
}
this.GetLatestIndexData=function()
{
if (this.LatestIndexData) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetLatestIndexData', //类名:: 函数
Explain:'最新大盘数据',
Request:{ Url:self.RealtimeApiUrl, Type:'POST' ,
Data: { symbol:['000001.sh'], field: ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","amplitude"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvLatestIndexData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","amplitude"],
"symbol": ['000001.sh']
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvLatestIndexData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvLatestIndexData=function(data)
{
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
this.LatestIndexData={ Symbol:stock.symbol, Name:stock.name, Date:stock.date, Time:stock.time,
YClose:stock.yclose,Price:stock.price, Open:stock.open, High:stock.high, Low:stock.low, Vol:stock.vol, Amount:stock.amount,
Increase:stock.increase, Amplitude:stock.amplitude};
JSConsole.Complier.Log('[JSSymbolData::RecvLatestIndexData]', this.LatestIndexData);
}
this.GetVolRateData=function(job,node)
{
var volrKey=job.ID.toString()+'-VolRate-'+this.Symbol;
if (this.ExtendData.has(volrKey)) return this.Execute.RunNextJob();
var self=this;
var dayCount=30;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var dayCount=1;
if (this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) dayCount=this.DayCount;
var obj=
{
Name:'JSSymbolData::GetVolRateData', //类名:: 函数
Explain:'分时量比数据(成交量)',
Request:
{
Url:self.KLineApiUrl, Type:'POST' ,
Data: { symbol:self.Symbol, dayCount:dayCount, field: ["name","symbol","vol"], period:0, right:0, dateRange:dateRange }
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
self.RecvVolRateData(recvData,volrKey);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": ["name","symbol","vol"],
"symbol": self.Symbol,
"start": -1,
"count": dayCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvVolRateData(recvData,volrKey);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvVolRateData=function(data,key)
{
var sumVol=0,avgVol5=0;
var mapAvgVol5=new Map();
if (data.Ver==2.0) // {Ver:2.0 , data:[ [日期,5日vol均值]] }
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return;
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
if (!IFrameSplitOperator.IsNonEmptyArray(item)) continue;
if (item.length<2) continue;
if (IFrameSplitOperator.IsNumber(item[0]) && IFrameSplitOperator.IsPlusNumber(item[1]))
{
mapAvgVol5.set(item[0],{ AvgVol5:item[1] } );
}
}
}
else
{
if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return;
var minuteCount=241;
if (IFrameSplitOperator.IsNumber(data.minutecount)) minuteCount=data.minutecount;
for(var i=0,j=0,dayCount=0;i<data.data.length;++i) //每天的5日成交均量
{
sumVol=0;
for(j=i,dayCount=0;j>=0 && dayCount<5;--j, ++dayCount)
{
var item=data.data[j];
if (IFrameSplitOperator.IsNumber(item[6]))
sumVol+=item[6];
}
if (dayCount>0)
{
avgVol5=sumVol/dayCount/minuteCount;
var item=data.data[i];
mapAvgVol5.set(item[0],
{
//for debug
//Vol5:sumVol, MinuteCount:minuteCount,,Count:dayCount,
AvgVol5:avgVol5
} );
}
}
}
if (mapAvgVol5.size>0) this.ExtendData.set(key,mapAvgVol5);
JSConsole.Complier.Log('[JSSymbolData::RecvVolRateData]', mapAvgVol5);
}
this.GetVolRateCacheData=function(node)
{
var key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA.toString()+'-VolRate-'+this.Symbol;
if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node,'不支持VOLR');
var result=[];
var mapAvgVol5=this.ExtendData.get(key);
var totalVol=0, preDate=0, avgVol5=null;
for(var i=0, j=0;i<this.Data.Data.length;++i)
{
result[i]=null;
var item=this.Data.Data[i];
if (preDate!=item.Date)
{
avgVol5=null;
j=0;
totalVol=0;
if (mapAvgVol5.has(item.Date))
{
var volItem=mapAvgVol5.get(item.Date);
avgVol5=volItem.AvgVol5;
}
preDate=item.Date;
}
if (avgVol5==null) continue;
totalVol+=item.Vol;
result[i]=totalVol/(j+1)/avgVol5*100;
++j;
}
return result;
}
//获取大盘指数数据
this.GetIndexData=function()
{
if (this.IndexData) return this.Execute.RunNextJob();
var self=this;
if (ChartData.IsDayPeriod(this.Period,true)) //请求日线数据 9=季线
{
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetIndexData', //类名::
Explain:'大盘数据',
Period:self.Period,
Request:
{
Url:self.KLineApiUrl, Type:'POST' ,
Data:
{
field:[ "name", "symbol","yclose","open","price","high","low","vol",'up','down','stop','unchanged'],
indexSymbol:"000001.sh", symbol: this.Symbol, period:this.Period,
dateRange:dateRange
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvIndexHistroyData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol",'up','down','stop','unchanged'],
"symbol": '000001.sh',
"start": -1,
"count": self.MaxRequestDataCount+500 //多请求2年的数据 确保股票剔除停牌日期以后可以对上
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvIndexHistroyData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (ChartData.IsMinutePeriod(this.Period, true)) //请求分钟数据
{
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetIndexData', //类名::
Explain:'大盘数据',
Period:self.Period,
Request:{ Url:self.MinuteKLineApiUrl, Type:'POST' ,
Data:
{
field:["name","symbol","yclose","open","price","high","low","vol"],
indexSymbol:"000001.sh", symbol: this.Symbol, period:this.Period,
dateRange:dateRange
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvIndexMinuteHistroyData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": '000001.sh',
"start": -1,
"count": self.MaxRequestMinuteDayCount+5
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvIndexMinuteHistroyData(data);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
}
this.RecvIndexHistroyData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvIndexHistroyData] recv data' , data);
let hisData=this.JsonDataToHistoryData(data);
this.IndexData=new ChartData();
this.IndexData.DataType=0; /*日线数据 */
this.IndexData.Data=hisData;
if (this.IsApiPeriod==true)
{
this.IndexData.Period=this.Period;
this.IndexData.Data=this.Data.FixKData(hisData,this.Period);
}
else
{
var aryOverlayData=this.SourceData.GetOverlayData(this.IndexData.Data); //和主图数据拟合以后的数据
this.IndexData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(this.Period,false)) //周期数据
{
let periodData=this.IndexData.GetPeriodData(this.Period);
this.IndexData.Data=periodData;
}
}
}
this.RecvIndexMinuteHistroyData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvIndexMinuteHistroyData] recv data' , data);
let hisData=this.JsonDataToMinuteHistoryData(data);
this.IndexData=new ChartData();
this.IndexData.DataType=1; /*分钟线数据 */
this.IndexData.Data=hisData;
if (this.IsApiPeriod==true)
{
this.IndexData.Period=this.Period;
this.IndexData.Data=this.Data.FixKData(hisData,this.Period);
}
else
{
if (ChartData.IsMinutePeriod(this.Period,false)) //周期数据
{
let periodData=this.IndexData.GetPeriodData(this.Period);
this.IndexData.Data=periodData;
}
}
}
this.GetOtherSymbolParam=function(name)
{
var args=name.split("$");
var setStockDataName=new Set(['CLOSE',"C",'VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
if (!setStockDataName.has(args[1])) return null;
var symbol=args[0];
if (symbol.length==6)
{
if (symbol[0]=="6" || symbol[0]=="5" || symbol[0]=="8" || symbol[0]=="9")
symbol+=".SH";
else if (symbol[0]=='0' || symbol[0]=='1' || symbol[0]=='2' || symbol[0]=='3')
symbol+='.SZ';
}
else if (symbol.indexOf("SZ")==0)
{
symbol=symbol.substr(2)+".SZ";
}
else if (symbol.indexOf("SH")==0)
{
symbol=symbol.substr(2)+".SH";
}
else if (symbol.indexOf("_")>0)
{
var arySymbol=symbol.split("_");
symbol=`${arySymbol[1]}.${arySymbol[0]}`;
}
else
return null;
return { Symbol:symbol.toLowerCase(), DataName:args[1] };
}
//获取其他股票数据
this.GetOtherSymbolData=function(job)
{
var symbol=this.Symbol;
if (job.Literal)
{
var args=this.GetOtherSymbolParam(job.Literal.toUpperCase());
if (!args)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.Literal} Error.`);
}
symbol=args.Symbol;
}
else
{
var args=job.Args;
if (args.length>0)
{
var item=args[0];
if (item.Type==Syntax.Literal)
{
symbol=item.Value;
}
else if (item.Type==Syntax.Identifier) //变量 !!只支持默认的变量值
{
var isFind=false;
for(var j in this.Arguments)
{
const argItem=this.Arguments[j];
if (argItem.Name==item.Name)
{
symbol=argItem.Value;
isFind=true;
break;
}
}
if (!isFind)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: can't read ${item.Name}`);
}
}
}
}
job.Symbol=symbol.toLowerCase();
if (job.Symbol==this.Symbol) return this.Execute.RunNextJob();
if (this.OtherSymbolData.has(job.Symbol)) return this.Execute.RunNextJob();
var self=this;
if (this.DataType==HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true)) //请求日线数据
{
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetOtherSymbolData', //类名::函数名
Explain:'指定个股数据',
Request:
{
Data:
{
symbol:job.Symbol,
right:self.Right,
period:self.Period,
dateRange:dateRange
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvOtherSymbolKData(data,job);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": job.Symbol,
"start": -1,
"count": self.MaxRequestDataCount+500 //多请求2年的数据 确保股票剔除停牌日期以后可以对上
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvOtherSymbolKDayData(recvData,job);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (ChartData.IsMinutePeriod(this.Period, true) || this.DataType==HQ_DATA_TYPE.MINUTE_ID || this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) //请求分钟数据
{
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetOtherSymbolData', //类名::函数名
Explain:'指定个股数据',
Request:
{
Data:
{
symbol:job.Symbol,
right:self.Right,
period:self.Period,
dateRange:dateRange
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvOtherSymbolKData(data,job);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": job.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount+5
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvOtherSymbolKMinuteData(data,job);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
}
//第3方数据对接
this.RecvOtherSymbolKData=function(data,job)
{
JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKData] recv data' , data);
var kData=new ChartData();
var hisData=null;
var period=this.Period;
if (this.DataType==HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true)) //日线数据
{
hisData=this.JsonDataToHistoryData(data);
kData.DataType=0;
}
else //分钟线数据
{
hisData=this.JsonDataToMinuteHistoryData(data);
kData.DataType=1;
//走势图使用1分钟K线模式
if (this.DataType==HQ_DATA_TYPE.MINUTE_ID || this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
period=4;
}
kData.Period=this.Period;
kData.Right=this.Right;
kData.Data=this.Data.FixKData(hisData,period);
this.OtherSymbolData.set(job.Symbol, kData);
}
this.RecvOtherSymbolKDayData=function(data,job)
{
JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKDayData] recv data' , data);
let hisData=this.JsonDataToHistoryData(data);
var kData=new ChartData();
kData.DataType=0; //日线数据
kData.Data=hisData;
var aryOverlayData=this.SourceData.GetOverlayData(kData.Data); //和主图数据拟合以后的数据
kData.Data=aryOverlayData;
if (ChartData.IsDayPeriod(this.Period,false)) //周期数据
{
let periodData=kData.GetPeriodData(this.Period);
kData.Data=periodData;
}
this.OtherSymbolData.set(job.Symbol, kData);
}
this.RecvOtherSymbolKMinuteData=function(data, job)
{
JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKMinuteData] recv data' , data);
let hisData=this.JsonDataToMinuteHistoryData(data);
var kData=new ChartData();
kData.DataType=1; /*分钟线数据 */
kData.Data=hisData;
if (ChartData.IsMinutePeriod(this.Period,false)) //周期数据
{
let periodData=kData.GetPeriodData(this.Period);
kData.Data=periodData;
}
this.OtherSymbolData.set(job.Symbol, kData);
}
this.GetOtherSymolCacheData=function(obj)
{
var symbol,dataName;
if (obj.FunctionName)
{
dataName=obj.FunctionName;
var args=obj.Args;
if (args.length<=0) return this.GetSymbolCacheData(dataName);
symbol=args[0].toString().toLowerCase();
}
else if (obj.Literal)
{
var args=this.GetOtherSymbolParam(obj.Literal.toUpperCase());
if (!args) return [];
symbol=args.Symbol;
dataName=args.DataName;
}
if (symbol==this.Symbol) return this.GetSymbolCacheData(dataName);
if (!this.OtherSymbolData.has(symbol)) return [];
var kData=this.OtherSymbolData.get(symbol);
var upperSymbol=symbol.toUpperCase();
switch(dataName)
{
case 'CLOSE':
case 'C':
return kData.GetClose();
case 'VOL':
case 'V':
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol))
return kData.GetVol(100); //A股的 把股转成手
return kData.GetVol();
case 'OPEN':
case 'O':
return kData.GetOpen();
case 'HIGH':
case 'H':
return kData.GetHigh();
case 'LOW':
case 'L':
return kData.GetLow();
case 'AMOUNT':
case 'AMO':
return kData.GetAmount();
case 'VOLINSTK':
return kData.GetPosition();
}
}
//获取大盘指数缓存数据
this.GetIndexCacheData=function(dataName)
{
if (!this.IndexData) return new Array();
switch(dataName)
{
case 'INDEXA':
return this.IndexData.GetAmount();
case 'INDEXC':
return this.IndexData.GetClose();
case 'INDEXH':
return this.IndexData.GetHigh();
case 'INDEXL':
return this.IndexData.GetLow();
case 'INDEXO':
return this.IndexData.GetOpen();
case 'INDEXV':
return this.IndexData.GetVol();
case 'INDEXADV':
return this.IndexData.GetUp();
case 'INDEXDEC':
return this.IndexData.GetDown();
}
}
//指数转成对应的板块
this.GetBlockSymbol=function(symbol)
{
//中文对应板块代码
const BLOCK_CN_NAME_MAP=new Map([ ["沪深A股","CNA.ci"], ["创业板","GEM.ci"], ["沪市A股","SHA.ci"], ["中小板","SME.ci"], ["深市A股","SZA.ci"] ]);
if (BLOCK_CN_NAME_MAP.has(symbol)) return BLOCK_CN_NAME_MAP.get(symbol);
if (!symbol) return null;
var blockSymbol=null;
var upperSymbol=symbol.toUpperCase();
if (upperSymbol.indexOf('.SH')>0 || upperSymbol.indexOf('.SZ')>0 )
{
const INDEX_SYMBOL_SET=new Set(["000001.SH", "000003.SH", "000016.SH", "000300.SH", "000905.SH", "399001.SZ", " 399005.SZ", "399006.SZ"]);
if (!INDEX_SYMBOL_SET.has(upperSymbol)) return null;
blockSymbol=symbol.replace('.SH','.sh');
blockSymbol=symbol.replace('.SZ','.sz');
}
else if (symbol.indexOf('.CI')>0)
{
blockSymbol=symbol.replace('.CI','.ci');
}
/*
const SYMBOL_TO_BLOCK_MAP=new Map([
["000001.SH","SME.ci"],
["399001.SZ","SZA.ci"],["399001.SZ"," GEM.ci"],["399005.SZ","SME.ci"]
]);
if (SYMBOL_TO_BLOCK_MAP.has(upperSymbol)) return SYMBOL_TO_BLOCK_MAP.get(upperSymbol);
if(upperSymbol.indexOf('.CI')<0) return null;
*/
return blockSymbol;
}
//分钟涨幅股票个数统计数据下载
this.GetIndexIncreaseData=function(job)
{
var symbol=null;
if (job.IsSelfSymbol)
{
symbol=this.Symbol;
}
else
{
if (!job.Args || job.Args.length<=0)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName} Error: 参数不能为空`);
}
symbol=job.Args[0].Value;
}
var blockSymbol=this.GetBlockSymbol(symbol);
if (!blockSymbol)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName} Error: can't support ${symbol}`);
}
var upKey=job.ID.toString()+'-UpCount-'+blockSymbol;
var downKey=job.ID.toString()+'-DownCount-'+blockSymbol;
if (this.ExtendData.has(upKey) && this.ExtendData.has(downKey)) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var dataType={Type: this.DataType};
if (this.DataType===HQ_DATA_TYPE.KLINE_ID) dataType.Period=this.Period;
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetIndexIncreaseData', //类名::
Explain:'涨停家数统计',
DateRange:dateRange,
DataType:dataType,
Request:{ Url:'数据地址', Type:'POST' ,
Data: { symbol:this.Symbol, blocksymbol:blockSymbol, field: ["up", "down"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
if (this.DataType===HQ_DATA_TYPE.KLINE_ID) this.RecvHistoryIncreaseDataV2(data, {UpKey:upKey,DownKey:downKey});
else this.RecvMinuteIncreaseDataV2(data, {UpKey:upKey,DownKey:downKey});
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID || this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) //走势图数据
{
var apiUrl=g_JSComplierResource.CacheDomain+'/cache/analyze/increaseanalyze/'+blockSymbol+'.json';
JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] minute Get url=' , apiUrl);
JSNetwork.HttpRequest({
url: apiUrl,
type:"get",
dataType: "json",
async:true,
success: function (data)
{
self.RecvMinuteIncreaseData(data, {UpKey:upKey,DownKey:downKey});
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (this.DataType===HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true)) //K线图 日线
{
JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] K day Get url=' , self.KLineApiUrl);
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"symbol": blockSymbol,
"start": -1,
"count": self.MaxRequestDataCount,
"field":['up', 'down']
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvHistoryIncreaseData(data, {UpKey:upKey,DownKey:downKey});
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else
{
this.Execute.RunNextJob();
}
}
//格式{ ver:2.0 data:[{date, time, up, down}, .....]}
this.RecvHistoryIncreaseDataV2=function(data,key)
{
JSConsole.Complier.Log('[JSSymbolData::RecvHistoryIncreaseData] recv data, key' , data,key);
var upData=[],downData=[];
for(var i in data.data)
{
var item=data.data[i];
let upItem=new SingleData();
let downItem=new SingleData();
var date=item[0];
var time=null;
upItem.Date=date;
downItem.Date=date;
if (ChartData.IsMinutePeriod(this.Period,true) && IFrameSplitOperator.IsNumber(item[1]))
{
time=item[1];
upItem.Time=time;
downItem.Time=time;
}
upItem.Value=item[2];
upData[i]=upItem;
downItem.Value=item[3];
downData[i]=downItem;
}
var upFixedData=this.Data.GetFittingData2(upData,0);
var downFixedData=this.Data.GetFittingData2(downData,0);
this.ExtendData.set(key.UpKey,upFixedData);
this.ExtendData.set(key.DownKey,downFixedData);
}
this.RecvHistoryIncreaseData=function(data,key)
{
JSConsole.Complier.Log('[JSSymbolData::RecvHistoryIncreaseData] recv data' , data);
var upData=[],downData=[];
for(var i in data.data)
{
var item=data.data[i];
let upItem=new SingleData();
let downItem=new SingleData();
upItem.Date=item[0];
upItem.Value=item[8];
upData[i]=upItem;
downItem.Date=item[0];
downItem.Value=item[9];
downData[i]=downItem;
}
var upFixedData, downFixedData;
if (this.SourceData) upFixedData=this.SourceData.GetFittingData(upData);
else upFixedData=this.Data.GetFittingData(aryData);
if (this.SourceData) downFixedData=this.SourceData.GetFittingData(downData);
else downFixedData=this.Data.GetFittingData(aryData);
this.ExtendData.set(key.UpKey,upFixedData);
this.ExtendData.set(key.DownKey,downFixedData);
}
this.RecvMinuteIncreaseDataV2=function(data, key)
{
JSConsole.Complier.Log('[JSSymbolData::RecvMinuteIncreaseDataV2] recv data, key' , data, key);
}
this.RecvMinuteIncreaseData=function(data,key)
{
JSConsole.Complier.Log('[JSSymbolData::RecvMinuteIncreaseData] recv data' , data);
if (!data.minute) return;
var minuteData=data.minute;
if (!minuteData.time || !minuteData.up || !minuteData.down) return;
var upData=[],downData=[];
if (this.IsBeforeData)
{
for(var i=0, j=0;i<this.Data.Data.length;++i)
{
upData[i]=null;
downData[i]=null;
var item=this.Data.Data[i];
if (item.Before) continue; //盘前数据
var dateTime=item.DateTime; //日期加时间
if (!dateTime) continue;
var aryValue=dateTime.split(' ');
if (aryValue.length!=2) continue;
var date=parseInt(aryValue[0]);
if (date!=data.date) continue;
upData[i]=minuteData.up[j];
downData[i]=minuteData.down[j];
++j;
}
}
else
{
for(var i=0, j=0;i<this.Data.Data.length;++i)
{
upData[i]=null;
downData[i]=null;
var item=this.Data.Data[i];
var dateTime=item.DateTime; //日期加时间
if (!dateTime) continue;
var aryValue=dateTime.split(' ');
if (aryValue.length!=2) continue;
var date=parseInt(aryValue[0]);
if (date!=data.date) continue;
upData[i]=minuteData.up[j];
downData[i]=minuteData.down[j];
++j;
}
}
this.ExtendData.set(key.UpKey,upData);
this.ExtendData.set(key.DownKey,downData);
}
//分钟涨幅股票个数统计数据
this.GetIndexIncreaseCacheData=function(funcName,symbol,node)
{
var blockSymbol=this.GetBlockSymbol(symbol);
if (!blockSymbol) this.Execute.ThrowUnexpectedNode(node,'不支持函数'+funcName+'('+symbol+')');
var key;
if (funcName=='UPCOUNT' || funcName=='ADVANCE') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-UpCount-'+blockSymbol;
else if (funcName=='DOWNCOUNT' || funcName=='DECLINE') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-DownCount-'+blockSymbol;
if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node,'不支持函数'+funcName+'('+symbol+')');
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID || this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) //分时图
{
return this.ExtendData.get(key);
}
else if (this.DataType===HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true)) //K线图
{
var data=this.ExtendData.get(key);
var bindData=new ChartData();
bindData.Data=data;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
return bindData.GetValue();
}
else
{
return null;
}
}
this.GetSymbolData=function()
{
if (this.Data) return this.Execute.RunNextJob();
let self=this;
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID) //当天分钟数据
{
JSNetwork.HttpRequest({
url: self.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","minute","time","minutecount"],
"symbol": [self.Symbol],
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMinuteData(recvData);
self.Execute.RunNextJob();
}
});
return;
}
if (this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
{
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:
{
"symbol": self.Symbol,
"daycount": self.DayCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMultiDayMinuteData(recvData);
self.Execute.RunNextJob();
}
});
return;
}
if (ChartData.IsDayPeriod(this.Period,true)) //请求日线数据
{
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetSymbolData',
Explain:"日线数据",
Request:
{ Url:self.RealtimeApiUrl, Type:'POST' ,
Data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount,
"period":this.Period,
"right":this.Right
}
},
Self:this,
PreventDefault:false
};
if (this.KLineDateTimeRange)
{
obj.Request.KLineDataTimeRange={Start:{ Date:this.KLineDateTimeRange.Start.Date}, End:{ Date:this.KLineDateTimeRange.End.Date} };
if (this.IsNumber(this.KLineDateTimeRange.Start.Time)) obj.Request.KLineDataTimeRange.Start.Time=this.KLineDateTimeRange.Start.Time;
if (this.IsNumber(this.KLineDateTimeRange.End.Time)) obj.Request.KLineDataTimeRange.End.Time=this.KLineDateTimeRange.End.Time;
}
this.NetworkFilter(obj, function(data)
{
self.RecvHistroyData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvHistroyData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (ChartData.IsMinutePeriod(this.Period, true) || ChartData.IsSecondPeriod(this.Period) || ChartData.IsMilliSecondPeriod(this.Period)) //请求分钟数据
{
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetSymbolData',
Explain:"分钟K线数据",
Request:
{ Url:self.MinuteKLineApiUrl, Type:'POST' ,
Data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount,
"period":this.Period,
"right":this.Right
}
},
Self:this,
PreventDefault:false
};
if (this.KLineDateTimeRange)
{
obj.Request.KLineDataTimeRange={Start:{ Date:this.KLineDateTimeRange.Start.Date}, End:{ Date:this.KLineDateTimeRange.End.Date} };
if (this.IsNumber(this.KLineDateTimeRange.Start.Time)) obj.Request.KLineDataTimeRange.Start.Time=this.KLineDateTimeRange.Start.Time;
if (this.IsNumber(this.KLineDateTimeRange.End.Time)) obj.Request.KLineDataTimeRange.End.Time=this.KLineDateTimeRange.End.Time;
}
this.NetworkFilter(obj, function(data)
{
self.RecvMinuteHistroyData(data);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvMinuteHistroyData(data);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
}
this.RecvHistroyData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvHistroyData] recv data' , data);
let hisData=this.JsonDataToHistoryData(data);
this.Data=new ChartData();
this.Data.DataType=0; /*日线数据 */
this.Data.Data=hisData;
this.SourceData=new ChartData;
this.SourceData.Data=hisData;
if (this.IsApiPeriod) //后台周期 前端不处理
{
}
else
{
if (this.Right>0) //复权
{
let rightData=this.Data.GetRightData(this.Right);
this.Data.Data=rightData;
}
if (ChartData.IsDayPeriod(this.Period,false)) //周期数据
{
let periodData=this.Data.GetPeriodData(this.Period);
this.Data.Data=periodData;
}
}
this.Data.Right=this.Right;
this.Data.Period=this.Period;
this.Name=data.name;
}
this.RecvMinuteHistroyData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvMinuteHistroyData] recv data' , data);
let hisData=this.JsonDataToMinuteHistoryData(data);
this.Data=new ChartData();
this.Data.DataType=1; /*分钟线数据 */
this.Data.Data=hisData;
this.SourceData=new ChartData;
this.SourceData.Data=hisData;
if (this.IsApiPeriod) //后台周期 前端不处理
{
}
else
{
if (ChartData.IsMinutePeriod(this.Period,false)) //周期数据
{
let periodData=this.Data.GetPeriodData(this.Period);
this.Data.Data=periodData;
}
}
this.Data.Period=this.Period;
this.Name=data.name;
}
//最新的分钟数据走势图
this.RecvMinuteData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvMinuteData] recv data' , data);
var aryMinuteData=this.JsonDataToMinuteData(data);
this.Data=new ChartData();
this.Data.DataType=2; /*分钟走势图数据 */
this.Data.Data=aryMinuteData;
this.Name=data.stock[0].name;
}
this.RecvMultiDayMinuteData=function(data)
{
var aryMinuteData=this.JsonDataToMultiDayMinuteData(data);
this.Data=new ChartData();
this.Data.DataType=2; /*分钟走势图数据 */
this.Data.Data=aryMinuteData;
this.Name=data.name;
}
this.GetSymbolCacheData=function(dataName)
{
if (!this.Data) return new Array();
var upperSymbol=this.Symbol.toUpperCase();
switch(dataName)
{
case 'CLOSE':
case 'C':
return this.Data.GetClose();
case 'VOL':
case 'V':
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol) && this.DataType==HQ_DATA_TYPE.KLINE_ID) //!! A股K线量单位时股,分时图单位还是手
return this.Data.GetVol(100); //A股的 把股转成手
return this.Data.GetVol();
case 'OPEN':
case 'O':
return this.Data.GetOpen();
case 'HIGH':
case 'H':
return this.Data.GetHigh();
case 'LOW':
case 'L':
return this.Data.GetLow();
case 'AMOUNT':
case 'AMO':
return this.Data.GetAmount();
case "OPI": //文华 持仓量
case 'VOLINSTK': //通达信 持仓量
return this.Data.GetPosition();
case "ZSTJJ": //均价
return this.Data.GetAvPrice();
case "SETTLE": //文华 结算价
case "QHJSJ": //通达信 结算价
return this.Data.GetSettlementPrice(); //结算价
case "ISEQUAL": //平盘
return this.Data.GetIsEqual();
case "ISUP": //收阳
return this.Data.GetIsUp();
case "ISDOWN": //收阴
return this.Data.GetIsDown();
}
}
this.GetSymbolPeriodData=function(job)
{
var periodID=JSComplierHelper.GetPeriodInfo({ Name:job.PeriodName }).Period;
var periodInfo={ PeriodID:periodID, PeriodName:job.PeriodName };
//同周期不请求
if (periodID==this.Period) this.Execute.RunNextJob();
if (this.IsApiPeriod)
{
if (this.PeriodData.has(job.PeriodName)) return this.Execute.RunNextJob();
}
else
{
if (ChartData.IsDayPeriod(periodID,true))
{
if (ChartData.IsDayPeriod(this.Period,true)) return this.Execute.RunNextJob();
periodInfo={PeriodID:0, PeriodName:'DAY' };
}
else if (ChartData.IsMinutePeriod(periodID,true))
{
if (ChartData.IsMinutePeriod(this.Period,true)) return this.Execute.RunNextJob();
periodInfo={ PeriodID:4, PeriodName:"MIN1" };
}
else
{
return this.Execute.RunNextJob();
}
}
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetSymbolPeriodData',
Explain:"跨周期数据",
Request:
{
Data:
{
"field": [ 'symbol','name', job.ValueName ],
"period":job.PeriodName,
"symbol": self.Symbol,
}
},
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvSymbolPeriodData(data, periodInfo);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
if (ChartData.IsMinutePeriod(periodID,true))
{
JSNetwork.HttpRequest({
url: this.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvSymbolPeriodData(data,periodInfo);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (ChartData.IsDayPeriod(periodID,true))
{
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvSymbolPeriodData(data, periodInfo);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else
{
return this.Execute.RunNextJob();
}
}
this.RecvSymbolPeriodData=function(data, periodInfo)
{
JSConsole.Complier.Log('[JSSymbolData::RecvSymbolPeriodData] data, periodInfo ' , data, periodInfo);
if (ChartData.IsDayPeriod(periodInfo.PeriodID,true))
{
var hisData=this.JsonDataToHistoryData(data);
var dayData=new ChartData();
dayData.DataType=0; //日线数据
dayData.Data=hisData; //保存原始数据 不复权
dayData.Right=0;
dayData.Period=periodInfo.PeriodID;
this.PeriodData.set(periodInfo.PeriodName, dayData);
}
else if (ChartData.IsMinutePeriod(periodInfo.PeriodID,true))
{
var hisData=this.JsonDataToMinuteHistoryData(data);
var minData=new ChartData();
minData.DataType=1; //分钟线数据
minData.Data=hisData;
minData.Right=0;
minData.Period=periodInfo.PeriodID;
this.PeriodData.set(periodInfo.PeriodName, minData);
}
}
this.GetSymbolPeriodCacheData=function(valueName,periodName)
{
var periodInfo=JSComplierHelper.GetPeriodInfo({Name:periodName});
if (this.Period==periodInfo.Period)
return this.GetSymbolCacheData(valueName);
var hisData=null;
if (this.IsApiPeriod)
{
var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
if (!curPeriodInfo) return null;
if (curPeriodInfo.Order>periodInfo.Order) return null; //只能小周期转大周期
if (!this.PeriodData.has(periodName)) return null;
hisData=this.PeriodData.get(periodName);
hisData=hisData.Data;
}
else
{
var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
if (!curPeriodInfo) return null;
if (curPeriodInfo.Order>periodInfo.Order) return null; //只能小周期转大周期
if (ChartData.IsDayPeriod(periodInfo.Period,true) && ChartData.IsMinutePeriod(this.Period,true))
{
var dayData=this.PeriodData.get('DAY'); //日线
if (periodInfo.Period==0) hisData=dayData.Data;
else hisData=dayData.GetPeriodData(periodInfo.Period); //日线周期
}
else
{
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (ChartData.IsDayPeriod(periodInfo.Period,true) && bindData.Right>0) //日线数据才复权
{
var rightData=bindData.GetRightData(bindData.Right);
bindData.Data=rightData;
}
hisData=bindData.GetPeriodData(periodInfo.Period);
}
}
var data=this.Data.ConverPeriod(hisData, this.Period, periodInfo.Period);
var result=new ChartData();
result.Data=data;
var upperSymbol=this.Symbol.toUpperCase();
switch(valueName)
{
case 'C':
case "CLOSE":
return result.GetClose();
case 'O':
case "OPEN":
return result.GetOpen();
case 'H':
case "HIGH":
return result.GetHigh();
case 'L':
case "LOW":
return result.GetLow();
case 'AMO':
case "AMOUNT":
return result.GetAmount();
case 'V':
case "VOL":
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol))
return result.GetVol(100);
return result.GetVol();
case "VOLINSTK":
return result.GetPosition();
default:
return null;
}
}
this.GetSymbolPeriodCacheData2=function(valueName,periodName,n)
{
var periodInfo=JSComplierHelper.GetPeriodInfo({Name:periodName});
if (!periodInfo) return null;
var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
if (!curPeriodInfo) return null;
if (curPeriodInfo.Order>periodInfo.Order) return null; //只能小周期转大周期
var result;
if (curPeriodInfo.Period==periodInfo.Period)
{
result=this.Data;
}
else
{
var hisData;
if (this.IsApiPeriod)
{
if (!this.PeriodData.has(periodName)) return null;
hisData=this.PeriodData.get(periodName);
}
else
{
if (ChartData.IsMinutePeriod(curPeriodInfo.Period,true) && ChartData.IsDayPeriod(periodInfo.Period,true))
{
var dayData=this.PeriodData.get('DAY'); //日线
if (periodInfo.Period==0) hisData=dayData;
else hisData=dayData.GetPeriodData(periodInfo.Period); //日线周期
}
else
{
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (ChartData.IsDayPeriod(periodInfo.Period,true) && bindData.Right>0) //日线数据才复权
{
var rightData=bindData.GetRightData(bindData.Right);
bindData.Data=rightData;
}
hisData=bindData.GetPeriodData(periodInfo.Period);
}
}
var data=this.Data.ConverPeriod(hisData, this.Period, periodInfo.Period);
var result=new ChartData();
result.Data=data;
}
if (IFrameSplitOperator.IsPlusNumber(n))
{
var refResult=new ChartData();
var data=result.GetRef(n);
refResult.Data=data;
result=refResult;
}
var upperSymbol=this.Symbol.toUpperCase();
switch(valueName)
{
case 'C':
case "CLOSE":
return result.GetClose();
case 'O':
case "OPEN":
return result.GetOpen();
case 'H':
case "HIGH":
return result.GetHigh();
case 'L':
case "LOW":
return result.GetLow();
case 'AMO':
case "AMOUNT":
return result.GetAmount();
case 'V':
case "VOL":
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol))
return result.GetVol(100);
return result.GetVol();
case "VOLINSTK":
return result.GetPosition();
default:
return null;
}
}
this.GetCurrBarsCount=function()
{
let result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
let lCount=this.Data.Data.length;
for(let i=lCount-1;i>=0;--i)
result.push(i+1); //数据从0开始
return result;
}
//BARPOS 返回从第一根K线开始到当前的周期数。
//注:
//1、BARPOS返回本地已有的K线根数,从本机上存在的数据开始算起。
//2、本机已有的第一根K线上返回值为1。
this.GetBarPos=function()
{
let result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
let lCount=this.Data.Data.length;
for(let i=0;i<lCount;++i)
result.push(i+1);
return result;
}
this.GetTotalTradeMinuteCount=function()
{
var data=g_MinuteCoordinateData.GetCoordinateData(this.Symbol);
if (data && data.Count>0) return data.Count-1;
return 242;
}
this.GetTotalBarsCount=function()
{
let lCount=this.Data.Data.length;
return lCount;
}
this.GetIsLastBar=function()
{
let result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result
let lCount=this.Data.Data.length;
for(let i=0;i<lCount;++i)
{
if (i==lCount-1) result.push(1);
else result.push(0);
}
return result;
}
//BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.
//例如:BARSTATUS=2表示当天是该数据的最后一个周期.
this.GetBarStatus=function()
{
let result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result
let lCount=this.Data.Data.length;
for(var i=0 ;i<lCount;++i)
{
if (i==0) result[i]=1;
else if (i==lCount-1) result[i]=2;
else result[i]=0;
}
return result;
}
//求真实波幅, (最高-最低),(最高-昨收),(最低-昨收)三者绝对值中的最大值.
//用法:
//TR,求真实波幅.
//例如:ATR:=MA(TR,10);
//表示求真实波幅的10周期均值
this.GetTRData=function(node)
{
var result=[];
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return result;
let lCount=this.Data.Data.length;
for(var i=0 ;i<lCount;++i)
{
var item=this.Data.Data[i];
var max=null;
if (IFrameSplitOperator.IsNumber(item.High) && IFrameSplitOperator.IsNumber(item.Low))
{
var value=Math.abs(item.High-item.Low);
if (max==null || max<value) max=value;
}
if (IFrameSplitOperator.IsNumber(item.High) && IFrameSplitOperator.IsNumber(item.YClose))
{
var value=Math.abs(item.High-item.YClose);
if (max==null || max<value) max=value;
}
if (IFrameSplitOperator.IsNumber(item.YClose) && IFrameSplitOperator.IsNumber(item.Low))
{
var value=Math.abs(item.Low-item.YClose);
if (max==null || max<value) max=value;
}
result[i]=max;
}
return result;
}
//融资融券函数
this.GetMarginCacheData=function(id, node)
{
let jobID=JS_EXECUTE_JOB_ID.GetMarginJobID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持MARGIN('+id+')');
if(this.MarginData.has(jobID)) return this.MarginData.get(jobID);
return [];
}
//下融资融券
this.GetMarginData=function(jobID)
{
if (this.MarginData.has(jobID)) return this.Execute.RunNextJob();
JSConsole.Complier.Log('[JSSymbolData::GetMarginData] jobID=', jobID);
var self=this;
let fieldList=["name","date","symbol"];
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE: //融资融券余额
fieldList.push("margin.balance");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE: //融资占比
fieldList.push("margin.rate");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入
fieldList.push("margin.buy");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出
fieldList.push("margin.sell");
break;
}
//请求数据
JSNetwork.HttpRequest({
url: this.StockHistoryDayApiUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"orderfield":"date"
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMarginData(recvData,jobID);
self.Execute.RunNextJob();
}
});
}
this.RecvMarginData=function(data,jobID)
{
JSConsole.Complier.Log(data);
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
var aryData=new Array();
var aryData2=[], aryData3=[], aryData4=[]; //其他3个数据
for(let i in stock.stockday)
{
var item=stock.stockday[i];
var marginData=item.margin;
if (!marginData) continue;
let indexData=new SingleData();
indexData.Date=item.date;
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE:
if (!this.IsNumber(marginData.balance)) continue;
indexData.Value=marginData.balance; //融资融券余额
aryData.push(indexData);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE:
if (!this.IsNumber(marginData.rate)) continue;
indexData.Value=marginData.rate; //融资占比
aryData.push(indexData);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入
var buyData=marginData.buy;
if (!buyData) continue;
if (!this.IsNumber(buyData.balance) || !this.IsNumber(buyData.amount) || !this.IsNumber(buyData.repay) || !this.IsNumber(buyData.net)) continue;
indexData.Value=buyData.balance;
var indexData2=new SingleData();
indexData2.Date=item.date;
indexData2.Value=buyData.amount;
var indexData3=new SingleData();
indexData3.Date=item.date;
indexData3.Value=buyData.repay;
var indexData4=new SingleData();
indexData4.Date=item.date;
indexData4.Value=buyData.net;
aryData.push(indexData);
aryData2.push(indexData2);
aryData3.push(indexData3);
aryData4.push(indexData4);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出
var sellData=marginData.sell;
if (!sellData) continue;
if (!this.IsNumber(sellData.balance) || !this.IsNumber(sellData.volume) || !this.IsNumber(sellData.repay) || !this.IsNumber(sellData.net)) continue;
indexData.Value=buyData.balance;
var indexData2=new SingleData();
indexData2.Date=item.date;
indexData2.Value=buyData.volume;
var indexData3=new SingleData();
indexData3.Date=item.date;
indexData3.Value=buyData.repay;
var indexData4=new SingleData();
indexData4.Date=item.date;
indexData4.Value=buyData.net;
aryData.push(indexData);
aryData2.push(indexData2);
aryData3.push(indexData3);
aryData4.push(indexData4);
break;
default:
continue;
}
}
var allData=[];
if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE)
{
allData.push({JobID:jobID,Data:aryData});
}
else if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT ||
jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET)
{
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE,Data:aryData});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT,Data:aryData2});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY,Data:aryData3});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET,Data:aryData4});
}
else if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME ||
jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET)
{
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE,Data:aryData});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME,Data:aryData2});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY,Data:aryData3});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET,Data:aryData4});
}
for(let i in allData)
{
let aryFixedData=this.SourceData.GetFittingData(allData[i].Data);
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
let data=bindData.GetValue();
this.MarginData.set(allData[i].JobID,data);
}
}
this.GetNewsAnalysisCacheData=function(id,node)
{
let jobID=JS_EXECUTE_JOB_ID.GetNewsAnalysisID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持NEWS('+id+')');
if(this.NewsAnalysisData.has(jobID)) return this.NewsAnalysisData.get(jobID);
return [];
}
this.GetHKToSHSZData=function(job)
{
var args=job.Args;
var code=this.Symbol;
if (args.length>0)
{
var item=args[0];
if (item.Type==Syntax.Literal)
{
code=item.Value;
}
else if (item.Type==Syntax.Identifier) //变量 !!只支持默认的变量值
{
var isFind=false;
for(var j in this.Arguments)
{
const argItem=this.Arguments[j];
if (argItem.Name==item.Name)
{
code=argItem.Value;
isFind=true;
break;
}
}
if (!isFind)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`HK2SHSZ() Error: can't read ${item.Name}`);
}
}
}
job.Symbol=code;
if (code==1 || code==2 || code==3) //下载全市场数据
this.GetHKToSHSZMarketData(code,job);
else
this.GetHKToSHSZStockData(code,job); //下载个股数据
}
this.GetHKToSHSZStockData=function(symbol,job)
{
if (this.HKToSHSZData.has(symbol)) return this.Execute.RunNextJob();
var upperSymbol=symbol.toLowerCase(); //代码小写
var self=this;
var url=`${this.HKToSHSZApiUrl[3]}/${upperSymbol}.json`;
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvHKToSHSZStockData(recvData,job);
self.Execute.RunNextJob();
},
error:function(request)
{
console.warn(`[JSSymbolData::GetHKToSHSZStockData] request url=${url} failed. error=${request.status}`);
self.RecvHKToSHSZStockData(null,job);
self.Execute.RunNextJob();
}
});
}
this.RecvHKToSHSZStockData=function(data,job)
{
if (!data) return;
var symbol=data.symbol;
var upperSymbol=symbol.toUpperCase();
var aryData=[];
for(var i=0;i<data.date.length;++i)
{
var item=new SingleData();
item.Date=data.date[i];
item.Value=data.vol[i]; //股
aryData.push(item);
}
var aryFixedData=this.Data.GetFittingData(aryData);
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
var data=bindData.GetValue();
this.HKToSHSZData.set(upperSymbol,data);
}
this.GetHKToSHSZMarketData=function(symbol,job)
{
if (this.HKToSHSZData.has(symbol)) return this.Execute.RunNextJob();
var url, dataType=0;
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID) dataType=1;
else if (this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) dataType=2;
else if (this.Period<=3) dataType=0;
url=this.HKToSHSZApiUrl[dataType];
var self=this;
JSConsole.Complier.Log(`[JSSymbolData::GetHKToSHSZMarketData] code=${symbol} url=${url}, dataType=${dataType}`);
if (dataType===2) //多日分时数据 (取这个股票的多日日期对应的北上数据)
{
//请求数据
JSNetwork.HttpRequest({
url: url,
data:
{
"symbol": this.Symbol,
'daycount': this.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMulitMinuteHKToSHSZData(recvData,job);
self.Execute.RunNextJob();
}
});
}
else
{
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
if (dataType==0) self.RecvHKToSHSZData(recvData,job);
else if (dataType==1) self.RecvMinuteHKToSHSZData(recvData,job);
self.Execute.RunNextJob();
}
});
}
}
this.RecvMinuteHKToSHSZData=function(data,job)
{
var arySHSZData=[], arySHData=[], arySZData=[];
if (this.IsBeforeData)
{
for( i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (item.Before)
{
arySHSZData.push(null);
arySHData.push(null);
arySZData.push(null);
}
else
{
break;
}
}
for(var i=0;i<data.time.length;++i)
{
var time=data.time[i];
if (time===925) continue;
var SHValue=data.hk2sh[i];
var SZValue=data.hk2sz[i];
var total=SHValue+SZValue;
arySHSZData.push(total);
arySHData.push(SHValue);
arySZData.push(SZValue);
}
}
else
{
for(var i=0;i<data.time.length;++i)
{
var time=data.time[i];
var SHValue=data.hk2sh[i];
var SZValue=data.hk2sz[i];
var total=SHValue+SZValue;
arySHSZData.push(total);
arySHData.push(SHValue);
arySZData.push(SZValue);
}
}
var allData=
[
{Data:arySHSZData, ID:1},
{Data:arySHData,ID:2},
{Data:arySZData,ID:3}
];
for(var i in allData)
{
var item=allData[i];
this.HKToSHSZData.set(item.ID,item.Data);
}
}
this.RecvHKToSHSZData=function(data,job)
{
var arySHSZData=[], arySHData=[], arySZData=[];
for(var i=0;i<data.date.length;++i)
{
var date=data.date[i];
var SHValue=data.hk2sh[i]*1000000; //单位是百万
var SZValue=data.hk2sz[i]*1000000; //单位是百万
var total=SHValue+SZValue;
let itemSHSZData=new SingleData();
itemSHSZData.Date=date;
itemSHSZData.Value=total;
let itemSHData=new SingleData();
itemSHData.Date=date;
itemSHData.Value=SHValue;
let itemSZData=new SingleData();
itemSZData.Date=date;
itemSZData.Value=SZValue;
arySHSZData.push(itemSHSZData);
arySHData.push(itemSHData);
arySZData.push(itemSZData);
}
var allData=
[
{Data:arySHSZData, ID:1},
{Data:arySHData,ID:2 },
{Data:arySZData,ID:3 }
];
for(let i in allData)
{
let aryFixedData=this.Data.GetFittingData(allData[i].Data);
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
let data=bindData.GetValue();
this.HKToSHSZData.set(allData[i].ID,data);
}
}
this.RecvMulitMinuteHKToSHSZData=function(data,job) //多日分时图北上资金
{
if (!data.data || data.data.length<=0) return;
var arySHSZData=[], arySHData=[], arySZData=[];
for(var i=0 ,j=0;i<this.Data.Data.length && j<data.data.length; )
{
arySHSZData[i]=null;
arySHData[i]=null;
arySZData[i]=null;
var item=this.Data.Data[i];
var dateTime=item.DateTime; //日期加时间
if (!dateTime)
{
++i;
continue;
}
var aryValue=dateTime.split(' ');
if (aryValue.length!=2)
{
++i;
continue;
}
var date=parseInt(aryValue[0]);
var day=data.data[j];
if (!day.minute || day.minute.length<=0)
{
++j;
continue;
}
if (day.date>date)
{
++i;
continue;
}
else if (day.date<date)
{
++j;
continue;
}
for(var k in day.minute)
{
var timeItem=day.minute[k];
var SHValue=timeItem[1];
var SZValue=timeItem[2];
var total=SHValue+SZValue;
arySHSZData[i]=total;
arySHData[i]=SHValue;
arySZData[i]=SZValue;
++i;
}
++j;
}
var allData=
[
{Data:arySHSZData, ID:1},
{Data:arySHData,ID:2},
{Data:arySZData,ID:3}
];
for(var i in allData)
{
var item=allData[i];
this.HKToSHSZData.set(item.ID,item.Data);
}
}
//北上资金函数
this.GetHKToSHSZCacheData=function(code, node)
{
//if (!this.HKToSHSZData.has(code)) this.Execute.ThrowUnexpectedNode(node,`不支持HK2SHSZ(${code})`);
if (!code) code=this.Symbol;
if (typeof(code)=='string') code=code.toUpperCase();
if(this.HKToSHSZData.has(code)) return this.HKToSHSZData.get(code);
return [];
}
//下载新闻统计
this.GetNewsAnalysisData=function(jobID)
{
if (this.NewsAnalysisData.has(jobID)) return this.Execute.RunNextJob();
var self=this;
var mapFolder=new Map([
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE, "negative"],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH, 'research'],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT, 'interact'],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE, 'holderchange'], //NEWS(4) 股东增持
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2,'holderchange'], //NEWS(5) 股东减持
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER, 'trustholder'], //NEWS(6) 信托持股
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING, 'Blocktrading'], //NEWS(7) 大宗交易
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS, 'companynews'], //NEWS(8) 官网新闻
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS, 'topmanagers'], //NEWS(9) 高管要闻
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE, 'Pledge'], //NEWS(10) 股权质押
]);
if (!mapFolder.has(jobID))
{
this.Execute.RunNextJob();
return;
}
var folderName=mapFolder.get(jobID);
var url=this.StockNewsAnalysisApiUrl+'/'+folderName+'/'+this.Symbol+'.json';
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvNewsAnalysisData(recvData,jobID);
self.Execute.RunNextJob();
},
error:function(request, textStatus)
{
self.RecvNewsAnalysisDataError(request, textStatus,jobID);
self.Execute.RunNextJob();
}
});
}
this.RecvNewsAnalysisDataError=function(request, textStatus,jobID)
{
JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisDataError] ajax error.',request.status);
//没有新闻使用0数据填充
var aryData=[];
for(var i=0;i<this.Data.Data.length;++i)
{
var item=new SingleData();
item.Date=this.Data.Data[i].Date;
item.Value=0
aryData.push(item);
}
var bindData=new ChartData();
bindData.Data=aryData;
this.NewsAnalysisData.set(jobID,bindData.GetValue());
}
this.RecvNewsAnalysisData=function(data,jobID)
{
if (!data.data || !data.date) return;
if (data.data.length<=0 || data.data.length!=data.date.length) return;
JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisData] jobID',jobID, data.update);
if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE|| jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2)
{
var aryData=[], aryData2=[];
for(var i=0;i<data.data.length;++i)
{
var item=new SingleData();
item.Date=data.date[i];
item.Value=data.data[i];
if (this.IsNumber(item.Value)) aryData.push(item);
if (i<data.data2.length)
{
item=new SingleData();
item.Date=data.date[i];
item.Value=data.data2[i];
if (this.IsNumber(item.Value)) aryData2.push(item);
}
}
let aryFixedData=this.Data.GetFittingData2(aryData,0);
var bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE,bindData.GetValue());
aryFixedData=this.Data.GetFittingData2(aryData2,0);
bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2,bindData.GetValue());
}
else
{
var aryData=[];
for(var i=0;i<data.data.length;++i)
{
var item=new SingleData();
item.Date=data.date[i];
item.Value=data.data[i];
aryData.push(item);
}
let aryFixedData=this.Data.GetFittingData2(aryData,0);
var bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(jobID,bindData.GetValue());
}
}
this.GetSectionFinanceData=function(job)
{
var sfKey=job.SF[0];
var period=job.SF[1].Period;
if (this.SectionFinanceData.has(sfKey)) return this.Execute.RunNextJob();
JSConsole.Complier.Log(`[JSSymbolData::GetSectionFinanceData] ${period.Year}-${period.Quarter}`);
var fieldName='announcement'+period.Quarter;
var self=this;
var fieldList=["name","date","symbol", fieldName,'finance'+period.Quarter];
var cond=[fieldName+'.year', "int32", "eq", period.Year.toString() ];
//请求数据
JSNetwork.HttpRequest({
url: this.StockHistoryDayApiUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"condition":[{item:cond}]
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvSectionFinanceData(recvData,job);
self.Execute.RunNextJob();
}
});
}
this.RecvSectionFinanceData=function(data,job)
{
if (!data.stock || data.stock.length!=1) return;
var stockItem=data.stock[0];
if (!stockItem.stockday || stockItem.stockday.length<=0) return;
var dayItem=stockItem.stockday[0];
var period=job.SF[1].Period;
var finance=null;
if (period.Quarter===1) finance=dayItem.finance1;
else if (period.Quarter===2) finance=dayItem.finance2;
else if (period.Quarter===3) finance=dayItem.finance3;
else if (period.Quarter===4) finance=dayItem.finance4;
if (!finance) return;
var data=new Map([
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_01,finance.currentassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_02,finance.monetaryfunds],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_03,finance.inventory],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_04,finance.currentliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_05,finance.ncurrentliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_06,finance.expenses3],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_07,finance.investmentincome],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_08,finance.pcnprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_09,finance.nnetprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_10,finance.npersearning],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_11,finance.woewa],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_12,finance.inprocess],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_13,finance.accdepreciation],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_14,finance.mholderprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_15,finance.lossexchange],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_16,finance.baddebts],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_17,finance.fixedassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_18,finance.curdepreciation],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_19,finance.orevenues],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_20,finance.moprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_21,finance.oprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_22,finance.nprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_23,finance.areceivable],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_24,finance.financialcost],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_25,finance.ccfo],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_26,finance.totalassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_27,finance.totalliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_28,finance.totalownersequity],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_29,finance.grossmargin],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_30,finance.percreserve],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_31,finance.peruprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_32,finance.persearning],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_33,finance.pernetasset],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_34,finance.perccfo],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_38,finance.alratio],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_39,finance.profityoy],
]);
if (period.Quarter===4) //年报才有的数据
{
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_35,finance.nnprofitincrease);
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_36,finance.nnprofitspeed);
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_37,finance.nprofitincrease);
}
var sfKey=job.SF[0];
this.SectionFinanceData.set(sfKey,data);
}
this.GetSectionFinanceCacheData=function(year,quarter,fieldName,node)
{
var period=JS_EXECUTE_JOB_ID.GetSectionReportPeriod(year,quarter);
if (!period) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 报告期错误`);
var id=JS_EXECUTE_JOB_ID.GetSectionFinanceID(fieldName);
if (!id) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter},'${fieldName}') 财务数据字段名称错误`);
var sfKey=period.Year+'-'+period.Quarter;
if (!this.SectionFinanceData.has(sfKey) && !this.ThrowSFPeirod.has(sfKey)) //动态下载的数据, 抛异常以后重新下载执行
{
this.ThrowSFPeirod.add(sfKey); //抛过的异常就不抛了
var job={ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF, SF:[sfKey, {Period:period, Fields:new Set([id])}]};
this.Execute.ThrowDownloadSF(node, job, `FS(${year}, ${quarter}, '${fieldName}') 动态下载`);
}
if (!this.SectionFinanceData.has(sfKey))
return this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 没有这期财务数据`);
var financeData=this.SectionFinanceData.get(sfKey);
if (!financeData.has(id)) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 没有这期财务数据字段`);
return financeData.get(id);
}
this.GetStockDataKey=function(jobItem, aryArgs)
{
var key=jobItem.FunctionName;
if (aryArgs.length>0)
{
key+="(";
for(var i=0;i<aryArgs.length;++i)
{
if (i>0) key+=",";
key+=aryArgs[i].toString();
}
key+=")";
}
return key;
}
this.GetFinance=function(jobItem)
{
var aryArgs=this.JobArgumentsToArray(jobItem, 1);
var lID=aryArgs[0];
var key=this.GetStockDataKey(jobItem,aryArgs);
if (this.StockData.has(key)) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetFinance', //类名::
Explain:'财务数据FINANCE(ID)',
JobID:jobItem.ID,
Request:{ Url:self.RealtimeApiUrl, Type:'POST', Data:{ id:lID, symbol: this.Symbol, daterange:dateRange } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
if (recvData.Error) self.AddStockValueError(key,recvData.Error);
else self.RecvStockValue(recvData,jobItem,key,0);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
var apiDownload=new DownloadFinanceData(
{
Job:jobItem,
Symbol:this.Symbol,
Url:this.StockHistoryDayApiUrl,
RealtimeUrl:this.RealtimeApiUrl,
Args:aryArgs,
DataKey:key,
Callback:function(recvData, jobItem, key)
{
self.RecvStockValue(recvData, jobItem, key,0);
self.Execute.RunNextJob();
},
ErrorCallback:function(strError)
{
self.AddStockValueError(key,strError);
}
});
apiDownload.Download();
}
this.GetProFinance=function(jobItem)
{
var jobID=jobItem.ID;
var finder=null;
for(var i=0;i<JS_ARRAY_PROFESSIONAL_FINANCE.length;++i)
{
var item=JS_ARRAY_PROFESSIONAL_FINANCE[i];
if (item.JobID==jobID)
{
finder=item;
break;
}
}
if (!finder) return this.Execute.RunNextJob();
var aryArgs=this.JobArgumentsToArray(jobItem, finder.ArgCount);
var key=this.GetStockDataKey(jobItem,aryArgs);
if (this.StockData.has(key)) return this.Execute.RunNextJob();
var self=this;
var dataType=0;
if ([JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYVALUE,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_BKJYVALUE].includes(jobID))
{
dataType=aryArgs[2]==1?0:2; //TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
}
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:finder.FuncName, //类名::
Explain:finder.Explain,
JobID:jobID,
Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
self.RecvStockValue(recvData,jobItem,key,dataType);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSConsole.Chart.Warn(`[JSSymbolData::GetProFinance] ${finder.FuncName} Not implemented.`);
}
this.GetVariantData=function(jobItem)
{
var key=jobItem.VariantName;
if (this.StockData.has(key)) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetVariantData', //类名::函数名
Explain:'变量数据下载',
JobID:jobItem.ID,
Request:{ Url:"数据地址", Type:'POST', Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
if (recvData.Error)
{
self.AddStockValueError(key,recvData.Error);
}
else
{
var dataType=0;
if (IFrameSplitOperator.IsNumber(recvData.DataType)) dataType=recvData.DataType;
self.RecvStockValue(recvData.Data,jobItem,key,dataType);
}
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
var errorCallback=function(strError)
{
self.AddStockValueError(key,strError);
};
var apiDownload;
if (jobItem.VariantName=="CAPITAL" || jobItem.VariantName=="TOTALCAPITAL" || jobItem.VariantName=="EXCHANGE")
{
var callback=function(recvData, jobItem, key)
{
self.RecvStockValue(recvData, jobItem, key,0);
self.Execute.RunNextJob();
};
apiDownload=new DownloadFinanceData(
{
Job:jobItem,
Symbol:this.Symbol,
Url:this.StockHistoryDayApiUrl,
RealtimeUrl:this.RealtimeApiUrl,
Args:[jobItem.VariantName],
DataKey:key,
Callback:callback,
ErrorCallback:errorCallback
});
}
else if (jobItem.VariantName=="HYBLOCK" || jobItem.VariantName=="DYBLOCK" || jobItem.VariantName=="GNBLOCK")
{
var callback=function(recvData, jobItem, key, dataType)
{
self.RecvStockValue(recvData, jobItem, key, dataType);
self.Execute.RunNextJob();
};
apiDownload=new DownloadGroupData(
{
Job:jobItem,
Symbol:this.Symbol,
Url:this.StockHistoryDayApiUrl,
RealtimeUrl:this.RealtimeApiUrl,
Args:[jobItem.VariantName],
DataKey:key,
Callback:callback,
ErrorCallback:errorCallback
});
}
else if (jobItem.VariantName=="INBLOCK")
{
var errorMessage=`${jobItem.VariantName}, 请对接外部数据.`;
this.AddStockValueError(key,errorMessage);
this.Execute.RunNextJob();
return;
}
else
{
var errorMessage=`不支持变量${jobItem.VariantName}, 请对接外部数据.`;
this.AddStockValueError(key,errorMessage);
this.Execute.RunNextJob();
return;
}
apiDownload.Download();
}
//自定义变量数据下载
this.GetCustomVariantData=function(jobItem)
{
var key=jobItem.VariantName;
if (this.StockData.has(key)) return this.Execute.RunNextJob();
var variantInfo=g_JSComplierResource.CustomVariant.Data.get(key);
var self=this;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetCustomVariantData', //类名::函数名
Explain:'自定义变量数据下载',
JobID:jobItem.ID,
Request:
{
Url:"数据地址", Type:'POST',
Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange, period:this.Period, right:this.Right }
},
Self:this,
VariantInfo:variantInfo,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
if (recvData.Error) self.AddStockValueError(key,recvData.Error);
else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType);
self.Execute.RunNextJob();
});
}
else
{
this.AddStockValueError(key, `自定义变量${key}下载失败`);
this.Execute.RunNextJob();
}
}
this.GetCustomFunctionData=function(jobItem)
{
var key=jobItem.FunctionName;
var functionInfo=g_JSComplierResource.CustomFunction.Data.get(key);
if (!functionInfo.IsDownload) return this.Execute.RunNextJob();
if (this.StockData.has(key)) return this.Execute.RunNextJob(); //一个函数只能缓存一个数据, 保存多个外部自己保存
var self=this;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetCustomFunctionData', //类名::函数名
Explain:'自定义函数数据下载',
JobID:jobItem.ID,
Request:
{
Url:"数据地址", Type:'POST',
Data:
{
FunctionName:jobItem.FunctionName,
symbol: this.Symbol, daterange:dateRange,
JobItem:jobItem, //函数编译信息
period:this.Period,
right:this.Right,
}
},
Self:this,
FunctionInfo:functionInfo,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
if (recvData.Error) self.AddStockValueError(key,recvData.Error);
else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType);
self.Execute.RunNextJob();
});
}
else
{
this.AddStockValueError(key, `自定义函数${key}下载失败`);
this.Execute.RunNextJob();
}
}
this.GetCustomFunctionDataV2=function(jobItem)
{
var funcName=jobItem.FunctionName;
var functionInfo=g_JSComplierResource.CustomDataFunction.Data.get(funcName);
if (!functionInfo) return;
var aryArgs=this.JobArgumentsToArray(jobItem, functionInfo.ArgCount);
var key=this.GetStockDataKey(jobItem,aryArgs);
if (this.StockData.has(key)) return this.Execute.RunNextJob(); //一个函数只能缓存一个数据, 保存多个外部自己保存
var self=this;
if (this.NetworkFilter)
{
var dateRange=this.Data.GetDateRange();
var obj=
{
Name:'JSSymbolData::GetCustomFunctionData', //类名::函数名
Explain:'自定义函数数据下载',
JobID:jobItem.ID,
Request:
{
Url:"数据地址", Type:'POST',
Data:
{
FunctionName:jobItem.FunctionName,
symbol: this.Symbol, daterange:dateRange,
JobItem:jobItem, //函数编译信息
Key:key,
period:this.Period,
right:this.Right,
}
},
Self:this,
FunctionInfo:functionInfo,
PreventDefault:false
};
this.NetworkFilter(obj, function(recvData)
{
if (recvData.Error) self.AddStockValueError(key,recvData.Error);
else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType);
self.Execute.RunNextJob();
});
}
else
{
this.AddStockValueError(key, `自定义函数${key}下载失败`);
this.Execute.RunNextJob();
}
}
this.RecvStockValue=function(recvData,jobItem,key,dataType)
{
if (!recvData)
{
JSConsole.Complier.Log(`[JSSymbolData::RecvStockValue] key=${key} data is null`);
return;
}
if (dataType==0)
{
if (Array.isArray(recvData))
{
var kdata=this.Data; //K线
var aryFittingData;
if (this.DataType==HQ_DATA_TYPE.KLINE_ID)
{
if (ChartData.IsDayPeriod(this.Period,true))
aryFittingData=kdata.GetFittingFinanceData(recvData); //数据和主图K线拟合
else if (ChartData.IsMinutePeriod(this.Period,true))
aryFittingData=kdata.GetMinuteFittingFinanceData(recvData); //数据和主图K线拟合
else
return;
}
else
{
aryFittingData=kdata.GetMinuteFittingFinanceData(recvData); //数据和主图分时拟合
}
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
if (key=="EXCHANGE") //计算换手率=成交量/流通股本*100
{
for(var i in result)
{
var kitem=kdata.Data[i];
if (IFrameSplitOperator.IsPlusNumber(result[i]))
result[i]=kitem.Vol/result[i] * 100;
}
}
this.StockData.set(key,{ Data:result });
}
else
{
this.StockData.set(key,{ Data:recvData.Value });
}
}
else if (dataType==1) //单数值
{
this.StockData.set(key,{ Data:recvData.Value });
}
else if (dataType==2)
{
var kdata=this.Data; //K线
var aryFittingData;
if (this.DataType==HQ_DATA_TYPE.KLINE_ID)
{
if (ChartData.IsDayPeriod(this.Period,true))
aryFittingData=kdata.GetFittingTradeData(recvData, 0); //数据和主图K线拟合
else if (ChartData.IsMinutePeriod(this.Period,true))
aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0); //数据和主图K线拟合
else if (ChartData.IsTickPeriod(this.Period))
aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0); //数据和主图K线拟合
else
return;
}
else
{
aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0); //数据和主图分钟拟合
}
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
this.StockData.set(key,{ Data:result });
}
}
this.AddStockValueError=function(key, message)
{
this.StockData.set(key,{ Error:message });
}
this.GetStockCacheData=function(obj)
{
var key;
if (obj.FunctionName)
key=this.GetStockDataKey({FunctionName:obj.FunctionName}, obj.Args);
else if (obj.VariantName)
key=obj.VariantName;
else if (obj.CustomName)
key=obj.CustomName; //自定义名字
else
return null;
if (!this.StockData.has(key)) return null;
var data=this.StockData.get(key);
if (data.Error) this.Execute.ThrowUnexpectedNode(obj.Node, data.Error);
return data.Data;
}
this.IsInBlock=function(blockName, node)
{
var data=this.GetStockCacheData({ VariantName:"INBLOCK", Node:node });
if (!data) return 0;
var aryBlock=data.split('|');
for(var i=0; i<aryBlock.length; ++i)
{
var item=aryBlock[i];
if (item==blockName) return 1;
}
return 0;
}
this.JobArgumentsToArray=function(job, lCount)
{
var args=job.Args;
if (args.length!=lCount)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: argument count error.`);
}
var aryValue=[];
for(var i=0;i<args.length;++i)
{
var item=args[i];
if (IFrameSplitOperator.IsNumber(item))
{
aryValue.push(item);
}
else if (item.Type==Syntax.Literal)
{
aryValue.push(item.Value);
}
else if (item.Type==Syntax.Identifier) //变量 !!只支持默认的变量值
{
var isFind=false;
for(var j in this.Arguments)
{
const argItem=this.Arguments[j];
if (argItem.Name==item.Name)
{
aryValue.push(argItem.Value);
isFind=true;
break;
}
}
if (!isFind)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: can't read ${item.Name}`);
}
}
}
return aryValue;
}
this.DownloadCustomAPIData=function(job)
{
if (!this.NetworkFilter) return this.Execute.RunNextJob();
var args=[];
for(var i in job.Args)
{
var item=job.Args[i];
if (item.Type==Syntax.Literal)
{
args.push(item.Value);
}
else if (item.Type==Syntax.Identifier) //变量 !!只支持默认的变量值
{
var isFind=false;
for(var j in this.Arguments)
{
const argItem=this.Arguments[j];
if (argItem.Name==item.Name)
{
args.push(argItem.Value);
isFind=true;
break;
}
}
if (!isFind)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`LoadAPIData() Error: can't read ${item.Name}`);
}
}
else
{
return this.Execute.RunNextJob();
}
}
var self=this;
var obj=
{
Name:'JSSymbolData::DownloadCustomAPIData', //类名::函数名
Explain:'下载自定义api数据',
Period:this.Period,
Right:this.Right,
Symbol:this.Symbol,
KData:this.Data, //K线数据
Cache:this.CustomAPIData,
Args:args,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvCustomAPIData(data,args);
self.Execute.RunNextJob();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
this.Execute.RunNextJob();
}
/*
recvData:
{
Type: 0=集合数据(默认) 1=单列数据
DataType: 0=K线类数据 1=财务类数据
}
*/
this.RecvCustomAPIData=function(recvData,args)
{
if (!recvData) return;
if (recvData.Type==1)
this.RecvCustomAPISingleData(recvData,args);
else
this.RecvCustomAPIGroupData(recvData,args);
}
//集合数据
this.RecvCustomAPIGroupData=function(recvData,args)
{
if (!recvData || !recvData.data) return;
var data=recvData.data;
var apiKey=this.GenerateCustomAPIKey(args);
if (ChartData.IsMinutePeriod(this.Period,true)) //分钟 TODO:
{
if (!data.date || !data.time) return;
var date=data.date;
var time=data.time;
for (var key in data)
{
if (key=='date' || key=='time') continue;
var item=data[key];
}
}
else if (ChartData.IsDayPeriod(this.Period,true))
{
if (!data.date) return;
var date=data.date;
var result={ __Type__:"Object" };
for (var key in data)
{
if (key=='date') continue;
var item=data[key];
if (Array.isArray(item))
{
var value=this.FittingCustomAPIArray(item,date);
result[key]=value;
}
else if (this.IsNumber(item))
{
result[key]=item;
}
}
this.CustomAPIData.set(apiKey, result);
}
}
//单列数据
this.RecvCustomAPISingleData=function(recvData,args)
{
var data=recvData.data;
var apiKey=this.GenerateCustomAPIKey(args);
if (ChartData.IsMinutePeriod(this.Period,true)) //分钟 TODO:
{
if (!data.date || !data.time) return;
var date=data.date;
var time=data.time;
for (var key in data)
{
if (key=='date' || key=='time') continue;
var item=data[key];
}
}
else if (ChartData.IsDayPeriod(this.Period,true)) //日线
{
if (!data.date) return;
var date=data.date;
var value=data.value;
var result=null;
if (Array.isArray(value))
{
if (recvData.DataType==1) result=this.FittingCustomAPIFinanceArray(value,date);
else result=this.FittingCustomAPIArray(value,date);
}
else
{
result=value;
}
this.CustomAPIData.set(apiKey, result);
}
}
//财务数据拟合
this.FittingCustomAPIFinanceArray=function(data, date, time)
{
var kdata=this.Data; //K线
var arySingleData=[];
for(var i in data)
{
var value=data[i];
var indexItem=new SingleData();
indexItem.Date=date[i];
if (time && i<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData;
if (ChartData.IsDayPeriod(this.Period,true))
aryFittingData=kdata.GetFittingFinanceData(arySingleData);
else if (ChartData.IsMinutePeriod(this.Period,true))
aryFittingData=kdata.GetMinuteFittingFinanceData(arySingleData);
else
return null;
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
return result;
}
//K线类数据拟合
this.FittingCustomAPIArray=function(data,date,time)
{
var kdata=this.Data; //K线
var arySingleData=[];
for(var i in data)
{
var value=data[i];
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=date[i];
if (time && i<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData;
if (ChartData.IsDayPeriod(this.Period,true))
aryFittingData=kdata.GetFittingData(arySingleData); //数据和主图K线拟合
else if (ChartData.IsMinutePeriod(this.Period,true))
aryFittingData=kdata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合
else
return null;
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
return result;
}
this.GenerateCustomAPIKey=function(args)
{
if (args.length<=0) return '__12_EMPTY_ARGS__';
var key='';
for(var i in args)
{
if (key.length>0) key+=','
key+=args[i];
}
return key;
}
this.GetCustomApiData=function(args)
{
var key=this.GenerateCustomAPIKey(args);
if (!this.CustomAPIData.has(key))
{
JSConsole.Complier.Log(`[JSSymbolData::GetCustomApiData] can't find api data key=[${key}]`);
return null;
}
return this.CustomAPIData.get(key);
}
this.ReadArgumentValue=function(item, result) //读取变量值
{
result.Name=item.Name;
if (item.Type==Syntax.Literal)
{
result.Value=item.Value;
return true;
}
if (item.Type==Syntax.Identifier)
{
var isFind=false;
for(var i in this.Arguments)
{
const argItem=this.Arguments[i];
if (argItem.Name==item.Name)
{
result.Value=argItem.Value;
isFind=true;
return true;
}
}
if (!isFind)
{
result.Error=`can't read ${item.Name}` ;
return false;
}
}
result.Error=`can't read ${item.Name}, type error.`;
return false;
}
this.ReadIndexFunctionOut=function(item, result)
{
var indexParam={};
if (typeof(item)=== 'object')
{
if (!this.ReadArgumentValue(item,indexParam))
{
result.Error=indexParam.Error;
return false;
}
}
else
{
indexParam.Value=item;
}
result.OutIndex=indexParam.Value;
result.Out=null;
return true;
}
//MA.MA1#WEEK
this.ReadIndexFunctionValue=function(item, result) //返回 {Period:周期, Out:输出变量, Error:, Name:脚本名字 }
{
var indexParam={};
if (typeof(item)=== 'object')
{
if (!this.ReadArgumentValue(item,indexParam))
{
result.Error=indexParam.Error;
return false;
}
}
else
{
indexParam.Value=item;
}
var pos=indexParam.Value.indexOf("\.");
if (pos!=-1)
{
result.Name=indexParam.Value.slice(0, pos); //名字
var pos2=indexParam.Value.indexOf('#', pos+1);
if (pos2!=-1)
{
result.Out=indexParam.Value.slice(pos+1, pos2); //输出变量
result.Period=indexParam.Value.slice(pos2+1); //周期
}
else
{
result.Out=indexParam.Value.slice(pos+1);
}
}
else
{
var pos2=indexParam.Value.indexOf('#');
if (pos2!=-1)
{
result.Name=indexParam.Value.slice(0,pos2);
result.Period=indexParam.Value.slice(pos2+1); //周期
}
else
{
result.Name=indexParam.Value;
}
}
const PERIOD_MAP=new Map([
["DAY",0 ], ["WEEK", 1 ], ["MONTH",2 ], ["SEASON",9 ], ["YEAR", 3], ["HALFYEAR",22], ["WEEK2",21],
["MIN1", 4], ["MIN5", 5 ], ["MIN15", 6 ], ["MIN30",7 ], ["MIN60", 8 ],["MIN120",11],["MIN240",12],
["DAY2", 40002],["MULTIDAY",40002],["DAY3", 40003],["DAY4", 40004],["DAY5",40005],
["DAY6", 40006],["DAY7", 40007],["DAY8", 40008],["DAY9", 40009],["DAY10",40010],
["DAY11", 40011],["DAY12", 40012],["DAY13", 40013],["DAY14", 40014],["DAY15", 40015],
]);
if (result.Period)
{
if (!PERIOD_MAP.has(result.Period))
{
result.Error=`${result.Period}, 周期错误`;
return false;
}
result.PeriodID=PERIOD_MAP.get(result.Period);
}
return true;
}
this.ReadSymbolArgumentValue=function(item, result) //返回{ Value:股票代码, Error:错误信息}
{
var readArgument={};
if (typeof(item)=== 'object')
{
if (!this.ReadArgumentValue(item,readArgument))
{
result.Error=readArgument.Error;
return false;
}
}
else
{
readArgument.Value=item;
}
if (readArgument.Value=='') readArgument.Value=this.Symbol; //缺省使用股票代码
var symbol=readArgument.Value;
//支持 SH60000, SZ000001
//A股后缀小写
if (symbol.indexOf('.SH')>0) result.Symbol=symbol.replace('.SH', ".sh");
else if (symbol.indexOf('.SZ')>0) result.Symbol=symbol.replace('.SZ', ".sz");
else if (symbol.indexOf("SH")==0) result.Symbol=symbol.slice(2)+".sh";
else if (symbol.indexOf("SZ")==0) result.Symbol=symbol.slice(2)+".sz";
else result.Symbol=symbol;
return true;
}
this.ReadIndexArgumentValue=function(args, result)
{
result.Args=[];
for(var i in result.SytemIndex.Args) //复制参数
{
var item=result.SytemIndex.Args[i];
result.Args.push({Value:item.Value, Name:item.Name});
}
if (args.length>2 && result.SytemIndex.Args && result.SytemIndex.Args.length>0)
{
for(var i=2, j=0; i<args.length && j<result.SytemIndex.Args.length; ++i, ++j)
{
var readArgument={};
var item=args[i];
if (typeof(item)=== 'object')
{
if (!this.ReadArgumentValue(item,readArgument))
{
result.Error=readArgument.Error;
return false;
}
}
else
{
readArgument.Value=item;
}
result.Args[j].Value=readArgument.Value;
}
}
return true;
}
//key= (代码,周期),指标(参数) => 输出
this.GenerateScriptIndexKey=function(indexInfo)
{
var indexParam='';
var args=indexInfo.Args;
for(var i in args)
{
if (indexParam.length>0) indexParam+=',';
var item=args[i];
indexParam+=item.Value.toString();
}
var out="ALL";
if (indexInfo.Out) out=indexInfo.Out;
else if (IFrameSplitOperator.IsPlusNumber(indexInfo.OutIndex)) out=`Out[${indexInfo.OutIndex-1}]`;
var key=`(${indexInfo.Symbol},${indexInfo.PeriodID}), ${indexInfo.Name}(${indexParam})=>${out}`;
return key;
}
//TMP2:=KDJ.K#WEEK;
this.CallMemberScriptIndex=function(job)
{
if (job.Member.Object.Type!=Syntax.Identifier ||job.Member.Property.Type!=Syntax.Identifier)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: 参数错误`);
}
var objName=job.Member.Object.Name;
var PropertyName=job.Member.Property.Name;
if (PropertyName=="" || PropertyName==null)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: ${objName}.${PropertyName} 指标输出变量错误`);
}
if (this.Execute.VarTable.has(objName))
{
var memberValue=this.Execute.VarTable.get(objName);
if (memberValue.hasOwnProperty(PropertyName))
{
JSConsole.Complier.Log(`[JSSymbolData::CallMemberScriptIndex] index data ${objName}.${PropertyName} in cache.`);
return this.Execute.RunNextJob();
}
}
var callInfo=objName+"."+PropertyName;
var indexInfo={ Job:job, PeriodID:this.Period , Symbol:this.Symbol };
if (!this.ReadIndexFunctionValue(callInfo,indexInfo)) //读取指标
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: '${callInfo}' ${indexInfo.Error}`);
}
var systemIndex=new JSIndexScript();
var systemItem=systemIndex.Get(indexInfo.Name);
if (!systemItem)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: '${callInfo}' ${indexInfo.Name} 指标不存在`);
}
if (Array.isArray(systemItem.Args) && systemItem.Args.length>0)
{
indexInfo.Args=[];
for(var i in systemItem.Args) //复制参数
{
var item=systemItem.Args[i];
indexInfo.Args.push({Value:item.Value, Name:item.Name});
}
}
JSConsole.Complier.Log('[JSSymbolData::CallMemberScriptIndex] call script index', indexInfo);
var dateTimeRange=this.Data.GetDateRange();
var option=
{
HQDataType:this.DataType,
Symbol:indexInfo.Symbol,
Name:'',
Right:this.Right, //复权
Period:indexInfo.PeriodID, //周期
Data:null,
SourceData:null,
Callback:(outVar,job, symbolData)=> {
this.RecvMemberScriptIndexData(outVar,job,symbolData);
this.Execute.RunNextJob();
},
CallbackParam:indexInfo,
Async:true,
MaxRequestDataCount:this.MaxRequestDataCount+30*2,
MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount+2,
Arguments:indexInfo.Args,
//Condition:this.Condition,
IsBeforeData:this.IsBeforeData,
NetworkFilter:this.NetworkFilter,
IsApiPeriod:this.IsApiPeriod,
KLineRange:dateTimeRange //K线数据范围
};
//执行脚本
var run=JSComplier.Execute(systemItem.Script,option,(error, indexInfo)=>{this.ExecuteScriptIndexError(error,indexInfo)});
}
this.CallDynamicScriptIndex=function(job, varTable)
{
var callInfo=job.DynamicName;
var indexInfo={ Job:job, PeriodID:this.Period , Symbol:this.Symbol };
if (!this.ReadIndexFunctionValue(callInfo,indexInfo)) //读取指标
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallDynamicScriptIndex() Error: '${callInfo}' ${indexInfo.Error}`);
}
var systemIndex=new JSIndexScript(); //系统指标
var systemItem=systemIndex.Get(indexInfo.Name);
if (!systemItem)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallDynamicScriptIndex() Error: '${callInfo}' ${indexInfo.Name} 指标不存在`);
}
indexInfo.SytemIndex=systemItem;
if (!this.ReadDynamicIndexArgumentValue(job.Args, indexInfo, varTable))
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallDynamicScriptIndex() ${indexInfo.Name} 指标参数错误 : ${indexInfo.Error} `);
}
JSConsole.Complier.Log('[JSSymbolData::CallMemberScriptIndex] call script index', indexInfo);
var dateTimeRange=this.Data.GetDateRange();
var option=
{
HQDataType:this.DataType,
Symbol:indexInfo.Symbol,
Name:'',
Right:this.Right, //复权
Period:indexInfo.PeriodID, //周期
Data:null,
SourceData:null,
Callback:(outVar,job, symbolData)=> {
this.RecvDynamicScriptIndexData(outVar,job,symbolData);
this.Execute.RunNextJob();
},
CallbackParam:indexInfo,
Async:true,
MaxRequestDataCount:this.MaxRequestDataCount+30*2,
MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount+2,
Arguments:indexInfo.Args,
//Condition:this.Condition,
IsBeforeData:this.IsBeforeData,
NetworkFilter:this.NetworkFilter,
IsApiPeriod:this.IsApiPeriod,
KLineRange:dateTimeRange //K线数据范围
};
//执行脚本
var run=JSComplier.Execute(systemItem.Script,option,(error, indexInfo)=>{this.ExecuteScriptIndexError(error,indexInfo)});
}
this.ReadDynamicIndexArgumentValue=function(args, result, varTable)
{
result.Args=[];
for(var i =0;i<result.SytemIndex.Args.length; ++i) //复制参数
{
var item=result.SytemIndex.Args[i];
result.Args.push({ Value:item.Value, Name:item.Name, IsDefault:true });
}
if (!IFrameSplitOperator.IsNonEmptyArray(args)) return true;
for(var i=0;i<args.length;++i)
{
var item=args[i];
var argItem=result.Args[i];
if (!argItem) continue;
if (item.Type==Syntax.Literal)
{
argItem.Value=item.Value;
argItem.IsDefault=false;
}
else if (item.Type==Syntax.Identifier) //支持传参
{
if (varTable.has(item.Name))
{
argItem.Value=varTable.get(item.Name);
argItem.IsDefault=false;
}
}
}
return true;
}
/*****************************************************************************************************************************
脚本调用
STKINDI
STKINDI('600000.sh','MA.MA1#WEEK',5,10,20,30,60,120);
1=股票代码 2=指标名字.输出变量#周期, 3....参数
CALCSTOCKINDEX
用法:CALCSTOCKINDEX(品种代码,指标名称,指标线),返回该指标相应输出的计算值.
例如:
CALCSTOCKINDEX('SH600000','KDJ',3)表示上证600000的KDJ指标第3个输出即J之值,第一个参数可在前面加SZ(深市),SH(沪市),BJ(京市),或市场_,,
CALCSTOCKINDEX('47_IFL0','MACD',2)表示IFL0品种的MACD指标第2个输出值.
"MA.MA1"(6,12,18)
*******************************************************************************************************************************/
this.CallScriptIndex=function(job, varTable)
{
if (job.Member) return this.CallMemberScriptIndex(job);
if (job.DynamicName) return this.CallDynamicScriptIndex(job, varTable);
if (!job.Args || !(job.Args.length>=2))
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${job.FunctionName} 参数错误`);
}
var indexInfo={ Job:job, PeriodID:this.Period };
if (!this.ReadSymbolArgumentValue(job.Args[0],indexInfo)) //读取代码
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${indexInfo.Error}`);
}
if (!this.ReadIndexFunctionValue(job.Args[1],indexInfo)) //读取指标
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${indexInfo.Error}`);
}
if (job.FunctionName=="CALCSTOCKINDEX")
{
if (!this.ReadIndexFunctionOut(job.Args[2],indexInfo)) //读取返回值索引
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${indexInfo.Error}`);
}
}
var systemIndex=new JSIndexScript();
var systemItem=systemIndex.Get(indexInfo.Name);
if (!systemItem)
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标不存在`);
}
indexInfo.SytemIndex=systemItem; //系统指标
if (!this.ReadIndexArgumentValue(job.Args,indexInfo))
{
var token=job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标参数错误 : ${indexInfo.Error} `);
}
JSConsole.Complier.Log('[JSSymbolData::CallScriptIndex] call script index', indexInfo);
var DateTimeRange=null;
if (this.Data && this.Data.Data.length>0)
{
var start=this.Data.Data[0];
var end=this.Data.Data[this.Data.Data.length-1];
DateTimeRange=
{
Start:{Date:start.Date, Time: start.Time},
End:{Date:end.Date, Time: end.Time},
}
}
var option=
{
HQDataType:this.DataType,
Symbol:indexInfo.Symbol,
Name:'',
Right:this.Right, //复权
Period:indexInfo.PeriodID, //周期
Data:null,
SourceData:null,
Callback:(outVar,job, symbolData)=> {
this.RecvScriptIndexData(outVar,job,symbolData);
this.Execute.RunNextJob();
},
CallbackParam:indexInfo,
Async:true,
MaxRequestDataCount:this.MaxRequestDataCount+30*2,
MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount+2,
Arguments:indexInfo.Args,
//Condition:this.Condition,
IsBeforeData:this.IsBeforeData,
NetworkFilter:this.NetworkFilter,
IsApiPeriod:this.IsApiPeriod,
KLineRange:DateTimeRange //K线数据范围
};
//执行脚本
var run=JSComplier.Execute(indexInfo.SytemIndex.Script,option,(error, indexInfo)=>{this.ExecuteScriptIndexError(error,indexInfo)});
}
this.RecvMemberScriptIndexData=function(outVar,indexInfo,symbolData)
{
JSConsole.Complier.Log('[JSSymbolData::RecvMemberScriptIndexData] ', outVar, indexInfo, symbolData);
var kLine=symbolData.Data.Data;
var aryOutVar=outVar;
var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
var member=indexInfo.Job.Member;
var objName=member.Object.Name;
var propertyName=member.Property.Name;
var memberValue={};
if (this.Execute.VarTable.has(objName))
memberValue=this.Execute.VarTable.get(objName);
else
this.Execute.VarTable.set(objName, memberValue);
//保存所有的指标数据, 下面用到了就可以不用算了
for(var i in data)
{
var key=outVar[i].Name;
if (indexInfo.Period) key+='#'+indexInfo.Period; //带周期的变量
memberValue[key]=data[i].Data;
}
}
this.RecvDynamicScriptIndexData=function(outVar,indexInfo,symbolData)
{
JSConsole.Complier.Log('[JSSymbolData::RecvDynamicScriptIndexData] ', outVar, indexInfo, symbolData);
var kLine=symbolData.Data.Data;
var aryOutVar=outVar;
var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
var objName=indexInfo.Name;
var memberValue={};
if (this.Execute.VarTable.has(objName))
memberValue=this.Execute.VarTable.get(objName);
else
this.Execute.VarTable.set(objName, memberValue);
var strValue="";
for(var i=0; i<indexInfo.Args.length; ++i)
{
var item=indexInfo.Args[i];
if (item.IsDefault===false)
{
if (strValue.length>0) strValue+=",";
strValue+=`${item.Value}`;
}
}
var strArgs=`(${strValue})`;
//保存所有的指标数据, 下面用到了就可以不用算了
for(var i=0; i<data.length; ++i)
{
var key=`${outVar[i].Name}#${strArgs}`;
if (indexInfo.Period) key+='#'+indexInfo.Period; //带周期的变量
memberValue[key]=data[i].Data;
}
}
this.RecvScriptIndexData=function(outVar,indexInfo,symbolData)
{
var key=this.GenerateScriptIndexKey(indexInfo);
JSConsole.Complier.Log('[JSSymbolData::RecvScriptIndexData] ', outVar, indexInfo, symbolData, key);
var kLine=symbolData.Data.Data;
var aryOutVar=outVar;
if (indexInfo.Out)
{
for(var i=0;i<outVar.length; ++i)
{
var item=outVar[i];
if (item.Name==indexInfo.Out)
{
aryOutVar=[item];
break;
}
}
var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
this.ScriptIndexOutData.set(key,data[0].Data);
}
else if (IFrameSplitOperator.IsPlusNumber(indexInfo.OutIndex))
{
var index=indexInfo.OutIndex-1;
aryOutVar=[outVar[index]];
var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
this.ScriptIndexOutData.set(key,data[0].Data);
}
else
{
var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
var result={ __Type__:"Object" };
for(var i in data)
{
var item=data[i];
result[item.Name]=item.Data;
}
this.ScriptIndexOutData.set(key,result);
}
}
this.ExecuteScriptIndexError=function(error,indexInfo)
{
var token=indexInfo.Job.Token;
this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标执行错误 : ${error} `);
}
this.GetScriptIndexOutData=function(args,node, funcName)
{
var indexInfo={ PeriodID:this.Period };
if (!this.ReadSymbolArgumentValue(args[0],indexInfo)) //读取代码
this.Execute.ThrowUnexpectedNode(node,`${funcName}() 股票代码错误: ${indexInfo.Error}`);
if (!this.ReadIndexFunctionValue(args[1],indexInfo)) //读取指标
this.Execute.ThrowUnexpectedNode(node,`${funcName}() 指标错误: ${indexInfo.Error}`);
if (funcName=="CALCSTOCKINDEX")
{
if (!this.ReadIndexFunctionOut(args[2],indexInfo)) //读取返回值索引
this.Execute.ThrowUnexpectedNode(node, `${funcName}() Error: ${indexInfo.Error}`);
}
var systemIndex=new JSIndexScript();
var systemItem=systemIndex.Get(indexInfo.Name);
if (!systemItem)
this.Execute.ThrowUnexpectedNode(node,`${funcName}() 指标错误: ${indexInfo.Name} 指标不存在`);
indexInfo.SytemIndex=systemItem; //系统指标
if (!this.ReadIndexArgumentValue(args,indexInfo))
this.Execute.ThrowUnexpectedNode(node,`${funcName}() 指标参数错误: ${indexInfo.Error}`);
var key=this.GenerateScriptIndexKey(indexInfo);
if (!this.ScriptIndexOutData.has(key)) return null;
return this.ScriptIndexOutData.get(key);
}
this.JsonDataToHistoryData=function(data)
{
var list = data.data;
var aryDayData=new Array();
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7;
var up=8,down=9,stop=10,unchanged=11;
for (var i = 0; i < list.length; ++i)
{
var item = new HistoryData();
item.Date = list[i][date];
item.Open = list[i][open];
item.YClose = list[i][yclose];
item.Close = list[i][close];
item.High = list[i][high];
item.Low = list[i][low];
item.Vol = list[i][vol]; //原始单位股
item.Amount = list[i][amount];
//上涨 下跌家数
if (list[i].length>up) item.Up=list[i][up];
if (list[i].length>down) item.Down=list[i][down];
if (list[i].length>stop) item.Stop=list[i][stop];
if (list[i].length>unchanged) item.Unchanged=list[i][unchanged];
if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除
aryDayData.push(item);
}
return aryDayData;
}
this.JsonDataToMinuteHistoryData=function(data)
{
var list = data.data;
var aryDayData=new Array();
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8;
for (var i = 0; i < list.length; ++i)
{
let item = new HistoryData();
item.Date = list[i][date];
item.Open = list[i][open];
item.YClose = list[i][yclose];
item.Close = list[i][close];
item.High = list[i][high];
item.Low = list[i][low];
item.Vol = list[i][vol]; //原始单位股
item.Amount = list[i][amount];
item.Time=list[i][time];
// if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除
aryDayData.push(item);
}
// 无效数据处理
for(let i = 0; i < aryDayData.length; ++i)
{
var minData = aryDayData[i];
if (minData == null) coninue;
if (isNaN(minData.Open) || minData.Open <= 0 || isNaN(minData.High) || minData.High <= 0 || isNaN(minData.Low) || minData.Low <= 0
|| isNaN(minData.Close) || minData.Close <= 0 || isNaN(minData.YClose) || minData.YClose <= 0)
{
if (i == 0)
{
if (minData.YClose > 0)
{
minData.Open = minData.YClose;
minData.High = minData.YClose;
minData.Low = minData.YClose;
minData.Close = minData.YClose;
}
}
else // 用前一个有效数据填充
{
for(let j = i-1; j >= 0; --j)
{
var minData2 = aryDayData[j];
if (minData2 == null) coninue;
if (minData2.Open > 0 && minData2.High > 0 && minData2.Low > 0 && minData2.Close > 0)
{
if (minData.YClose <= 0) minData.YClose = minData2.Close;
minData.Open = minData2.Open;
minData.High = minData2.High;
minData.Low = minData2.Low;
minData.Close = minData2.Close;
break;
}
}
}
}
}
return aryDayData;
}
//API 返回数据 转化为array[]
this.JsonDataToMinuteData=function(data)
{
var aryMinuteData=new Array();
for(var i in data.stock[0].minute)
{
var jsData=data.stock[0].minute[i];
var item=new MinuteData();
item.Close=jsData.price;
item.Open=jsData.open;
item.High=jsData.high;
item.Low=jsData.low;
item.Vol=jsData.vol; //股
item.Amount=jsData.amount;
if (i==0) //第1个数据 写死9:25
item.DateTime=data.stock[0].date.toString()+" 0925";
else
item.DateTime=data.stock[0].date.toString()+" "+jsData.time.toString();
item.Date=data.stock[0].date;
item.Time=jsData.time;
item.Increase=jsData.increase;
item.Risefall=jsData.risefall;
item.AvPrice=jsData.avprice;
aryMinuteData[i]=item;
}
return aryMinuteData;
}
//多日日线数据API 转化成array[];
this.JsonDataToMultiDayMinuteData=function(data)
{
var symbol=data.symbol;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol);
var result=[];
for(var i in data.data)
{
var minuteData=[];
var dayData=data.data[i];
var date=dayData.date;
var yClose=dayData.yclose; //前收盘 计算涨幅
var preClose=yClose; //前一个数据价格
var preAvPrice=null; //上一个均价
//var preAvPrice=data.stock[0].yclose; //前一个均价
for(var j in dayData.minute)
{
var jsData=dayData.minute[j];
if (jsData[2]) preClose=jsData[2]; //保存上一个收盘数据
var item=new MinuteData();
item.Close=jsData[2];
item.Open=jsData[1];
item.High=jsData[3];
item.Low=jsData[4];
item.Vol=jsData[5]/100; //原始单位股
item.Amount=jsData[6];
if (7<jsData.length && jsData[7]>0)
{
item.AvPrice=jsData[7]; //均价
preAvPrice=jsData[7];
}
item.DateTime=date.toString()+" "+jsData[0].toString();
item.Date=date
item.Time=jsData[0];
if (!item.Close) //当前没有价格 使用上一个价格填充
{
item.Close=preClose;
item.Open=item.High=item.Low=item.Close;
}
if (!item.AvPrice && preAvPrice) item.AvPrice=preAvPrice;
if (item.Close && yClose) item.Increase = (item.Close - yClose)/yClose*100;
else item.Increase=null;
if (j==0) //第1个数据 写死9:25
{
if (isSHSZ) item.DateTime=date.toString()+" 0925";
item.IsFristData=true;
}
//价格是0的 都用空
if (item.Open<=0) item.Open=null;
if (item.Close<=0) item.Close=null;
if (item.AvPrice<=0) item.AvPrice=null;
if (item.High<=0) item.High=null;
if (item.Low<=0) item.Low=null;
if (item.AvPrice<=0) item.AvPrice=null;
minuteData[j]=item;
}
var newData=new ChartData();
newData.Data=minuteData;
newData.YClose=yClose;
newData.Close=dayData.close;
newData.Date=date;
result.push(newData);
}
var minuteData=[];
for(var i=result.length-1; i>=0;--i)
{
var item=result[i];
for(var j in item.Data)
{
minuteData.push(item.Data[j]);
}
}
return minuteData;
}
//CODELIKE 模糊股票代码
this.CODELIKE=function(value)
{
if (this.Symbol && this.Symbol.indexOf(value)==0) return 1;
return 0;
}
this.NAMELIKE=function(value)
{
if (this.Name && this.Name.indexOf(value)==0) return 1;
return 0;
}
/*
SETCODE 市场类型
0:深圳 1:上海,47:中金所期货 28:郑州商品 29:大连商品 30:上海商品,27:香港指数 31:香港主板,48:香港创业板...
*/
this.SETCODE=function()
{
if (this.Symbol.indexOf('.sh')) return 1;
if (this.Symbol.indexOf('.sz')) return 0;
return 0;
}
this.GetSymbol=function()
{
return this.Symbol;
}
this.GetName=function()
{
return this.Name;
}
this.DATE=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
result[i]=item.Date-19000000;
}
return result;
}
this.YEAR=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
if (this.IsNumber(item.Date))
result[i]=parseInt(item.Date/10000);
else
result[i]=null;
}
return result;
}
this.DAY=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
if (this.IsNumber(item.Date))
result[i]=parseInt(item.Date%100);
else
result[i]=null;
}
return result;
}
this.MONTH=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
if (this.IsNumber(item.Date))
result[i]=parseInt(item.Date%10000/100);
else
result[i]=null;
}
return result;
}
this.TIME=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (this.IsNumber(item.Time))
result[i]=item.Time;
else
result[i]=0;
}
return result;
}
/*
取得该周期的时分秒,适用于日线以下周期.
用法: TIME2
函数返回有效值范围为(000000-235959)
*/
this.TIME2=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (this.IsNumber(item.Time))
result[i]=item.Time*100;
else
result[i]=0;
}
return result;
}
this.DateTime=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
var isKLineMinute=ChartData.IsMinutePeriod(this.Period, true);
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (isKLineMinute)
{
result[i]=item.Date*10000+item.Time;
}
else
{
result[i]=item.Date;
}
}
return result;
}
//星期 1-7
this.WEEK=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
var tempDate=new Date();
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
result[i]=null;
if (!this.IsNumber(item.Date)) continue;
var year=parseInt(item.Date/10000);
var month=parseInt(item.Date%10000/100);
var day=item.Date%100;
tempDate.setFullYear(year,month-1,day);
result[i]=tempDate.getDay();
}
return result;
}
/*
取得该周期的日期离今天的天数.
用法: DAYSTOTODAY
*/
this.DAYSTOTODAY=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
var nowDate=new Date();
var endDate=new Date(nowDate.getFullYear(), nowDate.getMonth(), nowDate.getDate());
for(let i=0; i<this.Data.Data.length; ++i)
{
var item=this.Data.Data[i];
result[i]=null;
if (!this.IsNumber(item.Date)) continue;
var year=parseInt(item.Date/10000);
var month=parseInt(item.Date%10000/100);
var day=item.Date%100;
var beginDate=new Date(year,month-1,day);
var diffDays = Math.ceil((endDate - beginDate)/(24*60*60*1000));
result[i]=diffDays;
}
return result;
}
/*
取得该周是年内第几个周.
用法:WEEKOFYEAR
*/
this.WEEKOFYEAR=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
var item=this.Data.Data[i];
result[i]=null;
if (!this.IsNumber(item.Date)) continue;
var year=parseInt(item.Date/10000);
var month=parseInt(item.Date%10000/100);
var day=item.Date%100;
var endDate=new Date(year,month-1,day);
var beginDate=new Date(year,0,1);
var diffDays = Math.ceil((endDate - beginDate)/(24*60*60*1000));
diffDays+=((beginDate.getDay() + 1) - 1);
var week = Math.ceil(diffDays/7);
var value=week;
result[i]=value;
}
return result;
}
this.GetYearWeek=function(endDate)
{
var beginDate = new Date(endDate.getFullYear(), 0, 1);
//星期从0-6,0代表星期天,6代表星期六
var endWeek = endDate.getDay();
if (endWeek == 0) endWeek = 7;
var beginWeek = beginDate.getDay();
if (beginWeek == 0) beginWeek = 7;
//计算两个日期的天数差
var millisDiff = endDate.getTime() - beginDate.getTime();
var dayDiff = Math.floor(( millisDiff + (beginWeek - endWeek) * (24 * 60 * 60 * 1000)) / 86400000);
return Math.ceil(dayDiff / 7) + 1;
}
this.REFDATE=function(data,date)
{
var result=null;
var findDate=null;
if (Array.isArray(date))
{
if (date.length>0) findDate=date[date.length-1];
}
else if (this.IsNumber(date))
{
findDate=date;
}
if (findDate==null) return null;
if (findDate<5000000) findDate+=19000000;
var index=null;
for(let i in this.Data.Data) //查找日期对应的索引
{
if (this.Data.Data[i].Date==findDate)
{
index=parseInt(i);
break;
}
}
if (index==null || index>=data.length) return null;
return data[index];
}
//用法:结果从0到11,依次分别是1/5/15/30/60分钟,日/周/月,多分钟,多日,季,年
this.PERIOD=function()
{
//Period周期 0=日线 1=周线 2=月线 3=年线 9=季线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟
const PERIOD_MAP=[5,6,7,11, 0,1,2,3,4,5, 9];
if (this.Period>=0 && this.Period<=PERIOD_MAP.length-1)
return PERIOD_MAP[this.Period];
return this.Period;
}
this.GetDrawNull=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;
for(let i in this.Data.Data)
{
result[i]=null;
}
return result;
}
this.HOUR=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return result;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
result[i]=0;
if (IFrameSplitOperator.IsNumber(item.Time)) result[i]=parseInt(item.Time/100);
}
return result;
}
this.MINUTE=function()
{
var result=[];
if (!this.Data || !this.Data.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return result;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
result[i]=0;
if (IFrameSplitOperator.IsNumber(item.Time)) result[i]=item.Time%100;
}
return result;
}
/*
飞狐函数 SYSPARAM
SYSPARAM(1)画面上光标位置(K线序号)
SYSPARAM(2)主图可见K线最初位置
SYSPARAM(3)主图可见K线最后位置,注意:该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
SYSPARAM(4)主图可见K线最高价,注意:该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
SYSPARAM(5)主图可见K线最低价,注意:该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
SYSPARAM(6)画面上光标数值,注意:该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
*/
this.SysParam=function(id, jsExec)
{
if (!this.DrawInfo) return [];
if (id==2)
{
jsExec.IsUsePageData=true;
if (IFrameSplitOperator.IsNumber(this.DrawInfo.Start))
return this.DrawInfo.Start+1;
}
else if (id==3)
{
jsExec.IsUsePageData=true;
if (IFrameSplitOperator.IsNumber(this.DrawInfo.End))
return this.DrawInfo.End+1;
}
else if (id==4)
{
jsExec.IsUsePageData=true;
if (!IFrameSplitOperator.IsNumber(this.DrawInfo.End) ||!IFrameSplitOperator.IsNumber(this.DrawInfo.Start)) return [];
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return [];
var high=null;
for(var i=this.DrawInfo.Start; i<=this.DrawInfo.End && i<this.Data.Data.length; ++i)
{
var item=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(item.High)) continue;
if (high==null) high=item.High;
else if(high<item.High) high=item.High;
}
return high;
}
else if (id==5)
{
jsExec.IsUsePageData=true;
if (!IFrameSplitOperator.IsNumber(this.DrawInfo.End) ||!IFrameSplitOperator.IsNumber(this.DrawInfo.Start)) return [];
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return [];
var low=null;
for(var i=this.DrawInfo.Start;i<=this.DrawInfo.End && i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(item.Low)) continue;
if (low==null) low=item.Low;
else if(low>item.Low) low=item.Low;
}
return low;
}
return [];
}
}
//是否有是有效的数字
JSSymbolData.prototype.IsNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return true;
}
JSSymbolData.prototype.IsDivideNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
if (value==0) return false;
return true;
}
JSSymbolData.prototype.JsonDataToFinance=function(data)
{
var financeData;
for(let i=1;i<=4;++i)
{
switch(i)
{
case 1:
var finance=data.finance1;
var announcement=data.announcement1;
break;
case 2:
var finance=data.finance2;
var announcement=data.announcement2;
break;
case 3:
var finance=data.finance3;
var announcement=data.announcement3;
break;
case 4:
var finance=data.finance4;
var announcement=data.announcement4;
break;
default:
break;
}
if (!finance || !announcement || !this.IsNumber(announcement.year) || !this.IsNumber(announcement.quarter)) continue;
if (financeData) //如果存在1天公布多个报告期数据 只取最新的一个公告期数据
{
if (financeData.Announcement.year<announcement.year)
financeData={Date:data.date, Finance:finance, Announcement:announcement};
}
else
{
financeData={Date:data.date, Finance:finance, Announcement:announcement};
}
}
return financeData;
}
var JS_EXECUTE_DEBUG_LOG=false;
var JS_EXECUTE_JOB_ID=
{
JOB_DOWNLOAD_SYMBOL_DATA:1, //下载股票的K线数据
JOB_DOWNLOAD_INDEX_DATA:2, //下载大盘的K线数据
JOB_DOWNLOAD_SYMBOL_LATEST_DATA:3, //最新的股票行情数据
JOB_DOWNLOAD_INDEX_INCREASE_DATA:4, //涨跌股票个数统计数据
JOB_DOWNLOAD_VOLR_DATA:5, //5日量比均量下载量比数据
JOB_DOWNLOAD_LATEST_INDEX_DATA:8, //下载最新大盘数据
JOB_DOWNLOAD_OTHER_SYMBOL_DATA:9, //下载其他股票的K线数据
JOB_DOWNLOAD_SYMBOL_PERIOD_DATA:10, //下载周期数据
JOB_DOWNLOAD_FINVALUE:301, //引用专业财务数据 FINVALUE(ID),ID为数据编号
JOB_DOWNLOAD_FINONE:302, //引用指定年和月日的某类型的财务数据 FINONE(ID,Y,MMDD),ID为数据编号,Y和MMDD表示年和月日.
JOB_DOWNLOAD_FINANCE:303, //FINANCE(ID) 基础财务数据
JOB_DOWNLOAD_GPJYVALUE:304, //引用股票交易类数据 GPJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
JOB_DOWNLOAD_VARIANT:305, //CAPITAL , TOTALCAPITAL, EXCHANGE
JOB_DOWNLOAD_SCJYVALUE:306, //引用市场总的交易类数据.SCJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
JOB_DOWNLOAD_GPJYONE:307, //GPJYONE(ID,N,Y,MMDD),ID为数据编号,N表示第几个数据(取1或2),Y和MMDD表示年和月日. 如果Y为0,MMDD为0,表示最新数据,MMDD为1,2,3...,表示倒数第2,3,4...个数据
JOB_DOWNLOAD_SCJYONE:308, //SCJYONE(ID,N,Y,MMDD),ID为数据编号,N表示第几个数据(取1或2),Y和MMDD表示年和月日.如果Y为0,MMDD为0,表示最新数据,MMDD为1,2,3...,表示倒数第2,3,4...个数据
JOB_DOWNLOAD_BKJYVALUE:309, //BKJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据(取1或2),TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理;2表示没有数据则为0.
JOB_DOWNLOAD_BKJYONE:310, //BKJYONE(ID,N,Y,MMDD),ID为数据编号,N表示第几个数据(取1或2),Y和MMDD表示年和月日.如果Y为0,MMDD为0,表示最新数据,MMDD为1,2,3...,表示倒数第2,3,4...个数据
JOB_DOWNLOAD_MARGIN_BALANCE:1000, //融资融券余额
JOB_DOWNLOAD_MARGIN_RATE:1001, //融资占比
JOB_DOWNLOAD_MARGIN_BUY_BALANCE:1010, //买入信息-融资余额
JOB_DOWNLOAD_MARGIN_BUY_AMOUNT:1011, //买入信息-买入额
JOB_DOWNLOAD_MARGIN_BUY_REPAY:1012, //买入信息-偿还额
JOB_DOWNLOAD_MARGIN_BUY_NET:1013, //买入信息-融资净买入
JOB_DOWNLOAD_MARGIN_SELL_BALANCE:1020, //卖出信息-融券余量
JOB_DOWNLOAD_MARGIN_SELL_VOLUME:1021, //卖出信息-卖出量
JOB_DOWNLOAD_MARGIN_SELL_REPAY:1022, //卖出信息-偿还量
JOB_DOWNLOAD_MARGIN_SELL_NET:1023, //卖出信息-融券净卖出
JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE:2000, //负面新闻统计
JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH:2001, //机构调研
JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT:2002, //互动易
JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE:2003, //股东增持
JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2:2004, //股东减持
JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER:2005, //信托持股
JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING:2006, //大宗交易
JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS:2007, //官网新闻
JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS:2008, //高管要闻
JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE:2009, //股权质押
JOB_DOWNLOAD_HK_TO_SH:2050, //北上流入上证
JOB_DOWNLOAD_HK_TO_SZ:2051, //北上流入深证
JOB_DOWNLOAD_HK_TO_SH_SZ:2052, //北上流总的
JOB_DOWNLOAD_HK_TO_SHSZ:2053, //个股北上流入
JOB_CUSTOM_FUNCTION_DATA:6000, //自定义函数
JOB_CUSTOM_VARIANT_DATA:6001, //自定义变量
JOB_CUSTOM_DATA_FUNCTION:6002, //自定义数据函数
//截面数据
//财务数据 SF(公告期,数据名称) 如: SF(201901,"流动资产");
JOB_DOWNLOAD_SECTION_SF:20000,
JOB_DOWNLOAD_SECTION_F_01:20001, //currentassets 流动资产
JOB_DOWNLOAD_SECTION_F_02:20002, //monetaryfunds 货币资金
JOB_DOWNLOAD_SECTION_F_03:20003, //inventory 存货
JOB_DOWNLOAD_SECTION_F_04:20004, //currentliabilities 流动负债
JOB_DOWNLOAD_SECTION_F_05:20005, //ncurrentliabilities 非流动负债
JOB_DOWNLOAD_SECTION_F_06:20006, //3expenses 三项费用
JOB_DOWNLOAD_SECTION_F_07:20007, //investmentincome 投资收益
JOB_DOWNLOAD_SECTION_F_08:20008, //pcnprofit 归母净利润
JOB_DOWNLOAD_SECTION_F_09:20009, //nnetprofit 扣非净利润
JOB_DOWNLOAD_SECTION_F_10:20010, //npersearning 扣非每股收益
JOB_DOWNLOAD_SECTION_F_11:20011, //woewa 加权平均净资产收益
JOB_DOWNLOAD_SECTION_F_12:20012, //inprocess 在建工程
JOB_DOWNLOAD_SECTION_F_13:20013, //accdepreciation 累计折旧
JOB_DOWNLOAD_SECTION_F_14:20014, //mholderprofit 少数股东利润
JOB_DOWNLOAD_SECTION_F_15:20015, //lossexchange 汇兑损益
JOB_DOWNLOAD_SECTION_F_16:20016, //baddebts 坏账计提
JOB_DOWNLOAD_SECTION_F_17:20017, //fixedassets 固定资产
JOB_DOWNLOAD_SECTION_F_18:20018, //curdepreciation 当期折旧
JOB_DOWNLOAD_SECTION_F_19:20019, //orevenues 营业总收入
JOB_DOWNLOAD_SECTION_F_20:20020, //moprofit 主营业务利润
JOB_DOWNLOAD_SECTION_F_21:20021, //oprofit 营业利润
JOB_DOWNLOAD_SECTION_F_22:20022, //nprofit 净利润
JOB_DOWNLOAD_SECTION_F_23:20023, //areceivable 应收账款
JOB_DOWNLOAD_SECTION_F_24:20024, //financialcost 财务费用
JOB_DOWNLOAD_SECTION_F_25:20025, //ccfo 经营性现金流
JOB_DOWNLOAD_SECTION_F_26:20026, //totalassets 资产总计
JOB_DOWNLOAD_SECTION_F_27:20027, //totalliabilities 负债总计
JOB_DOWNLOAD_SECTION_F_28:20028, //totalownersequity 所有者权益总计
JOB_DOWNLOAD_SECTION_F_29:20029, //grossmargin 毛利率
JOB_DOWNLOAD_SECTION_F_30:20030, //percreserve 每股资本公积金
JOB_DOWNLOAD_SECTION_F_31:20031, //peruprofit 每股未分配利润
JOB_DOWNLOAD_SECTION_F_32:20032, //persearning 每股收益
JOB_DOWNLOAD_SECTION_F_33:20033, //pernetasset 每股净资产
JOB_DOWNLOAD_SECTION_F_34:20034, //perccfo 每股经营性现金流
JOB_DOWNLOAD_SECTION_F_35:20035, //nnprofitincrease finance4特有,扣非净利润涨幅
JOB_DOWNLOAD_SECTION_F_36:20036, //nnprofitspeed finance4特有,扣非净利润涨速
JOB_DOWNLOAD_SECTION_F_37:20037, //nprofitincrease finance4特有,净利润涨幅
JOB_DOWNLOAD_SECTION_F_38:20038, //alratio 资产负债率(数值乘以100)
JOB_DOWNLOAD_SECTION_F_39:20039, //profityoy 利润同比%(数值乘以100)
JOB_DOWNLOAD_CUSTOM_API_DATA:30000, //自定义数据
//调用其他脚本指标
//KDJ.K , KDJ.K#WEEK
//STKINDI('600000.sh','MA.MA1#WEEK',5,10,20,30,60,120);
//CALCSTOCKINDEX('SH600000','KDJ',3)表示上证600000的KDJ指标第3个输出即J之值,第一个参数可在前面加SZ(深市),SH(沪市),BJ(京市)
//"MA.MA(5,5,5)" 调用动态指标
JOB_EXECUTE_INDEX:30010,
JOB_RUN_SCRIPT:10000, //执行脚本
//融资融券
GetMarginJobID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE], //MARGIN(1) 融资融券余额
[2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE], //MARGIN(2) 融资占比
[3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE], //MARGIN(3) 买入信息-融资余额
[4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT], //MARGIN(4) 买入信息-买入额
[5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY], //MARGIN(5) 买入信息-偿还额
[6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET], //MARGIN(6) 买入信息-融资净买入
[7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE], //MARGIN(7) 卖出信息-融券余量
[8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME], //MARGIN(8) 卖出信息-卖出量
[9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY], //MARGIN(9) 卖出信息-偿还量
[10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET], //MARGIN(10) 卖出信息-融券净卖出
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
GetNewsAnalysisID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE], //NEWS(1) 负面新闻统计
[2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH], //NEWS(2) 机构调研统计
[3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT], //NEWS(3) 互动易
[4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE], //NEWS(4) 股东增持
[5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2], //NEWS(5) 股东减持
[6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER], //NEWS(6) 信托持股
[7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING], //NEWS(7) 大宗交易
[8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS], //NEWS(8) 官网新闻
[9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS], //NEWS(9) 高管要闻
[10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE], //NEWS(10) 股权质押
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//财务截面数据 分报告期
GetSectionFinanceID:function(value)
{
let dataMap=new Map([
['流动资产', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_01],
['货币资金', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_02],
['存货', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_03],
['流动负债', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_04],
['非流动负债',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_05],
['三项费用',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_06],
['投资收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_07],
['归母净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_08],
['扣非净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_09],
['扣非每股收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_10],
['加权平均净资产收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_11],
['在建工程',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_12],
['累计折旧',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_13],
['少数股东利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_14],
['汇兑损益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_15],
['坏账计提',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_16],
['固定资产',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_17],
['当期折旧',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_18],
['营业总收入',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_19],
['主营业务利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_20],
['营业利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_21],
['净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_22],
['应收账款',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_23],
['财务费用',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_24],
['经营性现金流',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_25],
['资产总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_26],
['负债总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_27],
['所有者权益总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_28],
['毛利率',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_29],
['每股资本公积金',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_30],
['每股未分配利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_31],
['每股收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_32],
['每股净资产',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_33],
['每股经营性现金流',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_34],
['扣非净利润涨幅',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_35],
['扣非净利润涨速',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_36],
['净利润涨幅',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_37],
['资产负债率',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_38],
['利润同比',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_39],
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//获取报告期 2018, 1
GetSectionReportPeriod:function(year,quarter)
{
if (year>=2000 && quarter>=1 && quarter<=4)
return { Year:year, Quarter:quarter };
return null;
}
};
//专业财务数据
var JS_ARRAY_PROFESSIONAL_FINANCE=
[
{
Name:"GPJYVALUE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE,
Explain:"股票交易类数据GPJYVALUE(ID,N,TYPE)", FuncName:"JSSymbolData::GetGPJYValue", ArgCount:3
},
{
Name:"GPJYONE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYONE,
Explain:"股票交易类数据GPJYONE(ID,N,Y,MMDD)", FuncName:"JSSymbolData::GetGPJYOne", ArgCount:4
},
{
Name:"SCJYVALUE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYVALUE,
Explain:"市场交易类数据SCJYVALUE(ID,N,TYPE)", FuncName:"JSSymbolData::GetSCJYValue",ArgCount:3
},
{
Name:"SCJYONE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYONE,
Explain:"市场交易类数据SCJYONE(ID,N,Y,MMDD)", FuncName:"JSSymbolData::GetSCJYOne",ArgCount:4
},
{
Name:"BKJYVALUE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_BKJYVALUE,
Explain:"板块交易类数据BKJYVALUE(ID,N,TYPE)", FuncName:"JSSymbolData::GetBKJYValue",ArgCount:3
},
{
Name:"BKJYONE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_BKJYONE,
Explain:"板块交易类数据BKJYONE(ID,N,Y,MMDD)", FuncName:"JSSymbolData::GetBKJYOne",ArgCount:4
},
{
Name:"FINVALUE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE,
Explain:"财务数据FINVALUE(ID)", FuncName:"JSSymbolData::GetFinValue",ArgCount:1
},
{
Name:"FINONE", JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE,
Explain:"财务数据FINONE(ID,Y,MMDD)", FuncName:"JSSymbolData::GetFinOne",ArgCount:3
}
];
function JSExecute(ast,option)
{
this.AST=ast; //语法树
this.ErrorHandler=new ErrorHandler();
this.VarTable=new Map(); //变量表
this.VarDrawTable=new Map(); //绘图变量表
this.OutVarTable=[]; //输出变量
this.Arguments=[];
this.ErrorCallback; //执行错误回调
this.GetEventCallback;
this.IsUsePageData=false;
this.IndexCtrl;
this.Debug=0; //0=非debug模式 1=debug 模式
this.DebugFilter;
this.Interrupt={ Exit:false }; //中断信息
//脚本自动变量表, 只读
this.ConstVarTable=new Map([
//个股数据
['CLOSE',null],['VOL',null],['OPEN',null],['HIGH',null],['LOW',null],['AMOUNT',null],
['C',null],['V',null],['O',null],['H',null],['L',null],['AMO',null],
['VOLR',null], //量比
['VOLINSTK',null], ["OPI",null], //持仓量
["QHJSJ",null], ["SETTLE",null], //结算价
["ZSTJJ",null], //分时图均价线,对于分时图周期指标有效.
["ISEQUAL",null], ["ISUP",null],["ISDOWN"], //ISUP=收阳 ISEQUAL=平盘 ISDOWN=收阴
//日期类
['DATE',null],['YEAR',null],['MONTH',null],['PERIOD', null],['WEEK',null],['WEEKDAY',null],["TIME",null],["DAY",null],["DATETIME",null],["TIME2",null],
["WEEKOFYEAR", null],["DAYSTOTODAY", null],
["HOUR",null],["MINUTE",null],
//大盘数据
['INDEXA',null],['INDEXC',null],['INDEXH',null],['INDEXL',null],['INDEXO',null],['INDEXV',null],
['INDEXADV',null],['INDEXDEC',null],
["ADVANCE",null],['DECLINE', null],
['FROMOPEN',null], //已开盘有多长分钟
['TOTALFZNUM', null], //该品种的每天的总交易分钟数.
['CURRBARSCOUNT',null], //到最后交易日的周期数
['TOTALBARSCOUNT',null],
['ISLASTBAR',null], //判断是否为最后一个周期
['BARSTATUS',null], //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.
["BARPOS", null], //返回从第一根K线开始到当前的周期数
['CAPITAL',null], //流通股本(手)
["TOTALCAPITAL",null], //TOTALCAPITAL 当前总股本 手
['EXCHANGE',null], //换手率
['SETCODE', null], //市场类型
['CODE',null], //品种代码
['STKNAME',null], //品种名称
["TQFLAG",null], //TQFLAG 当前的复权状态,0:无复权 1:前复权 2:后复权
['HYBLOCK',null], //所属行业板块
['DYBLOCK',null], //所属地域板块
['GNBLOCK',null], //所属概念
["FGBLOCK",null], //所属风格板块
["ZSBLOCK",null], //所属指数板块
["ZHBLOCK",null], //所属组合板块
["ZDBLOCK",null], //所属自定义板块
["HYZSCODE",null],
["GNBLOCKNUM",null], //所属概念板块的个数
["FGBLOCKNUM",null], //所属风格板块的个数
["ZSBLOCKNUM",null], //所属指数板块的个数
["ZHBLOCKNUM",null], //所属组合板块的个数
["ZDBLOCKNUM",null], //所属自定义板块的个数
["HYSYL",null], //指数市盈率或个股所属行业的市盈率
["HYSJL",null], //指数市净率或个股所属行业的市净率
['DRAWNULL',null],
["NULL",null],
["MACHINEDATE",null],["MACHINETIME",null],["MACHINEWEEK",null],
["TR", null], //真实波幅
["AUTOFILTER", null],
['LARGEINTRDVOL', null], //逐笔买入大单成交量,相当于L2_VOL(0,0)+L2_VOL(1,0),沪深京品种的资金流向,仅日线以上周期,用于特定版本
['LARGEOUTTRDVOL', null], //逐笔卖出大单成交量,相当于L2_VOL(0,1)+L2_VOL(1,1),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["TRADENUM", null], //逐笔成交总单数,沪深京品种的资金流向,仅日线以上周期,用于特定版本
["TRADEINNUM", null], //逐笔买入成交单数,相当于L2_VOLNUM(0,0)+L2_VOLNUM(1,0),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["TRADEOUTNUM", null], //逐笔卖出成交单数,相当于L2_VOLNUM(0,1)+L2_VOLNUM(1,1),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["LARGETRDINNUM", null], //逐笔买入大单成交单数,相当于L2_VOLNUM(0,0),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["LARGETRDOUTNUM", null], //逐笔卖出大单成交单数,相当于L2_VOLNUM(0,1),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["CUR_BUYORDER", null], //总委买量,序列数据,专业版等(资金流向功能)沪深京品种行情专用
["CUR_SELLORDER", null], //总委卖量,序列数据,专业版等(资金流向功能)沪深京品种行情专用
["ACTINVOL", null], //主动买成交量,相当于L2_VOL(0,2)+L2_VOL(1,2)+L2_VOL(2,2)+L2_VOL(3,2),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["ACTOUTVOL", null], //主动卖成交量,相当于L2_VOL(0,3)+L2_VOL(1,3)+L2_VOL(2,3)+L2_VOL(3,3),沪深京品种的资金流向,仅日线以上周期,用于特定版本
["BIDORDERVOL", null], //累计总有效委买量,专业版等(资金流向功能)沪深京品种行情专用 累计总有效委买量-累计总有效撤买量=总买+总成交量
["BIDCANCELVOL", null], //累计总有效撤买量,专业版等(资金流向功能)沪深京品种行情专用 累计总有效委买量-累计总有效撤买量=总买+总成交量
["AVGBIDPX", null], //专业版等(资金流向功能)沪深京品种行情专用:最新委买均价
["OFFERORDERVOL", null], //累计总有效委卖量,专业版等(资金流向功能)沪深京品种行情专用 累计总有效委卖量-累计总有效撤卖量=总卖+总成交量
["OFFERCANCELVOL", null], //累计总有效撤卖量,专业版等(资金流向功能)沪深京品种行情专用 累计总有效委卖量-累计总有效撤卖量=总卖+总成交量
["AVGOFFERPX", null], //专业版等(资金流向功能)沪深京品种行情专用:最新委卖均价
//["", null],
]);
this.SymbolData=new JSSymbolData(this.AST,option,this);
this.Algorithm=new JSAlgorithm(this.ErrorHandler,this.SymbolData);
this.Draw=new JSDraw(this.ErrorHandler,this.SymbolData);
this.JobList=[]; //执行的任务队列
this.UpdateUICallback=null; //回调
this.CallbackParam=null;
this.IsSectionMode=false;
if (option)
{
if (option.Callback) this.UpdateUICallback=option.Callback;
if (option.CallbackParam)
{
this.CallbackParam=option.CallbackParam;
if (this.CallbackParam.HQChart)
this.GetEventCallback=(id)=> { return this.CallbackParam.HQChart.GetEventCallback(id); }
}
if (option.Arguments) this.Arguments=option.Arguments;
if (option.IsSectionMode) this.IsSectionMode=option.IsSectionMode;
if (option.Self) this.IndexCtrl=option.Self;
//调试模式信息
if (IFrameSplitOperator.IsNumber(option.Debug)) this.Debug=option.Debug;
if (option.DebugFilter) this.DebugFilter=option.DebugFilter;
}
this.Execute=function()
{
this.OutVarTable=[];
this.VarTable=new Map();
this.VarDrawTable=new Map(); //绘图变量表
JSConsole.Complier.Log('[JSExecute::Execute] Load Arguments', this.Arguments);
for(let i in this.Arguments) //预定义的变量
{
let item =this.Arguments[i];
this.VarTable.set(item.Name,item.Value);
}
this.RunNextJob();
}
this.RunNextJob=function()
{
if (this.JobList.length<=0) return;
JSConsole.Complier.Log('[JSExecute::Execute] JobList', this.JobList);
var jobItem=this.JobList.shift();
switch(jobItem.ID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA:
return this.SymbolData.GetSymbolData();
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_PERIOD_DATA:
return this.SymbolData.GetSymbolPeriodData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_DATA:
return this.SymbolData.GetIndexData();
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_LATEST_INDEX_DATA:
return this.SymbolData.GetLatestIndexData();
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA:
return this.SymbolData.GetIndexIncreaseData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_LATEST_DATA:
return this.SymbolData.GetLatestData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA: //量比
return this.SymbolData.GetVolRateData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA: //指定股票数据
return this.SymbolData.GetOtherSymbolData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_RELEASE_DATE_DATA:
return this.SymbolData.GetCompanyReleaseDate(jobItem.ID);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出
return this.SymbolData.GetMarginData(jobItem.ID);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE: //负面新闻
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH: //机构调研
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT: //互动易
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE: //股东增持
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2: //股东减持
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER: //信托持股
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING: //大宗交易
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS: //官网新闻
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS: //高管要闻
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE: //股权质押
return this.SymbolData.GetNewsAnalysisData(jobItem.ID);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SHSZ:
return this.SymbolData.GetHKToSHSZData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF:
return this.SymbolData.GetSectionFinanceData(jobItem); //财务截面报告数据
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE:
return this.SymbolData.GetFinance(jobItem);
//专业财务数据
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYONE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYVALUE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYONE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_BKJYVALUE:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_BKJYONE:
return this.SymbolData.GetProFinance(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT: //CAPITAL, TOTALCAPITAL
return this.SymbolData.GetVariantData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA:
return this.SymbolData.GetCustomVariantData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA:
return this.SymbolData.GetCustomFunctionData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_CUSTOM_DATA_FUNCTION:
return this.SymbolData.GetCustomFunctionDataV2(jobItem);
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA:
return this.SymbolData.DownloadCustomAPIData(jobItem);
case JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX:
return this.SymbolData.CallScriptIndex(jobItem, this.VarTable);
case JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT:
if (this.Debug===1 && this.DebugFilter)
return this.DebugRun();
else
return this.Run();
}
}
this.ReadSymbolData=function(name,node)
{
switch(name)
{
case 'CLOSE':
case 'C':
case 'VOL':
case 'V':
case 'OPEN':
case 'O':
case 'HIGH':
case 'H':
case 'LOW':
case 'L':
case 'AMOUNT':
case 'AMO':
case "OPI":
case 'VOLINSTK':
case "SETTLE":
case "QHJSJ":
case "ZSTJJ":
case "ISEQUAL": //平盘
case "ISUP": //收阳
case "ISDOWN": //收阴
return this.SymbolData.GetSymbolCacheData(name);
case 'VOLR':
return this.SymbolData.GetVolRateCacheData(node);
case "TR": //TR,求真实波幅.
return this.SymbolData.GetTRData(node);
//大盘数据
case 'INDEXA':
case 'INDEXC':
case 'INDEXH':
case 'INDEXH':
case 'INDEXO':
case 'INDEXV':
case 'INDEXL':
case 'INDEXADV':
case 'INDEXDEC':
return this.SymbolData.GetIndexCacheData(name);
case 'CURRBARSCOUNT':
return this.SymbolData.GetCurrBarsCount();
case "BARPOS":
return this.SymbolData.GetBarPos();
case "TOTALBARSCOUNT":
return this.SymbolData.GetTotalBarsCount();
case "TOTALFZNUM":
return this.SymbolData.GetTotalTradeMinuteCount();
case 'ISLASTBAR':
return this.SymbolData.GetIsLastBar();
case "BARSTATUS":
return this.SymbolData.GetBarStatus();
case "TOTALCAPITAL":
case 'CAPITAL':
case 'EXCHANGE':
case "HYBLOCK":
case "DYBLOCK":
case "GNBLOCK":
case "FGBLOCK":
case "ZSBLOCK":
case "ZHBLOCK":
case "ZDBLOCK":
case "HYZSCODE":
case "GNBLOCKNUM":
case "FGBLOCKNUM":
case "ZSBLOCKNUM":
case "ZHBLOCKNUM":
case "ZDBLOCKNUM":
case "HYSYL":
case "HYSJL":
case 'FROMOPEN':
case "LARGEINTRDVOL":
case "LARGEOUTTRDVOL":
case "TRADENUM":
case "TRADEINNUM":
case "TRADEOUTNUM":
case "LARGETRDINNUM":
case "LARGETRDOUTNUM":
case "CUR_BUYORDER":
case "CUR_SELLORDER":
case "ACTINVOL":
case "ACTOUTVOL":
case "BIDORDERVOL":
case "BIDCANCELVOL":
case "AVGBIDPX":
case "OFFERORDERVOL":
case "OFFERCANCELVOL":
case "AVGOFFERPX":
return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node });
case 'SETCODE':
return this.SymbolData.SETCODE();
case 'CODE':
return this.SymbolData.GetSymbol();
case 'STKNAME':
return this.SymbolData.GetName();
case "TIME":
return this.SymbolData.TIME();
case "TIME2":
return this.SymbolData.TIME2();
case 'DATE':
return this.SymbolData.DATE();
case "DATETIME":
return this.SymbolData.DateTime();
case 'YEAR':
return this.SymbolData.YEAR();
case 'MONTH':
return this.SymbolData.MONTH();
case 'WEEK':
case "WEEKDAY":
return this.SymbolData.WEEK();
case "DAY":
return this.SymbolData.DAY();
case 'PERIOD':
return this.SymbolData.PERIOD();
case "HOUR":
return this.SymbolData.HOUR();
case "MINUTE":
return this.SymbolData.MINUTE();
case 'DRAWNULL':
case "NULL":
return this.SymbolData.GetDrawNull();
case 'ADVANCE':
case 'DECLINE':
return this.SymbolData.GetIndexIncreaseCacheData(name,this.SymbolData.Symbol,node);
case "TQFLAG":
return this.SymbolData.Right;
case "MACHINEDATE":
{
var now=new Date();
return (now.getFullYear()*10000+(now.getMonth()*1)*100+now.getDate())-19000000;
}
case "MACHINETIME":
{
var now=new Date();
return now.getHours()*10000+(now.getMinutes()*1)*100+now.getSeconds();
}
case "MACHINEWEEK":
{
var now=new Date();
return now.getDay();
}
case "WEEKOFYEAR":
return this.SymbolData.WEEKOFYEAR();
case "DAYSTOTODAY":
return this.SymbolData.DAYSTOTODAY();
}
this.ThrowUnexpectedNode(node, '变量'+name+'不存在', name);
}
this.ReadCustomVariant=function(name,node)
{
return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node });
}
//读取变量
this.ReadVariable=function(name,node)
{
if (this.ConstVarTable.has(name))
{
let data=this.ConstVarTable.get(name);
if (data==null) //动态加载,用到再加载
{
data=this.ReadSymbolData(name,node);
this.ConstVarTable.set(name,data);
}
return data;
}
if (g_JSComplierResource.IsCustomVariant(name)) return this.ReadCustomVariant(name,node); //读取自定义变量
if (this.VarTable.has(name)) return this.VarTable.get(name);
if (name.indexOf('#')>0)
{
var aryPeriod=name.split('#');
return this.SymbolData.GetSymbolPeriodCacheData(aryPeriod[0],aryPeriod[1]);
}
if (name.indexOf("COLOR")==0)
{
var colorValue=JSComplier.ColorVarToRGB(name);
if (colorValue) return colorValue;
}
this.ThrowUnexpectedNode(node, '变量'+name+'不存在', name);
return null;
}
this.ReadMemberVariable=function(node)
{
var obj=node.Object;
var member=node.Property;
let maiObj;
if (obj.Type==Syntax.BinaryExpression || obj.Type==Syntax.LogicalExpression )
maiObj=this.VisitBinaryExpression(obj);
else if (obj.Type==Syntax.CallExpression)
maiObj=this.VisitCallExpression(obj);
else
maiObj=this.GetNodeValue(obj);
if (!maiObj) return null;
var value=maiObj[member.Name];
if (value) return value;
return null;
}
//单数据转成数组 个数和历史数据一致
this.SingleDataToArrayData=function(value)
{
let count=this.SymbolData.Data.Data.length;
let result=[];
for(let i=0;i<count;++i)
{
result[i]=value;
}
return result;
}
this.RunAST=function()
{
if (!this.AST) this.ThrowError();
if (!this.AST.Body) this.ThrowError();
for(let i=0; i<this.AST.Body.length; ++i)
{
let item =this.AST.Body[i];
this.RunASTNode(item,i);
if (this.Interrupt && this.Interrupt.Exit)
{
JSConsole.Complier.Log('[JSExecute::RunAST] Interrupt', this.Interrupt); //中断退出
break;
}
}
JSConsole.Complier.Log('[JSExecute::RunAST]', this.VarTable);
return this.OutVarTable;
}
this.RunASTNode=function(item, lineID)
{
this.VisitNode(item);
var i=lineID;
//输出变量
if (item.Type==Syntax.ExpressionStatement && item.Expression)
{
if (item.Expression.Type==Syntax.AssignmentExpression)
{
if (item.Expression.Operator==':' && item.Expression.Left)
{
let assignmentItem=item.Expression;
let varName=assignmentItem.Left.Name;
let outVar=this.VarTable.get(varName);
if (this.VarDrawTable.has(varName)) //绘图函数赋值
{
let draw=this.VarDrawTable.get(varName);
this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1});
}
else
{
var type=0;
if (outVar && typeof(outVar)=='object' && outVar.__Type__=='Object')
{
type=1000;
}
else if (!this.IsSectionMode && !Array.isArray(outVar))
{
if (typeof(outVar)=='string')
{
var floatValue=parseFloat(outVar);
if (IFrameSplitOperator.IsNumber(floatValue))
{
outVar=this.SingleDataToArrayData(floatValue);
}
else
{
outVar=this.SingleDataToArrayData(outVar);
type=1001;
}
}
else outVar=this.SingleDataToArrayData(outVar);
}
this.OutVarTable.push({Name:varName, Data:outVar,Type:type});
}
}
}
else if (item.Expression.Type==Syntax.CallExpression)
{
let callItem=item.Expression;
if (this.Draw.IsDrawFunction(callItem.Callee.Name) )
{
let draw=callItem.Draw;
draw.Name=callItem.Callee.Name;
this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1});
}
else if (callItem.Callee.Name==="IFC" && callItem.Draw)
{
let draw=callItem.Draw;
draw.Name=draw.DrawType;
this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1});
}
else
{
let outVar=callItem.Out;
varName=`__temp_c_${callItem.Callee.Name}_${i}__`;
var type=0;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
this.OutVarTable.push({Name:varName, Data:outVar,Type:type,NoneName:true});
}
}
else if (item.Expression.Type==Syntax.Identifier)
{
let varName=item.Expression.Name;
let outVar=this.ReadVariable(varName,item.Expression);
var type=0;
if (outVar && typeof(outVar)=='object' && outVar.__Type__=='Object')
{
type=1000;
}
else if (!this.IsSectionMode && !Array.isArray(outVar))
{
if (typeof(outVar)=='string') outVar=this.SingleDataToArrayData(parseFloat(outVar));
else outVar=this.SingleDataToArrayData(outVar);
}
varName="__temp_i_"+i+"__";
this.OutVarTable.push({Name:varName, Data:outVar, Type:type, NoneName:true});
}
else if (item.Expression.Type==Syntax.Literal) //常量
{
let outVar=item.Expression.Value;
if (IFrameSplitOperator.IsString(outVar) && outVar.indexOf("$")>0)
outVar=this.SymbolData.GetOtherSymolCacheData({ Literal:outVar });
varName="__temp_li_"+i+"__";
var type=0;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
this.OutVarTable.push({Name:varName, Data:outVar, Type:type, NoneName:true});
}
else if (item.Expression.Type==Syntax.BinaryExpression)
{
var varName="__temp_b_"+i+"__";
let outVar=item.Expression.Out;
var type=0;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true});
}
else if (item.Expression.Type==Syntax.LogicalExpression) //逻辑语句 如 T1 AND T2
{
var varName="__temp_l_"+i+"__";
let outVar=item.Expression.Out;
var type=0;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true});
}
else if (item.Expression.Type==Syntax.UnaryExpression)
{
var varName="__temp_u_"+i+"__";
var varInfo={ };
if (this.ReadUnaryExpression(item.Expression, varInfo))
{
var type=0;
this.OutVarTable.push({Name:varName, Data:varInfo.OutVar,Type:type, NoneName:true});
}
}
else if (item.Expression.Type==Syntax.MemberExpression) //MA.MA2
{
var outVar=this.ReadMemberVariable(item.Expression);
if (outVar)
{
var type=0;
var varName="__temp_di_"+i+"__";
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true});
}
}
else if (item.Expression.Type==Syntax.SequenceExpression)
{
let varName;
let draw;
let color, upColor, downColor, stickType;
let lineWidth;
let colorStick=false;
let pointDot=false;
let upDownDot=false;
let circleDot=false;
let lineStick=false;
let stick=false;
let volStick=false;
let lineArea=false;
let stepLine=false;
let isShow=true;
let isExData=false;
let isDotLine=false;
let isOverlayLine=false; //叠加线
let isSingleLine=false; //独立线段
var isNoneName=false;
var isShowTitle=true;
//显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如:
//DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE;
var isDrawAbove=false;
var isDrawCenter=false;
var isDrawBelow=false;
//VALIGN0,VALIGN1,VALIGN2 设置文字垂直对齐方式(上中下)
//ALIGN0,ALIGN1,ALIGN2 设置文字水平对齐方式(左中右)
var drawAlign=-1, drawVAlign=-1;
var fontSize=-1;
var bgConfig=null; //背景设置
var vLineConfig=null;
var isFirstDraw=null;
let xOffset=null, yOffset=null;
var klineType=null;
var lineDash=null;
for(let j=0; j<item.Expression.Expression.length; ++j)
{
let itemExpression=item.Expression.Expression[j];
if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
{
if (j==0)
{
varName=itemExpression.Left.Name;
let varValue=this.VarTable.get(varName);
if (this.VarDrawTable.has(varName)) //绘图函数赋值
{
draw=this.VarDrawTable.get(varName);
}
else if (!Array.isArray(varValue))
{
varValue=this.SingleDataToArrayData(varValue);
this.VarTable.set(varName,varValue); //把常量放到变量表里
}
}
else
{
}
}
else if (itemExpression.Type==Syntax.Identifier)
{
let value=itemExpression.Name;
if (value==='COLORSTICK') colorStick=true;
else if (value==='POINTDOT') pointDot=true;
else if (value==='CIRCLEDOT') circleDot=true;
else if (value==='DOTLINE') isDotLine=true;
else if (value=="UPDOWNDOT") upDownDot=true;
else if (value==='LINESTICK') lineStick=true;
else if (value==='STICK') stick=true;
else if (value==='VOLSTICK') volStick=true;
else if (value=="LINEAREA") lineArea=true;
else if (value==="DRAWABOVE") isDrawAbove=true;
else if (value==="DRAWCENTER") isDrawCenter=true;
else if (value=="DRAWBELOW") isDrawBelow=true;
else if (value=="STEPLINE") stepLine=true;
else if (value=="SINGLELINE") isSingleLine=true;
else if (value.indexOf('COLOR')==0) color=value;
else if (value.indexOf("RGBX")==0 && value.length==10) color=value; //RGBX+“RRGGBB”
else if (value.indexOf('LINETHICK')==0) lineWidth=value;
else if (value=="ALIGN0") drawAlign=0;
else if (value=="ALIGN1") drawAlign=1;
else if (value=="ALIGN2") drawAlign=2;
else if (value=="VALIGN0") drawVAlign=0;
else if (value=="VALIGN1") drawVAlign=1;
else if (value=="VALIGN2") drawVAlign=2;
else if (value.indexOf('NODRAW')==0) isShow=false;
else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
else if (value.indexOf('LINEOVERLAY')==0) isOverlayLine=true;
else if (value.indexOf("NOTEXT")==0 || value.indexOf("NOTITLE")==0) isShowTitle=false; //标题不显示
else if (value.indexOf("FONTSIZE")==0)
{
var strFontSize=value.replace("FONTSIZE","");
fontSize=parseInt(strFontSize);
}
else
{
if (j==0)
{
varName=itemExpression.Name;
let varValue=this.ReadVariable(varName,itemExpression);
if (!Array.isArray(varValue)) varValue=this.SingleDataToArrayData(varValue);
varName="__temp_si_"+i+"__";
isNoneName=true;
this.VarTable.set(varName,varValue); //放到变量表里
}
}
}
else if(itemExpression.Type==Syntax.Literal) //常量
{
if (j==0)
{
let aryValue=this.SingleDataToArrayData(itemExpression.Value);
varName=itemExpression.Value.toString();
this.VarTable.set(varName,aryValue); //把常量放到变量表里
}
}
else if (itemExpression.Type==Syntax.CallExpression)
{
if (j==0)
{
if (this.Draw.IsDrawFunction(itemExpression.Callee.Name))
{
draw=itemExpression.Draw;
draw.Name=itemExpression.Callee.Name;
}
else
{
let varValue=itemExpression.Out;
varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`;
isNoneName=true;
this.VarTable.set(varName,varValue);
}
}
else
{
if (itemExpression.Callee.Name=="RGB" || itemExpression.Callee.Name=="RGBA")
{
color=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="UPCOLOR")
{
upColor=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="DOWNCOLOR")
{
downColor=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="STICKTYPE")
{
stickType=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="XMOVE")
{
xOffset=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="YMOVE")
{
yOffset=itemExpression.Out;
}
else if (itemExpression.Callee.Name=="LINEDASH")
{
if (IFrameSplitOperator.IsNonEmptyArray(itemExpression.Out))
lineDash=itemExpression.Out.slice();
}
else if (itemExpression.Callee.Name=="FIRSTDRAW")
{
if (itemExpression.Out===0) isFirstDraw=false;
else if (itemExpression.Out===1) isFirstDraw=true;
}
else if (itemExpression.Callee.Name=="SOUND")
{
var event=this.GetSoundEvent();
if (event)
{
}
varName=null;
}
else if (itemExpression.Callee.Name=="ICON")
{
let drawCond=this.VarTable.get(varName);
if (drawCond)
{
draw=this.GetOutIconData(drawCond,itemExpression.Draw);
if (draw) draw.Name=itemExpression.Callee.Name;
}
varName=null;
}
else if (itemExpression.Callee.Name=="BACKGROUND")
{
bgConfig=itemExpression.Draw;
varName=null;
}
else if (itemExpression.Callee.Name=="CKLINE")
{
vLineConfig=itemExpression.Draw;
varName=null;
}
else if (itemExpression.Callee.Name=="KLINETYPE")
{
klineType=itemExpression.Out;
}
}
}
else if (itemExpression.Type==Syntax.BinaryExpression)
{
if (j==0)
{
varName="__temp_sb_"+i+"__";
let aryValue=itemExpression.Out;
isNoneName=true;
this.VarTable.set(varName,aryValue);
}
}
else if (itemExpression.Type==Syntax.UnaryExpression)
{
if (j==0)
{
varName="__temp_su_"+i+"__";
var varInfo={ };
if (this.ReadUnaryExpression(itemExpression, varInfo))
{
isNoneName=true;
this.VarTable.set(varName,varInfo.OutVar);
}
}
}
else if (itemExpression.Type==Syntax.MemberExpression) //"MA.MA2"(5,12,29), COLORRED;
{
if (j==0)
{
var outVar=this.ReadMemberVariable(itemExpression);
if (outVar)
{
if (!Array.isArray(outVar)) varValue=this.SingleDataToArrayData(outVar);
isNoneName=true;
varName="__temp_di_"+i+"__";
this.VarTable.set(varName,outVar); //把常量放到变量表里
}
}
}
}
if (pointDot && varName) //圆点
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Radius:g_JSChartResource.POINTDOT.Radius, Type:3};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (circleDot && varName) //圆点
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (upDownDot && varName) //彩色点
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3, UpDownDot:true };
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (lineStick && varName) //LINESTICK 同时画出柱状线和指标线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:4};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (stick && varName) //STICK 画柱状线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:5};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (volStick && varName) //VOLSTICK 画彩色柱状线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:6};
if (color) value.Color=color;
if (upColor) value.UpColor=upColor;
if (downColor) value.DownColor=downColor;
if (lineWidth) value.LineWidth=lineWidth;
if (IFrameSplitOperator.IsNumber(stickType)) value.StickType=stickType;
this.OutVarTable.push(value);
}
else if (lineArea && varName) //LINEAREA 面积
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:9};
if (color) value.Color=color;
if (upColor) value.UpColor=upColor;
if (downColor) value.DownColor=downColor;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (colorStick && varName) //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Color:color, Type:2};
if (lineWidth) value.LineWidth=lineWidth;
if (color) value.Color=color;
if (upColor) value.UpColor=upColor;
if (downColor) value.DownColor=downColor;
this.OutVarTable.push(value);
}
else if (varName && color && !draw)
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Color:color, Type:0};
if (lineWidth) value.LineWidth=lineWidth;
if (isShow == false) value.IsShow = false;
if (isExData==true) value.IsExData = true;
if (isDotLine==true) value.IsDotLine=true;
if (IFrameSplitOperator.IsNonEmptyArray(lineDash)) value.LineDash=lineDash;
if (isOverlayLine==true) value.IsOverlayLine=true;
if (isSingleLine==true) value.IsSingleLine=true;
if (isNoneName==true) value.NoneName=true;
if (isShowTitle==false) value.IsShowTitle=false;
if (stepLine==true) value.Type=7;
this.OutVarTable.push(value);
}
else if (draw) //画图函数
{
var outVar={Name:draw.Name, Draw:draw, Type:1};
if (color) outVar.Color=color;
if (isDotLine==true) outVar.IsDotLine=true;
if (IFrameSplitOperator.IsNonEmptyArray(lineDash)) outVar.LineDash=lineDash;
if (lineWidth) outVar.LineWidth=lineWidth;
if (isDrawAbove) outVar.IsDrawAbove=true;
if (isDrawCenter) outVar.IsDrawCenter=true;
if (isDrawBelow) outVar.IsDrawBelow=true;
if (drawAlign>=0) outVar.DrawAlign=drawAlign;
if (drawVAlign>=0) outVar.DrawVAlign=drawVAlign;
if (fontSize>0) outVar.DrawFontSize=fontSize;
if (bgConfig) outVar.Background=bgConfig;
if (vLineConfig) outVar.VerticalLine=vLineConfig;
if (IFrameSplitOperator.IsNumber(xOffset)) outVar.XOffset=xOffset;
if (IFrameSplitOperator.IsNumber(yOffset)) outVar.YOffset=yOffset;
if (IFrameSplitOperator.IsBool(isFirstDraw)) outVar.IsFirstDraw=isFirstDraw;
if (IFrameSplitOperator.IsNumber(klineType)) outVar.KLineType=klineType;
this.OutVarTable.push(outVar);
}
else if (varName)
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar,Type:0};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
if (isShow==false) value.IsShow=false;
if (isExData==true) value.IsExData = true;
if (isDotLine==true) value.IsDotLine=true;
if (IFrameSplitOperator.IsNonEmptyArray(lineDash)) value.LineDash=lineDash;
if (isOverlayLine==true) value.IsOverlayLine=true;
if (isSingleLine==true) value.IsSingleLine=true;
if (isShowTitle==false) value.IsShowTitle=false;
if (stepLine==true) value.Type=7;
this.OutVarTable.push(value);
}
}
}
}
this.ReadUnaryExpression=function(item, varInfo)
{
var argument=item.Argument;
var outVar=null;
if (argument.Type==Syntax.Literal)
{
outVar=argument.Value;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
}
else if (argument.Type==Syntax.Identifier)
{
var varName=argument.Name;
outVar=this.ReadVariable(varName,item.Expression);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
}
else if (argument.Type==Syntax.BinaryExpression)
{
outVar=argument.Out;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
}
else if (argument.Type==Syntax.CallExpression)
{
var callItem=argument;
if (this.Draw.IsDrawFunction(callItem.Callee.Name) )
{
return false;
}
else if (callItem.Callee.Name==="IFC" && callItem.Draw)
{
return false;
}
else
{
outVar=callItem.Out;
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
}
}
else
{
return false;
}
if (item.Operator=='-')
{
if (outVar) outVar=this.Algorithm.Subtract(0,outVar);
}
varInfo.OutVar=outVar;
return true;
}
this.GetOutIconData=function(cond, iconDraw)
{
if (Array.isArray(cond))
{
for(var i=0; i<cond.length && i<iconDraw.DrawData.length; ++i)
{
var item=cond[i];
if (item<=0) iconDraw.DrawData[i]=null;
}
return iconDraw;
}
if (cond) return iconDraw;
return null;
}
this.GetSoundEvent=function()
{
if (!this.GetEventCallback) return null;
return this.GetEventCallback(JSCHART_EVENT_ID.ON_PLAY_SOUND);
}
this.Run=function()
{
try
{
let data=this.RunAST();//执行脚本
JSConsole.Complier.Log('[JSComplier.Run] execute finish', data);
if (this.IndexCtrl) this.IndexCtrl.Status=0;
if (this.UpdateUICallback)
{
JSConsole.Complier.Log('[JSComplier.Run] invoke UpdateUICallback.');
if (this.CallbackParam && this.CallbackParam.Job && this.CallbackParam.Job.ID==JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX)
{
this.UpdateUICallback(data,this.CallbackParam, this.SymbolData);
}
else
{
if (this.CallbackParam && this.CallbackParam.Self && this.CallbackParam.Self.ClassName==='ScriptIndexConsole') this.CallbackParam.JSExecute=this;
if (this.IsUsePageData==true) this.CallbackParam.Self.IsUsePageData=true;
this.UpdateUICallback(data,this.CallbackParam);
}
}
}
catch(error)
{
JSConsole.Complier.Log(error);
if (error.Job)
{
JSConsole.Complier.Log('[JSComplier.Run] download job and reexectue', error.Job);
this.JobList.push(error.Job);
this.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
this.Execute();
}
else if (this.ErrorCallback)
{
if (this.IndexCtrl) this.IndexCtrl.Status=0;
this.ErrorCallback(error, this.CallbackParam);
}
}
}
this.DebugRun_End=function()
{
var data=this.OutVarTable;
JSConsole.Complier.Log('[JSComplier.DebugRun_End] execute finish', data);
if (this.IndexCtrl) this.IndexCtrl.Status=0;
if (this.UpdateUICallback)
{
JSConsole.Complier.Log('[JSComplier.DebugRun_End] invoke UpdateUICallback.');
if (this.CallbackParam && this.CallbackParam.Job && this.CallbackParam.Job.ID==JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX)
{
this.UpdateUICallback(data,this.CallbackParam, this.SymbolData);
}
else
{
if (this.CallbackParam && this.CallbackParam.Self && this.CallbackParam.Self.ClassName==='ScriptIndexConsole') this.CallbackParam.JSExecute=this;
if (this.IsUsePageData==true) this.CallbackParam.Self.IsUsePageData=true;
this.UpdateUICallback(data,this.CallbackParam);
}
}
}
this.DebugRun_Next=function(debugCtrl)
{
if (debugCtrl.ExeLine<debugCtrl.LineCount)
{
var item =this.AST.Body[debugCtrl.ExeLine];
this.RunASTNode(item);
++debugCtrl.ExeLine;
this.DebugFilter(debugCtrl, ()=>
{
this.DebugRun_Next(debugCtrl);
});
}
else
{
this.DebugRun_End();
debugCtrl.Status=2;
this.DebugFilter(debugCtrl,null);
}
}
//debug模式
this.DebugRun=function()
{
try
{
if (!this.AST) this.ThrowError();
if (!this.AST.Body) this.ThrowError();
var debugCtrl={ LineCount:this.AST.Body.length, ExeLine:0, Self:this, Status:1 };
this.DebugFilter(debugCtrl, ()=>
{
this.DebugRun_Next(debugCtrl);
});
}
catch(error)
{
if (this.ErrorCallback)
{
if (this.IndexCtrl) this.IndexCtrl.Status=0;
this.ErrorCallback(error, this.CallbackParam);
}
}
}
this.VisitNode=function(node)
{
switch(node.Type)
{
case Syntax.SequenceExpression:
this.VisitSequenceExpression(node);
break;
case Syntax.ExpressionStatement:
this.VisitNode(node.Expression);
break;
case Syntax.AssignmentExpression:
this.VisitAssignmentExpression(node);
break;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
this.VisitBinaryExpression(node);
break;
case Syntax.CallExpression:
this.VisitCallExpression(node);
break;
case Syntax.UnaryExpression:
this.VisitUnaryExpression(node);
break;
}
}
this.VisitUnaryExpression=function(node)
{
if (node.Operator=='-')
{
var tempValue=this.GetNodeValueEx(node.Argument);
var value=this.Algorithm.Subtract(0,tempValue);
}
else
{
var value=node.Argument.Value;
}
return value;
}
this.VisitSequenceExpression=function(node)
{
for(let i in node.Expression)
{
let item =node.Expression[i];
this.VisitNode(item);
}
}
this.GetDynamicScriptIndex=function(node, args)
{
var dynamicName=node.Callee.Value;
var aryValue=dynamicName.split(".");
if (aryValue.length!=2)
{
this.ThrowUnexpectedNode(node,`调用指标格式'${dynamicName}'错误`);
}
var name=aryValue[0];
var outName=aryValue[1];
var period=null;
var pos=outName.indexOf('#');
if (pos!=-1)
{
period=outName.slice(pos+1); //周期
outName=outName.slice(0,pos);
}
var strValue="";
for(var i=0; i<args.length; ++i)
{
var value=args[i];
if (strValue.length>0) strValue+=",";
strValue+=`${value}`;
}
var strArgs=`(${strValue})`;
var key=`${outName}#${strArgs}`;
if (period) key+=`#${period}`;
if (!this.VarTable.has(name)) return null;
var indexData=this.VarTable.get(name);
var value=indexData[key];
return value;
}
//函数调用
this.VisitCallExpression=function(node)
{
var funcName=node.Callee.Name;
var args=[];
for(var i=0;i<node.Arguments.length;++i)
{
var item=node.Arguments[i];
var value;
if (funcName==="IFC" && i>=1)
break; //IFC先处理第1个条件参数
if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(item);
else if (item.Type==Syntax.CallExpression)
value=this.VisitCallExpression(item);
else
value=this.GetNodeValue(item);
args.push(value);
}
if (node.Callee.Type==Syntax.Literal)
{
node.Out=[];
node.Draw=null;
var data=this.GetDynamicScriptIndex(node, args);
if (data) node.Out=data;
return node.Out;
}
if (funcName==="IFC")
{
//IFC(X,A,B)若X不为0则执行A,否则执行B.IFC与IF函数的区别:根据X的值来选择性执行A、B表达式.
var bResult=this.Algorithm.IFC(args[0]);
var item=bResult? node.Arguments[1] : node.Arguments[2];
var value;
if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(item);
else if (item.Type==Syntax.CallExpression)
value=this.VisitCallExpression(item);
else
value=this.GetNodeValue(item);
node.Out=value;
if (item.Draw) node.Draw=item.Draw;
return node.Out;
}
//JSConsole.Complier.Log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')');
if (g_JSComplierResource.IsCustomFunction(funcName))
{
var data=this.Algorithm.CallCustomFunction(funcName, args, this.SymbolData, node);
node.Out=[];
node.Draw=null;
if (data)
{
if (data.Out) node.Out=data.Out;
if (data.Draw) node.Draw=data.Draw;
}
return node.Out;
}
if (g_JSComplierResource.IsCustomDataFunction(funcName))
{
var functionInfo=g_JSComplierResource.CustomDataFunction.Data.get(funcName);
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:functionInfo.ArgCount, Node:node } );
node.Draw=null;
return node.Out;
}
switch(funcName)
{
case 'DYNAINFO': //行情最新数据
node.Out=this.SymbolData.GetLatestCacheData(args[0]);
break;
case 'STICKLINE':
node.Draw=this.Draw.STICKLINE(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWTEXT':
node.Draw=this.Draw.DRAWTEXT(args[0],args[1],args[2]);
node.Out=[];
break;
case 'DRAWTEXT_FIX':
node.Draw=this.Draw.DRAWTEXT_FIX(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'SUPERDRAWTEXT':
node.Draw=this.Draw.SUPERDRAWTEXT(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWICON':
node.Draw=this.Draw.DRAWICON(args[0],args[1],args[2]);
node.Out=[];
break;
case "ICON":
node.Draw=this.Draw.ICON(args[0],args[1]);
node.Out=[];
break;
case "TIPICON":
node.Draw=this.Draw.TIPICON(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case "BACKGROUND":
node.Draw=this.Draw.BACKGROUND(args[0],args[1],args[2],args[3],args[4],args[5]);
node.Out=[];
break;
case "CKLINE":
node.Draw=this.Draw.CKLINE(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWLINE':
node.Draw=this.Draw.DRAWLINE(args[0],args[1],args[2],args[3],args[4]);
node.Out=node.Draw.DrawData;
break;
case 'DRAWBAND':
node.Draw=this.Draw.DRAWBAND(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case "FILLRGN":
if (args.length>=4) node.Draw=this.Draw.FILLRGN2(args);
else node.Draw=this.Draw.FILLRGN(args[0],args[1],args[2]);
node.Out=[];
break;
case "FLOATRGN":
node.Draw=this.Draw.FLOATRGN(args);
node.Out=[];
break;
case "FILLTOPRGN":
node.Draw=this.Draw.FILLBGRGN(1, args);
node.Out=[];
break;
case "FILLBOTTOMRGN":
node.Draw=this.Draw.FILLBGRGN(0, args);
node.Out=[];
break;
case "FILLVERTICALRGN":
node.Draw=this.Draw.FILLVERTICALRGN(args);
node.Out=[];
break;
case 'DRAWKLINE':
case "DRAWKLINE1":
node.Draw=this.Draw.DRAWKLINE(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case 'DRAWKLINE_IF':
node.Draw=this.Draw.DRAWKLINE_IF(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case "KLINETYPE": //K线类型 和DRAWKLINE连用
node.Out=this.Draw.KLINETYPE(args[0]);
break;
case "DRAWOVERLAYKLINE":
node.Draw=this.Draw.DRAWOVERLAYKLINE(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case "DRAWCOLORKLINE":
node.Draw=this.Draw.DRAWCOLORKLINE(args[0],args[1],args[2]);
node.Out=[];
break;
case 'PLOYLINE':
case 'POLYLINE':
node.Draw=this.Draw.POLYLINE(args[0],args[1]);
node.Out=node.Draw.DrawData;
break;
case 'DRAWNUMBER':
node.Draw=this.Draw.DRAWNUMBER(args[0],args[1],args[2], args[3]);
node.Out=node.Draw.DrawData.Value;
break;
case "DRAWNUMBER_FIX":
node.Draw=this.Draw.DRAWNUMBER_FIX(args[0],args[1],args[2],args[3],args[4]);
node.Out=node.Draw.DrawData.Value;
break;
case "DRAWCHANNEL":
node.Draw=this.Draw.DRAWCHANNEL(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
node.Out=[];
break;
case 'RGB':
node.Out=this.Draw.RGB(args[0],args[1],args[2]);
break;
case "RGBA":
node.Out=this.Draw.RGBA(args[0],args[1],args[2],args[3]);
break;
case "UPCOLOR":
node.Out=this.Draw.UPCOLOR(args[0]);
break;
case "DOWNCOLOR":
node.Out=this.Draw.DOWNCOLOR(args[0]);
break;
case "STICKTYPE": //柱子类型
node.Out=this.Draw.STICKTYPE(args[0]);
break;
case "XMOVE":
node.Out=this.Draw.XMOVE(args[0]);
break;
case "YMOVE":
node.Out=this.Draw.YMOVE(args[0]);
break;
case "LINEDASH":
node.Out=this.Draw.LINEDASH(args);
break;
case "FIRSTDRAW":
node.Out=this.Draw.FIRSTDRAW(args[0]);
break;
case 'PARTLINE':
node.Draw=this.Draw.PARTLINE(args);
node.Out=[];
break;
case 'DRAWGBK':
node.Draw=this.Draw.DRAWGBK(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case 'DRAWGBK2':
node.Draw=this.Draw.DRAWGBK2(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case "DRAWGBK_DIV":
node.Draw=this.Draw.DRAWGBK_DIV(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWTEXT_LINE':
node.Draw=this.Draw.DRAWTEXT_LINE(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
node.Out=[];
break;
case 'DRAWRECTREL':
node.Draw=this.Draw.DRAWRECTREL(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case "DRAWTEXTREL":
node.Draw=this.Draw.DRAWTEXTREL(args[0],args[1],args[2]);
node.Out=[];
break;
case "DRAWTEXTABS":
node.Draw=this.Draw.DRAWTEXTABS(args[0],args[1],args[2]);
node.Out=[];
break;
case "DRAWOVERLAYLINE":
node.Draw=this.Draw.DRAWOVERLAYLINE(args[0],args[1],args[2]);
node.Out=node.Draw.DrawData.Data;
break;
case "DRAWSL":
node.Draw=this.Draw.DRAWSL(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case "VERTLINE":
node.Draw=this.Draw.VERTLINE(args[0],args[1]);
node.Out=node.Draw.DrawData.Data;
break;
case "HORLINE":
node.Draw=this.Draw.HORLINE(args[0],args[1],args[2],args[3]);
node.Out=node.Draw.DrawData.Data;
break;
case 'CODELIKE':
node.Out=this.SymbolData.CODELIKE(args[0]);
break;
case 'NAMELIKE':
case "NAMEINCLUDE":
node.Out=this.SymbolData.NAMELIKE(args[1]);
break;
case 'REFDATE':
node.Out=this.SymbolData.REFDATE(args[0],args[1]);
break;
case 'FINANCE':
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } );
break;
case "FINVALUE":
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } );
break;
case "FINONE":
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } );
break;
case "GPJYVALUE":
case "SCJYVALUE":
case "BKJYVALUE":
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } );
break;
case "GPJYONE":
case "SCJYONE":
case "BKJYONE":
node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:4, Node:node } );
break;
case "MARGIN":
node.Out=this.SymbolData.GetMarginCacheData(args[0],node);
break;
case "HK2SHSZ":
node.Out=this.SymbolData.GetHKToSHSZCacheData(args[0],node);
break;
case "NEWS":
node.Out=this.SymbolData.GetNewsAnalysisCacheData(args[0],node);
break;
case 'UPCOUNT':
case 'DOWNCOUNT':
node.Out=this.SymbolData.GetIndexIncreaseCacheData(funcName,args[0],node);
break;
case 'SF':
node.Out=this.SymbolData.GetSectionFinanceCacheData(args[0],args[1],args[2],node);
break;
case 'LOADAPIDATA':
node.Out=this.SymbolData.GetCustomApiData(args);
break;
case "STKINDI":
case "CALCSTOCKINDEX":
node.Out=this.SymbolData.GetScriptIndexOutData(args,node,funcName);
break;
case "SOUND":
node.Draw=this.Draw.SOUND(args[0]);
node.Out=[];
break;
case "PLAYSOUND":
node.Draw=this.Draw.PLAYSOUND(args[0],args[1]);
node.Out=[];
break;
case 'CLOSE':
case 'C':
case 'VOL':
case 'V':
case 'OPEN':
case 'O':
case 'HIGH':
case 'H':
case 'LOW':
case 'L':
case 'AMOUNT':
case 'AMO':
node.Out=this.SymbolData.GetOtherSymolCacheData( {FunctionName:funcName, Args:args} );
break;
case "INBLOCK":
node.Out=this.SymbolData.IsInBlock(args[0],node);
break;
case 'COVER_C':
case 'COVER_O':
case 'COVER_H':
case 'COVER_L':
case 'COVER_A':
case 'COVER_V':
if (args.length==2) return this.SymbolData.GetSymbolPeriodCacheData2(JSComplierHelper.GetConvertValueName(funcName),args[0],args[1]);
return this.SymbolData.GetSymbolPeriodCacheData(JSComplierHelper.GetConvertValueName(funcName),args[0]);
case "SYSPARAM":
node.Out=this.SymbolData.SysParam(args[0], this);
break;
case "TESTSKIP":
var bExit=this.Algorithm.TESTSKIP(args[0],node);
node.Out=null;
if (bExit)
{
this.Interrupt.Exit=true;
if (node && node.Marker)
{
var marker=node.Marker;
this.Interrupt.Line=marker.Line;
this.Interrupt.Index=marker.Index;
this.Interrupt.Column=marker.Column;
}
}
break;
//交易函数
case "BUY":
node.Draw=this.Draw.BUY(args[0],args[1],args[2],args[3]);
node.Out=node.Draw.DrawData.Data;
break;
case "SELL":
node.Draw=this.Draw.SELL(args[0],args[1],args[2],args[3]);
node.Out=node.Draw.DrawData.Data;
break;
case "SELLSHORT":
node.Draw=this.Draw.SELLSHORT(args[0],args[1],args[2],args[3]);
node.Out=node.Draw.DrawData.Data;
break;
case "BUYSHORT":
node.Draw=this.Draw.BUYSHORT(args[0],args[1],args[2],args[3]);
node.Out=node.Draw.DrawData.Data;
break;
default:
node.Out=this.Algorithm.CallFunction(funcName, args, node, this.SymbolData);
break;
}
return node.Out;
}
//赋值
this.VisitAssignmentExpression=function(node)
{
let left=node.Left;
if (left.Type!=Syntax.Identifier) this.ThrowUnexpectedNode(node);
let varName=left.Name;
let right=node.Right;
let value=null, drawValue=null;
if (right.Type==Syntax.BinaryExpression || right.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(right);
else if (right.Type==Syntax.CallExpression)
{
value=this.VisitCallExpression(right);
if (right.Draw) drawValue=right.Draw;
}
else if (right.Type==Syntax.Literal)
{
value=right.Value;
if (IFrameSplitOperator.IsString(value) && right.Value.indexOf("$")>0)
value=this.SymbolData.GetOtherSymolCacheData( {Literal:value} );
}
else if (right.Type==Syntax.Identifier) //右值是变量
value=this.ReadVariable(right.Name,right);
else if (right.Type==Syntax.MemberExpression)
value=this.ReadMemberVariable(right);
else if (right.Type==Syntax.UnaryExpression)
value=this.VisitUnaryExpression(right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitAssignmentExpression]' , varName, ' = ',value);
if (drawValue) this.VarDrawTable.set(varName, drawValue);
this.VarTable.set(varName,value);
}
//逻辑运算
this.VisitBinaryExpression=function(node)
{
let stack=[];
stack.push(node);
let temp=null;
while(stack.length!=0)
{
temp=stack[stack.length-1];
if (temp.Left && node!=temp.Left && node!=temp.Right)
{
stack.push(temp.Left);
}
else if (temp.Right && node!=temp.Right)
{
stack.push(temp.Right);
}
else
{
let value=stack.pop();
if (value.Type==Syntax.BinaryExpression) //只遍历操作符就可以
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
switch(value.Operator)
{
case '-':
value.Out=this.Algorithm.Subtract(leftValue,rightValue);
break;
case '*':
value.Out=this.Algorithm.Multiply(leftValue,rightValue);
break;
case '/':
value.Out=this.Algorithm.Divide(leftValue,rightValue)
break;
case '+':
value.Out=this.Algorithm.Add(leftValue,rightValue);
break;
case '>':
value.Out=this.Algorithm.GT(leftValue,rightValue);
break;
case '>=':
value.Out=this.Algorithm.GTE(leftValue,rightValue);
break;
case '<':
value.Out=this.Algorithm.LT(leftValue,rightValue);
break;
case '<=':
value.Out=this.Algorithm.LTE(leftValue,rightValue);
break;
case '==':
case '=': //= 比较
value.Out=this.Algorithm.EQ(leftValue,rightValue);
break;
case '!=':
case '<>':
value.Out=this.Algorithm.NEQ(leftValue,rightValue);
break;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value);
}
else if (value.Type==Syntax.LogicalExpression)
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
switch(value.Operator)
{
case '&&':
case 'AND':
value.Out=this.Algorithm.And(leftValue,rightValue);
break;
case '||':
case 'OR':
value.Out=this.Algorithm.Or(leftValue,rightValue);
break;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value);
}
node=temp;
}
}
return node.Out;
}
//获取节点值,BinaryExpression,LogicalExpression会重新计算
this.GetNodeValueEx=function(item)
{
var value=null;
if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(item);
else if (item.Type==Syntax.CallExpression)
value=this.VisitCallExpression(item);
else
value=this.GetNodeValue(item);
return value;
}
this.GetNodeValue=function(node)
{
switch(node.Type)
{
case Syntax.Literal: //数字
return node.Value;
case Syntax.UnaryExpression:
var value=this.VisitUnaryExpression(node);
return value;
case Syntax.Identifier:
var value=this.ReadVariable(node.Name,node);
return value;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
return node.Out;
case Syntax.CallExpression:
return this.VisitCallExpression(node);
case Syntax.MemberExpression:
return this.ReadMemberVariable(node);
default:
this.ThrowUnexpectedNode(node);
}
}
this.ThrowUnexpectedNode=function(node,message,word)
{
let marker=node.Marker;
let msg=message || "执行异常";
return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg, word);
}
this.ThrowDownloadSF=function(node,job,message)
{
let marker=node.Marker;
let msg=message;
return this.ErrorHandler.ThrowDownloadJob(marker.Index,marker.Line,marker.Column,msg,job);
}
this.ThrowError=function()
{
}
}
//脚本说明
function JSExplainer(ast,option)
{
this.AST=ast;
this.ErrorHandler=new ErrorHandler();
this.ErrorCallback; //执行错误回调
this.UpdateUICallback;
this.CallbackParam;
this.JobList=[]; //执行的任务队列
this.VarTable=new Map(); //变量表
this.OutVarTable=[]; //输出变量
this.MaxValueLength=150; //最长的字符
//脚本自动变量表, 只读
this.ConstVarTable=new Map(
[
//个股数据
['CLOSE',"收盘价"],['VOL',"成交量"],['OPEN',"开盘价"],['HIGH',"最高价"],['LOW',"最低价"],['AMOUNT',"成交量"],
['C',"收盘价"],['V',"成交量"],['O',"开盘价"],['H',"最高价"],['L',"最低价"],['AMO',"成交量"],
['VOLR',"量比"], ['VOLINSTK',"持仓量"], ["OPI","持仓量"], ["ZSTJJ","均价"], ["QHJSJ","结算价"], ["SETTLE", "结算价"],
//日期类
['DATE',"日期"],['YEAR',"年份"],['MONTH',"月份"],["DAY","日"],['PERIOD', "周期"],['WEEK',"星期"],["TIME","时间"],
//大盘数据
['INDEXA',"大盘成交额"],['INDEXC',"大盘收盘价"],['INDEXH',"大盘最高价"],['INDEXL',"大盘最低价"],['INDEXO',"大盘开盘价"],['INDEXV',"大盘成交量"],
['INDEXADV',"大盘上涨家数"],['INDEXDEC',"´大盘下跌家数"],
["ADVANCE","上涨家数"], ['DECLINE', "下跌家数"],
['FROMOPEN',"当前离开盘分钟数"],
['TOTALFZNUM', "总分钟数"],
['CURRBARSCOUNT',"到最后交易的周期"], //到最后交易日的周期数
['TOTALBARSCOUNT',"总的周期数"],
['ISLASTBAR',"是否是最后一个周期"], //判断是否为最后一个周期
['BARSTATUS',"数据位置状态"], //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.
['CAPITAL',"当前流通股本(手)"], ["TOTALCAPITAL","当前总股本(手)"],
['EXCHANGE',"换手率"], //换手率
['SETCODE', "市场类型"], //市场类型
['CODE',"品种代码"], //品种代码
['STKNAME',"品种名称"], //品种名称
["TQFLAG","当前复权状态"], //TQFLAG 当前的复权状态,0:无复权 1:前复权 2:后复权
['HYBLOCK',"所属行业"], //所属行业板块
['DYBLOCK',"所属地域"], //所属地域板块
['GNBLOCK',"所属概念"], //所属概念
["FGBLOCK","所属风格板块"],
["ZSBLOCK","所属指数板块"],
["ZHBLOCK",'所属组合板块'],
["ZDBLOCK",'所属自定义板块'],
["HYZSCODE","所属行业的板块指数代码"],
["GNBLOCKNUM","所属概念板块的个数"],
["FGBLOCKNUM","所属风格板块的个数"],
["ZSBLOCKNUM","所属指数板块的个数"],
["ZHBLOCKNUM","所属组合板块的个数"],
["ZDBLOCKNUM","所属自定义板块的个数"],
["HYSYL","指数市盈率或个股所属行业的市盈率"],
["HYSJL","指数市净率或个股所属行业的市净率"],
['DRAWNULL',"无效数据"],
["TR", "求真实波幅"],
["LARGEINTRDVOL","逐笔买入大单成交量"],
["LARGEOUTTRDVOL","逐笔卖出大单成交量"],
["TRADENUM", "逐笔成交总单数"],
["TRADEINNUM", "逐笔买入成交单数"],
["TRADEOUTNUM", "逐笔卖出成交单数"],
["LARGETRDINNUM", "逐笔买入大单成交单数"],
["LARGETRDOUTNUM", "逐笔卖出大单成交单数"],
["CUR_BUYORDER", "总委买量"],
["CUR_SELLORDER", "总委卖量"],
["ACTINVOL", "主动买成交量"],
["ACTOUTVOL", "主动卖成交量"],
["BIDORDERVOL", "累计总有效委买量"],
["BIDCANCELVOL", "累计总有效撤买量"],
["AVGBIDPX", "最新委买均价"],
["OFFERORDERVOL", "累计总有效委卖量"],
["OFFERCANCELVOL", "累计总有效撤卖量"],
["AVGOFFERPX", "最新委卖均价"],
]);
if (option)
{
if (option.Callback) this.UpdateUICallback=option.Callback;
if (option.CallbackParam) this.CallbackParam=option.CallbackParam;
if (option.Arguments) this.Arguments=option.Arguments;
}
this.Run=function()
{
try
{
this.OutVarTable=[];
this.VarTable=new Map();
JSConsole.Complier.Log('[JSExecute::JSExplainer] Load Arguments', this.Arguments);
for(let i in this.Arguments) //预定义的变量
{
let item =this.Arguments[i];
this.VarTable.set(item.Name,item.Value);
}
let data=this.RunAST();//执行脚本
JSConsole.Complier.Log('[JSExplainer.Run] explain finish', data);
if (this.UpdateUICallback) //回调发送结果, 可以支持异步
{
JSConsole.Complier.Log('[JSExplainer.Run] invoke UpdateUICallback.');
this.UpdateUICallback(data);
}
}
catch(error)
{
JSConsole.Complier.Log('[JSExplainer.Run] throw error ', error);
if (this.ErrorCallback)
{
this.ErrorCallback(error, this.OutVarTable);
}
}
}
this.RunAST=function()
{
if (!this.AST) this.ThrowError();
if (!this.AST.Body) this.ThrowError();
for(var i=0; i<this.AST.Body.length; ++i)
{
//console.log(`[JSExplainer::RunAST] ${i}`);
var item =this.AST.Body[i];
this.VisitNode(item);
//输出变量
if (item.Type==Syntax.ExpressionStatement && item.Expression)
{
if (item.Expression.Type==Syntax.AssignmentExpression)
{
if (item.Expression.Operator==':' && item.Expression.Left)
{
let assignmentItem=item.Expression;
let varName=assignmentItem.Left.Name;
let outVar=`输出${varName}: ${this.VarTable.get(varName)}`;
this.OutVarTable.push({ Name:varName, Data:outVar,Type:0});
}
else if (item.Expression.Operator==':=' && item.Expression.Left)
{
let assignmentItem=item.Expression;
let varName=assignmentItem.Left.Name;
let outVar=`赋值${varName}: ${this.VarTable.get(varName)}`;
this.OutVarTable.push({ Name:varName, Data:outVar,Type:0, IsOut:false });
}
}
else if (item.Expression.Type==Syntax.CallExpression)
{
let callItem=item.Expression;
if (this.IsDrawFunction(callItem.Callee.Name))
{
let outVar=callItem.Out;
var drawName=callItem.Callee.Name;
this.OutVarTable.push({Name:drawName, Draw:`输出: ${outVar}`, Type:1});
}
else
{
let outVar=callItem.Out;
varName=`__temp_c_${callItem.Callee.Name}_${i}__`;
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
}
}
else if (item.Expression.Type==Syntax.Identifier)
{
let varName=item.Expression.Name;
let outVar=this.ReadVariable(varName,item.Expression);
varName="__temp_i_"+i+"__";
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
}
else if (item.Expression.Type==Syntax.Literal) //常量
{
let outVar=item.Expression.Value;
if (IFrameSplitOperator.IsString(outVar) && outVar.indexOf("$")>0)
outVar=this.GetOtherSymbolExplain({ Literal:outVar }, item);
varName="__temp_li_"+i+"__";
var type=0;
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
}
else if (item.Expression.Type==Syntax.BinaryExpression) // CLOSE+OPEN;
{
var varName="__temp_b_"+i+"__";
let outVar=item.Expression.Out;
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
}
else if (item.Expression.Type==Syntax.LogicalExpression) //逻辑语句 如 T1 AND T2
{
var varName="__temp_l_"+i+"__";
let outVar=item.Expression.Out;
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
}
else if (item.Expression.Type==Syntax.UnaryExpression) //一元运算 如-C, -7, -(C+10)
{
var varName="__temp_l_"+i+"__";
var argument=item.Expression.Argument;
let outVar=null;
if (argument.Type==Syntax.Literal)
{
outVar=argument.Value;
}
else if (argument.Type==Syntax.Identifier)
{
let varName=argument.Name;
outVar=this.ReadVariable(varName,item.Expression);
}
else if (argument.Type==Syntax.BinaryExpression)
{
outVar=argument.Out;
}
if (item.Expression.Operator=='-')
{
outVar=`-${outVar}`;
}
this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
}
else if (item.Expression.Type==Syntax.SequenceExpression)
{
let varName;
let drawName;
let draw;
let color;
let lineWidth;
let colorStick=false;
let pointDot=false;
let circleDot=false;
let lineStick=false;
let stick=false;
let volStick=false;
let isShow=true;
let isExData=false;
let isDotLine=false;
let isOverlayLine=false; //叠加线
var isNoneName=false;
var fontSize=-1;
var drawAlign=-1, drawVAlign=-1;
//显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如:
//DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE;
var isDrawAbove=false;
for(let j in item.Expression.Expression)
{
let itemExpression=item.Expression.Expression[j];
if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
{
varName=itemExpression.Left.Name;
let varValue=this.VarTable.get(varName);
this.VarTable.set(varName,this.ConvertToShortValue(varValue)); //把常量放到变量表里
}
else if (itemExpression.Type==Syntax.Identifier)
{
let value=itemExpression.Name;
if (value==='COLORSTICK') colorStick=true;
else if (value==='POINTDOT') pointDot=true;
else if (value==='CIRCLEDOT') circleDot=true;
else if (value==='DOTLINE') isDotLine=true;
else if (value==='LINESTICK') lineStick=true;
else if (value==='STICK') stick=true;
else if (value==='VOLSTICK') volStick=true;
else if (value==="DRAWABOVE") isDrawAbove=true;
else if (value.indexOf('COLOR')==0) color=value;
else if (value.indexOf('LINETHICK')==0) lineWidth=value;
else if (value=="ALIGN0") drawAlign=0;
else if (value=="ALIGN1") drawAlign=1;
else if (value=="ALIGN2") drawAlign=2;
else if (value=="VALIGN0") drawVAlign=0;
else if (value=="VALIGN1") drawVAlign=1;
else if (value=="VALIGN2") drawVAlign=2;
else if (value.indexOf('NODRAW')==0) isShow=false;
else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
else if (value.indexOf('LINEOVERLAY')==0) isOverlayLine=true;
else if (value.indexOf("FONTSIZE")==0)
{
var strFontSize=value.replace("FONTSIZE","");
fontSize=parseInt(strFontSize);
}
else
{
varName=itemExpression.Name;
let varValue=this.ReadVariable(varName,itemExpression);
varName="__temp_si_"+i+"__";
isNoneName=true;
this.VarTable.set(varName,this.ConvertToShortValue(varValue)); //放到变量表里
}
}
else if(itemExpression.Type==Syntax.Literal) //常量
{
let aryValue=itemExpression.Value;
varName=itemExpression.Value.toString();
isNoneName=true;
this.VarTable.set(varName,aryValue); //把常量放到变量表里
}
else if (itemExpression.Type==Syntax.CallExpression)
{
if (j==0)
{
if (this.IsDrawFunction(itemExpression.Callee.Name))
{
draw=itemExpression.Out;
drawName=itemExpression.Callee.Name;
}
else
{
let varValue=itemExpression.Out;
varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`;
isNoneName=true;
this.VarTable.set(varName,varValue);
}
}
}
else if (itemExpression.Type==Syntax.BinaryExpression)
{
varName="__temp_sb_"+i+"__";
let aryValue=itemExpression.Out;
isNoneName=true;
this.VarTable.set(varName,aryValue);
}
else if (itemExpression.Type==Syntax.UnaryExpression)
{
varName="__temp_sb_"+i+"__";
var argument=itemExpression.Argument;
let aryValue=null;
if (argument.Type==Syntax.Literal)
{
aryValue=argument.Value;
}
else if (argument.Type==Syntax.Identifier)
{
let varName=argument.Name;
aryValue=this.ReadVariable(varName,item.Expression);
}
else if (argument.Type==Syntax.BinaryExpression)
{
aryValue=argument.Out;
}
if (itemExpression.Operator=='-')
{
aryValue=`-${aryValue}`;
}
isNoneName=true;
this.VarTable.set(varName,aryValue);
}
}
var outValue;
if (draw) outValue=`输出: ${draw}`;
else if (isNoneName) outValue=`输出: ${this.VarTable.get(varName)}`;
else outValue=`输出${varName}: ${this.VarTable.get(varName)}`;
if (color) outValue+=`,颜色${this.GetColorExplain(color)}`;
if (lineWidth) outValue+=`,线段粗细${this.GetLineWidthExplain(lineWidth)}`;
if (isShow==false) outValue+=",不显示";
if (isDotLine==true) outValue+=",画虚线";
if (isDrawAbove==true) outValue+=',显示在位置之上';
if (pointDot && varName) //圆点
{
outValue+=",画小圆点线";
let value={Name:varName, Draw:outValue, Radius:g_JSChartResource.POINTDOT.Radius, Type:3};
this.OutVarTable.push(value);
}
else if (circleDot && varName) //圆点
{
outValue+=",画小圆圈线";
let value={Name:varName, Draw:outValue, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3};
this.OutVarTable.push(value);
}
else if (lineStick && varName) //LINESTICK 同时画出柱状线和指标线
{
outValue+=",画出柱状线和指标线";
let value={Name:varName, Draw:outValue, Type:4};
this.OutVarTable.push(value);
}
else if (stick && varName) //STICK 画柱状线
{
outValue+=",画柱状线";
let value={Name:varName, Draw:outValue, Type:5};
this.OutVarTable.push(value);
}
else if (volStick && varName) //VOLSTICK 画彩色柱状线
{
outValue+=",画成交量柱状线";
let value={Name:varName, Draw:outValue, Type:6};
this.OutVarTable.push(value);
}
else if (varName && color)
{
let value={Name:varName, Data:outValue, Color:color, Type:0};
this.OutVarTable.push(value);
}
else if (draw) //画图函数
{
var outVar={ Name:drawName, Draw:outValue, Type:1 };
this.OutVarTable.push(outVar);
}
else if (colorStick && varName) //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
{
outValue+=",画彩色柱状线";
let value={Name:varName, Draw:outValue, Color:color, Type:2};
this.OutVarTable.push(value);
}
else if (varName)
{
let value={Name:varName, Data:outValue,Type:0};
this.OutVarTable.push(value);
}
}
}
}
JSConsole.Complier.Log('[JSExplainer::Run]', this.VarTable);
return this.OutVarTable;
}
this.VisitNode=function(node)
{
switch(node.Type)
{
case Syntax.SequenceExpression:
this.VisitSequenceExpression(node);
break;
case Syntax.ExpressionStatement:
this.VisitNode(node.Expression);
break;
case Syntax.AssignmentExpression:
this.VisitAssignmentExpression(node);
break;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
this.VisitBinaryExpression(node);
break;
case Syntax.CallExpression:
this.VisitCallExpression(node);
break;
case Syntax.UnaryExpression:
this.VisitUnaryExpression(node);
break;
}
}
this.VisitSequenceExpression=function(node)
{
for(let i in node.Expression)
{
let item =node.Expression[i];
this.VisitNode(item);
}
}
this.VisitUnaryExpression=function(node)
{
if (node.Operator=='-')
{
let value=this.GetNodeValueEx(node.Argument);
return '-'+value;
}
return node.Argument.Value;
}
//函数调用
this.VisitCallExpression=function(node)
{
let funcName=node.Callee.Name;
let args=[];
for(let i in node.Arguments)
{
let item=node.Arguments[i];
let value;
if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(item);
else if (item.Type==Syntax.CallExpression)
value=this.VisitCallExpression(item);
else
value=this.GetNodeValue(item);
args.push(value);
}
if (node.Callee.Type==Syntax.Literal)
{
var dynamicName=node.Callee.Value;
node.Out=`指标引用'${dynamicName}'`;
return node.Out;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExplainer::VisitCallExpression]' , funcName, '(', args.toString() ,')');
if (g_JSComplierResource.IsCustomFunction(funcName))
{
var functionInfo=g_JSComplierResource.CustomFunction.Data.get(funcName);
if (!functionInfo.Description) node.Out=`自定义函数${funcName}`;
else node.Out=functionInfo.Description;
return node.Out;
}
node.Out=this.CallFunctionExplain(funcName, args, node);
return node.Out;
}
this.FUNCTION_INFO_LIST=new Map(
[
["REF", { Name:"REF", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的${args[0]}`; } } ],
["REFX", { Name:"REFX", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的${args[0]}`; } } ],
["REFV", { Name:"REFV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的(未作平滑处理)${args[0]}`; } } ],
["REFXV", { Name:"REFXV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的(未作平滑处理)${args[0]}`; } } ],
["REFDATE", { Name:"REFDATE", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日${args[0]}`; } } ],
["COUNT", { Name:"COUNT", Param:{ Count:2 }, ToString:function(args) { return `统计${args[1]}日中满足${args[0]}的天数`; } } ],
["BARSLASTCOUNT", { Name:"BARSLASTCOUNT", Param:{ Count:1 }, ToString:function(args) { return `条件${args[0]}连续成立次数`; } } ],
["BARSCOUNT", { Name:"BARSCOUNT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}有效数据周期数`; } } ],
["BARSLAST", { Name:"BARSLAST", Param:{ Count:1 }, ToString:function(args) { return `上次${args[0]}不为0距今天数`; } } ],
["BARSLASTS", { Name:"BARSLASTS", Param:{ Count:2 }, ToString:function(args) { return `倒数第N次成立时距今的周期数`; } } ],
["BARSNEXT", { Name:"BARSNEXT", Param:{ Count:1 }, ToString:function(args) { return `下次${args[0]}不为0距今天数`; } } ],
["BARSSINCEN", { Name:"BARSSINCEN", Param:{ Count:2 }, ToString:function(args) { return `在${args[1]}周期内首次${args[0]}距今天数`; } } ],
["BARSSINCE", { Name:"BARSSINCE", Param:{ Count:1 }, ToString:function(args) { return `首次${args[0]}距今天数`; } } ],
["HHV", { Name:"HHV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最高值`; } } ],
["LLV", { Name:"LLV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最低值`; } } ],
["ZTPRICE", { Name:"ZTPRICE", Param:{ Count:2 }, ToString:function(args) { return '计算涨停价'; } } ],
["DTPRICE", { Name:"DTPRICE", Param:{ Count:2 }, ToString:function(args) { return '计算跌停价'; } } ],
["BACKSET", { Name:"BACKSET", Param:{ Count:2 }, ToString:function(args) { return `若${args[0]}则将最近${args[1]}周期置为1`; } } ],
["HOD", { Name:"HOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的高值名次`; } } ],
["LOD", { Name:"LOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的低值名次`; } } ],
["REVERSE", { Name:"REVERSE", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的相反数`; } } ],
["FILTER", { Name:"FILTER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日过滤`; } } ],
["FILTERX", { Name:"FILTERX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日反向过滤`; } } ],
["TFILTER", { Name:"TFILTER", Param:{Count:3}, ToString:function(args) { return `信号过滤(多头)`; } }],
["SUMBARS", { Name:"SUMBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}累加至${args[1]}的天数`; } } ],
["MA", { Name:"MA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日简单移动平均`; } } ],
["SMA", { Name:"SMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}的${args[1]}日[${args[2]}日权重]移动平均`; } } ],
["MEMA", { Name:"MEMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日平滑移动平均`; } } ],
["EMA", { Name:"EMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数移动平均`; } } ],
["EXPMA", { Name:"EXPMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数移动平均`; } } ],
["EXPMEMA", { Name:"EXPMEMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数平滑移动平均`; } }],
["WMA", { Name:"WMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日加权移动平均`; } } ],
["DMA", { Name:"DMA", Param:{ Count:2 }, ToString:function(args) { return `以${args[1]}为权重${args[0]}的动态移动平均`; } } ],
["XMA", { Name:"XMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日偏移移动平均`; } } ],
["RANGE", { Name:"RANGE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}和${args[2]}之间`; } } ],
["CONST", { Name:"CONST", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的最后一日值`; } } ],
["TOPRANGE", { Name:"TOPRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最大值`; } } ],
["LOWRANGE", { Name:"LOWRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最小值`; } } ],
["FINDHIGH", { Name:"FINDHIGH", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最高价`; } } ],
["FINDHIGHBARS", { Name:"FINDHIGHBARS", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最高价到当前周期的周期数`; } } ],
["FINDLOW", { Name:"FINDLOW", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最低价`; } } ],
["FINDLOWBARS", { Name:"FINDLOWBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最低价到当前周期的周期数`; } } ],
["SUM", { Name:"SUM", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日累加`; } } ],
["MULAR", { Name:"MULAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}日累乘`; } } ],
["AMA", { Name:"AMA", Param:{ Count:2 }, ToString:function(args) { return `以${args[1]}为权重${args[0]}的自适应均线`; } } ],
["TMA", { Name:"TMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}的${args[1]}日[${args[2]}日权重]移动平均`; } } ],
["CROSS", { Name:"CROSS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}上穿${args[1]}`; } } ],
["LONGCROSS", { Name:"LONGCROSS", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}小于${args[1]}保持${args[2]}个交易日后交叉上穿`; } } ],
["UPNDAY", { Name:"UPNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日${args[0]}连涨`; } } ],
["DOWNNDAY", { Name:"DOWNNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日${args[0]}连跌`; } } ],
["NDAY", { Name:"NDAY", Param:{ Count:3 }, ToString:function(args) { return `最近${args[2]}日${args[0]}一直大于${args[1]}`; } } ],
["EXIST", { Name:"EXIST", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日存在${args[0]}`; } } ],
["EXISTR", { Name:"EXISTR", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日存在${args[0]}`; } } ],
["EVERY", { Name:"EVERY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日一直存在${args[0]}`; } } ],
["LAST", { Name:"LAST", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日持续${args[0]}`; } } ],
["NOT", { Name:"NOT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}取反`; } } ],
["IF", { Name:"IF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
["IFF", { Name:"IFF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
["IFN", { Name:"IFN", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
["IFC", { Name:"IFC", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
["TESTSKIP", { Name:"TESTSKIP", Param:{ Count:1 }, ToString:function(args) { return `如果满足条件${args[0]},公式返回`; } } ],
["VALUEWHEN", { Name:"VALUEWHEN", Param:{ Count:2 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回上个输出值 `; } } ],
["MAX", { Name:"MAX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}的较大值`; } } ],
["MIN", { Name:"MIN", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}的较小值`; } } ],
["ACOS", { Name:"ACOS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反余弦`; } } ],
["ASIN", { Name:"ASIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正弦`; } } ],
["ATAN", { Name:"ATAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正切`; } } ],
["COS", { Name:"COS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的余弦`; } } ],
["SIN", { Name:"SIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正弦`; } } ],
["TAN", { Name:"TAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正切`; } } ],
["EXP", { Name:"EXP", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的指数`; } } ],
["LN", { Name:"LN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的自然对数`; } } ],
["LOG", { Name:"LOG", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的对数`; } } ],
["SQRT", { Name:"SQRT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的开方`; } } ],
["ABS", { Name:"ABS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的绝对值`; } } ],
["POW", { Name:"POW", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}乘幂`; } } ],
["CEILING", { Name:"CEILING", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
["FLOOR", { Name:"FLOOR", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
["INTPART", { Name:"INTPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的整数部分`; } } ],
["BETWEEN", { Name:"BETWEEN", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}和${args[2]}之间`; } } ],
["FRACPART", { Name:"FRACPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的小数部分`; } } ],
["ROUND", { Name:"ROUND", Param:{ Count:1 }, ToString:function(args) { return `对${args[0]}(进行)四舍五入`; } } ],
["ROUND2", { Name:"ROUND2", Param:{ Count:2 }, ToString:function(args) { return `对${args[0]}(进行)四舍五入`; } } ],
["SIGN", { Name:"SIGN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的符号`; } } ],
["MOD", { Name:"MOD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}关于${args[1]}的模`; } } ],
["RAND", { Name:"RAND", Param:{ Count:1 }, ToString:function(args) { return `随机正整数`; } } ],
["AVEDEV", { Name:"AVEDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日平均绝对偏差`; } } ],
["DEVSQ", { Name:"DEVSQ", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日数据偏差平方和`; } } ],
["FORCAST", { Name:"FORCAST", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日线性回归预测值`; } } ],
["TSMA", { Name:"TSMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}在${args[1]}个周期内的时间序列三角移动平均`; } } ],
["SLOPE", { Name:"SLOPE", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日线性回归斜率`; } } ],
["STD", { Name:"STD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日估算标准差`; } } ],
["STDP", { Name:"STDP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日总体标准差`; } } ],
["STDDEV", { Name:"STDDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日标准偏差`; } } ],
["VAR", { Name:"VAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日估算样本方差`; } } ],
["VARP", { Name:"VARP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日总体样本方差`; } } ],
["COVAR", { Name:"COVAR", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[2]}周期的协方差`; } } ],
["RELATE", { Name:"RELATE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[0]}周期的相关系数`; } } ],
["BETA", { Name:"BETA", Param:{ Count:1 }, ToString:function(args) { return `β(Beta)系数`; } } ],
["BETAEX", { Name:"BETAEX", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[2]}周期的相关放大系数`; } } ],
["COST", { Name:"COST", Param:{ Count:1 }, ToString:function(args) { return `获利盘为${args[0]}%的成本分布`; } } ],
["WINNER", { Name:"WINNER", Param:{ Count:1 }, ToString:function(args) { return `以${args[0]}计算的获利盘比例`; } } ],
["LWINNER", { Name:"LWINNER", Param:{ Count:2 }, ToString:function(args) { return `最近${args[0]}日那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
["PWINNER", { Name:"PWINNER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
["COSTEX", { Name:"COSTEX", Param:{ Count:2 }, ToString:function(args) { return `位于价格${args[0]}和${args[1]}间的成本`; } } ],
["PPART", { Name:"PPART", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本占总成本的比例`; } } ],
["SAR", { Name:"SAR", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}的${args[2]}日抛物转向`; } } ],
["SARTURN", { Name:"SARTURN", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}的${args[2]}日抛物转向点`; } } ],
//字符串函数
["CON2STR", { Name:"CON2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
["VAR2STR", { Name:"VAR2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
["STR2CON", { Name:"STR2CON", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}转为数字`; } } ],
["STRLEN", { Name:"STRLEN", Param:{ Count:1 }, ToString:function(args) { return `得到${args[0]}字符串长度`; } } ],
["STRCAT", { Name:"STRCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
["VARCAT", { Name:"VARCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
["STRSPACE", { Name:"STRSPACE", Param:{ Count:1 }, ToString:function(args) { return `字符串${args[0]}加一空格`; } } ],
["SUBSTR", { Name:"SUBSTR", Param:{ Count:3 }, ToString:function(args) { return `字符串${args[0]}中取一部分`; } } ],
["STRCMP", { Name:"STRCMP", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}和字符串${args[1]}比较`; } } ],
["FINDSTR", { Name:"FINDSTR", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}中查找字符串${args[1]}`; } } ],
["NAMEINCLUDE", { Name:"NAMEINCLUDE", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
["CODELIKE", { Name:"CODELIKE", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
["INBLOCK", { Name:"AVEDEV", Param:{ Count:1 }, ToString:function(args) { return `属于${args[0]}板块`; } } ],
["STKINDI",{ Name:"STKINDI", Param:{ Dynamic:true }, ToString:function(args) { return "指标引用"; } }],
["STRFORMAT",{ Name:"STRFORMAT", Param:{ Dynamic:true }, ToString:function(args) { return `格式化${args[0]}字符串`; } }],
["NAMELIKE",{ Name:"NAMELIKE", Param:{ Count:1 }, ToString:function(args) { return `品种名称是否以'${args[0]}'开头`; } }],
[
"HHVBARS",
{
Name:"HHVBARS", Param:{ Count:2 },
ToString:function(args)
{
if (args[1]==0) return `历史${args[0]}新高距今天数`;
return `${args[1]}日内${args[0]}新高距今天数`;
}
}
],
[
"LLVBARS",
{
Name:"LLVBARS", Param:{ Count:2 },
ToString:function(args)
{
if (args[1]==0) return `历史${args[0]}新低距今天数`;
return `${args[1]}日内${args[0]}新低距今天数`;
}
}
],
["L2_VOLNUM", { Name:"L2_VOLNUM", Param:{ Count:2 }, ToString:function(args) { return `单数分档`; } }],
["L2_VOL", { Name:"L2_VOL", Param:{ Count:2 }, ToString:function(args) { return `成交量分档`; } }],
["L2_AMO", { Name:"L2_AMO", Param:{ Count:2 }, ToString:function(args) { return `成交额分档`; } }],
]
);
this.CallFunctionExplain=function(funcName, args, node)
{
if (this.FUNCTION_INFO_LIST.has(funcName))
{
var item=this.FUNCTION_INFO_LIST.get(funcName);
if (item.Param.Dynamic===true) //动态参数
{
}
else
{
if (item.Param.Count!=args.length)
this.ThrowUnexpectedNode(node,`函数${funcName}参数个数不正确. 需要${item.Param.Count}个参数`);
}
return item.ToString(args);
}
switch(funcName)
{
case "CALCSTOCKINDEX":
return `引用${args[0]}的${args[1]}指标第${args[2]}个输出值`;
case "PEAK":
case "PEAKBARS":
case "ZIG":
case "ZIGA":
case "TROUGH":
case "TROUGHBARS":
return this.GetZIGExplain(funcName,args);
case "FINANCE":
return this.GetFinanceExplain(args);
case "DYNAINFO":
return this.GetDynainfoExplain(args);
case 'CLOSE':
case 'C':
case 'VOL':
case 'V':
case 'OPEN':
case 'O':
case 'HIGH':
case 'H':
case 'LOW':
case 'L':
case 'AMOUNT':
case 'AMO':
return this.GetOtherSymbolExplain( {FunctionName:funcName, Args:args} ,node);
//绘图函数
case "PLOYLINE":
return `当满足条件${args[0]}时以${args[1]}位置为顶点画折线连接`;
case "DRAWLINE":
return `当满足条件${args[0]}时,在${args[1]}位置画直线起点,当满足条件${args[2]}时,在${args[3]}位置画直线终点,${args[4]}表示是否延长`;
case "DRAWSL":
return `当满足条件${args[0]}时,在${args[1]}位置画斜线线性回归,${args[2]}斜率,${args[3]}长度,${args[4]}方向`;
case "DRAWKLINE":
case "DRAWKLINE1":
return 'K线';
case "DRAWICON":
return `当满足条件${args[0]}时,在${args[1]}位置画${args[2]}号图标`;
case "DRAWTEXT":
return `当满足条件${args[0]}时,在${args[1]}位置书写文字`;
case "DRAWTEXT_FIX":
return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写文字`;
case "DRAWNUMBER":
return `当满足条件${args[0]}时,在${args[1]}位置书写数字`;
case "DRAWNUMBER_FIX":
return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写数字`;
case "RGB":
return `自定色[${args[0]},${args[1]},${args[2]}]`;
case "RGBA":
return `自定色[${args[0]},${args[1]},${args[2]},${args[3]}]`;
case "DRAWBAND":
return '画带状线';
case "DRAWRECTREL":
return "相对位置上画矩形.";
case "DRAWGBK":
return "填充背景";
case "TIPICON":
return `当满足条件${args[0]}时,在${args[1]}位置画${args[2]}号图标`;
case "STICKLINE":
var barType="";
if (args[4]==-1) barType="虚线空心柱";
else if (args[4]==0) barType="实心柱";
else barType="实线空心柱";
return `当满足条件${args[0]}时, 在${args[1]}和${args[2]}位置之间画柱状线,宽度为${args[3]},${barType}`;
case "PARTLINE":
return "画折线"
case "SELL":
return "卖出平仓";
case "BUY":
return "买入开仓";
case "SELLSHORT":
return "卖出开仓";
case "BUYSHORT":
return "买入平仓";
case "YMOVE":
return;
case "BACKGROUND":
return "绘制背景";
case "UPCOLOR":
return `上涨颜色${args[0]}`;
case "DOWNCOLOR":
return `下跌颜色${args[0]}`;
case "STICKTYPE":
case "FIRSTDRAW":
return "";
default:
this.ThrowUnexpectedNode(node,`函数${funcName}不存在`);
}
}
this.GetDynainfoExplain=function(args)
{
const DATA_NAME_MAP=new Map(
[
[3,"前收盘价"], [4,"开盘价"], [5,"最高价"], [6,"最低价"], [7,"现价"], [8,'总量'], [9,"现量"],
[10,"总金额"], [11,"均价"], [12,"日涨跌"], [13,"振幅"], [14,"涨幅"], [15,"开盘时的成交金额"],
[16,"前5日每分钟均量"], [17,"量比"], [18,"上涨家数"], [19,"下跌家数"]
]);
var id=args[0];
if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);
return `即时行情[${id}]`;
}
this.GetFinanceExplain=function(args)
{
const DATA_NAME_MAP=new Map(
[
[1,"总股本"], [2,"市场类型"], [3,"沪深品种类型"], [4,"沪深行业代码"], [5,"B股"], [6,"H股"], [7,"流通股本[股]"], [8,"股东人数[户]"], [9,"资产负债率%"],
[10,"总资产"], [11,"流动资产"], [12,"固定资产"], [13,"无形资产"], [15,"流动负债"], [16,"少数股东权益"]
]);
var id=args[0];
if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);
return `财务数据[${id}]`;
}
this.GetZIGExplain=function(funcName,args)
{
var value=args[0];
if (value==0) value="开盘价";
else if (value==1) value="最高价";
else if (value==2) value="最低价";
else if (value==3) value="收盘价";
switch(funcName)
{
case "PEAK":
return `${value}的${args[1]}%之字转向的前${args[2]}个波峰值`;
case "PEAKBARS":
return `${value}的${args[1]}5%之字转向的前${args[2]}个波峰位置`;
case "ZIG":
return `${value}的${args[1]}的之字转向`;
case "ZIGA":
return `${value}变化${args[1]}的之字转向`;
case "TROUGH":
return `${value}的${args[1]}%之字转向的前${args[2]}个波谷值`;
case "TROUGHBARS":
return `${value}的${args[1]}%之字转向的前${args[2]}个波谷位置`;
}
}
this.GetColorExplain=function(colorName)
{
const COLOR_MAP=new Map(
[
['COLORBLACK','黑色'],['COLORBLUE','蓝色'],['COLORGREEN','绿色'],['COLORCYAN','青色'],['COLORRED','红色'],
['COLORMAGENTA','洋红色'],['COLORBROWN','棕色'],['COLORLIGRAY','淡灰色'],['COLORGRAY','深灰色'],['COLORLIBLUE','淡蓝色'],
['COLORLIGREEN','淡绿色'],['COLORLICYAN','淡青色'],['COLORLIRED','淡红色'],['COLORLIMAGENTA','淡洋红色'],['COLORWHITE','白色'],['COLORYELLOW','黄色']
]);
if (COLOR_MAP.has(colorName)) return COLOR_MAP.get(colorName);
//COLOR 自定义色
//格式为COLOR+“RRGGBB”:RR、GG、BB表示红色、绿色和蓝色的分量,每种颜色的取值范围是00-FF,采用了16进制。
//例如:MA5:MA(CLOSE,5),COLOR00FFFF 表示纯红色与纯绿色的混合色:COLOR808000表示淡蓝色和淡绿色的混合色。
if (colorName.indexOf('COLOR')==0) return '#'+colorName.substr(5);
return 'rgb(30,144,255)';
}
this.GetLineWidthExplain=function(lineWidth)
{
var width=parseInt(lineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) return width;
return 1;
}
this.SymbolPeriodExplain=function(valueName,period)
{
const mapStockDataName=new Map(
[
['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"],
['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"],
['VOLINSTK',"持仓量"]
]);
//MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR
const mapPeriodName=new Map(
[
["MIN1","1分钟"], ["MIN5", "5分钟"], ["MIN15", "15分钟"], ["MIN30","30分钟"],["MIN60","60分钟"],
["DAY","日"],["WEEK","周"], ["MONTH", "月"], ['SEASON',"季"], ["YEAR", "年"],["WEEK2","双周"], ["HALFYEAR", "半年"]
]);
var dataName=valueName;
if (mapStockDataName.has(valueName)) dataName=mapStockDataName.get(valueName);
var periodName=period;
if (mapPeriodName.has(period)) periodName=mapPeriodName.get(period);
return `${dataName}[取${periodName}数据]`;
}
this.GetOtherSymbolExplain=function(obj, node)
{
const mapStockDataName=new Map(
[
['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"],
['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"],
['VOLINSTK',"持仓量"]
]);
if (obj.FunctionName)
{
var args=obj.Args;
var dataName=mapStockDataName.get(obj.FunctionName);
return `[${args[0]}]${dataName}`;
}
else if (obj.Literal)
{
var value=obj.Literal.toUpperCase();
var args=value.split("$");
if (!mapStockDataName.has(args[1])) return "";
var symbol=args[0];
var dataName=mapStockDataName.get(args[1]);
return `[${symbol}]${dataName}`;
}
}
this.IsDrawFunction=function(name)
{
let setFunctionName=new Set(
[
"STICKLINE","DRAWTEXT",'SUPERDRAWTEXT','DRAWLINE','DRAWBAND','DRAWKLINE',"DRAWKLINE1",'DRAWKLINE_IF','PLOYLINE',
'POLYLINE','DRAWNUMBER',"DRAWNUMBER_FIX",'DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL',"DRAWTEXTABS",
'DRAWOVERLAYLINE',"FILLRGN", "FILLRGN2","FILLTOPRGN", "FILLBOTTOMRGN", "FILLVERTICALRGN","FLOATRGN","DRAWSL", "DRAWGBK2",
"BUY","BUYSHORT","SELL","SELLSHORT",
]);
if (setFunctionName.has(name)) return true;
return false;
}
//赋值
this.VisitAssignmentExpression=function(node)
{
let left=node.Left;
if (left.Type!=Syntax.Identifier) this.ThrowUnexpectedNode(node);
let varName=left.Name;
let right=node.Right;
let value=null;
if (right.Type==Syntax.BinaryExpression || right.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(right);
else if (right.Type==Syntax.CallExpression)
value=this.VisitCallExpression(right);
else if (right.Type==Syntax.Literal)
{
value=right.Value;
if (IFrameSplitOperator.IsString(value) && right.Value.indexOf("$")>0)
value=this.GetOtherSymbolExplain({ Literal:value }, node);
}
else if (right.Type==Syntax.Identifier) //右值是变量
value=this.ReadVariable(right.Name,right);
else if (right.Type==Syntax.MemberExpression)
value=this.ReadMemberVariable(right);
else if (right.Type==Syntax.UnaryExpression)
value=this.VisitUnaryExpression(right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExplainer::VisitAssignmentExpression]' , varName, ' = ',value);
this.VarTable.set(varName,this.ConvertToShortValue(value));
}
this.ConvertToShortValue=function(value)
{
var maxLength=this.MaxValueLength;
if (value && value.length>=maxLength)
{
var shortValue=value.slice(0, maxLength-10);
shortValue+="......";
return shortValue;
}
return value;
}
this.ReadMemberVariable=function(node)
{
var obj=node.Object;
var member=node.Property;
let maiObj;
if (obj.Type==Syntax.BinaryExpression || obj.Type==Syntax.LogicalExpression )
maiObj=this.VisitBinaryExpression(obj);
else if (obj.Type==Syntax.CallExpression)
maiObj=this.VisitCallExpression(obj);
else
{
if (member.Name.indexOf('#')>0)
{
var aryValue=member.Name.split("#");
var value=`${obj.Name}的${aryValue[0]}[周期${aryValue[1]}]`;
}
else
{
var value=`${obj.Name}的${member.Name}`;
}
return value;
}
if (!maiObj) return null;
var value=maiObj[member.Name];
if (value) return value;
return null;
}
//逻辑运算
this.VisitBinaryExpression=function(node)
{
let stack=[];
stack.push(node);
let temp=null;
while(stack.length!=0)
{
temp=stack[stack.length-1];
if (temp.Left && node!=temp.Left && node!=temp.Right)
{
stack.push(temp.Left);
}
else if (temp.Right && node!=temp.Right)
{
stack.push(temp.Right);
}
else
{
let value=stack.pop();
if (value.Type==Syntax.BinaryExpression) //只遍历操作符就可以
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
value.Out=`(${leftValue} ${value.Operator} ${rightValue})`;
if (leftValue=="收盘价" && rightValue=="开盘价")
{
if (value.Operator==">") value.Out='(收阳线)';
else if (value.Operator=="<") value.Out='(收阴线)';
else if (value.Operator=="=") value.Out='(平盘)';
}
else if (leftValue=="开盘价" && rightValue=="收盘价")
{
if (value.Operator=="<") value.Out='(收阳线)';
else if (value.Operator==">") value.Out='(收阴线)';
else if (value.Operator=="=") value.Out='(平盘)';
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value);
}
else if (value.Type==Syntax.LogicalExpression)
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
switch(value.Operator)
{
case '&&':
case 'AND':
value.Out=`(${leftValue} 并且 ${rightValue})`;
break;
case '||':
case 'OR':
value.Out=`(${leftValue} 或者 ${rightValue})`;
break;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] LogicalExpression',value);
}
node=temp;
}
}
return node.Out;
}
this.GetNodeValueEx=function(node)
{
var value=null;
if (node.Type==Syntax.BinaryExpression || node.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(node);
else if (node.Type==Syntax.CallExpression)
value=this.VisitCallExpression(node);
else
value=this.GetNodeValue(node);
return value;
}
this.GetNodeValue=function(node)
{
switch(node.Type)
{
case Syntax.Literal: //数字
return node.Value;
case Syntax.UnaryExpression:
return this.VisitUnaryExpression(node);
case Syntax.Identifier:
let value=this.ReadVariable(node.Name,node);
return value;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
return node.Out;
case Syntax.CallExpression:
return this.VisitCallExpression(node);
default:
this.ThrowUnexpectedNode(node);
}
}
//读取变量
this.ReadVariable=function(name,node)
{
if (this.ConstVarTable.has(name))
{
let data=this.ConstVarTable.get(name);
return data;
}
if (g_JSComplierResource.IsCustomVariant(name))
{
var variantInfo=g_JSComplierResource.CustomVariant.Data.get(name); //读取自定义变量
if (variantInfo.Description) return variantInfo.Description;
else return name;
}
if (this.VarTable.has(name)) return this.VarTable.get(name);
if (name.indexOf('#')>0)
{
var aryPeriod=name.split('#');
return this.SymbolPeriodExplain(aryPeriod[0],aryPeriod[1]);
}
if (name=="AUTOFILTER") //信号过滤
{
return this.AUTOFILTER();
}
this.ThrowUnexpectedNode(node, '变量'+name+'不存在');
return name;
}
this.AUTOFILTER=function()
{
//TODO:过滤信号
return null;
}
this.ThrowUnexpectedNode=function(node,message)
{
let marker=node.Marker;
let msg=message || "执行异常";
return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg);
}
this.ThrowError=function()
{
}
}
//对外导出类
function JSComplier()
{
}
//词法分析
JSComplier.Tokenize=function(code)
{
JSConsole.Complier.Log('[JSComplier.Tokenize]', code);
let tokenizer=new Tokenizer(code);
let tokens=[];
try
{
while(true)
{
let token=tokenizer.GetNextToken();
if (!token) break;
tokens.push(token);
}
}
catch(e)
{
}
return tokens;
}
//语法解析 生成抽象语法树(Abstract Syntax Tree)
JSComplier.Parse=function(code)
{
JSConsole.Complier.Log('[JSComplier.Parse]',code);
let parser=new JSParser(code);
parser.Initialize();
let program=parser.ParseScript();
let ast=program;
return ast;
}
/*
执行
option.Symbol=股票代码
option.Name=股票名称
option.Data=这个股票的ChartData
option.Right=复权
option.MaxRequestDataCount=请求数据的最大个数
*/
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
JSComplier.Execute=function(code,option,errorCallback)
{
//异步调用
//var asyncExecute= async function() es5不能执行 去掉异步
var asyncExecute= function()
{
try
{
if (option.Self) option.Self.Status=1;
JSConsole.Complier.Log('[JSComplier.Execute]',code,option);
JSConsole.Complier.Log('[JSComplier.Execute] parser .....');
let parser=new JSParser(code);
parser.Initialize();
let program=parser.ParseScript();
let ast=program;
JSConsole.Complier.Log('[JSComplier.Execute] parser finish.', ast);
if (option.Self) option.Self.Status=2;
JSConsole.Complier.Log('[JSComplier.Execute] execute .....');
let execute=new JSExecute(ast,option);
execute.ErrorCallback=errorCallback; //执行错误回调
execute.JobList=parser.Node.GetDataJobList();
if (option.ClassName=='ScriptIndexConsole' && !option.Data) execute.JobList.unshift({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA});
execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
if (option.Self) option.Self.Status=3;
let result=execute.Execute();
}catch(error)
{
JSConsole.Complier.Log(error);
if (errorCallback) errorCallback(error, option.CallbackParam);
if (option.Self) option.Self.Status=0;
}
}
asyncExecute();
JSConsole.Complier.Log('[JSComplier.Execute] async execute.');
}
JSComplier.Explain=function(code,option, errorCallback)
{
//异步调用
//var asyncExecute= async function() es5不能执行 去掉异步
var asyncExplain= function()
{
try
{
JSConsole.Complier.Log('[JSComplier.Explain]',code,option);
JSConsole.Complier.Log('[JSComplier.Explain] parser .....');
let parser=new JSParser(code);
parser.Initialize();
let program=parser.ParseScript();
let ast=program;
JSConsole.Complier.Log('[JSComplier.Explain] parser finish.', ast);
JSConsole.Complier.Log('[JSComplier.Explain] explain .....');
let execute=new JSExplainer(ast,option);
execute.ErrorCallback=errorCallback; //执行错误回调
execute.JobList=parser.Node.GetDataJobList();
execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
let result=execute.Run();
}catch(error)
{
JSConsole.Complier.Log(error);
if (errorCallback) errorCallback(error, option.CallbackParam);
}
}
asyncExplain();
JSConsole.Complier.Log('[JSComplier.Explain] async explain.');
}
JSComplier.SetDomain = function (domain, cacheDomain) //修改API地址
{
if (domain) g_JSComplierResource.Domain = domain;
if (cacheDomain) g_JSComplierResource.CacheDomain = cacheDomain;
}
JSComplier.AddIcon=function(obj) //添加一个obj={ID:, Text:, Color, Family: }
{
g_JSComplierResource.CustomDrawIcon.Data.set(obj.ID, obj);
}
JSComplier.AddFunction=function(obj) //添加函数 { Name:函数名, Description:描述信息, IsDownload:是否需要下载数据, Invoke:函数执行(可选) }
{
if (!obj || !obj.Name) return;
var ID=obj.Name.toUpperCase();
g_JSComplierResource.CustomFunction.Data.set(ID, obj);
}
JSComplier.AddVariant=function(obj) //{ Name:变量名, Description:描述信息 }
{
if (!obj || !obj.Name) return;
var ID=obj.Name.toUpperCase();
g_JSComplierResource.CustomVariant.Data.set(ID, obj);
}
JSComplier.ColorVarToRGB=function(colorName)
{
let COLOR_MAP=new Map(
[
['COLORBLACK','rgb(0,0,0)'],
['COLORBLUE','rgb(18,95,216)'],
['COLORGREEN','rgb(25,158,0)'],
['COLORCYAN','rgb(0,255,198)'],
['COLORRED','rgb(238,21,21)'],
['COLORMAGENTA','rgb(255,0,222)'],
['COLORBROWN','rgb(149,94,15)'],
['COLORLIGRAY','rgb(218,218,218)'], //画淡灰色
['COLORGRAY','rgb(133,133,133)'], //画深灰色
['COLORLIBLUE','rgb(94,204,255)'], //淡蓝色
['COLORLIGREEN','rgb(183,255,190)'], //淡绿色
['COLORLICYAN','rgb(154,255,242)'], //淡青色
['COLORLIRED','rgb(255,172,172)'], //淡红色
['COLORLIMAGENTA','rgb(255,145,241)'], //淡洋红色
['COLORWHITE','rgb(255,255,255)'], //白色
['COLORYELLOW','rgb(255,198,0)']
]);
if (COLOR_MAP.has(colorName)) return COLOR_MAP.get(colorName);
//COLOR 自定义色
//格式为COLOR+“BBGGRR”:BB、GG、RR表示蓝色、绿色和红色的分量,每种颜色的取值范围是00-FF,采用了16进制。
//例如:MA5:MA(CLOSE,5),COLOR00FFFF表示纯红色与纯绿色的混合色:COLOR808000表示淡蓝色和淡绿色的混合色。
if (colorName.indexOf('COLOR')==0)
{
var strColor=colorName.substr(5);
if (strColor.length!=6) return null;
var value=strColor.substr(0,2);
var b=parseInt(value,16);
value=strColor.substr(2,2);
var g=parseInt(value,16);
value=strColor.substr(4,2);
var r=parseInt(value,16);
return `rgb(${r},${g},${b})`;
}
//格式为RGBX+“RRGGBB”:RR、GG、BB表示红色、绿色和的蓝色分量,每种颜色的取值范围是00-FF,采用了16进制。
//例如:MA5:MA(CLOSE,5),RGBXFFFF00表示纯红色与纯绿色的混合色:RGBX008080表示淡蓝色和淡绿色的混合色。
if (colorName.indexOf("RGBX")==0)
{
var strColor=colorName.substr(4);
if (strColor.length!=6) return null;
var value=strColor.substr(0,2);
var r=parseInt(value,16);
value=strColor.substr(2,2);
var g=parseInt(value,16);
value=strColor.substr(4,2);
var b=parseInt(value,16);
return `rgb(${r},${g},${b})`;
}
return null;
}
var HQ_DATA_TYPE=
{
KLINE_ID:0, //K线
MINUTE_ID:2, //当日走势图
HISTORY_MINUTE_ID:3,//历史分钟走势图
MULTIDAY_MINUTE_ID:4,//多日走势图
};
// 图形指标名字
var SCRIPT_CHART_NAME=
{
OVERLAY_BARS:"OVERLAY_BARS", //叠加柱子图
KLINE_TABLE:"KLINE_TABLE",
SCATTER_PLOT:"SCATTER_PLOT", //散点图
CLIP_COLOR_STICK:"CLIP_COLOR_STICK", //上下柱子 裁剪
}
// 外部对接API指标数据及图形
function ScriptIndexChartFactory()
{
this.DataMap=new Map(); //["图形名字", {} ]
this.Add=function(name, option)
{
this.DataMap.set(name,
{
MinuteFittingCallback:option.MinuteFittingCallback,
KLineFittingCallback:option.KLineFittingCallback,
CreateChartCallback:option.CreateChartCallback,
FormatTitleCallback:option.FormatTitleCallback,
}
);
}
this.Get=function(name)
{
if (!this.DataMap.has(name)) return null;
return this.DataMap.get(name);
}
this.Has=function(name)
{
return this.DataMap.has(name);
}
}
var g_ScriptIndexChartFactory=new ScriptIndexChartFactory();
//脚本指标
//name=指标名字 args=参数名字 参数值
function ScriptIndex(name,script,args,option)
{
this.newMethod=BaseIndex; //派生
this.newMethod(name);
delete this.newMethod;
this.ClassName="ScriptIndex";
this.Script=script;
this.Arguments=[];
this.OutVar=[];
this.ID; //指标ID
this.FloatPrecision=2; //小数位数
this.StringFormat;
this.IsShowIndexTitle=true; //是否显示指标标题
this.KLineType=null; //K线显示类型
this.InstructionType; //五彩K线, 交易指标
this.YSpecificMaxMin=null; //最大最小值
this.YSplitScale=null; //固定刻度
this.Condition=null; //限制条件
this.OutName=null; //动态输出指标名字
this.YSplitType;
//指标上锁配置信息
this.IsLocked=false; //是否锁住指标
this.LockCallback=null;
this.LockID=null;
this.LockBG=null; //锁背景色
this.LockTextColor=null;
this.LockText=null;
this.LockFont=null;
this.LockCount=20;
this.LockMinWidth=null;
this.TitleFont=g_JSChartResource.TitleFont; //标题字体
this.IsShortTitle=false; //是否显示指标参数
this.IsUsePageData=false; //是否使用了K线界面数据
this.YAxis=null; //Y轴刻度设置 { FloatPrecision, StringFormat, EnableRemoveZero }
//调试信息
this.Debug; // { Callback:, Count: }
this.IsSync=false; //是否是同步计算 (无数据请求)
this.IsShow=true; //是否显示图形
this.RunCount=0; //已执行次数
this.MaxRunCount=-1; //最大执行次数 -1=无限
if (option)
{
if (option.FloatPrecision>=0) this.FloatPrecision=option.FloatPrecision;
if (option.StringFormat>0) this.StringFormat=option.StringFormat;
if (IFrameSplitOperator.IsBool(option.IsShowIndexTitle)) this.IsShowIndexTitle=option.IsShowIndexTitle;
if (option.ID) this.ID=option.ID;
if (option.KLineType>=0 || option.KLineType===-1) this.KLineType=option.KLineType;
if (option.InstructionType) this.InstructionType=option.InstructionType;
if (option.YSpecificMaxMin) this.YSpecificMaxMin=option.YSpecificMaxMin;
if (option.YSplitScale) this.YSplitScale=option.YSplitScale;
if (option.Condition) this.Condition=option.Condition;
if (option.TitleFont) this.TitleFont=option.TitleFont;
if (option.IsShortTitle) this.IsShortTitle=option.IsShortTitle;
if (option.OutName) this.OutName=option.OutName;
if (IFrameSplitOperator.IsNumber(option.YSplitType)) this.YSplitType=option.YSplitType;
if (IFrameSplitOperator.IsBool(option.IsSync)) this.IsSync=option.IsSync;
if (IFrameSplitOperator.IsNumber(option.MaxRunCount)) this.MaxRunCount=option.MaxRunCount;
if (option.Debug)
{
if (IFrameSplitOperator.IsPlusNumber(option.Debug.Count) && option.Debug.Callback)
{
this.Debug={ Count:option.Debug.Count, Callback:option.Debug.Callback }
}
}
}
if (option && option.Lock)
{
if (option.Lock.IsLocked==true) this.IsLocked=true; //指标上锁
if (option.Lock.Callback) this.LockCallback=option.Lock.Callback; //锁回调
if (option.Lock.ID) this.LockID=option.Lock.ID; //锁ID
if (option.Lock.BG) this.LockBG=option.Lock.BG;
if (option.Lock.TextColor) this.LockTextColor=option.Lock.TextColor;
if (option.Lock.Text) this.LockText=option.Lock.Text;
if (option.Lock.Font) this.LockFont=option.Lock.Font;
if (option.Lock.Count) this.LockCount=option.Lock.Count;
if (option.Lock.MinWidth) this.LockMinWidth=option.Lock.MinWidth*GetDevicePixelRatio();
}
if (option && option.YAxis)
{
this.YAxis={ };
if (IFrameSplitOperator.IsNumber(option.YAxis.FloatPrecision)) this.YAxis.FloatPrecision=option.YAxis.FloatPrecision;
if (IFrameSplitOperator.IsNumber(option.YAxis.StringFormat)) this.YAxis.StringFormat=option.YAxis.StringFormat;
if (IFrameSplitOperator.IsBool(option.YAxis.EnableRemoveZero)) this.YAxis.EnableRemoveZero=option.YAxis.EnableRemoveZero;
if (IFrameSplitOperator.IsBool(option.YAxis.ExcludeValue)) this.YAxis.ExcludeValue=option.YAxis.ExcludeValue; //不参数Y轴的计算
}
if (args) this.Arguments=args;
this.CopyTo=function(dest) //赋值到新实例出来
{
dest.FloatPrecision=this.FloatPrecision;
dest.StringFormat=this.StringFormat;
dest.KLineType=this.KLineType;
dest.InstructionType=this.InstructionType;
dest.Condition=this.Condition;
dest.TitleFont=this.TitleFont;
dest.IsShortTitle=this.IsShortTitle;
dest.OutName=this.OutName;
dest.Arguments=this.Arguments;
dest.Script=this.Script;
dest.Name=this.Name;
dest.ID=this.ID;
}
this.SetLock=function(lockData)
{
if (lockData.IsLocked==true)
{
this.IsLocked=true; //指标上锁
if (lockData.Callback) this.LockCallback=lockData.Callback; //锁回调
if (lockData.ID) this.LockID=lockData.ID; //锁ID
if (lockData.BG) this.LockBG=lockData.BG;
if (lockData.TextColor) this.LockTextColor=lockData.TextColor;
if (lockData.Text) this.LockText=lockData.Text;
if (lockData.Font) this.LockFont=lockData.Font;
if (lockData.Count) this.LockCount=lockData.Count;
if (lockData.MinWidth) this.LockMinWidth=lockData.MinWidth*GetDevicePixelRatio();
}
else
{ //清空锁配置信息
this.IsLocked=false; //是否锁住指标
this.LockCallback=null;
this.LockID=null;
this.LockBG=null; //锁背景色
this.LockTextColor=null;
this.LockText=null;
this.LockFont=null;
this.LockCount=20;
}
}
//是否超出执行的最大次数
this.IsExcessRunCount=function()
{
if (this.MaxRunCount<0) return false; //没有限制
return this.RunCount>=this.MaxRunCount;
}
this.ExecuteScript=function(hqChart,windowIndex,hisData)
{
this.OutVar=[];
let self = this;
let param=
{
HQChart:hqChart,
WindowIndex:windowIndex,
HistoryData:hisData,
Self:this
};
//数据类型
let hqDataType=HQ_DATA_TYPE.KLINE_ID; //默认K线
if (hqChart.ClassName==='MinuteChartContainer' || hqChart.ClassName==='MinuteChartHScreenContainer')
{
if (hqChart.DayCount>1) hqDataType=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID; //多日分钟
else hqDataType=HQ_DATA_TYPE.MINUTE_ID; //分钟数据
}
else if (hqChart.ClassName==='HistoryMinuteChartContainer')
{
hqDataType=HQ_DATA_TYPE.HISTORY_MINUTE_ID; //历史分钟
}
let option=
{
HQDataType:hqDataType,
Symbol:hqChart.Symbol,
Name:hqChart.Name,
Data:hisData,
SourceData:hqChart.SourceData,
Callback:this.RecvResultData, CallbackParam:param,
Async:true,
MaxRequestDataCount:hqChart.MaxRequestDataCount,
MaxRequestMinuteDayCount:hqChart.MaxRequestMinuteDayCount,
Arguments:this.Arguments,
Condition:this.Condition,
IsBeforeData:hqChart.IsBeforeData,
IsApiPeriod:hqChart.IsApiPeriod,
DrawInfo:null,
Self:this,
};
if (this.Debug && IFrameSplitOperator.IsPlusNumber(this.Debug.Count) && this.Debug.Callback)
{
--this.Debug.Count;
option.Debug=1;
option.DebugFilter=this.Debug.Callback;
}
if (hqChart) //当前屏K线信息
{
if (hqChart.ChartPaint[0])
{
var item=hqChart.ChartPaint[0];
if (item && item.DrawKRange) option.DrawInfo={Start:item.DrawKRange.Start, End:item.DrawKRange.End };
}
}
if (hqDataType===HQ_DATA_TYPE.HISTORY_MINUTE_ID) option.TrateDate=hqChart.TradeDate;
if (hqDataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) option.DayCount=hqChart.DayCount;
if (hqChart.NetworkFilter) option.NetworkFilter=hqChart.NetworkFilter;
if (this.Condition && !this.IsMeetCondition(param,option))
{
this.ShowConditionError(param, this.Condition.Message);
return;
}
++this.RunCount;
let code=this.Script;
let run=JSComplier.Execute(code,option,hqChart.ScriptErrorCallback);
}
//是否符合限制条件
this.IsMeetCondition=function(param,option)
{
JSConsole.Complier.Log('[ScriptIndex::IsMeetCondition] ', this.Condition);
if (this.Condition.Period) //周期是否满足
{
if (!this.IsMeetPeriodCondition(param,option)) return false;
if (!this.IsMeetIncludeCondition(param,option)) return false;
}
return true;
}
//周期是否满足条件
this.IsMeetPeriodCondition=function(param,option)
{
if (!this.Condition.Period) return true;
for(var i in this.Condition.Period)
{
var item=this.Condition.Period[i];
switch(item)
{
case CONDITION_PERIOD.MINUTE_ID:
if (option.HQDataType==HQ_DATA_TYPE.MINUTE_ID) return true;
break;
case CONDITION_PERIOD.MULTIDAY_MINUTE_ID:
if (option.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) return true;
break;
case CONDITION_PERIOD.KLINE_DAY_ID:
case CONDITION_PERIOD.KLINE_WEEK_ID:
case CONDITION_PERIOD.KLINE_MONTH_ID:
case CONDITION_PERIOD.KLINE_YEAR_ID:
case CONDITION_PERIOD.KLINE_TWOWEEK_ID:
case CONDITION_PERIOD.KLINE_QUARTER_ID:
case CONDITION_PERIOD.KLINE_MINUTE_ID:
case CONDITION_PERIOD.KLINE_5_MINUTE_ID:
case CONDITION_PERIOD.KLINE_15_MINUTE_ID:
case CONDITION_PERIOD.KLINE_30_MINUTE_ID:
case CONDITION_PERIOD.KLINE_60_MINUTE_ID:
if (param.HQChart.Period==item) return true;
break;
}
}
return false;
}
this.IsMeetIncludeCondition=function(param,option)
{
if (!this.Condition.Include || this.Condition.Include.length<=0) return true;
var symbol=param.HQChart.Symbol;
if (symbol) symbol=symbol.toUpperCase();
for(var i in this.Condition.Include)
{
var item=this.Condition.Include[i];
if (symbol==item) return true;
}
return false;
}
//显示指标不符合条件
this.ShowConditionError=function(param,msg)
{
var hqChart=param.HQChart;
var windowIndex=param.WindowIndex;
hqChart.DeleteIndexPaint(windowIndex);
if (windowIndex==0) hqChart.ShowKLine(true);
var message='指标不支持当前品种或周期';
if (msg) message=msg;
let line=new ChartLine();
line.Canvas=hqChart.Canvas;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
line.NotSupportMessage=message;
hqChart.ChartPaint.push(line);
hqChart.UpdataDataoffset(); //更新数据偏移
hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
hqChart.Draw();
}
this.RecvResultData=function(outVar,param)
{
let hqChart=param.HQChart;
let windowIndex=param.WindowIndex;
let hisData=param.HistoryData;
param.Self.OutVar=outVar;
param.Self.BindData(hqChart,windowIndex,hisData);
if (param.Self.IsLocked==false) //不上锁
{
param.HQChart.Frame.SubFrame[windowIndex].Frame.SetLock(null);
}
else //上锁
{
let lockData={ IsLocked:true,Callback:param.Self.LockCallback,IndexName:param.Self.Name ,ID:param.Self.LockID,
BG:param.Self.LockBG,Text:param.Self.LockText,TextColor:param.Self.LockTextColor, Font:param.Self.LockFont, Count:param.Self.LockCount, MinWidth:param.Self.LockMinWidth };
param.HQChart.Frame.SubFrame[windowIndex].Frame.SetLock(lockData);
}
param.HQChart.UpdataDataoffset(); //更新数据偏移
param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
if (param.Self.IsSync===false) //异步需要马上刷新,同步主图数据更新的时候会刷新的
param.HQChart.Draw();
if (hqChart.GetIndexEvent)
{
var event=hqChart.GetIndexEvent(); //指标计算完成回调
if (event)
{
var self=param.Self;
var data={ OutVar:self.OutVar, WindowIndex: windowIndex, Name: self.Name, Arguments: self.Arguments, HistoryData: hisData,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
event.Callback(event,data,self);
}
}
}
//给图形设置指标名字
this.SetChartIndexName=function(chart)
{
if (this.Name) chart.IndexName=this.Name;
else if (this.ID) chart.IndexName==this.ID;
if (this.ID) chart.IndexID=this.ID;
if (this.YAxis)
{
if (IFrameSplitOperator.IsBool(this.YAxis.ExcludeValue)) chart.IsExcludeYValue=this.YAxis.ExcludeValue;
}
chart.Script=this; //指标内容绑定上去
}
//设置标题数据
this.SetTitleData=function(titleData, chart)
{
titleData.ChartClassName=chart.ClassName;
titleData.IsVisible=chart.IsVisible;
}
//自定义图形配色
this.ReloadChartResource=function(hqChart, windowIndex, chart)
{
var event=hqChart.GetEventCallback(JSCHART_EVENT_ID.ON_RELOAD_INDEX_CHART_RESOURCE); //指标计算完成回调
if (!event || !event.Callback) return;
var sendData={ Chart:chart, IndexName:this.Name,IndexID:this.ID, HQChart:hqChart, WindowIndex:windowIndex };
event.Callback(event,sendData,this);
}
this.CreateLine=function(hqChart,windowIndex,varItem, id, lineType)
{
if (lineType==7) var line=new ChartStepLine();
else var line=new ChartLine();
line.Canvas=hqChart.Canvas;
line.DrawType=1;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
line.Identify=this.Guid;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (lineType==8)
{
line.DrawType=2;
line.BreakPoint=varItem.BreakPoint;
}
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
if (varItem.IsDotLine)
{
line.IsDotLine=true; //虚线
line.LineDash=g_JSChartResource.DOTLINE.LineDash.slice();
}
//虚线设置
if (IFrameSplitOperator.IsNonEmptyArray(varItem.LineDash)) line.LineDash=varItem.LineDash;
if (varItem.IsShow==false) line.IsShow=false;
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Data;
this.ReloadChartResource(hqChart,windowIndex,line);
if (varItem.IsShowTitle===false) //NOTEXT 不绘制标题
{
}
else if (IFrameSplitOperator.IsString(varItem.Name) && varItem.Name.indexOf("NOTEXT")==0) //标题中包含NOTEXT不绘制标题
{
}
else
{
if (varItem.NoneName)
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);
else
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
this.SetTitleData(hqChart.TitlePaint[titleIndex].Data[id],line);
}
this.SetChartIndexName(line);
hqChart.ChartPaint.push(line);
}
this.CreateArea=function(hqChart, windowIndex, varItem, id,)
{
var line=new ChartArea();
line.Canvas=hqChart.Canvas;
line.DrawType=1;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
line.Identify=this.Guid;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.DownColor)
{
line.AreaColor=varItem.DownColor;
}
else if (varItem.UpColor)
{
line.AreaColor=varItem.UpColor;
line.AreaDirection=1;
}
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) line.LineWidth=width;
}
if (IFrameSplitOperator.IsNonEmptyArray(varItem.LineDash)) line.LineDash=varItem.LineDash; //虚线
if (varItem.IsShow==false) line.IsShow=false;
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Data;
if (varItem.IsShowTitle===false) //NOTEXT 不绘制标题
{
}
else if (IFrameSplitOperator.IsString(varItem.Name) && varItem.Name.indexOf("NOTEXT")==0) //标题中包含NOTEXT不绘制标题
{
}
else
{
if (varItem.NoneName)
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);
else
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
hqChart.TitlePaint[titleIndex].Data[id].ChartClassName=line.ClassName;
}
this.SetChartIndexName(line);
hqChart.ChartPaint.push(line);
}
this.CreateOverlayLine=function(hqChart,windowIndex,varItem,id,lineType)
{
if (lineType==7) var line=new ChartStepLine();
var line=new ChartSubLine();
line.Canvas=hqChart.Canvas;
line.DrawType=1;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
if (varItem.IsDotLine) line.IsDotLine=true; //虚线
if (varItem.IsShow==false) line.IsShow=false;
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Data;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
hqChart.TitlePaint[titleIndex].Data[id].ChartClassName=line.ClassName;
hqChart.ChartPaint.push(line);
}
this.CreateSingleLine=function(hqChart,windowIndex,varItem,id,lineType)
{
var line=new ChartSingleLine();
line.Canvas=hqChart.Canvas;
line.DrawType=1;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
line.Identify=this.Guid;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
if (varItem.IsDotLine) line.IsDotLine=true; //虚线
if (varItem.IsShow==false) line.IsShow=false;
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Data;
this.ReloadChartResource(hqChart,windowIndex,line);
if (varItem.IsShowTitle===false) //NOTEXT 不绘制标题
{
}
else if (IFrameSplitOperator.IsString(varItem.Name) && varItem.Name.indexOf("NOTEXT")==0) //标题中包含NOTEXT不绘制标题
{
}
else
{
if (varItem.NoneName)
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);
else
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
this.SetTitleData(hqChart.TitlePaint[titleIndex].Data[id],line);
}
this.SetChartIndexName(line);
hqChart.ChartPaint.push(line);
}
//创建柱子
this.CreateBar=function(hqChart,windowIndex,varItem,id)
{
let bar=new ChartStickLine();
bar.Canvas=hqChart.Canvas;
if (varItem.Draw.Width>0) bar.Width=varItem.Draw.Width;
else bar.Width=0;
bar.Name=varItem.Name;
bar.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
bar.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) bar.Color=this.GetColor(varItem.Color);
else bar.Color=this.GetDefaultColor(id);
let titleIndex=windowIndex+1;
bar.Data.Data=varItem.Draw.DrawData;
bar.BarType=varItem.Draw.Type;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(bar);
hqChart.ChartPaint.push(bar);
}
//创建文本
this.CreateText=function(hqChart,windowIndex,varItem,id,resource)
{
let chartText=new ChartSingleText();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.ReloadResource();
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawCenter===true) chartText.TextAlign='center';
if (varItem.IsDrawAbove===true) chartText.Direction=1;
if (varItem.IsDrawBelow===true) chartText.Direction=2;
let titleIndex=windowIndex+1;
if (varItem.Draw.Position) chartText.Position=varItem.Draw.Position; //赋值坐标
if (varItem.Draw.DrawData) chartText.Data.Data=varItem.Draw.DrawData;
chartText.Text=varItem.Draw.Text;
if (varItem.Draw.Direction>0) chartText.Direction=varItem.Draw.Direction;
if (varItem.Draw.YOffset>0) chartText.YOffset=varItem.Draw.YOffset;
if (varItem.Draw.TextAlign) chartText.TextAlign=varItem.Draw.TextAlign;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chartText.Direction=1;
else if (varItem.DrawVAlign==1) chartText.Direction=0;
else if (varItem.DrawVAlign==2) chartText.Direction=2;
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chartText.TextAlign="left";
else if (varItem.DrawAlign==1) chartText.TextAlign="center";
else if (varItem.DrawAlign==2) chartText.TextAlign='right';
}
if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
if (varItem.Background) chartText.TextBG=varItem.Background;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chartText);
hqChart.ChartPaint.push(chartText);
}
//DRAWNUMBER
this.CreateDrawNumber=function(hqChart,windowIndex,varItem,id)
{
var chartText=new ChartDrawNumber();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.ReloadResource();
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawCenter===true) chartText.TextAlign='center';
if (varItem.IsDrawAbove===true) chartText.TextBaseline='bottom'
if (varItem.IsDrawBelow===true) chartText.TextBaseline='top';
chartText.Data.Data=varItem.Draw.DrawData.Value;
chartText.Text=varItem.Draw.DrawData.Text;
if (varItem.Draw.Direction>0) chartText.Direction=varItem.Draw.Direction;
if (varItem.Draw.YOffset>0) chartText.YOffset=varItem.Draw.YOffset;
if (varItem.Draw.TextAlign) chartText.TextAlign=varItem.Draw.TextAlign;
//指定输出位置
if (varItem.Draw.FixedPosition==="TOP") chartText.FixedPosition=1;
else if (varItem.Draw.FixedPosition==="BOTTOM") chartText.FixedPosition=2;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chartText.TextBaseline='top';
else if (varItem.DrawVAlign==1) chartText.TextBaseline='middle';
else if (varItem.DrawVAlign==2) chartText.TextBaseline='bottom';
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chartText.TextAlign="left";
else if (varItem.DrawAlign==1) chartText.TextAlign="center";
else if (varItem.DrawAlign==2) chartText.TextAlign='right';
}
if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
if (varItem.Background) chartText.TextBG=varItem.Background;
if (varItem.VerticalLine) chartText.VerticalLine=varItem.VerticalLine;
let titleIndex=windowIndex+1;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
hqChart.ChartPaint.push(chartText);
}
//DRAWTEXT
this.CreateDrawTextV2=function(hqChart,windowIndex,varItem,id)
{
var chartText=new ChartDrawText();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.ReloadResource();
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawCenter===true) chartText.TextAlign='center';
if (varItem.IsDrawAbove===true) chartText.TextBaseline='bottom'
if (varItem.IsDrawBelow===true) chartText.TextBaseline='top';
if (varItem.Draw.DrawData) chartText.Data.Data=varItem.Draw.DrawData;
chartText.Text=varItem.Draw.Text;
if (varItem.Draw.Direction>0) chartText.Direction=varItem.Draw.Direction;
if (varItem.Draw.YOffset>0) chartText.YOffset=varItem.Draw.YOffset;
if (varItem.Draw.TextAlign) chartText.TextAlign=varItem.Draw.TextAlign;
//指定输出位置
if (varItem.Draw.FixedPosition==="TOP") chartText.FixedPosition=1;
else if (varItem.Draw.FixedPosition==="BOTTOM") chartText.FixedPosition=2;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chartText.TextBaseline='top';
else if (varItem.DrawVAlign==1) chartText.TextBaseline='middle';
else if (varItem.DrawVAlign==2) chartText.TextBaseline='bottom';
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chartText.TextAlign="left";
else if (varItem.DrawAlign==1) chartText.TextAlign="center";
else if (varItem.DrawAlign==2) chartText.TextAlign='right';
}
if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
if (varItem.Background) chartText.TextBG=varItem.Background;
if (varItem.VerticalLine) chartText.VerticalLine=varItem.VerticalLine;
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) chartText.ShowOffset.Y=varItem.YOffset;
if (IFrameSplitOperator.IsNumber(varItem.XOffset)) chartText.ShowOffset.X=varItem.XOffset;
let titleIndex=windowIndex+1;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chartText);
hqChart.ChartPaint.push(chartText);
}
//COLORSTICK
this.CreateMACD=function(hqChart,windowIndex,varItem,id)
{
let chartMACD=new ChartMACD();
chartMACD.Canvas=hqChart.Canvas;
chartMACD.Identify=this.Guid;
chartMACD.Name=varItem.Name;
chartMACD.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartMACD.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.LineWidth)
{
var width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chartMACD.LineWidth=width;
}
let titleIndex=windowIndex+1;
chartMACD.Data.Data=varItem.Data;
var clrTitle=this.GetDefaultColor(id);
if (varItem.Color) clrTitle=this.GetColor(varItem.Color);
if (varItem.UpColor) chartMACD.UpColor=varItem.UpColor;
if (varItem.DownColor) chartMACD.DownColor=varItem.DownColor;
this.ReloadChartResource(hqChart,windowIndex,chartMACD);
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chartMACD.Data,varItem.Name,clrTitle);
this.SetChartIndexName(chartMACD);
hqChart.ChartPaint.push(chartMACD);
}
this.CreatePointDot=function(hqChart,windowIndex,varItem,id, hisData)
{
let pointDot=new ChartPointDot();
pointDot.Canvas=hqChart.Canvas;
pointDot.Name=varItem.Name;
pointDot.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
pointDot.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) pointDot.Color=this.GetColor(varItem.Color);
else pointDot.Color=this.GetDefaultColor(id);
if (varItem.Radius) pointDot.Radius=varItem.Radius;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) pointDot.Radius=width;
}
if (IFrameSplitOperator.IsBool(varItem.UpDownDot))
{
pointDot.EnableUpDownColor=varItem.UpDownDot;
pointDot.HistoryData=hisData;
}
let titleIndex=windowIndex+1;
pointDot.Data.Data=varItem.Data;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(pointDot.Data,varItem.Name,pointDot.Color);
this.SetChartIndexName(pointDot);
hqChart.ChartPaint.push(pointDot);
}
this.CreateStick=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
this.ReloadChartResource(hqChart,windowIndex,chart);
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateLineStick=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartLineStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
hqChart.ChartPaint.push(chart);
}
this.CreateStraightLine=function(hqChart,windowIndex,varItem,id)
{
let line=new ChartLine();
line.DrawType=1;
line.Canvas=hqChart.Canvas;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Draw.DrawData;
if (varItem.Name=="DRAWLINE")
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
hqChart.ChartPaint.push(line);
}
this.CreateVolStick=function(hqChart,windowIndex,varItem,id,hisData)
{
let chart=new ChartVolStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.KLineDrawType=hqChart.KLineDrawType; //设置K线显示类型
chart.Identify=this.Guid;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.UpColor) chart.UpColor=varItem.UpColor;
if (varItem.DownColor) chart.DownColor=varItem.DownColor;
if (IFrameSplitOperator.IsNumber(varItem.StickType)) chart.BarType=varItem.StickType;
if (IFrameSplitOperator.IsNumber(varItem.BarColorType)) chart.BarColorType=varItem.BarColorType;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) chart.BarWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
chart.HistoryData=hisData;
this.ReloadChartResource(hqChart,windowIndex,chart);
if (varItem.IsShowTitle===false) //NOTEXT 不绘制标题
{
}
else if (IFrameSplitOperator.IsString(varItem.Name) && varItem.Name.indexOf("NOTEXT")==0) //标题中包含NOTEXT不绘制标题
{
}
else
{
var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
hqChart.TitlePaint[titleIndex].Data[id]=titleData;
this.SetTitleData(titleData,chart);
}
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateBand=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartBand();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.FirstColor = varItem.Draw.Color[0];
chart.SecondColor = varItem.Draw.Color[1];
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsBool(varItem.IsFirstDraw)) chart.IsDrawFirst=varItem.IsFirstDraw;
var titleIndex=windowIndex+1;
var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
titleData.DataType=chart.ClassName;
titleData.ExtendData={ Color:[chart.FirstColor, chart.SecondColor] };
hqChart.TitlePaint[titleIndex].Data[id]=titleData;
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateFillRGN=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartLineArea();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
hqChart.ChartPaint.push(chart);
}
this.CreateFillRGN2=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartFillRGN();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
hqChart.ChartPaint.push(chart);
}
this.CreateFillBGRGN=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartFillBGRGN();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
hqChart.ChartPaint.push(chart);
}
this.CreateFLOATRGN=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartFLOATRGN();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
hqChart.ChartPaint.push(chart);
}
//创建K线图
this.CreateKLine=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartKLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.Identify=this.Guid;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
chart.IsShowMaxMinPrice=false;
chart.IsShowKTooltip=false;
if (IFrameSplitOperator.IsNumber(varItem.KLineType)) chart.DrawType=varItem.KLineType;
if (varItem.Color) //如果设置了颜色,使用外面设置的颜色
chart.UnchagneColor=chart.DownColor=chart.UpColor=this.GetColor(varItem.Color);
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateOverlayKLine=function(hqChart,windowIndex,varItem,id)
{
var chart=null;
if (hqChart.IsKLineContainer()) chart=new ChartOverlayKLine();
else if (hqChart.IsMinuteContainer()) chart=new ChartOverlayMinutePriceLine();
else return;
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.Identify=this.Guid;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color); //如果设置了颜色,使用外面设置的颜色
else chart.Color=this.GetDefaultColor(id);
chart.Data.Data=varItem.Draw.DrawData;
chart.MainData=hqChart.ChartPaint[0].Data;//绑定K线
hqChart.ChartPaint.push(chart);
}
this.CreateDrawColorKLine=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartColorKline();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.DrawName="DRAWCOLORKLINE";
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsBool(varItem.Draw.IsEmptyBar)) chart.IsEmptyBar=varItem.Draw.IsEmptyBar;
if (varItem.Draw.Color) chart.Color=varItem.Draw.Color;
hqChart.ChartPaint.push(chart);
}
this.CreatePolyLine=function(hqChart,windowIndex,varItem,id)
{
let line=new ChartLine();
line.Canvas=hqChart.Canvas;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.IsDotLine) line.IsDotLine=true; //虚线
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Draw.DrawData;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,' ',line.Color); //给一个空的标题
hqChart.ChartPaint.push(line);
}
this.CreateChartSlopeLine=function(hqChart,windowIndex,varItem,id)
{
let line=new ChartSlopeLine();
line.Canvas=hqChart.Canvas;
line.Name=varItem.Name;
line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) line.Color=this.GetColor(varItem.Color);
else line.Color=this.GetDefaultColor(id);
if (varItem.IsDotLine) line.IsDotLine=true; //虚线
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) line.LineWidth=width;
}
let titleIndex=windowIndex+1;
line.Data.Data=varItem.Draw.DrawData.Data;
line.Option=varItem.Draw.DrawData.Option;
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color); //给一个空的标题
hqChart.ChartPaint.push(line);
}
this.CreateChartVericaltLine=function(hqChart,windowIndex,varItem,id)
{
var chart=new ChartVericaltLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
this.SetChartLineDash(chart,varItem.Draw.DrawData);
chart.Data.Data=varItem.Draw.DrawData.Data;
hqChart.ChartPaint.push(chart);
}
this.SetChartLineDash=function(chart, option)
{
if (IFrameSplitOperator.IsNumber(option.LineType))
{
var lineType=option.LineType;
var pixelRatio=GetDevicePixelRatio();
switch(lineType)
{
case 1:
chart.LineType=[10*pixelRatio,10*pixelRatio];
break;
case 2:
chart.LineType=[0,10*pixelRatio];
chart.LineCap="square";
break;
case 3:
chart.LineType=[10*pixelRatio, 3*pixelRatio, 3*pixelRatio, 3*pixelRatio];
break;
case 4:
chart.LineType=[10*pixelRatio, 3*pixelRatio, 3*pixelRatio, 3*pixelRatio,3*pixelRatio,3*pixelRatio];
break;
}
}
else if (IFrameSplitOperator.IsString(option.LineType))
{
var aryString=option.LineType.split(',');
var aryLinType=[];
for(var i=0;i<aryString.length;++i)
{
aryLinType.push(parseInt(aryString[i]));
}
chart.LineType=aryLinType;
}
}
this.CreateChartHorizontalLine=function(hqChart,windowIndex,varItem,id)
{
var chart=new ChartHorizontalLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
this.SetChartLineDash(chart,varItem.Draw.DrawData);
chart.ExtendType=varItem.Draw.DrawData.Extend;
chart.Data.Data=varItem.Draw.DrawData.Data;
hqChart.ChartPaint.push(chart);
}
this.CreateBackgroud=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartBackground();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.Color=drawData.Color;
chart.ColorAngle=drawData.Angle;
if (drawData.Data) chart.Data.Data=drawData.Data;
}
hqChart.ChartPaint.push(chart);
}
this.CreateBackgroundDiv=function(hqChart,windowIndex,varItem,id)
{
var chart=new ChartBackgroundDiv();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.AryColor=drawData.AryColor;
chart.ColorType=drawData.ColorType;
if (drawData.Data) chart.Data.Data=drawData.Data;
}
hqChart.ChartPaint.push(chart);
}
this.CreateLineMultiData=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartLineMultiData();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.Color=drawData.Color;
if (drawData.PointColor) chart.PointColor=drawData.PointColor;
if (IFrameSplitOperator.IsPlusNumber(drawData.PointRadius)) chart.PointRadius=drawData.PointRadius;
if (IFrameSplitOperator.IsPlusNumber(drawData.LineWidth)) chart.LineWidth=drawData.LineWidth;
if (drawData.Data) chart.Data.Data=drawData.Data;
}
let titleIndex=windowIndex+1;
var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); //标题
titleData.DataType="MULTI_POINT_LINE";
hqChart.TitlePaint[titleIndex].Data[id]=titleData;
hqChart.ChartPaint.push(chart);
}
this.CreateTradeIcon=function(hqChart,windowIndex,varItem,id)
{
var chart=new ChartTradeIcon();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data.Data=varItem.Draw.DrawData.Data;
chart.AryIcon=varItem.Draw.DrawData.Icons;
chart.TradeType=varItem.Draw.DrawType;
//修改颜色
if (varItem.Color && IFrameSplitOperator.IsNonEmptyArray(chart.AryIcon))
{
for(var i=0;i<chart.AryIcon.length;++i)
{
var item=chart.AryIcon[i];
if (!item || !item.Color) continue;
item.Color=varItem.Color;
}
}
//图片大小
if (varItem.DrawFontSize>0) chart.SVG.Size=varItem.DrawFontSize*GetDevicePixelRatio(); //图标大小
hqChart.ChartPaint.push(chart);
}
this.CreateTextLine=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartTextLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.Text=drawData.Text;
chart.Line=drawData.Line;
chart.Price=drawData.Price;
}
hqChart.ChartPaint.push(chart);
}
this.CreateNumberText=function(hqChart,windowIndex,varItem,id)
{
let chartText=new ChartSingleText();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.ReloadResource();
chartText.TextAlign="center";
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawAbove) chartText.Direction=1;
else chartText.Direction=2;
if (varItem.Draw.Position) chartText.Position=varItem.Draw.Position; //赋值坐标
let titleIndex=windowIndex+1;
chartText.Data.Data=varItem.Draw.DrawData.Value;
chartText.Text=varItem.Draw.DrawData.Text;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chartText);
hqChart.ChartPaint.push(chartText);
}
this.CreateDrawText=function(hqChart,windowIndex,varItem,id)
{
let chartText=new ChartSingleText();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.ReloadResource();
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawAbove) chartText.Direction=1;
else chartText.Direction=0;
if (varItem.DrawFontSize>0) chartText.TextFont=`${varItem.DrawFontSize*GetDevicePixelRatio()}px 微软雅黑`; //临时用下吧
let titleIndex=windowIndex+1;
chartText.DrawData=varItem.Draw.DrawData;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chartText);
hqChart.ChartPaint.push(chartText);
}
//创建图标
this.CreateIcon=function(hqChart,windowIndex,varItem,id)
{
let chartText=new ChartSingleText();
chartText.Canvas=hqChart.Canvas;
chartText.TextAlign='center';
chartText.Name=varItem.Name;
chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chartText.Direction=2;
if (varItem.IsDrawAbove) chartText.Direction=1;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chartText.Direction=1;
else if (varItem.DrawVAlign==1) chartText.Direction=0;
else if (varItem.DrawVAlign==2) chartText.Direction=2;
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chartText.TextAlign="left";
else if (varItem.DrawAlign==1) chartText.TextAlign="center";
else if (varItem.DrawAlign==2) chartText.TextAlign='right';
}
let titleIndex=windowIndex+1;
chartText.Data.Data=varItem.Draw.DrawData;
var icon=varItem.Draw.Icon;
if (icon.IconFont==true)
{
chartText.IconFont={ Family:icon.Family, Text:icon.Symbol, Color:icon.Color };
if (varItem.Color) chartText.IconFont.Color=this.GetColor(varItem.Color);
}
else
{
chartText.Text=icon.Symbol;
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else if (icon.Color) chartText.Color=icon.Color;
else chartText.Color='rgb(0,0,0)';
}
if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
if (IFrameSplitOperator.IsNumber(varItem.XOffset)) chartText.ShowOffset.X=varItem.XOffset;
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) chartText.ShowOffset.Y=varItem.YOffset;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chartText);
hqChart.ChartPaint.push(chartText);
}
this.CreateTipIcon=function(hqChart,windowIndex,varItem,i)
{
var chart=new ChartDrawSVG();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (hqChart.ChartPaint[0].IsMinuteFrame())
chart.Data=hqChart.SourceData;
else
chart.Data=hqChart.ChartPaint[0].Data; //绑定K线
chart.Family=varItem.Draw.Icon.Family;
chart.TextFont=g_JSChartResource.TIPICON.TextFont;
var svgSize=g_JSChartResource.TIPICON.Size;
var svgColor=g_JSChartResource.TIPICON.Color;
var svgYOffset=0;
var svgVAlign=2; //上下对齐方式
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) svgYOffset=varItem.YOffset;
if (varItem.Color) svgColor=this.GetColor(varItem.Color);
if (varItem.DrawFontSize>0) svgSize=varItem.DrawFontSize;
if (varItem.DrawVAlign>=0) svgVAlign=varItem.DrawVAlign;
if (varItem.Draw && IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.DrawData) && varItem.Draw.Icon)
{
var drawData=varItem.Draw.DrawData;
var aryData=[];
var isArrayTip=Array.isArray(varItem.Draw.Text);
var singleTip=null;
if (!isArrayTip && varItem.Draw.Text) singleTip={ Text:varItem.Draw.Text };
for(var j=0;j<drawData.length;++j)
{
var item=drawData[j];
if (!IFrameSplitOperator.IsNumber(item)) continue;
var svgItem=
{
Index:j, Value:item,
SVG:{ Symbol:varItem.Draw.Icon.Symbol, Size:svgSize, Color:svgColor, YOffset:svgYOffset, VAlign:svgVAlign }
};
if (isArrayTip)
{
var text=varItem.Draw.Text[j];
if (text) svgItem.Tooltip={ Text:text };
}
else
{
svgItem.Tooltip=singleTip;
}
aryData.push(svgItem);
}
chart.Texts= aryData;
}
hqChart.ChartPaint.push(chart);
}
//创建通道
this.CreateChannel=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartChannel();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if(varItem.Draw.AreaColor) chart.AreaColor=varItem.Draw.AreaColor;
else if (varItem.Color) chart.AreaColor=this.GetColor(varItem.Color);
else chart.AreaColor=this.GetDefaultColor(id);
if (varItem.Draw.Border.Color) chart.LineColor=varItem.Draw.Border.Color;
else chart.LineColor=null;
if (varItem.Draw.Border.Dotted) chart.LineDotted=varItem.Draw.Border.Dotted;
if (varItem.Draw.Border.Width>0) chart.LineWidth=varItem.Draw.Border.Width;
//let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData;
hqChart.ChartPaint.push(chart);
}
this.CreatePartLine=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartPartLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) chart.LineWidth=width;
}
chart.Data.Data=varItem.Draw.DrawData;
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateMultiLine=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartMultiLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Lines=varItem.Draw.DrawData;
if (varItem.Draw.Name) chart.Name=varItem.Draw.Name;
if (varItem.Draw.LineDash) chart.LineDash=varItem.Draw.LineDash;
if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
if (IFrameSplitOperator.IsBool(varItem.Draw.IsFullRangeMaxMin)) chart.IsFullRangeMaxMin=varItem.Draw.IsFullRangeMaxMin;
if(varItem.Draw.Arrow) //箭头配置
{
var item=varItem.Draw.Arrow;
if (item.Start==true) chart.Arrow.Start=true;
if (item.End==true) chart.Arrow.End=true;
if (IFrameSplitOperator.IsNumber(item.Angle)) chart.ArrawAngle=item.Angle;
if (IFrameSplitOperator.IsNumber(item.Length)) chart.ArrawLength=item.Length;
if (IFrameSplitOperator.IsNumber(item.LineWidth)) chart.ArrawLineWidth=item.LineWidth;
}
this.ReloadChartResource(hqChart, windowIndex, chart);
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
var titleIndex=windowIndex+1;
if (varItem.IsShowTitle===false)
{
}
else
{
var titleData=new DynamicTitleData(chart.Data,chart.Name, null);
titleData.DataType="ChartMultiLine";
titleData.Lines=chart.Lines;
hqChart.TitlePaint[titleIndex].Data[i]=titleData;
}
}
this.CreateMultiPoint=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartMultiPoint();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.PointGroup=varItem.Draw.DrawData;
if (varItem.Draw.Name) chart.Name=varItem.Draw.Name;
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
var titleIndex=windowIndex+1;
var titleData=new DynamicTitleData(chart.Data,chart.Name, null);
titleData.DataType="ChartMultiPoint";
titleData.PointGroup=chart.PointGroup;
hqChart.TitlePaint[titleIndex].Data[i]=titleData;
}
this.CreateMultiBar=function(hqChart,windowIndex,varItem,id)
{
let chart=new ChartMultiBar();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Bars=varItem.Draw.DrawData;
var titleIndex=windowIndex+1;
var titleData=new DynamicTitleData({ KData:chart.Data, BarData:chart.Bars },varItem.Name,null);
titleData.IsShow=false;
titleData.DataType="MULTI_BAR";
hqChart.TitlePaint[titleIndex].Data[id]=titleData;
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateMultiText=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartMultiText();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Texts=varItem.Draw.DrawData;
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateMultiSVGIcon=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartMultiSVGIconV2();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Family=varItem.Draw.DrawData.Family;
chart.AryIcon= varItem.Draw.DrawData.Icon;
chart.BuildCacheData();
this.SetChartIndexName(chart);
hqChart.ChartPaint.push(chart);
}
this.CreateChartDrawSVG=function(hqChart,windowIndex,varItem,i)
{
var chart=new ChartDrawSVG();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (hqChart.ChartPaint[0].IsMinuteFrame())
chart.Data=hqChart.SourceData;
else
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
if (IFrameSplitOperator.IsBool(varItem.Draw.DrawData.EnableTooltip)) chart.EnableTooltip=varItem.Draw.DrawData.EnableTooltip;
if (IFrameSplitOperator.IsBool(varItem.Draw.DrawData.IsDrawFirst)) chart.IsDrawFirst=varItem.Draw.DrawData.IsDrawFirst;
chart.Family=varItem.Draw.DrawData.Family;
chart.TextFont=varItem.Draw.DrawData.TextFont;
chart.Texts= varItem.Draw.DrawData.Data;
hqChart.ChartPaint.push(chart);
}
this.CreateMulitHtmlDom=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartMultiHtmlDom();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.HQChart=hqChart;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Texts=varItem.Draw.DrawData;
chart.DrawCallback= varItem.Draw.Callback;
hqChart.ChartPaint.push(chart);
}
this.CreateStackedBar=function(hqChart,windowIndex,varItem,i)
{
var chart=new ChartStackedBar();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.HQChart=hqChart;
chart.Identify=this.Guid;
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.BarColor)) chart.BarColor=varItem.Draw.BarColor;
if (IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.BarName)) chart.BarName=varItem.Draw.BarName;
if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
if (IFrameSplitOperator.IsNumber(varItem.Draw.BarType)) chart.BarType=varItem.Draw.BarType;
hqChart.ChartPaint.push(chart);
var titleIndex=windowIndex+1;
var titleData=new DynamicTitleData(chart.Data,chart.BarName,chart.BarColor);
titleData.DataType="ChartStackedBar";
hqChart.TitlePaint[titleIndex].Data[i]=titleData;
}
this.CreateKLineTable=function(hqChart,windowIndex,varItem,i)
{
var chart=new ChartKLineTable();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.HQChart=hqChart;
chart.Identify=this.Guid;
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsNumber(varItem.Draw.RowCount)) chart.RowCount=varItem.Draw.RowCount;
if (IFrameSplitOperator.IsBool(varItem.Draw.IsShowRowName)) chart.IsShowRowName=varItem.Draw.IsShowRowName;
if (IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.RowName)) chart.RowName=varItem.Draw.RowName;
if (varItem.Draw.BGColor) chart.BGColor=varItem.Draw.BGColor;
hqChart.ChartPaint.push(chart);
var titleIndex=windowIndex+1;
var titleData=new DynamicTitleData(chart.Data,chart.BarName,chart.BarColor);
titleData.DataType="ChartKLineTable";
hqChart.TitlePaint[titleIndex].Data[i]=titleData;
}
this.CreateScatterPlot=function(hqChart,windowIndex,varItem,i)
{
var chart=new ChartScatterPlot();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.HQChart=hqChart;
chart.Identify=this.Guid;
chart.Data.Data=varItem.Draw.DrawData;
chart.Color=varItem.Draw.Color;
chart.Radius=varItem.Draw.Radius;
hqChart.ChartPaint.push(chart);
}
this.CreateClipColorStick=function(hqChart,windowIndex,varItem,id)
{
var chart=new ChartClipColorStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.HQChart=hqChart;
chart.Identify=this.Guid;
chart.Data.Data=varItem.Draw.DrawData;
if (varItem.Option && chart.SetOption) chart.SetOption(varItem.Option);
hqChart.ChartPaint.push(chart);
var titleIndex=windowIndex+1;
if (varItem.IsShowTitle===false)
{
}
else
{
var clrTitle=this.GetDefaultColor(id);
if (varItem.Option && varItem.Option.TitleColor) clrTitle=this.GetColor(varItem.Option.TitleColor);
hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,clrTitle);
}
}
this.CreateColorKLine=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartColorKline();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.KLineColor= varItem.Draw.DrawData.KLine;
if (varItem.Color) chart.Color=varItem.Color;
hqChart.ChartPaint.push(chart);
}
this.CreateRectangle=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartRectangle();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Color=[varItem.Draw.DrawData.Color];
chart.Rect=varItem.Draw.DrawData.Rect;
if (varItem.Color) chart.BorderColor=this.GetColor(varItem.Color);
hqChart.ChartPaint.push(chart);
}
this.CreateScriptOverlayLine=function(hqChart,windowIndex,varItem,i)
{
let chart=new ChartOverlayLine();
chart.Canvas=hqChart.Canvas;
chart.DrawType=1;
chart.Name=varItem.Name;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(i);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
if (varItem.IsDotLine) chart.IsDotLine=true; //虚线
if (varItem.IsShow==false) chart.IsShow=false;
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData.Data;
chart.MainData.Data=varItem.Draw.DrawData.MainData;
if (varItem.Draw.DrawData.Title)
hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(chart.Data,varItem.Draw.DrawData.Title,chart.Color);
hqChart.ChartPaint.push(chart);
}
//创建K线
this.CreateSelfKLine=function(hqChart,windowIndex,hisData)
{
let chart=new ChartKLine();
chart.Canvas=hqChart.Canvas;
chart.Name="Self Kline";
chart.Identify=this.Guid;
chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
chart.Data=hisData
chart.IsShowMaxMinPrice=false;
chart.IsShowKTooltip=false;
chart.DrawType=this.KLineType;
hqChart.ChartPaint.push(chart);
}
this.BindInstructionData=function(hqChart,windowIndex,hisData) //绑定指示指标
{
if (this.OutVar==null || this.OutVar.length<0) return;
//参数
var indexParam='';
for(let i in this.Arguments)
{
let item=this.Arguments[i];
if (indexParam.length>0) indexParam+=',';
indexParam+=item.Value.toString();
}
if (indexParam.length>0) indexParam='('+indexParam+')';
if (this.InstructionType==2) //五彩K线
{
let varItem=this.OutVar[this.OutVar.length-1]; //取最后一组数据作为指示数据
hqChart.SetInstructionData(this.InstructionType, {Data:varItem.Data, Name:this.Name, Param:indexParam, ID:this.ID }); //设置指示数据
return true;
}
else if (this.InstructionType==1) //交易系统
{
var buyData, sellData;
for(var i in this.OutVar)
{
let item=this.OutVar[i];
if (item.Name=='ENTERLONG') buyData=item.Data;
else if (item.Name=='EXITLONG') sellData=item.Data;
}
hqChart.SetInstructionData(this.InstructionType, {Buy:buyData, Sell:sellData, Name:this.Name, Param:indexParam, ID:this.ID}); //设置指示数据
return true;
}
}
this.BindData=function(hqChart,windowIndex,hisData)
{
if (windowIndex==0 && this.InstructionType)
{
this.BindInstructionData(hqChart,windowIndex,hisData);
return;
}
//清空主指标图形
hqChart.DeleteIndexPaint(windowIndex);
if (windowIndex==0) hqChart.ShowKLine(true);
if (this.OutVar==null || this.OutVar.length<0) return;
//叠加一个K线背景
if (this.KLineType!=null)
{
if (this.KLineType===0 || this.KLineType===1 || this.KLineType===2) this.CreateSelfKLine(hqChart,windowIndex,hisData);
else if (this.KLineType===-1 && windowIndex==0) hqChart.ShowKLine(false);
}
if (windowIndex>=1 && hqChart.Frame)
{
//Y轴刻度格式 默认跟标题栏一致
var ySpliter=hqChart.Frame.SubFrame[windowIndex].Frame.YSplitOperator;
if (ySpliter)
{
ySpliter.Reset();
ySpliter.FloatPrecision=this.FloatPrecision;
if (this.YAxis) ySpliter.SetOption(this.YAxis);
}
if (this.YSpecificMaxMin) hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=this.YSpecificMaxMin; //最大最小值
if (this.YSplitScale) hqChart.Frame.SubFrame[windowIndex].Frame.YSplitScale=this.YSplitScale; //固定刻度
}
if (IFrameSplitOperator.IsNumber(this.YSplitType)) hqChart.Frame.SubFrame[windowIndex].Frame.YSplitOperator.SplitType=this.YSplitType;
/*
if (this.Name=='MA') //测试多线段
{
var point1={Point:[{Index:300, Value:15.5}, {Index:301, Value:14.2} , {Index:304, Value:14.05}], Color:'rgb(244,55,50)'};
var point2={Point:[{Index:307, Value:14.5}, {Index:308, Value:14.2} , {Index:309, Value:14.15}], Color:'rgb(0,55,50)'};
var testData={ Name:'MULTI_LINE', Type:1,Draw:{ DrawType:'MULTI_LINE', DrawData:[point1,point2] } };
this.OutVar.push(testData);
}
*/
for(let i=0; i<this.OutVar.length; ++i)
{
let item=this.OutVar[i];
if (item.IsExData===true) continue; //扩展数据不显示图形
if (item.Type==1000 || item.Type==1001) continue; //数据集合, 字符串
if (item.Type==0)
{
if (item.IsOverlayLine) this.CreateOverlayLine(hqChart,windowIndex,item,i,item.Type);
else if (item.IsSingleLine) this.CreateSingleLine(hqChart,windowIndex,item,i,item.Type);
else this.CreateLine(hqChart,windowIndex,item,i,item.Type);
}
else if (item.Type==1)
{
switch(item.Draw.DrawType)
{
case 'STICKLINE':
this.CreateBar(hqChart,windowIndex,item,i);
break;
case 'DRAWTEXT':
this.CreateDrawTextV2(hqChart,windowIndex,item,i);
break;
case 'SUPERDRAWTEXT':
this.CreateText(hqChart,windowIndex,item,i);
break;
case 'DRAWLINE':
this.CreateStraightLine(hqChart,windowIndex,item,i);
break;
case 'DRAWBAND':
this.CreateBand(hqChart,windowIndex,item,i);
break;
case "FILLRGN":
this.CreateFillRGN(hqChart,windowIndex,item,i);
break;
case "FILLRGN2":
this.CreateFillRGN2(hqChart,windowIndex,item,i);
break;
case "FILLTOPRGN":
case "FILLBOTTOMRGN":
case "FILLVERTICALRGN":
this.CreateFillBGRGN(hqChart,windowIndex,item,i);
break;
case "FLOATRGN":
this.CreateFLOATRGN(hqChart,windowIndex,item,i);
break;
case 'DRAWKLINE':
case "DRAWKLINE1":
this.CreateKLine(hqChart,windowIndex,item,i);
break;
case "DRAWOVERLAYKLINE":
this.CreateOverlayKLine(hqChart,windowIndex,item,i);
break;
case "DRAWCOLORKLINE":
this.CreateDrawColorKLine(hqChart,windowIndex,item,i);
break;
case 'DRAWKLINE_IF':
this.CreateKLine(hqChart,windowIndex,item,i);
break;
case 'POLYLINE':
this.CreatePolyLine(hqChart,windowIndex,item,i);
break;
case 'DRAWGBK':
case "DRAWGBK2":
this.CreateBackgroud(hqChart,windowIndex,item,i);
break;
case "DRAWGBK_DIV":
this.CreateBackgroundDiv(hqChart,windowIndex,item,i);
break;
case 'DRAWTEXT_LINE':
this.CreateTextLine(hqChart,windowIndex,item,i);
break;
case 'DRAWNUMBER':
this.CreateDrawNumber(hqChart,windowIndex,item,i);
break;
case "DRAWNUMBER_FIX":
case 'DRAWTEXT_FIX':
this.CreateNumberText(hqChart,windowIndex,item,i);
break;
case 'DRAWICON':
this.CreateIcon(hqChart,windowIndex,item,i);
break;
case "ICON":
this.CreateIcon(hqChart,windowIndex,item,i);
break;
case "TIPICON":
this.CreateTipIcon(hqChart,windowIndex,item,i);
break;
case 'DRAWCHANNEL':
this.CreateChannel(hqChart,windowIndex,item,i);
break;
case 'PARTLINE':
this.CreatePartLine(hqChart,windowIndex,item,i);
break;
case 'DRAWRECTREL':
this.CreateRectangle(hqChart,windowIndex,item,i);
break;
case "DRAWTEXTABS":
case "DRAWTEXTREL":
this.CreateDrawText(hqChart,windowIndex,item,i);
break;
case "DRAWOVERLAYLINE":
this.CreateScriptOverlayLine(hqChart,windowIndex,item,i);
break;
case "DRAWSL":
this.CreateChartSlopeLine(hqChart,windowIndex,item,i);
break;
case "VERTLINE":
this.CreateChartVericaltLine(hqChart,windowIndex,item,i);
break;
case "HORLINE":
this.CreateChartHorizontalLine(hqChart,windowIndex,item,i);
break;
case 'MULTI_LINE':
this.CreateMultiLine(hqChart,windowIndex,item,i);
break;
case "MULTI_POINT":
this.CreateMultiPoint(hqChart,windowIndex,item,i);
break;
case 'MULTI_BAR':
this.CreateMultiBar(hqChart,windowIndex,item,i);
break;
case 'MULTI_TEXT':
this.CreateMultiText(hqChart,windowIndex,item,i);
break;
case 'MULTI_SVGICON':
this.CreateMultiSVGIcon(hqChart,windowIndex,item,i);
break;
case "DRAWSVG":
this.CreateChartDrawSVG(hqChart,windowIndex,item,i);
break;
case "MULTI_HTMLDOM":
this.CreateMulitHtmlDom(hqChart,windowIndex,item,i);
break;
case "COLOR_KLINE":
this.CreateColorKLine(hqChart,windowIndex,item,i);
break;
case "KLINE_BG":
this.CreateBackgroud(hqChart,windowIndex,item,i);
break;
case "MULTI_POINT_LINE":
this.CreateLineMultiData(hqChart,windowIndex,item,i);
break;
case "BUY":
case "SELL":
case "SELLSHORT":
case "BUYSHORT":
this.CreateTradeIcon(hqChart,windowIndex,item,i);
break;
case SCRIPT_CHART_NAME.OVERLAY_BARS:
this.CreateStackedBar(hqChart,windowIndex,item,i);
break;
case SCRIPT_CHART_NAME.KLINE_TABLE:
this.CreateKLineTable(hqChart,windowIndex,item,i);
break;
case SCRIPT_CHART_NAME.SCATTER_PLOT:
this.CreateScatterPlot(hqChart,windowIndex,item,i);
break;
case SCRIPT_CHART_NAME.CLIP_COLOR_STICK:
this.CreateClipColorStick(hqChart,windowIndex,item,i);
break;
default:
{
var find=g_ScriptIndexChartFactory.Get(item.Draw.DrawType); //外部挂接
if (find && find.CreateChartCallback)
find.CreateChartCallback(hqChart,windowIndex,item,i, this);
}
break;
}
}
else if (item.Type==2)
{
this.CreateMACD(hqChart,windowIndex,item,i);
}
else if (item.Type==3)
{
this.CreatePointDot(hqChart,windowIndex,item,i, hisData);
}
else if (item.Type==4)
{
this.CreateLineStick(hqChart,windowIndex,item,i);
}
else if (item.Type==5)
{
this.CreateStick(hqChart,windowIndex,item,i);
}
else if (item.Type==6)
{
this.CreateVolStick(hqChart,windowIndex,item,i,hisData);
}
else if (item.Type==7)
{
this.CreateLine(hqChart,windowIndex,item,i, item.Type);
}
else if (item.Type==8)
{
this.CreateLine(hqChart,windowIndex,item,i, item.Type);
}
else if (item.Type==9)
{
this.CreateArea(hqChart,windowIndex,item,i);
}
var titlePaint=hqChart.TitlePaint[windowIndex+1];
if (titlePaint && titlePaint.Data && i<titlePaint.Data.length) //设置标题数值 小数位数和格式
{
if (this.StringFormat>0) titlePaint.Data[i].StringFormat=this.StringFormat;
if (this.FloatPrecision>=0) titlePaint.Data[i].FloatPrecision=this.FloatPrecision;
if (this.OutName && this.OutName.length>0 && this.Arguments && this.Arguments.length>0)
{
titlePaint.SetDynamicTitle(this.OutName,this.Arguments);
}
}
}
let titleIndex=windowIndex+1;
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.Title=this.Name;
titlePaint.Identify=this.Guid; //指标ID
titlePaint.ArgumentsText=null;
titlePaint.Script=this;
titlePaint.IsShowMainIndexTitle=this.IsShowIndexTitle;
if (!this.IsShortTitle)
{
let indexParam='';
for(let i=0; i<this.Arguments.length; ++i)
{
let item=this.Arguments[i];
if (indexParam.length>0) indexParam+=',';
indexParam+=item.Value.toString();
}
if (indexParam.length>0) titlePaint.ArgumentsText=`(${indexParam})`;
}
if (this.TitleFont) titlePaint.Font=this.TitleFont;
return true;
}
//给一个默认的颜色
this.GetDefaultColor=function(id)
{
let COLOR_ARRAY=null;
//使用全局线段配置
if (g_JSChartResource && g_JSChartResource.Index && g_JSChartResource.Index.LineColor)
{
COLOR_ARRAY=g_JSChartResource.Index.LineColor;
}
if (!COLOR_ARRAY || !Array.isArray(COLOR_ARRAY))
{
COLOR_ARRAY=
[
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
];
}
let number=parseInt(id);
return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)];
}
//获取颜色
this.GetColor=function(colorName)
{
if (colorName.indexOf("RGB(")==0) return colorName.toLowerCase();
if (colorName.indexOf("rgb(")==0) return colorName;
if (colorName.indexOf("RGBA(")==0) return colorName.toLowerCase();
if (colorName.indexOf("rgba(")==0) return colorName;
var color=JSComplier.ColorVarToRGB(colorName);
if (color) return color;
return 'rgb(30,144,255)';
/*
let COLOR_MAP=new Map([
['COLORBLACK','rgb(0,0,0)'],
['COLORBLUE','rgb(18,95,216)'],
['COLORGREEN','rgb(25,158,0)'],
['COLORCYAN','rgb(0,255,198)'],
['COLORRED','rgb(238,21,21)'],
['COLORMAGENTA','rgb(255,0,222)'],
['COLORBROWN','rgb(149,94,15)'],
['COLORLIGRAY','rgb(218,218,218)'], //画淡灰色
['COLORGRAY','rgb(133,133,133)'], //画深灰色
['COLORLIBLUE','rgb(94,204,255)'], //淡蓝色
['COLORLIGREEN','rgb(183,255,190)'], //淡绿色
['COLORLICYAN','rgb(154,255,242)'], //淡青色
['COLORLIRED','rgb(255,172,172)'], //淡红色
['COLORLIMAGENTA','rgb(255,145,241)'], //淡洋红色
['COLORWHITE','rgb(255,255,255)'], //白色
['COLORYELLOW','rgb(255,198,0)']
]);
if (COLOR_MAP.has(colorName)) return COLOR_MAP.get(colorName);
//COLOR 自定义色
//格式为COLOR+“RRGGBB”:RR、GG、BB表示红色、绿色和蓝色的分量,每种颜色的取值范围是00-FF,采用了16进制。
//例如:MA5:MA(CLOSE,5),COLOR00FFFF 表示纯红色与纯绿色的混合色:COLOR808000表示淡蓝色和淡绿色的混合色。
if (colorName.indexOf('COLOR')==0) return '#'+colorName.substr(5);
return 'rgb(30,144,255)';
*/
}
}
function OverlayScriptIndex(name,script,args,option)
{
this.newMethod=ScriptIndex; //派生
this.newMethod(name,script,args,option);
delete this.newMethod;
this.ClassName="OverlayScriptIndex";
//叠加指标
this.OverlayIndex=null; // { IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }
//显示指标不符合条件
this.ShowConditionError=function(param,msg)
{
var hqChart=param.HQChart;
var windowIndex=param.WindowIndex;
var message='指标不支持当前品种或周期';
if (msg) message=msg;
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
frame.ChartPaint=[];
var chart=new ChartLine();
chart.Canvas=hqChart.Canvas;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.NotSupportMessage=message;
frame.ChartPaint.push(chart);
hqChart.Draw();
}
this.BindData=function(hqChart,windowIndex,hisData)
{
if (!this.OverlayIndex || this.OverlayIndex.IsOverlay!=true) return;
this.OverlayIndex.Frame.ChartPaint=[];
if (!IFrameSplitOperator.IsNonEmptyArray(this.OutVar)) return;
//修改Y轴分割方式
var ySpliter=this.OverlayIndex.Frame.Frame.YSplitOperator;
if (ySpliter)
{
ySpliter.Reset();
ySpliter.FloatPrecision=this.FloatPrecision;
if (IFrameSplitOperator.IsNumber(this.YSplitType)) ySpliter.SplitType=this.YSplitType;
if (this.YAxis) ySpliter.SetOption(this.YAxis);
}
//指标名字
var titleInfo={ Data:[], Title:this.Name, Frame:this.OverlayIndex.Frame.Frame, Script:this, IsShowIndexTitle:this.IsShowIndexTitle };
let indexParam='';
for(var i in this.Arguments)
{
let item=this.Arguments[i];
if (indexParam.length>0) indexParam+=',';
indexParam+=item.Value.toString();
}
if (indexParam.length>0) titleInfo.Title=this.Name+'('+indexParam+')';
var titleIndex=windowIndex+1;
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo);
if (this.OutName && this.OutName.length>0 && this.Arguments && this.Arguments.length>0)
{
titlePaint.SetDynamicTitle(this.OutName,this.Arguments, this.OverlayIndex.Identify);
}
this.OverlayIndex.Frame.Frame.Title=this.Name; //给子框架设置标题
if (hqChart.Frame.SubFrame[windowIndex])
{
var mainFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
if (mainFrame) this.OverlayIndex.Frame.Frame.XPointCount=mainFrame.XPointCount; //跟主窗口同步下页面显示数据个数
}
for(var i=0; i<this.OutVar.length; ++i)
{
let item=this.OutVar[i];
if (item.IsExData===true) continue; //扩展数据不显示图形
if (item.Type==0)
{
this.CreateLine(hqChart,windowIndex,item,i,item.Type);
}
else if (item.Type==1)
{
switch(item.Draw.DrawType)
{
case 'STICKLINE':
this.CreateBar(hqChart,windowIndex,item,i);
break;
case 'DRAWTEXT':
this.CreateDrawTextV2(hqChart,windowIndex,item,i);
break;
case 'SUPERDRAWTEXT':
this.CreateText(hqChart,windowIndex,item,i);
break;
case 'DRAWLINE':
this.CreateStraightLine(hqChart,windowIndex,item,i);
break;
case 'DRAWBAND':
this.CreateBand(hqChart,windowIndex,item,i);
break;
case 'DRAWKLINE':
this.CreateKLine(hqChart,windowIndex,item,i);
break;
case 'DRAWKLINE_IF':
this.CreateKLine(hqChart,windowIndex,item,i);
break;
case 'POLYLINE':
this.CreatePolyLine(hqChart,windowIndex,item,i);
break;
case 'DRAWGBK':
case "DRAWGBK2":
this.CreateBackgroud(hqChart,windowIndex,item,i);
break;
case 'DRAWNUMBER':
case "DRAWNUMBER_FIX":
case 'DRAWTEXT_FIX':
this.CreateNumberText(hqChart,windowIndex,item,i);
break;
case 'DRAWICON':
this.CreateIcon(hqChart,windowIndex,item,i);
break;
case "TIPICON":
this.CreateTipIcon(hqChart,windowIndex,item,i);
break;
case 'DRAWCHANNEL':
this.CreateChannel(hqChart,windowIndex,item,i);
break;
case 'DRAWTEXT_LINE':
this.CreateTextLine(hqChart,windowIndex,item,i);
break;
case "VERTLINE":
this.CreateChartVericaltLine(hqChart,windowIndex,item,i);
break;
case "HORLINE":
this.CreateChartHorizontalLine(hqChart,windowIndex,item,i);
break;
case 'MULTI_LINE':
this.CreateMultiLine(hqChart,windowIndex,item,i);
break;
case "MULTI_POINT":
this.CreateMultiPoint(hqChart,windowIndex,item,i);
break;
case 'MULTI_BAR':
this.CreateMultiBar(hqChart,windowIndex,item,i);
break;
case 'MULTI_TEXT':
this.CreateMultiText(hqChart,windowIndex,item,i);
break;
case 'MULTI_SVGICON':
this.CreateMultiSVGIcon(hqChart,windowIndex,item,i);
break;
case "DRAWSVG":
this.CreateChartDrawSVG(hqChart,windowIndex,item,i);
break;
case "MULTI_HTMLDOM":
this.CreateMulitHtmlDom(hqChart,windowIndex,item,i);
break;
case "KLINE_BG":
this.CreateBackgroud(hqChart,windowIndex,item,i);
break;
case 'PARTLINE':
this.CreatePartLine(hqChart,windowIndex,item,i);
break;
case "DRAWTEXTABS":
case "DRAWTEXTREL":
this.CreateDrawText(hqChart,windowIndex,item,i);
break;
case SCRIPT_CHART_NAME.OVERLAY_BARS:
this.CreateStackedBar(hqChart,windowIndex,item,i);
break;
case "DRAWCOLORKLINE":
this.CreateDrawColorKLine(hqChart,windowIndex,item,i);
break;
default:
{
var find=g_ScriptIndexChartFactory.Get(item.Draw.DrawType); //外部挂接
if (find && find.CreateChartCallback)
find.CreateChartCallback(hqChart,windowIndex,item,i, this);
}
break;
}
}
else if (item.Type==2)
{
this.CreateMACD(hqChart,windowIndex,item,i);
}
else if (item.Type==3)
{
this.CreatePointDot(hqChart,windowIndex,item,i, hisData);
}
else if (item.Type==4)
{
this.CreateLineStick(hqChart,windowIndex,item,i);
}
else if (item.Type==5)
{
this.CreateStick(hqChart,windowIndex,item,i);
}
else if (item.Type==6)
{
this.CreateVolStick(hqChart,windowIndex,item,i,hisData);
}
else if (item.Type==7)
{
this.CreateLine(hqChart,windowIndex,item,i,item.Type);
}
else if (item.Type==8)
{
this.CreateLine(hqChart,windowIndex,item,i, item.Type);
}
var titleData=titleInfo.Data[i];
if (titleData)
{
if (this.FloatPrecision>=0) titleData.FloatPrecision=this.FloatPrecision;
if (IFrameSplitOperator.IsNumber(this.StringFormat)) titleData.StringFormat=this.StringFormat;
}
}
/*
hqChart.TitlePaint[titleIndex].Title=this.Name;
let indexParam='';
for(let i in this.Arguments)
{
let item=this.Arguments[i];
if (indexParam.length>0) indexParam+=',';
indexParam+=item.Value.toString();
}
if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')';
*/
return true;
}
//指标执行完成
this.RecvResultData=function(outVar,param)
{
let hqChart=param.HQChart;
let windowIndex=param.WindowIndex;
let hisData=param.HistoryData;
param.Self.OutVar=outVar;
param.Self.BindData(hqChart,windowIndex,hisData);
param.HQChart.UpdataDataoffset(); //更新数据偏移
param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
if (param.Self.IsSync===false) //异步需要马上刷新,同步主图数据更新的时候会刷新的
param.HQChart.Draw();
var event=hqChart.GetOverlayIndexEvent(); //指标计算完成回调
if (event)
{
var self=param.Self;
var data={ OutVar:self.OutVar, WindowIndex: windowIndex, Name: self.Name, Arguments: self.Arguments, HistoryData: hisData,
Identify:self.OverlayIndex.Identify,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
event.Callback(event,data,self);
}
}
//自定义图形配色
this.ReloadChartResource=function(hqChart, windowIndex, chart)
{
var event=hqChart.GetEventCallback(JSCHART_EVENT_ID.ON_RELOAD_OVERLAY_INDEX_CHART_RESOURCE); //指标计算完成回调
if (!event || !event.Callback) return;
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var script=frame.Script;
var sendData={ Chart:chart, IndexName:script.Name,IndexID:script.ID, HQChart:hqChart, WindowIndex:windowIndex, Guid:overlayIndex.Identify };
event.Callback(event,sendData,this);
}
//////////////////////////////////////////////////////////////////////////////////////
// 图形创建
/////////////////////////////////////////////////////////////////////////////////////
this.CreateLine=function(hqChart,windowIndex,varItem,id,lineType)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
if (lineType==7) var chart=new ChartStepLine();
else var chart=new ChartLine();
chart.Canvas=hqChart.Canvas;
chart.DrawType=1;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (lineType==8)
{
chart.DrawType=2;
chart.BreakPoint=varItem.BreakPoint;
}
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
if (varItem.IsShow==false) chart.IsShow=false;
chart.Data.Data=varItem.Data;
this.ReloadChartResource(hqChart, windowIndex, chart);
let titleIndex=windowIndex+1;
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
this.SetTitleData(titleData,chart);
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=titleData;
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
//创建柱子
this.CreateBar=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartStickLine();
chart.Canvas=hqChart.Canvas;
if (varItem.Draw.Width>0) chart.Width=varItem.Draw.Width;
else chart.Width=1;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateDrawText=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chart=new ChartSingleText();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.ReloadResource();
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.IsDrawAbove) chart.Direction=1;
else chart.Direction=0;
chart.DrawData=varItem.Draw.DrawData;
if (varItem.DrawFontSize>0) chart.TextFont=`${varItem.DrawFontSize*GetDevicePixelRatio()}px 微软雅黑`; //临时用下吧
frame.ChartPaint.push(chart);
}
//DRAWTEXT
this.CreateDrawTextV2=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chartText=new ChartDrawText();
chartText.Canvas=hqChart.Canvas;
chartText.Name=varItem.Name;
chartText.ChartBorder=frame.Frame.ChartBorder;
chartText.ChartFrame=frame.Frame;
chartText.Identify=overlayIndex.Identify;
chartText.ReloadResource();
if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
else chartText.Color=this.GetDefaultColor(id);
if (varItem.IsDrawCenter===true) chartText.TextAlign='center';
if (varItem.IsDrawAbove===true) chartText.TextBaseline='bottom'
if (varItem.IsDrawBelow===true) chartText.TextBaseline='top';
if (varItem.Draw.DrawData) chartText.Data.Data=varItem.Draw.DrawData;
chartText.Text=varItem.Draw.Text;
if (varItem.Draw.Direction>0) chartText.Direction=varItem.Draw.Direction;
if (varItem.Draw.YOffset>0) chartText.YOffset=varItem.Draw.YOffset;
if (varItem.Draw.TextAlign) chartText.TextAlign=varItem.Draw.TextAlign;
//指定输出位置
if (varItem.Draw.FixedPosition==="TOP") chartText.FixedPosition=1;
else if (varItem.Draw.FixedPosition==="BOTTOM") chartText.FixedPosition=2;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chartText.TextBaseline='top';
else if (varItem.DrawVAlign==1) chartText.TextBaseline='middle';
else if (varItem.DrawVAlign==2) chartText.TextBaseline='bottom';
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chartText.TextAlign="left";
else if (varItem.DrawAlign==1) chartText.TextAlign="center";
else if (varItem.DrawAlign==2) chartText.TextAlign='right';
}
if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
if (varItem.Background) chartText.TextBG=varItem.Background;
if (varItem.VerticalLine) chartText.VerticalLine=varItem.VerticalLine;
if (IFrameSplitOperator.IsNumber(varItem.XOffset)) chartText.ShowOffset.X=varItem.XOffset;
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) chartText.ShowOffset.Y=varItem.YOffset;
//let titleIndex=windowIndex+1;
frame.ChartPaint.push(chartText);
}
//创建文本
this.CreateText=function(hqChart,windowIndex,varItem,id, drawName)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartSingleText();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.ReloadResource();
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
let titleIndex=windowIndex+1;
if (varItem.Draw.Position) chart.Position=varItem.Draw.Position; //赋值坐标
if (varItem.Draw.DrawData) chart.Data.Data=varItem.Draw.DrawData;
chart.Text=varItem.Draw.Text;
if (varItem.Draw.Direction>0) chart.Direction=varItem.Draw.Direction;
if (varItem.Draw.YOffset>0) chart.YOffset=varItem.Draw.YOffset;
if (varItem.Draw.TextAlign) chart.TextAlign=varItem.Draw.TextAlign;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
frame.ChartPaint.push(chart);
}
//COLORSTICK
this.CreateMACD=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMACD();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
var titlePaint=hqChart.TitlePaint[titleIndex];
var clrTitle=this.GetDefaultColor(id);
if (varItem.Color) clrTitle=this.GetColor(varItem.Color);
if (varItem.UpColor) chart.UpColor=varItem.UpColor;
if (varItem.DownColor) chart.DownColor=varItem.DownColor;
this.ReloadChartResource(hqChart, windowIndex, chart);
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,clrTitle);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreatePointDot=function(hqChart,windowIndex,varItem,id,hisData)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartPointDot();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.Radius) chart.Radius=varItem.Radius;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.Radius=width;
}
if (IFrameSplitOperator.IsBool(varItem.UpDownDot))
{
chart.EnableUpDownColor=varItem.UpDownDot;
chart.HistoryData=hisData;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateStick=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
this.ReloadChartResource(hqChart, windowIndex, chart);
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
frame.ChartPaint.push(chart);
}
this.CreateLineStick=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartLineStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
frame.ChartPaint.push(chart);
}
this.CreateStraightLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartLine();
chart.DrawType=1;
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
frame.ChartPaint.push(chart);
}
this.CreateVolStick=function(hqChart,windowIndex,varItem,id,hisData)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartVolStick();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.KLineDrawType=hqChart.KLineDrawType; //设置K线显示类型
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.UpColor) chart.UpColor=varItem.UpColor;
if (varItem.DownColor) chart.DownColor=varItem.DownColor;
if (IFrameSplitOperator.IsNumber(varItem.StickType)) chart.BarType=varItem.StickType;
if (IFrameSplitOperator.IsNumber(varItem.BarColorType)) chart.BarColorType=varItem.BarColorType;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) chart.BarWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Data;
chart.HistoryData=hisData;
this.ReloadChartResource(hqChart, windowIndex, chart);
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color);
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=titleData;
this.SetTitleData(titleData,chart);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateBand=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartBand();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.FirstColor = varItem.Draw.Color[0];
chart.SecondColor = varItem.Draw.Color[1];
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsBool(varItem.IsFirstDraw)) chart.IsDrawFirst=varItem.IsFirstDraw;
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
//创建K线图
this.CreateKLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartKLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data.Data=varItem.Draw.DrawData;
chart.IsShowMaxMinPrice=false;
chart.IsShowKTooltip=false;
if (varItem.Color) //如果设置了颜色,使用外面设置的颜色
chart.UnchagneColor=chart.DownColor=chart.UpColor=this.GetColor(varItem.Color);
frame.ChartPaint.push(chart);
}
this.CreatePolyLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData;
var titlePaint=hqChart.TitlePaint[titleIndex];
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(line.Data,' ',line.Color); //给一个空的标题
frame.ChartPaint.push(chart);
}
this.CreateNumberText=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartSingleText();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.ReloadResource();
chart.TextAlign="center";
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.IsDrawAbove) chart.Direction=1;
else chart.Direction=2;
if (varItem.Draw.Position) chart.Position=varItem.Draw.Position; //赋值坐标
let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData.Value;
chart.Text=varItem.Draw.DrawData.Text;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateTextLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartTextLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.Text=drawData.Text;
chart.Line=drawData.Line;
chart.Price=drawData.Price;
}
frame.ChartPaint.push(chart);
}
this.CreateStackedBar=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartStackedBar();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.BarColor)) chart.BarColor=varItem.Draw.BarColor;
if (IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.BarName)) chart.BarName=varItem.Draw.BarName;
if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
if (IFrameSplitOperator.IsNumber(varItem.Draw.BarType)) chart.BarType=varItem.Draw.BarType;
chart.Data.Data=varItem.Draw.DrawData;
var titleIndex=windowIndex+1;
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleData=new DynamicTitleData(chart.Data,chart.BarName,chart.BarColor);
titleData.DataType="ChartStackedBar";
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=titleData;
frame.ChartPaint.push(chart);
}
this.CreateDrawColorKLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartColorKline();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.DrawName="DRAWCOLORKLINE";
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data.Data=varItem.Draw.DrawData;
if (IFrameSplitOperator.IsBool(varItem.Draw.IsEmptyBar)) chart.IsEmptyBar=varItem.Draw.IsEmptyBar;
if (varItem.Draw.Color) chart.Color=varItem.Draw.Color;
frame.ChartPaint.push(chart);
}
//创建图标
this.CreateIcon=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartSingleText();
chart.Canvas=hqChart.Canvas;
chart.TextAlign='center';
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.DrawVAlign>=0)
{
if (varItem.DrawVAlign==0) chart.Direction=1;
else if (varItem.DrawVAlign==1) chart.Direction=0;
else if (varItem.DrawVAlign==2) chart.Direction=2;
}
if (varItem.DrawAlign>=0)
{
if (varItem.DrawAlign==0) chart.TextAlign="left";
else if (varItem.DrawAlign==1) chart.TextAlign="center";
else if (varItem.DrawAlign==2) chart.TextAlign='right';
}
if (IFrameSplitOperator.IsNumber(varItem.XOffset)) chart.ShowOffset.X=varItem.XOffset;
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) chart.ShowOffset.Y=varItem.YOffset;
chart.Data.Data=varItem.Draw.DrawData;
var icon=varItem.Draw.Icon;
if (icon.IconFont==true)
{
chart.IconFont={ Family:icon.Family, Text:icon.Symbol, Color:icon.Color };
}
else
{
chart.Text=icon.Symbol;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else if (icon.Color) chart.Color=icon.Color;
else chart.Color='rgb(0,0,0)';
}
//var titleIndex=windowIndex+1;
//hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateTipIcon=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chart=new ChartDrawSVG();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (hqChart.ChartPaint[0].IsMinuteFrame())
chart.Data=hqChart.SourceData;
else
chart.Data=hqChart.ChartPaint[0].Data; //绑定K线
chart.Family=varItem.Draw.Icon.Family;
chart.TextFont=g_JSChartResource.TIPICON.TextFont;
var svgSize=g_JSChartResource.TIPICON.Size;
var svgColor=g_JSChartResource.TIPICON.Color;
var svgYOffset=0;
var svgVAlign=2; //上下对齐方式
if (IFrameSplitOperator.IsNumber(varItem.YOffset)) svgYOffset=varItem.YOffset;
if (varItem.Color) svgColor=this.GetColor(varItem.Color);
if (varItem.DrawFontSize>0) svgSize=varItem.DrawFontSize;
if (varItem.DrawVAlign>=0) svgVAlign=varItem.DrawVAlign;
if (varItem.Draw && IFrameSplitOperator.IsNonEmptyArray(varItem.Draw.DrawData) && varItem.Draw.Icon)
{
var drawData=varItem.Draw.DrawData;
var aryData=[];
var isArrayTip=Array.isArray(varItem.Draw.Text);
var singleTip=null;
if (!isArrayTip && varItem.Draw.Text) singleTip={ Text:varItem.Draw.Text };
for(var j=0;j<drawData.length;++j)
{
var item=drawData[j];
if (!IFrameSplitOperator.IsNumber(item)) continue;
var svgItem=
{
Index:j, Value:item,
SVG:{ Symbol:varItem.Draw.Icon.Symbol, Size:svgSize, Color:svgColor, YOffset:svgYOffset, VAlign:svgVAlign }
};
if (isArrayTip)
{
var text=varItem.Draw.Text[j];
if (text) svgItem.Tooltip={ Text:text };
}
else
{
svgItem.Tooltip=singleTip;
}
aryData.push(svgItem);
}
chart.Texts= aryData;
}
frame.ChartPaint.push(chart);
}
//创建通道
this.CreateChannel=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartChannel();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if(varItem.Draw.AreaColor) chart.AreaColor=varItem.Draw.AreaColor;
else if (varItem.Color) chart.AreaColor=this.GetColor(varItem.Color);
else chart.AreaColor=this.GetDefaultColor(id);
if (varItem.Draw.Border.Color) chart.LineColor=varItem.Draw.Border.Color;
else chart.LineColor=null;
if (varItem.Draw.Border.Dotted) chart.LineDotted=varItem.Draw.Border.Dotted;
if (varItem.Draw.Border.Width>0) chart.LineWidth=varItem.Draw.Border.Width;
//let titleIndex=windowIndex+1;
chart.Data.Data=varItem.Draw.DrawData;
frame.ChartPaint.push(chart);
}
//
this.CreatePartLine=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartPartLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (IFrameSplitOperator.IsPlusNumber(width)) chart.LineWidth=width;
}
chart.Data.Data=varItem.Draw.DrawData;
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateMultiLine=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Lines=varItem.Draw.DrawData;
if (varItem.Draw.LineDash) chart.LineDash=varItem.Draw.LineDash;
if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
if (IFrameSplitOperator.IsBool(varItem.Draw.IsFullRangeMaxMin)) chart.IsFullRangeMaxMin=varItem.Draw.IsFullRangeMaxMin;
if(varItem.Draw.Arrow) //箭头配置
{
var item=varItem.Draw.Arrow;
if (item.Start==true) chart.Arrow.Start=true;
if (item.End==true) chart.Arrow.End=true;
if (IFrameSplitOperator.IsNumber(item.Angle)) chart.ArrawAngle=item.Angle;
if (IFrameSplitOperator.IsNumber(item.Length)) chart.ArrawLength=item.Length;
if (IFrameSplitOperator.IsNumber(item.LineWidth)) chart.ArrawLineWidth=item.LineWidth;
}
this.ReloadChartResource(hqChart, windowIndex, chart);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateMultiPoint=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiPoint();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.PointGroup=varItem.Draw.DrawData;
frame.ChartPaint.push(chart);
}
this.CreateBackgroud=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartBackground();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (varItem.Draw && varItem.Draw.DrawData)
{
var drawData=varItem.Draw.DrawData;
chart.Color=drawData.Color;
chart.ColorAngle=drawData.Angle;
if (drawData.Data) chart.Data.Data=drawData.Data;
}
frame.ChartPaint.push(chart);
}
this.CreateMultiBar=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiBar();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Bars=varItem.Draw.DrawData;
var titleIndex=windowIndex+1;
var titlePaint=hqChart.TitlePaint[titleIndex];
var titleData=new DynamicTitleData({ KData:chart.Data, BarData:chart.Bars },varItem.Name,null);
titleData.IsShow=false;
titleData.DataType="MULTI_BAR";
titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=titleData;
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateMultiText=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiText();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Texts=varItem.Draw.DrawData;
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateMultiSVGIcon=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiSVGIconV2();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Family=varItem.Draw.DrawData.Family;
chart.AryIcon= varItem.Draw.DrawData.Icon;
chart.BuildCacheData();
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateChartDrawSVG=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chart=new ChartDrawSVG();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
if (hqChart.ChartPaint[0].IsMinuteFrame())
chart.Data=hqChart.SourceData;
else
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
if (IFrameSplitOperator.IsBool(varItem.Draw.DrawData.EnableTooltip)) chart.EnableTooltip=varItem.Draw.DrawData.EnableTooltip;
if (IFrameSplitOperator.IsBool(varItem.Draw.DrawData.IsDrawFirst)) chart.IsDrawFirst=varItem.Draw.DrawData.IsDrawFirst;
chart.Family=varItem.Draw.DrawData.Family;
chart.TextFont=varItem.Draw.DrawData.TextFont;
chart.Texts= varItem.Draw.DrawData.Data;
if (varItem.Draw.AutoPosition) chart.AutoPosition=varItem.Draw.AutoPosition;
this.ReloadChartResource(hqChart, windowIndex, chart);
this.SetChartIndexName(chart);
frame.ChartPaint.push(chart);
}
this.CreateMulitHtmlDom=function(hqChart,windowIndex,varItem,i)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartMultiHtmlDom();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.HQChart=hqChart;
chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
chart.Texts=varItem.Draw.DrawData;
chart.DrawCallback= varItem.Draw.Callback;
frame.ChartPaint.push(chart);
}
this.CreateChartVericaltLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chart=new ChartVericaltLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.HQChart=hqChart;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
this.SetChartLineDash(chart,varItem.Draw.DrawData);
chart.Data.Data=varItem.Draw.DrawData.Data;
frame.ChartPaint.push(chart);
}
this.CreateChartHorizontalLine=function(hqChart,windowIndex,varItem,id)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
var chart=new ChartHorizontalLine();
chart.Canvas=hqChart.Canvas;
chart.Name=varItem.Name;
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.HQChart=hqChart;
if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
else chart.Color=this.GetDefaultColor(id);
if (varItem.LineWidth)
{
let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
if (!isNaN(width) && width>0) chart.LineWidth=width;
}
this.SetChartLineDash(chart,varItem.Draw.DrawData);
chart.ExtendType=varItem.Draw.DrawData.Extend;
chart.Data.Data=varItem.Draw.DrawData.Data;
frame.ChartPaint.push(chart);
}
//创建K线
this.CreateSelfKLine=function(hqChart,windowIndex,hisData)
{
var overlayIndex=this.OverlayIndex;
var frame=overlayIndex.Frame;
let chart=new ChartKLine();
chart.Canvas=hqChart.Canvas;
chart.Name="Self Kline"
chart.ChartBorder=frame.Frame.ChartBorder;
chart.ChartFrame=frame.Frame;
chart.Identify=overlayIndex.Identify;
chart.Data=hisData
chart.IsShowMaxMinPrice=false;
chart.IsShowKTooltip=false;
chart.DrawType=this.KLineType;
frame.ChartPaint.push(chart);
}
//给一个默认的颜色
this.GetDefaultColor=function(id)
{
let COLOR_ARRAY=
[
"rgb(24,71,178)",
"rgb(42,230,215)",
"rgb(252,96,154)",
"rgb(0,128,255)",
"rgb(229,0,79)",
"rgb(68,114,196)",
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
];
let number=parseInt(id);
return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)];
}
}
//后台执行指标
function APIScriptIndex(name,script,args,option, isOverlay)
{
if (isOverlay) this.newMethod=OverlayScriptIndex;
else this.newMethod=ScriptIndex;
this.newMethod(name,script,args,option);
delete this.newMethod;
this.ClassName="APIScriptIndex";
this.IsOverlayIndex=(isOverlay==true); //是否是叠加指标
this.ApiUrl; //指标执行api地址
this.HQDataType;
this.Version=1; //1=默认数据格式 1=新的.net数据格式
if (option && option.API)
{
if (option.API.Url) this.ApiUrl=option.API.Url;
if (option.API.Name) this.Name=this.ID=option.API.Name;
if (option.API.ID) this.ID=option.API.ID;
if (option.API.Version>0) this.Version=option.API.Version;
if (option.API.IsUsePageData===true) this.IsUsePageData=option.API.IsUsePageData;
}
this.Super_CopyTo=this.CopyTo; //父类方法
this.CopyTo=function(dest) //赋值到新实例出来
{
this.Super_CopyTo(dest);
dest.ApiUrl=this.ApiUrl;
dest.Version=this.Version;
dest.IsOverlayIndex=this.IsOverlayIndex;
}
//接收到订阅指标数据
this.RecvSubscribeData=function(data, hqChart, windowIndex, hisData)
{
if (this.Version==2)
this.RecvAPIData2(data,hqChart,windowIndex,hisData);
else
this.RecvAPIData(data,hqChart,windowIndex,hisData);
}
this.ExecuteScript=function(hqChart,windowIndex,hisData)
{
JSConsole.Complier.Log('[APIScriptIndex::ExecuteScript] name, Arguments ', this.Name,this.Arguments );
//数据类型
let hqDataType=HQ_DATA_TYPE.KLINE_ID; //默认K线
var dateRange=null;
if (hqChart.ClassName==='MinuteChartContainer' || hqChart.ClassName==='MinuteChartHScreenContainer')
{
if (hqChart.DayCount>1) hqDataType=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID; //多日分钟
else hqDataType=HQ_DATA_TYPE.MINUTE_ID; //分钟数据
dateRange=hisData.GetDateRange();
}
else if (hqChart.ClassName==='HistoryMinuteChartContainer')
{
hqDataType=HQ_DATA_TYPE.HISTORY_MINUTE_ID; //历史分钟
}
else
{
dateRange=hisData.GetDateRange();
}
var args=[];
if (this.Arguments)
{
for(var i in this.Arguments)
{
var item=this.Arguments[i];
args.push({name:item.Name, value:item.Value});
}
}
var requestCount;
if (hqChart.GetRequestDataCount) requestCount=hqChart.GetRequestDataCount();
var self=this;
var postData =
{
indexname:this.ID, symbol: hqChart.Symbol, script:this.Script, args:args,
period:hqChart.Period, right:hqChart.Right, hqdatatype: hqDataType
};
if (dateRange) postData.DateRange=dateRange;
if (requestCount)
{
postData.maxdatacount=requestCount.MaxRequestDataCount;
postData.maxminutedaycount=requestCount.MaxRequestMinuteDayCount;
}
if (hqDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID || hqDataType==HQ_DATA_TYPE.MINUTE_ID) postData.daycount=hqChart.DayCount;
this.HQDataType=hqDataType;
++this.RunCount;
if (hqChart.NetworkFilter)
{
var obj=
{
Name:'APIScriptIndex::ExecuteScript', //类名::
Explain:'指标计算',
Request:{ Url:self.ApiUrl, Type:'POST', Data: postData },
Self:this,
HQChart:hqChart,
PreventDefault:false
};
hqChart.NetworkFilter(obj, function(data)
{
if (self.Version==2)
self.RecvAPIData2(data,hqChart,windowIndex,hisData);
else
self.RecvAPIData(data,hqChart,windowIndex,hisData);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.ApiUrl,
data: postData,
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvAPIData(recvData,hqChart,windowIndex,hisData);
},
error: function(request)
{
self.RecvError(request);
}
});
}
//py 后台指标计算格式
this.RecvAPIData2=function(data,hqChart,windowIndex,hisData)
{
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] recv data ', this.Name,data );
//if (data.code!=0) return;
if (this.HQDataType==HQ_DATA_TYPE.KLINE_ID)
{
this.OutVar=this.ConvertToLocalData(data,hqChart);
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
}
else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID)
{
this.OutVar=this.ConvertToLocalData(data,hqChart);
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
}
else if (this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
{
this.OutVar=this.ConvertToLocalData(data,hqChart);
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
}
this.BindData(hqChart,windowIndex,hisData);
hqChart.UpdataDataoffset(); //更新数据偏移
hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
hqChart.Draw();
if (hqChart.GetIndexEvent)
{
var event=hqChart.GetIndexEvent(); //指标计算完成回调
if (event)
{
var data={ OutVar:this.OutVar, WindowIndex: windowIndex, Name: this.Name, Arguments: this.Arguments, HistoryData: hisData,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
event.Callback(event,data,this);
}
}
}
this.ConvertToLocalData=function(jsonData, hqChart)
{
var outVar=jsonData.OutVar;
if (hqChart.ClassName=="MinuteChartContainer" || hqChart.ClassName=="MinuteChartHScreenContainer")
{
var kdata=hqChart.SourceData;
var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date,jsonData.Time);
}
else
{
var kdata=hqChart.ChartPaint[0].Data;
if (ChartData.IsDayPeriod(jsonData.Period,true))
var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date);
else
var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date,jsonData.Time);
}
var localOutVar=[];
for(var i in outVar)
{
var item=outVar[i];
var outItem={ Type:item.Type, Name:item.Name };
if (item.Type==0)
{
outItem.Data=[];
for(var j=0;j<aryDataIndex.length;++j)
{
var indexItem=aryDataIndex[j];
if (indexItem.Index<0) outItem.Data[j]=null;
else outItem.Data[j]=item.Data[indexItem.Index];
}
if (outItem.Name && outItem.Name.indexOf("@NODRAW@")>=0)
outItem.Name=outItem.Name.replace("@NODRAW@","");
}
else if (item.Type==1) //绘图函数
{
outItem.Name=item.DrawType;
outItem.Draw={ DrawType:item.DrawType };
var draw=item.Draw;
switch(item.DrawType)
{
case "STICKLINE":
{
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var price=draw.Price[index];
var price2=draw.Price2[index];
if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(price2))
continue;
drawData[j]={ Value:price, Value2:price2 };
}
outItem.Draw.DrawData=drawData;
outItem.Draw.Width=draw.Width;
outItem.Draw.Type=draw.Empty;
}
break;
case "DRAWTEXT":
{
var drawData=[];
var aryText=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var price=draw.Price[index];
if ( IFrameSplitOperator.IsNumber(price))
{
drawData[j]=price;
}
if (Array.isArray(draw.Text)) //字符串数组
{
var item=draw.Text[index];
if (IFrameSplitOperator.IsString(item)) aryText[j]=item;
}
}
if (Array.isArray(draw.Text)) outItem.Draw.Text=aryText;
else outItem.Draw.Text=draw.Text;
outItem.Draw.DrawData=drawData;
}
break;
case "DRAWNUMBER":
{
var drawData={Value:[], Text:[]};
for(var j=0;j<aryDataIndex.length;++j)
{
drawData.Value[j]=null;
drawData.Text[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var price=draw.Price[index];
var number=draw.Number[index];
if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(number)) continue;
drawData.Value[j]=price;
drawData.Text[j]=number.toFixed(2);
}
outItem.Draw.DrawData=drawData;
}
break;
case "DRAWBAND":
{
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var price=draw.Val1[index];
var price2=draw.Val2[index];
if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(price2)) continue;
drawData[j]={ Value:price, Value2:price2 };
}
outItem.Draw.DrawData=drawData;
outItem.Draw.Color=[null, null];
if (draw.Color1) outItem.Draw.Color[0]=draw.Color1.toLowerCase();
if (draw.Color2) outItem.Draw.Color[1]=draw.Color2.toLowerCase();
}
break;
case "DRAWKLINE":
{
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
var item={ Open:null,High:null, Low:null, Close:null };
drawData[j]=item;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var high=draw.High[index];
var low=draw.Low[index];
var open=draw.Open[index];
var close=draw.Close[index];
if ( IFrameSplitOperator.IsPlusNumber(high) && IFrameSplitOperator.IsPlusNumber(low) &&
IFrameSplitOperator.IsPlusNumber(open) && IFrameSplitOperator.IsPlusNumber(close))
{
item.Open=open;
item.Close=close;
item.High=high;
item.Low=low;
}
}
outItem.Draw.DrawData=drawData;
}
break;
case "DRAWTEXT_FIX":
{
var drawData={ Value:[], Text:[] };
for(var j=0;j<aryDataIndex.length;++j)
{
drawData.Value[j]=0;
drawData.Text[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var condItem=draw.Cond[index];
if (!condItem) continue;
drawData.Value[j]=1;
drawData.Text[j]=draw.Text;
}
outItem.Draw.DrawData=drawData;
outItem.Draw.Position={ X:draw.X, Y:draw.Y, Type:draw.Type };
}
break;
case "DRAWNUMBER_FIX":
{
var drawData={ Value:[], Text:[] };
for(var j=0;j<aryDataIndex.length;++j)
{
drawData.Value[j]=null;
drawData.Text[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var value=draw.Number[index];
if (!IFrameSplitOperator.IsNumber(value)) continue;
drawData.Value[j]=value;
drawData.Text[j]=IFrameSplitOperator.RemoveZero(value.toFixed(2));
}
outItem.Draw.DrawData=drawData;
outItem.Draw.Position={ X:draw.X, Y:draw.Y, Type:draw.Type };
}
break;
case "DRAWICON":
{
var icon=g_JSComplierResource.GetDrawIcon(draw.Type);
if (!icon) g_JSComplierResource.GetDrawTextIcon(draw.Type);
if (!icon) icon={Symbol:'🚩'};
outItem.Draw.Icon=icon;
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var value=draw.Price[index];
if (!IFrameSplitOperator.IsNumber(value)) continue;
drawData[j]=value;
}
outItem.Draw.DrawData=drawData;
}
break;
case "PARTLINE":
{
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]={Value:null, RGB:null};
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var color=draw.Color[index];
if (!IFrameSplitOperator.IsString(color)) continue;
var value=draw.Price[index];
if (!IFrameSplitOperator.IsNumber(value)) continue;
drawData[j].Value=value;
drawData[j].RGB=color;
}
outItem.Draw.DrawData=drawData;
}
break;
case "FILLRGN":
{
var drawData=[];
for(var j=0;j<aryDataIndex.length;++j)
{
drawData[j]=null;
var indexItem=aryDataIndex[j];
var index=indexItem.Index;
if (index<0) continue;
var color=draw.Color[index];
if (!IFrameSplitOperator.IsString(color)) continue;
var value=draw.Price[index];
if (!IFrameSplitOperator.IsNumber(value)) continue;
var value2=draw.Price2[index];
if (!IFrameSplitOperator.IsNumber(value2)) continue;
drawData[j]={ Value:value, Value2:value2, Color:color };
}
outItem.Draw.DrawData=drawData;
outItem.Draw.DrawType="FILLRGN2";
}
break;
default:
continue;
}
}
else
{
continue;
}
for(var i in item.Attribute)
{
var attr=item.Attribute[i];
switch(attr)
{
case "COLORSTICK":
outItem.Type=2; //画上下柱子
break;
case "POINTDOT":
outItem.Radius=g_JSChartResource.POINTDOT.Radius;
outItem.Type=3;
break;
case "CIRCLEDOT":
outItem.Radius=g_JSChartResource.CIRCLEDOT.Radius;
outItem.Type=3;
break;
case "DOTLINE":
outItem.IsDotLine=true;
break;
case "DRAWABOVE":
outItem.IsDrawAbove=true;
break;
case "LINESTICK":
outItem.Type=4;
break;
case "STICK": //STICK 画柱状线
outItem.Type=5;
break;
case "VOLSTICK": //成交量柱子
outItem.Type=6;
break;
case "LINEAREA":
outItem.Type=9; //面积
break;
case "NODRAW": //不画该线
outItem.IsShow = false;
break;
case "NONE_OUT_NAME": //不显示标题
outItem.NoneName=true;
break;
case "NOTEXT": //不显示标题
outItem.IsShowTitle=false;
break;
}
if (attr.indexOf('COLOR')==0)
{
outItem.Color=attr;
}
else if (attr.indexOf('LINETHICK')==0)
{
outItem.LineWidth=attr;
}
}
localOutVar.push(outItem);
}
return localOutVar;
}
this.RecvAPIData=function(data,hqChart,windowIndex,hisData)
{
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData] recv data ', this.Name,data );
if (data.code!=0) return;
if (hqChart.EnableVerifyRecvData)
{
if (!data.stock || hqChart.Symbol!=data.stock.symbol)
{
JSConsole.Chart.Warn(`[APIScriptIndex::RecvAPIData] recv data symbol not match. HQChart[${hqChart.Symbol}]`);
return;
}
}
if (data.error && IFrameSplitOperator.IsString(data.error.message))
{
var param=
{
HQChart:hqChart,
WindowIndex:windowIndex,
HistoryData:hisData,
Self:this
};
this.ShowConditionError(param, data.error.message);
return;
}
if (data.outdata && data.outdata.name) this.Name=data.outdata.name;
if (data.outdata.args) //外部修改参数
{
this.Arguments=[];
for(var i in data.outdata.args)
{
var item= data.outdata.args[i];
this.Arguments.push({Name:item.name, Value:item.value});
}
}
if (this.HQDataType==HQ_DATA_TYPE.KLINE_ID)
{
this.OutVar=this.FittingData(data.outdata,hqChart);
JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData] conver to OutVar ', this.OutVar);
}
else
{
this.OutVar=this.FittingMinuteData(data.outdata,hqChart); //走势图数据
}
this.BindData(hqChart,windowIndex,hisData);
if (this.IsLocked==false) //不上锁
{
hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(null);
}
else //上锁
{
let lockData={ IsLocked:true,Callback:this.LockCallback,IndexName:this.Name ,ID:this.LockID,
BG:this.LockBG,Text:this.LockText,TextColor:this.LockTextColor, Font:this.LockFont, Count:this.LockCount, MinWidth:this.LockMinWidth };
hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(lockData);
}
hqChart.UpdataDataoffset(); //更新数据偏移
hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值
if (data.Redraw===false) //是否重绘
{
}
else
{
if (this.IsSync===false) //同步的指标不用刷新
hqChart.Draw();
}
if (hqChart.GetIndexEvent)
{
var event=hqChart.GetIndexEvent(); //指标计算完成回调
if (event)
{
var data={ OutVar:this.OutVar, WindowIndex: windowIndex, Name: this.Name, Arguments: this.Arguments, HistoryData: hisData,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
event.Callback(event,data,this);
}
}
}
this.FittingArray=function(sourceData,date,time,hqChart,arrayType) //arrayType 0=单值数组 1=结构体
{
var kdata=hqChart.ChartPaint[0].Data; //K线
var arySingleData=[];
for(var i in sourceData)
{
var value=sourceData[i];
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=date[i];
if (time && i<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData;
if (ChartData.IsDayPeriod(hqChart.Period,true))
aryFittingData=kdata.GetFittingData(arySingleData); //数据和主图K线拟合
else
aryFittingData=kdata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result;
if (arrayType==1) result=bindData.GetObject();
else result=bindData.GetValue();
return result;
}
this.FittingMultiLine=function(sourceData,date,time,hqChart)
{
var kdata=hqChart.ChartPaint[0].Data; //K线
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
var kdata=hqChart.ChartPaint[0].Data; //K线
var aryPoint=[];
for(var i in sourceData)
{
var item=sourceData[i];
for(var j in item.Point)
{
var point=item.Point[j];
aryPoint.push(point);
}
}
aryPoint.sort(function(a,b) { return a.Date-b.Date; });
kdata.GetDateIndex(aryPoint);
return sourceData;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true) || ChartData.IsTickPeriod(hqChart.Period) || ChartData.IsSecondPeriod(hqChart.Period)) //分钟线
{
var kdata=hqChart.ChartPaint[0].Data; //K线
var aryPoint=[];
for(var i in sourceData)
{
var item=sourceData[i];
for(var j in item.Point)
{
var point=item.Point[j];
aryPoint.push(point);
}
}
aryPoint.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
kdata.GetDateTimeIndex(aryPoint);
return sourceData;
}
else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
{
var minuteData=hqChart.SourceData;
var aryPoint=[];
for(var i in sourceData)
{
var item=sourceData[i];
for(var j in item.Point)
{
var point=item.Point[j];
aryPoint.push(point);
}
}
aryPoint.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
minuteData.GetDateTimeIndex(aryPoint);
return sourceData;
}
return null;
}
this.FittingMultiText=function(sourceData,date,time,hqChart)
{
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
var kdata=hqChart.ChartPaint[0].Data; //K线
sourceData.sort(function(a,b) { return a.Date-b.Date; });
kdata.GetDateIndex(sourceData);
return sourceData;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true) || ChartData.IsTickPeriod(hqChart.Period) || ChartData.IsSecondPeriod(hqChart.Period) || ChartData.IsMilliSecondPeriod(hqChart.Period)) //分钟线
{
var kdata=hqChart.ChartPaint[0].Data; //K线
sourceData.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
kdata.GetDateTimeIndex(sourceData);
return sourceData;
}
else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
{
var minuteData=hqChart.SourceData;
sourceData.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
minuteData.GetDateTimeIndex(sourceData);
return sourceData;
}
return null;
}
this.FittingData=function(jsonData, hqChart)
{
var outVar=jsonData.outvar;
var date=jsonData.date;
var time=jsonData.time;
var kdata=hqChart.ChartPaint[0].Data;
//把数据拟合到kdata上
var result=[];
if (!outVar) return result;
for(var i=0;i<outVar.length; ++i)
{
var item=outVar[i];
var indexData=[];
var outVarItem={Name:item.name,Type:item.type};
if (item.color) outVarItem.Color=item.color;
if (IFrameSplitOperator.IsBool(item.IsShowTitle)) outVarItem.IsShowTitle = item.IsShowTitle; //是否显示指标标题
if (item.data)
{
outVarItem.Data=this.FittingArray(item.data,date,time,hqChart);
if (item.color) outVarItem.Color=item.color;
if (item.linewidth) outVarItem.LineWidth=item.linewidth;
if (IFrameSplitOperator.IsBool(item.isshow)) outVarItem.IsShow = item.isshow; //是否绘制线段
if (item.isexdata==true) outVarItem.IsExData = true;
if (item.BreakPoint) outVarItem.BreakPoint=item.BreakPoint;
if (item.UpColor) outVarItem.UpColor=item.UpColor;
if (item.DownColor) outVarItem.DownColor=item.DownColor;
if (IFrameSplitOperator.IsBool(item.isDotLine)) outVarItem.IsDotLine = item.isDotLine;
if (IFrameSplitOperator.IsNonEmptyArray(item.lineDash)) outVarItem.LineDash=item.lineDash;
if (IFrameSplitOperator.IsBool(item.isSingleLine)) outVarItem.IsSingleLine=item.isSingleLine;
if (IFrameSplitOperator.IsNumber(item.StickType)) outVarItem.StickType=item.StickType;
if (IFrameSplitOperator.IsNumber(item.BarColorType)) outVarItem.BarColorType=item.BarColorType;
result.push(outVarItem);
}
else if (item.Draw)
{
var draw=item.Draw;
var drawItem={};
if (draw.DrawType=='DRAWICON') //图标
{
drawItem.Icon=draw.Icon;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='DRAWTEXT') //文本
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='STICKLINE') //柱子
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.Width=draw.Width;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="DRAWBAND")
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
drawItem.Color=draw.Color;
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_LINE')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart);
if (IFrameSplitOperator.IsNonEmptyArray(drawItem.DrawData))
{
for(var k=0; k<drawItem.DrawData.length; ++k)
{
this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
}
}
outVarItem.Draw=drawItem;
if (draw.LineDash) drawItem.LineDash=draw.LineDash;
if (IFrameSplitOperator.IsBool(draw.IsFullRangeMaxMin)) drawItem.IsFullRangeMaxMin=draw.IsFullRangeMaxMin;
if (draw.Arrow) drawItem.Arrow=draw.Arrow;
if (IFrameSplitOperator.IsNumber(draw.LineWidth)) drawItem.LineWidth=draw.LineWidth;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_POINT')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart);
if (IFrameSplitOperator.IsNonEmptyArray(drawItem.DrawData))
{
for(var k=0; k<drawItem.DrawData.length; ++k)
{
this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
}
}
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_BAR')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.OVERLAY_BARS)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.BarName=draw.BarName;
drawItem.BarColor=draw.BarColor;
drawItem.LineWidth=draw.LineWidth;
drawItem.BarType=draw.BarType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.SCATTER_PLOT)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
//默认的值
drawItem.Color=draw.Color;
drawItem.Radius=draw.Radius;
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.KLINE_TABLE)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
drawItem.RowCount=draw.RowCount;
drawItem.RowName=draw.RowName;
drawItem.IsShowRowName=draw.IsShowRowName;
drawItem.BGColor=draw.BGColor;
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_TEXT')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
this.GetKLineData(drawItem.DrawData, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_SVGICON')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData={ Icon:draw.DrawData.Icon, Family:draw.DrawData.Family };
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='DRAWSVG')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
if (draw.AutoPosition) drawItem.AutoPosition=draw.AutoPosition;
drawItem.DrawData={ Data:this.FittingMultiText(draw.Data,date,time,hqChart), Family:draw.Family, TextFont:draw.TextFont, EnableTooltip:draw.EnableTooltip, IsDrawFirst:draw.IsDrawFirst };
this.GetKLineData(drawItem.DrawData.Data, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="MULTI_HTMLDOM") //外部自己创建dom
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.Callback=draw.Callback;
drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
this.GetKLineData(drawItem.DrawData, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="COLOR_KLINE")
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
var klineOption=this.FittingMultiText(draw.DrawData.KLine,date,time,hqChart);
var mapKLineOption=new Map();
for(var i in klineOption)
{
var item=klineOption[i];
mapKLineOption.set(item.Index,item);
}
drawItem.DrawData={ KLine:mapKLineOption };
if (draw.Color) outVarItem.Color=draw.Color;
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="KLINE_BG")
{
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData={ };
drawItem.DrawData.Color=draw.Color;
drawItem.DrawData.Angle=draw.Angle;
if (draw.Ver==2.0) drawItem.DrawData.Data=this.FittingKLineBG_V2(draw.DrawData, hqChart);
else drawItem.DrawData.Data=this.FittingKLineBG(draw.DrawData, hqChart);
outVarItem.Draw=drawItem;
outVarItem.Name=draw.DrawType;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_POINT_LINE')
{
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData={ };
drawItem.DrawData.Color=draw.Color;
drawItem.DrawData.PointRadius=draw.PointRadius;
drawItem.DrawData.PointColor=draw.PointColor;
drawItem.DrawData.LineWidth=draw.LineWidth;
drawItem.DrawData.Data=this.FittingMultiPointLine(draw.DrawData, hqChart);
outVarItem.Draw=drawItem;
//outVarItem.Name=draw.DrawType;
result.push(outVarItem);
}
else if (draw.DrawType=="PARTLINE")
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
if (draw.LineWidth) outVarItem.LineWidth=draw.LineWidth;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.CLIP_COLOR_STICK)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.Data,date,time,hqChart);
outVarItem.Draw=drawItem;
if (draw.LineWidth) outVarItem.LineWidth=draw.LineWidth;
if (draw.UpColor) outVarItem.UpColor=draw.UpColor;
if (draw.DownColor) outVarItem.DownColor=draw.DownColor;
result.push(outVarItem);
}
else if (draw.DrawType=="DRAWCOLORKLINE")
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
if (draw.Color) drawItem.Color=draw.Color;
if (IFrameSplitOperator.IsBool(draw.IsEmptyBar)) drawItem.IsEmptyBar=draw.IsEmptyBar;
result.push(outVarItem);
}
else
{
var find=g_ScriptIndexChartFactory.Get(draw.DrawType); //外部挂接
if (find && find.KLineFittingCallback)
{
if (find.KLineFittingCallback(item, outVarItem, { Date:date, Time:time, HQChart:hqChart }, this))
result.push(outVarItem);
}
}
}
}
return result;
}
// h, high, low l. c, close
this.GetKLineData=function(data,hqChart)
{
if (!data) return;
if (!Array.isArray(data)) return;
if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
var kData=hqChart.SourceData; //走势图分钟数据
else
var kData=hqChart.ChartPaint[0].Data; //K线
for(var i in data)
{
var item=data[i];
if (!IFrameSplitOperator.IsString(item.Value)) continue;
if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
if (item.Index<0 || item.Index>=kData.Data.length) continue;
var valueName=item.Value.toUpperCase();
var kItem=kData.Data[item.Index];
switch(valueName)
{
case "HIGH":
case "H":
item.Value=kItem.High;
break;
case "L":
case "LOW":
item.Value=kItem.Low;
break;
case "C":
case "CLOSE":
item.Value=kItem.Close;
break;
}
}
}
this.FittingKLineBG=function(data, hqChart)
{
var kData=hqChart.ChartPaint[0].Data; //K线
var result=[];
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
var bFill=false;
for(var i=0,j=0;i<kData.Data.length;)
{
result[i]=0;
var kItem=kData.Data[i];
if (j>=data.length)
{
++i;
continue;
}
var dataItem=data[j];
if (dataItem.Date<kItem.Date)
{
++j;
}
else if (dataItem.Date>kItem.Date)
{
++i;
}
else
{
bFill=true;
result[i]=1;
++j;
++i;
}
}
if (bFill) return result;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
{
var bFill=false;
for(var i=0,j=0;i<kData.Data.length;)
{
result[i]=0;
var kItem=kData.Data[i];
if (j>=data.length)
{
++i;
continue;
}
var dataItem=data[j];
if (dataItem.Date<kItem.Date || (dataItem.Date==kItem.Date && dataItem.Time<kItem.Time))
{
++j;
}
else if (dataItem.Date>kItem.Date || (dataItem.Date==kItem.Date && dataItem.Time>kItem.Time))
{
++i;
}
else
{
bFill=true;
result[i]=1;
++j;
++i;
}
}
if (bFill) return result;
}
return null;
}
this.FittingKLineBG_V2=function(data, hqChart) //2.0版本通过 [{ Start:, End: }, .....]来填充背景色
{
var kData=hqChart.ChartPaint[0].Data; //K线
var result=[];
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
var bFill=false;
for(var i=0,j=0;i<kData.Data.length;++i)
{
result[i]=0;
var kItem=kData.Data[i];
var date=kItem.Date;
for(j=0;j<data.length;++j)
{
var rangeItem=data[j];
if (date>=rangeItem.Start.Date && date<=rangeItem.End.Date)
{
result[i]=1;
bFill=true;
break;
}
}
}
if (bFill) return result;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
{
var aryRange=[];
for(var i=0;i<data.length;++i)
{
var item=data[i];
var startDatetime=item.Start.Date*10000;
if (IFrameSplitOperator.IsNumber(item.Start.Time)) startDatetime+=item.Start.Time;
var endDatetime=item.End.Date*10000;
if (IFrameSplitOperator.IsNumber(item.End.Time)) endDatetime+=item.End.Time;
aryRange.push({ Start:startDatetime , End:endDatetime});
}
var bFill=false;
for(var i=0,j=0;i<kData.Data.length; ++i)
{
result[i]=0;
var kItem=kData.Data[i];
var date=kItem.Date*10000+kItem.Time;
for(j=0;j<aryRange.length;++j)
{
var rangeItem=aryRange[j];
if (date>=rangeItem.Start && date<=rangeItem.End)
{
result[i]=1;
bFill=true;
break;
}
}
}
if (bFill) return result;
}
return null;
}
this.FittingMinuteData=function(jsonData, hqChart)
{
var outVar=jsonData.outvar;
var date=jsonData.date;
var time=jsonData.time;
var result=[];
for(var i=0;i<outVar.length;++i)
{
var item=outVar[i];
var outVarItem={ Name:item.name,Type:item.type };
if (IFrameSplitOperator.IsBool(item.IsShowTitle)) outVarItem.IsShowTitle = item.IsShowTitle; //是否显示指标标题
if (item.data)
{
outVarItem.Data=this.FittingMinuteArray(item.data,date,time,hqChart);
if (item.color) outVarItem.Color=item.color;
if (item.linewidth>=1) outVarItem.LineWidth=item.linewidth;
if (item.isshow==false) outVarItem.IsShow = false;
if (item.isexdata==true) outVarItem.IsExData = true;
if (item.BreakPoint) outVarItem.BreakPoint=item.BreakPoint;
if (item.UpColor) outVarItem.UpColor=item.UpColor;
if (item.DownColor) outVarItem.DownColor=item.DownColor;
if (IFrameSplitOperator.IsBool(item.isDotLine)) outVarItem.IsDotLine = item.isDotLine;
if (IFrameSplitOperator.IsNonEmptyArray(item.lineDash)) outVarItem.LineDash=item.lineDash;
if (IFrameSplitOperator.IsBool(item.isSingleLine)) outVarItem.IsSingleLine=item.isSingleLine;
result.push(outVarItem);
}
else if (item.Draw)
{
var draw=item.Draw;
var drawItem={};
if (draw.DrawType=='DRAWICON') //图标
{
drawItem.Icon=draw.Icon;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMinuteArray(draw.DrawData,date,time,hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='DRAWTEXT') //文本
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMinuteArray(draw.DrawData,date,time,hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='STICKLINE') //柱子
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.Width=draw.Width;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMinuteArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.OVERLAY_BARS)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.BarName=draw.BarName;
drawItem.BarColor=draw.BarColor;
drawItem.LineWidth=draw.LineWidth;
drawItem.DrawData=this.FittingMinuteArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType==SCRIPT_CHART_NAME.CLIP_COLOR_STICK)
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMinuteArray(draw.Data,date,time,hqChart);
outVarItem.Draw=drawItem;
if (draw.Option) outVarItem.Option=draw.Option;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_LINE')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart);
for(var k in drawItem.DrawData)
{
this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
}
outVarItem.Draw=drawItem;
if (draw.LineDash) drawItem.LineDash=draw.LineDash;
if (draw.Arrow) drawItem.Arrow=draw.Arrow;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_POINT')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart);
if (IFrameSplitOperator.IsNonEmptyArray(drawItem.DrawData))
{
for(var k=0; k<drawItem.DrawData.length; ++k)
{
this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
}
}
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_TEXT')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
this.GetKLineData(drawItem.DrawData, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='MULTI_SVGICON')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData={ Icon:draw.DrawData.Icon, Family:draw.DrawData.Family };
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=='DRAWSVG')
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
if (draw.AutoPosition) drawItem.AutoPosition=draw.AutoPosition;
drawItem.DrawData={ Data:this.FittingMultiText(draw.Data,date,time,hqChart), Family:draw.Family, TextFont:draw.TextFont ,EnableTooltip:draw.EnableTooltip,IsDrawFirst:draw.IsDrawFirst };
this.GetKLineData(drawItem.DrawData.Data, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="MULTI_HTMLDOM") //外部自己创建dom
{
drawItem.Text=draw.Text;
drawItem.Name=draw.Name;
drawItem.DrawType=draw.DrawType;
drawItem.Callback=draw.Callback;
drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
this.GetKLineData(drawItem.DrawData, hqChart);
outVarItem.Draw=drawItem;
result.push(outVarItem);
}
else if (draw.DrawType=="DRAWCOLORKLINE")
{
drawItem.Name=draw.Name;
drawItem.Type=draw.Type;
drawItem.DrawType=draw.DrawType;
drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1);
outVarItem.Draw=drawItem;
if (draw.Color) drawItem.Color=draw.Color;
if (IFrameSplitOperator.IsBool(draw.IsEmptyBar)) drawItem.IsEmptyBar=draw.IsEmptyBar;
result.push(outVarItem);
}
else
{
var find=g_ScriptIndexChartFactory.Get(draw.DrawType); //外部挂接
if (find && find.MinuteFittingCallback)
{
if (find.MinuteFittingCallback(item, outVarItem, { Date:date, Time:time, HQChart:hqChart }, this))
result.push(outVarItem);
}
}
}
}
return result;
}
//matchType 0=精确匹配(默认) 5=模糊匹配
this.FittingMinuteArray=function(sourceData,date,time,hqChart,matchType)
{
var minutedata=hqChart.SourceData;; //分钟线
var arySingleData=[];
for(var i in sourceData)
{
var value=sourceData[i];
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=date[i];
if (time && i<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData;
if (matchType==5)
aryFittingData=minutedata.GetMinuteFittingDataV2(arySingleData); //数据和主图K线拟合
else
aryFittingData=minutedata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合 精确匹配(默认)
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
return result;
}
this.FittingMultiPointLine=function(data, hqChart)
{
var period=hqChart.Period; //周期
var arySrouceData=data.Data;
var aryData=[];
if (ChartData.IsDayPeriod(period,true)) //日线
{
//arySrouceData.sort((a,b)=> { return a.Date-b.Date});
var firstItem=arySrouceData[0];
var kdata=hqChart.ChartPaint[0].Data; //K线
var firstKItem=kdata.Data[0];
var kIndex=0, dataIndex=0;
if (firstItem.Date>firstKItem.Date)
{
var preIndex=0;
for(kIndex=0;kIndex<kdata.Data.length;++kIndex)
{
var kItem=kdata.Data[kIndex];
if (kItem.Date==firstItem.Date)
break;
if (kItem.Date>firstItem.Date)
{
kIndex=preIndex;
break;
}
preIndex=kIndex;
}
}
else
{
for(dataIndex=0;dataIndex<arySrouceData.length;++dataIndex)
{
var item=arySrouceData[dataIndex];
if (item.Date>=firstKItem.Date)
break;
}
}
var preItem=null;
for(var i=kIndex, j=dataIndex; i<kdata.Data.length && j<arySrouceData.length; )
{
var kItem=kdata.Data[i];
var item=arySrouceData[j];
if (item.Date<=kItem.Date)
{
if (!aryData[i]) aryData[i]=[];
aryData[i].push({Date:item.Date, Value:item.Value, Data:item.Data, KDate:kItem.Date, Type:1 });
preItem=item;
++j;
}
else
{
if (preItem && !aryData[i]) aryData[i]={ Date:preItem.Date, Value:preItem.Value , Type: 0 };
++i;
}
}
if (preItem)
{
for( ;i<kdata.Data.length; ++i) //补齐最后的数据
{
if (!aryData[i]) aryData[i]={ Date:preItem.Date, Value:preItem.Value , Type: 0 };
}
}
return aryData;
}
else if (ChartData.IsMinutePeriod(period,true)) //分钟线
{
var kdata=hqChart.ChartPaint[0].Data; //K线
return aryData;
}
}
}
// 本地json数据指标
function LocalJsonDataIndex(name,args,option)
{
this.newMethod=ScriptIndex; //派生
this.newMethod(name,null,args,null);
delete this.newMethod;
this.JsonData; //json格式数据
if (option.JsonData) this.JsonData=option.JsonData;
this.RequestData=function(hqChart,windowIndex,hisData)
{
if (!this.JsonData)
{
console.warn("[LocalJsonDataIndex::RequestData] JsonData is null");
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback('json 数据不能为空');
return;
}
this.OutVar=this.FittingData(this.JsonData,hisData);
this.BindData(hqChart,windowIndex,hisData);
}
this.FittingData=function(jsonData, hisData)
{
outVar=jsonData.OutVar;
date=jsonData.Date;
time=jsonData.Time;
result=[];
for(i in outVar)
{
item=outVar[i];
JSConsole.Complier.Log('[LocalJsonDataIndex::FittingData] item', item);
if (item.Type!=0 && item.Type!=3) //复杂的图形不支持
{
console.warn("[LocalJsonDataIndex::FittingData] can't support ", item.Name, item.Type);
continue;
}
var indexData=[];
outVarItem={Name:item.Name,Type:item.Type}
for(j in item.Data)
{
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=date[j];
if (time && j<time.length) indexItem.Time=time[j];
indexItem.Value=item.Data[j];
indexData.push(indexItem);
}
if (hisData.Period<4)
var aryFittingData=hisData.GetFittingData(indexData); //数据和主图K线拟合
else
var aryFittingData=hisData.GetMinuteFittingData(indexData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
outVarItem.Data=bindData.GetValue();
result.push(outVarItem)
}
return result;
}
}
////////////////////////////////////////////////////////////////////////
// 无UI指标执行
// obj: { Name:指标名字 , ID:指标ID , Script:指标脚本, Args:指标参数, ErrorCallback:错误回调 }
//
///////////////////////////////////////////////////////////////////////
function ScriptIndexConsole(obj)
{
this.ID; //指标ID
this.Name; //指标名字
this.Script; //脚本
this.Arguments=[]; //参数
this.ClassName='ScriptIndexConsole';
this.ErrorCallback; //执行错误回调
this.FinishCallback; //执行完成回调
this.IsSectionMode=false; //截面报表模式
this.NetworkFilter; //数据接口
this.IsApiPeriod=false;
if (obj)
{
if (obj.Name) this.Name=obj.Name;
if (obj.Script) this.Script=obj.Script;
if (obj.ID) this.ID=obj.ID;
if (obj.Args) this.Arguments=obj.Args;
if (obj.ErrorCallback) this.ErrorCallback=obj.ErrorCallback;
if (obj.FinishCallback) this.FinishCallback=obj.FinishCallback;
if (obj.IsSectionMode) this.IsSectionMode=obj.IsSectionMode;
if (obj.NetworkFilter) this.NetworkFilter=obj.NetworkFilter;
if (IFrameSplitOperator.IsBool(obj.IsApiPeriod)) this.IsApiPeriod=obj.IsApiPeriod;
}
//执行脚本
//obj:
// HQDataType:(HQ_DATA_TYPE), Period:周期, Right:复权
// Stock: {Name:, Symbol:}, Request: { MaxDataCount:请求K线数据个数, MaxMinuteDayCount:请求分钟数据天数, TradeDate: 历史走势图才用}, :
// Data: 当前计算数据(周期|复权以后), Source: 原始股票数据
this.ExecuteScript=function(obj)
{
this.OutVar=[];
let param= { Self:this };
let option=
{
HQDataType:obj.HQDataType,
Symbol:obj.Stock.Symbol,
Name:obj.Stock.Name,
Period:obj.Period,
Right:obj.Right,
Callback:this.RecvResultData, CallbackParam:param,
Async:true,
MaxRequestDataCount:obj.Request.MaxDataCount,
MaxRequestMinuteDayCount:obj.Request.MaxMinuteDayCount,
Arguments:this.Arguments,
IsSectionMode:this.IsSectionMode,
ClassName:'ScriptIndexConsole',
NetworkFilter:this.NetworkFilter,
IsApiPeriod:this.IsApiPeriod,
Self:this,
};
if (obj.HQDataType===HQ_DATA_TYPE.HISTORY_MINUTE_ID) option.TrateDate=obj.Request.TradeDate;
if (obj.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) option.DayCount=obj.DayCount;
if (obj.Data) option.Data=obj.Data; //K线数据
let code=this.Script;
let run=JSComplier.Execute(code,option,this.ErrorCallback);
}
this.RecvResultData=function(outVar,param)
{
var self=param.Self;
var jsExec=param.JSExecute;
var date=null;
if (jsExec.SymbolData.Data)
date=jsExec.SymbolData.Data.GetDate();
var result=
{
Out:outVar,
Date:date, //日期对应 上面的数据
Stock:{ Name:jsExec.SymbolData.Name, Symbol:jsExec.SymbolData.Symbol }, //股票信息
Index: { Name:self.Name, ID:self.ID } //指标信息
};
if (jsExec.SymbolData.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID || jsExec.SymbolData.DataType==HQ_DATA_TYPE.MINUTE_ID) result.Time=jsExec.SymbolData.Data.GetTime();
else if (jsExec.SymbolData.DataType==HQ_DATA_TYPE.KLINE_ID && ChartData.IsMinutePeriod(jsExec.SymbolData.Period,true)) result.Time=jsExec.SymbolData.Data.GetTime();
//JSConsole.Complier.Log('[ScriptIndexConsole::RecvResultData] outVar ', outVar);
if (self.FinishCallback) self.FinishCallback(result, param.JSExecute);
}
}
ScriptIndexConsole.SetDomain = function (domain, cacheDomain) //修改API地址
{
JSComplier.SetDomain(domain,cacheDomain);
}
function DownloadFinanceData(obj)
{
this.Url=obj.Url;
this.RealtimeUrl=obj.RealtimeUrl;
this.Job=obj.Job;
this.Symbol=obj.Symbol;
this.Args=obj.Args;
this.DataKey=obj.DataKey;
this.RecvCallback=obj.Callback;
this.ErrorCallback=obj.ErrorCallback;
this.Download=function()
{
var id=this.Args[0];
switch(id)
{
case 1: //FINANCE(1) 总股本(随时间可能有变化) 股
case 7: //FINANCE(7) 流通股本(随时间可能有变化) 股
case "EXCHANGE": //换手率
this.DownloadHistoryData(id);
break;
case 3:
this.GetSymbolType(id);
break;
case 9: //FINANCE(9) 资产负债率
case 18: //FINANCE(18) 每股公积金
case 30: //FINANCE(30) 净利润
case 32: //FINANCE(32) 每股未分配利润
case 33: //FINANCE(33) 每股收益(折算为全年收益),对于沪深品种有效
case 34: //FINANCE(34) 每股净资产
case 38: //FINANCE(38) 每股收益(最近一期季报)
case 40: //FINANCE(40) 流通市值
case 41: //FINANCE(41) 总市值
case 42: //FINANCE(42) 上市的天数
case 43: //FINANCE(43) 利润同比
case "CAPITAL":
case "TOTALCAPITAL":
//定制
case 100: //股东人数
this.DownloadRealtimeData(id);
break;
default:
this.DownloadRealtimeData(id);
break;
}
}
//FINANCE(3) 沪深品种类型
//0:指数,1:A股主板,2:中小板,3:创业板,4:科创板,5:B股,6:债券,7:基金,8:权证,9:其它,10:非沪深品种
this.GetSymbolType=function(id)
{
var value=1;
if (MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) value=0;
var data={ Date:null, Value:value };
this.RecvCallback(data,this.Job, this.DataKey);
}
//最新一期数据
this.DownloadRealtimeData=function(id)
{
var self=this;
var fieldList=this.GetFieldList();
if (!fieldList)
{
if (this.Job.FunctionName2) message=`${this.Job.FunctionName2} can't support.`;
else if (this.Job.FunctionName) message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`;
else message=`${this.Args[0]} can't support.`;
this.ErrorCallback(message);
self.RecvCallback(null, self.Job, self.DataKey);
return;
}
//请求数据
JSNetwork.HttpRequest({
url: this.RealtimeUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"condition":[ ] ,
"start": 0,
"end": 10
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
var data=self.RealtimeDataToHQChartData(recvData);
self.RecvCallback(data, self.Job, self.DataKey);
}
});
}
//历史数据
this.DownloadHistoryData=function(id)
{
var self=this;
var fieldList=this.GetFieldList();
if (!fieldList)
{
message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`;
this.ErrorCallback(message);
self.RecvCallback(null, self.Job, self.DataKey);
return;
}
//请求数据
JSNetwork.HttpRequest({
url: this.Url,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"condition":[ ] ,
"start": 0,
"end": 200
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
var data=self.ToHQChartData(recvData);
if (data) //排序
data.sort(function (a, b) { return (a.Date - b.Date) });
self.RecvCallback(data, self.Job, self.DataKey);
}
});
}
this.GetFieldList=function()
{
var id=this.Args[0];
switch(id)
{
case 1:
return ["capital.total", "capital.date"];
case 7:
return ["capital.a", "capital.date"];
case "EXCHANGE":
return ["capital.a", "capital.date"];
case 9:
return ["finance.peruprofit","symbol","date"];
case 18:
return ["finance.percreserve","symbol","date"];
case 30:
return ["finance.nprofit","symbol","date"];
case 32:
return ["finance.peruprofit","symbol","date"];
case 33:
return ["finance.persearning","symbol","date"];
case 34:
return ["finance.pernetasset","symbol","date"];
case 38:
return ["finance.persearning","symbol","date"];
case 40:
return ["capital.a", "capital.date","symbol","date", "price"];
case 41:
return ["capital.total", "capital.date","symbol","date","price"];
case "CAPITAL":
return ["capital.a", "capital.date","symbol","date"];
case "TOTALCAPITAL":
return ["capital.total", "capital.date","symbol","date"];
case 42:
return ["company.releasedate","symbol","date"];
case 43:
return ["dividendyield","symbol","date"];
case 100:
return ["shareholder","symbol","date"]
default:
return null;
}
}
//最新报告期数据
this.RealtimeDataToHQChartData=function(recvData,id)
{
if (!recvData.stock || recvData.stock.length!=1) return null;
var stock=recvData.stock[0];
var id=this.Args[0];
var date=stock.date;
switch(id)
{
case 9:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.peruprofit };
case 18:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.percreserve };
case 30:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.nprofit };
case 32:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.peruprofit };
case 33:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.persearning };
case 34:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.pernetasset };
case 38:
if (!stock.finance) return null;
return { Date:date, Value:stock.finance.persearning };
case 40: //FINANCE(40) 流通市值
if (!stock.capital) return null;
return { Date:date, Value:stock.capital.a*stock.price }; //流通股*最新价格
case 41: //FINANCE(41) 总市值
if (!stock.capital) return null;
return { Date:date, Value:stock.capital.total*stock.price }; //总股本*最新价格
case 42: //FINANCE(42) 上市的天数
if (!stock.company) return null;
{
var releaseDate=stock.company.releasedate;
var year=parseInt(releaseDate/10000);
var month=parseInt((releaseDate%10000)/100);
var day=releaseDate%100;
var firstDate=new Date(year, month-1, day);
var nowDate=new Date();
var days=parseInt((nowDate.getTime()-firstDate.getTime())/(1000 * 60 * 60 * 24));
return { Date:date, Value:days+1 };
}
case 43:
if (!stock.dividendyield) return null;
return { Date:date, Value:stock.dividendyield.quarter4 };
case 100:
if (!stock.shareholder) return null;
return { Date:date, Value:stock.shareholder.count };
case "CAPITAL":
if (!stock.capital) return null;
return { Date:date, Value:stock.capital.a/100 }; //当前流通股本 手
case "TOTALCAPITAL":
if (!stock.capital) return null;
return { Date:date, Value:stock.capital.total/100 }; //当前流通股本 手
}
}
//历史数据转
this.ToHQChartData=function(recvData)
{
if (!recvData.stock || recvData.stock.length!=1) return null;
var aryData=[];
var setDate=new Set(); //有重复数据 去掉
var stock=recvData.stock[0];
var id=this.Args[0];
for(var i in stock.stockday)
{
var item=stock.stockday[i];
var hqchartItem=this.ToHQChartItemData(item,id);
if (hqchartItem && !setDate.has(hqchartItem.Date))
{
aryData.push(hqchartItem);
setDate.add(hqchartItem.Date);
}
}
return aryData;
}
this.ToHQChartItemData=function(item, id)
{
if (!item) return null;
var date=item.date;
switch(id)
{
case 1:
if (!item.capital) return null;
return { Date:date, Value:item.capital.total };
case 7:
case "EXCHANGE": //换手率 历史流通股本
if (!item.capital) return null;
return { Date:date, Value:item.capital.a };
default:
return null;
}
}
}
function DownloadGroupData(obj)
{
this.Url=obj.Url;
this.RealtimeUrl=obj.RealtimeUrl;
this.Job=obj.Job;
this.Symbol=obj.Symbol;
this.Args=obj.Args;
this.DataKey=obj.DataKey;
this.RecvCallback=obj.Callback;
this.ErrorCallback=obj.ErrorCallback;
this.Download=function()
{
var varName=this.Args[0];
switch(varName)
{
case "HYBLOCK":
case "DYBLOCK":
case "GNBLOCK":
this.DownloadGroupName(varName);
break;
}
}
this.DownloadGroupName=function(blockType)
{
var self=this;
var field=["name","symbol"];
if (blockType=="HYBLOCK") field.push("industry");
else if (blockType=="DYBLOCK") field.push("region");
else if (blockType=="GNBLOCK") field.push("concept");
JSNetwork.HttpRequest({
url: self.RealtimeUrl,
data:
{
"field": field,
"symbol": [this.Symbol]
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
var data=self.RecvGroupName(recvData);
self.RecvCallback(data, self.Job, self.DataKey, 1);
},
error: function(request)
{
self.ErrorCallback(request);
}
});
}
this.RecvGroupName=function(recvData)
{
if (!recvData.stock || recvData.stock.length!=1) return null;
var stock=recvData.stock[0];
var varName=this.Args[0];
var value=null;
if (varName=="HYBLOCK")
{
var industry=stock.industry;
if (!industry) return null;
var value;
for(var i in industry)
{
var item=industry[i];
value=item.name;
}
}
else if (varName=="DYBLOCK")
{
var region=stock.region;
if (!region) return null;
for(var i in region)
{
var item=region[i];
value=item.name;
}
}
else if (varName=="GNBLOCK")
{
var concept=stock.concept;
if (!concept) return null;
value="";
for(var i in concept)
{
var item=concept[i];
if (value.length>0) value+=' ';
value+=item.name;
}
}
return { Value:value };
}
}
/* 测试例子
var code1='VARHIGH:IF(VAR1<=REF(HH,-1),REF(H,BARSLAST(VAR1>=REF(HH,1))),DRAWNULL),COLORYELLOW;';
var code2='VAR1=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);';
var code3='mm1=1-2*-9+20;';
JSConsole.Complier.Log(code1+code2)
var tokens=JSComplier.Tokenize(code1+code2);
var ast=JSComplier.Parse(code2+code1);
JSConsole.Complier.Log(ast);
*/
//外部通达信的变量 这些需要外部自己计算
JSComplier.AddVariant({ Name:'DHIGH', Description:'不定周期最高价' } );
JSComplier.AddVariant({ Name:'DOPEN', Description:'不定周期开盘价' } );
JSComplier.AddVariant({ Name:'DLOW', Description:'不定周期最低价' } );
JSComplier.AddVariant({ Name:'DCLOSE', Description:'不定周期收盘价' } );
JSComplier.AddVariant({ Name:'DVOL', Description:'不定周期成交量价' } );
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
配色
*/
/*
不同风格行情配置文件
!!手机上字体大小需要*分辨率比
*/
/* umychart.js 里面已经有了
function GetDevicePixelRatio()
{
return window.devicePixelRatio || 1;
}
*/
//黑色风格
function GetBlackStyle()
{
var BLACK_STYLE=
{
BGColor:'rgb(0,0,0)', //背景色
TooltipBGColor: "rgb(255, 255, 255)", //背景色
TooltipAlpha: 0.92, //透明度
SelectRectBGColor: "rgba(1,130,212,0.06)", //背景色
// SelectRectAlpha: 0.06; //透明度
//K线颜色
UpBarColor: "rgb(238,21,21)", //上涨
DownBarColor: "rgb(25,158,0)", //下跌
UnchagneBarColor: "rgb(228,228,228)", //平盘
EmptyBarBGColor:'rgb(0,0,0)', //空心柱子背景色
SplashScreen:
{
BGColor:"rgba(112,128,144,0.5)",
TextColor:"rgb(230,230,230)",
},
HLCArea:
{
HighLineColor:'rgb(238,21,21)',
LowLineColor:"rgb(25,158,0)",
CloseLineColor:"rgb(156,156,156)",
LineWidth:2*GetDevicePixelRatio(),
UpAreaColor:"rgba(238,21,21, 0.3)",
DownAreaColor:"rgba(25,158,0, 0.3)",
},
Minute:
{
VolBarColor: null,
PriceColor: "rgb(25,180,231)",
AreaPriceColor:"rgba(63,158,255,.3)",
AvPriceColor: "rgb(255,236,0)",
PositionColor:'rgb(218,165,32)',
VolTitleColor:"rgb(190,190,190)",
Before:
{
BGColor:"rgba(105,105,105,0.5)",
AvPriceColor:'rgb(248,248,255)', //均线
CloseIcon:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
}
},
After:
{
BGColor:"rgba(105,105,105,0.5)",
AvPriceColor:'rgb(248,248,255)' //均线
},
NightDay:
{
NightBGColor:"rgb(22,22,22)",
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
Day: { Color:"rgb(153,153,153)", BGColor:"rgb(51,51,51)", BorderColor:"rgb(51,51,51)", Margin:{ Left:5, Top:2, Bottom:2, Right:5 } },
Night: { Color:"rgb(153,153,153)", BGColor:"rgb(51,51,51)", BorderColor:"rgb(51,51,51)", Margin:{ Left:5, Top:2, Bottom:2, Right:5 } },
}
},
PopMinuteChart:
{
BGColor:"rgba(0,0,0,0.95)",
BorderColor:"rgb(230,230,230)",
},
DefaultTextColor: "rgb(101,104,112)",
DefaultTextFont: 14*GetDevicePixelRatio() +'px 微软雅黑',
TitleFont: 13*GetDevicePixelRatio() +'px 微软雅黑', //标题字体(动态标题 K线及指标的动态信息字体)
IndexTitleColor:"rgb(190, 190 ,190)", //指标名字颜色
IndexTitleBGColor:'rgb(0,0,0)', //指标名字背景色
IndexTitleBorderColor:'rgb(211, 211, 211)', //指标名字边框颜色
IndexTitleBorderMoveOnColor:'rgb(30,144,255)', //指标名字边框颜色(鼠标在上面)
UpTextColor: "rgb(238,21,21)",
DownTextColor: "rgb(25,158,0)",
UnchagneTextColor: "rgb(190, 190 ,190)",
CloseLineColor: 'rgb(250,250,250)',
IndexTitle:
{
UpDownArrow: //数值涨跌箭头
{
UpColor:"rgb(238,21,21)", //上涨
DownColor:"rgb(25,158,0)", //下跌
UnchangeColor:"rgb(190, 190 ,190)" //不变
},
NameArrow:{ Color:"rgb(190, 190 ,190)", Space:2, Symbol:'▼' },
},
Title:
{
TradeIndexColor:'rgb(105,105,105)', //交易指标颜色
ColorIndexColor:'rgb(112,128,144)', //五彩K线颜色
VolColor:"rgb(190, 190 ,190)", //标题成交量
AmountColor:"rgb(190, 190 ,190)", //成交金额
DateTimeColor:"rgb(190, 190 ,190)", //时间,日期
SettingColor:"rgb(190, 190 ,190)", //周期,复权
NameColor:"rgb(190, 190 ,190)" , //股票名称
TurnoverRateColor:'rgb(101,104,112)', //换手率
PositionColor:"rgb(101,104,112)" //持仓
},
FrameBorderPen: "rgb(47,51,62)", //边框
MultiDayBorderPen:"rgba(236,236,236,0.5)",
FrameSplitPen: "rgba(236,236,236,0.13)", //分割线
FrameSplitTextColor: "rgb(220,220,220)", //刻度文字颜色
FrameSplitTextFont: 12*GetDevicePixelRatio() +"px 微软雅黑", //坐标刻度文字字体
FrameTitleBGColor: "rgb(0,0,0)", //标题栏背景色
OverlayIndexTitleBGColor:'rgba(0,0,0,0.7)', //叠加指标背景色
Frame:
{
XBottomOffset:2*GetDevicePixelRatio(), //X轴文字向下偏移
PercentageText: //百分比坐标文字颜色
{
PriceColor:'rgb(101,104,112)',
PercentageColor:"rgb(101,104,112)",
SplitColor:"rgb(101,104,112)",
Font:14*GetDevicePixelRatio() +"px 微软雅黑"
}
},
//叠加指标框架
OverlayFrame:
{
BolderPen:'rgb(130,130,130)', //指标边框线
TitleColor:'rgb(181,181,181)', //指标名字颜色
TitleFont:11*GetDevicePixelRatio() +'px arial', //指标名字字体
},
FrameLatestPrice : {
TextColor:'rgb(255,255,255)', //最新价格文字颜色
UpBarColor:"rgb(238,21,21)", //上涨
DownBarColor:"rgb(25,158,0)", //下跌
UnchagneBarColor:"rgb(190,190,190)", //平盘
BGAlpha:0.6,
EmptyBGColor:"rgb(0,0,0)"
},
CorssCursorBGColor: "rgb(43,54,69)", //十字光标背景
CorssCursorTextColor: "rgb(255,255,255)",
CorssCursorTextFont: 12*GetDevicePixelRatio() +"px 微软雅黑",
CorssCursorHPenColor: "rgb(130,130,130)", //十字光标线段颜色
CorssCursorVPenColor: "rgb(130,130,130)", //十字光标线段颜色
CorssCursor:
{
RightButton :
{
BGColor:'rgb(43,54,69)',
PenColor:'rgb(255,255,255)',
Icon: { Text:'\ue6a3', Color:'rgb(255,255,255)', Family:"iconfont", Size:18 }
}
},
//订单流配置
OrderFlow:
{
UpColor:{BG:'rgb(223,191,180)', Border:"rgb(196,84,86)" }, //阳线
DownColor:{ BG:"rgb(176,212,184)", Border:'rgb(66,94,74)' }, //阴线
UnchagneColor: {BG:"rgb(216,221,177)", Border:"rgb(209,172,129)"}, //平盘
Text:{ Color: "rgb(248,248,255)" , Family:'Arial', FontMaxSize:16, MaxValue:"8888" }, //文字
Line:{ UpDownColor: "rgb(220,220,220)", MiddleColor:"rgb(211,211,211)" } //最大, 最低,中间 竖线
},
KLine:
{
MaxMin: { Font: 12*GetDevicePixelRatio() +'px 微软雅黑', Color: 'rgb(255,250,240)', RightArrow:"→", LeftArrow:"←", HighYOffset:0, LowYOffset:0 }, //K线最大最小值显示
Info: //信息地雷
{
Investor:
{
ApiUrl:'/API/NewsInteract', //互动易
IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本
},
Announcement: //公告
{
ApiUrl:'/API/ReportList',
IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' }, //SVG 文本
IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' } //SVG 文本 //季报
},
Pforecast: //业绩预告
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本
},
Research: //调研
{
ApiUrl:'/API/InvestorRelationsList',
IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本
},
BlockTrading: //大宗交易
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本
},
TradeDetail: //龙虎榜
{
ApiUrl:'/API/StockHistoryDay',
IconFont: { Family:'iconfont', Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' } //SVG 文本
}
},
NumIcon:
{
Color:'rgb(251,80,80)',Family:'iconfont',
Text:[ '\ue649',
'\ue63b','\ue640','\ue63d','\ue63f','\ue645','\ue641','\ue647','\ue648','\ue646','\ue636',
'\ue635','\ue637','\ue638','\ue639','\ue63a','\ue63c','\ue63e','\ue642','\ue644','\ue643'
]
},
TradeIcon: //交易指标 图标
{
Family:'iconfont',
Buy: { Color:'rgb(255,15,4)', Text:'\ue683', HScreenText:'\ue682'},
Sell: { Color:'rgb(64,122,22)', Text:'\ue681',HScreenText:'\ue680'},
}
},
VirtualKLine:
{
Color:'rgb(119,136,153)',
LineDash:[2,2]
},
PriceGapStyple:
{
Line:{ Color:"rgb(128,128,128)" },
Text:{ Color:"rgb(219,220,220)", Font:`${12*GetDevicePixelRatio()}px 微软雅黑` }
},
Index:
{
LineColor: //指标线段颜色
[
"rgb(255,189,09)",
"rgb(22,198,255)",
"rgb(174,35,161)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
],
NotSupport: { Font: `${14*GetDevicePixelRatio()}px 微软雅黑`, TextColor: "rgb(250,250,250)" }
},
ColorArray: //自定义指标默认颜色
[
"rgb(255,174,0)",
"rgb(25,199,255)",
"rgb(175,95,162)",
"rgb(236,105,65)",
"rgb(68,114,196)",
"rgb(229,0,79)",
"rgb(0,128,255)",
"rgb(252,96,154)",
"rgb(42,230,215)",
"rgb(24,71,178)",
],
//按钮
Buttons:
{
CloseOverlayIndex:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
CloseWindow:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
ChangeIndex:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
OverlayIndex:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
ModifyIndexParam:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
//最大化, 最小化
MaxMinWindow:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
TitleWindow:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
ExportData:
{
MoveOnColor:"rgb(255,255,255)",
Color:"rgb(156,156,156)"
},
Tooltip:
{
//Font:12*GetDevicePixelRatio() +"px 微软雅黑",
Color:'rgb(204,204,204)',
ColorBG:'rgb(32,32,32)',
ColorBorder:'rgb(69,69,69)',
//BorderRadius:4,
//Mergin:{ Left:4, Right:4, Top:2, Bottom:4 },
}
},
DrawPicture: //画图工具
{
LineColor:
[
"rgb(41,98,255)"
],
PointColor:
[
"rgb(41,98,255)", //选中颜色
"rgb(89,135,255)", //moveon颜色
"rgb(0,0,0)" //空心点背景色
],
},
TooltipPaint :
{
BGColor:'rgba(20,20,20,0.8)', //背景色
BorderColor:'rgb(210,210,210)', //边框颜色
TitleColor:'rgb(210,210,210)', //标题颜色
TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑', //字体
DateTimeColor:'rgb(210,210,210)',
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(210,210,210)", //成交金额
PositionColor:"rgb(255,215,0)", //持仓量
},
PCTooltipPaint:
{
BGColor:'rgba(20,20,20,0.8)', //背景色
BorderColor:'rgb(210,210,210)', //边框颜色
TitleColor:'rgb(210,210,210)', //标题颜色
TitleFont:12*GetDevicePixelRatio() +'px 微软雅黑', //字体
DateTimeColor:'rgb(210,210,210)',
VolColor:"rgb(161,154,3)", //标题成交量
AmountColor:"rgb(161,154,3)", //成交金额
},
DialogTooltip:
{
BGColor:'rgb(20,20,20)', //背景色
BorderColor:'rgb(170,170,170)', //边框颜色
TitleColor:'rgb(250,250,250)', //标题颜色
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(210,210,210)", //成交金额
DateTimeColor:'rgb(210,210,210)',
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)", //持仓
TextColor:"rgb(210,210,210)", //数值名称
ValueColor:"rgb(210,210,210)", //数值
TitleBGColor:"rgb(200, 66, 69)",
},
FloatTooltip:
{
BGColor:'rgb(20,20,20)', //背景色
BorderColor:'rgb(170,170,170)', //边框颜色
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(210,210,210)", //成交金额
DateTimeColor:'rgb(210,210,210)',
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)", //持仓
TextColor:"rgb(210,210,210)", //数值名称
ValueColor:"rgb(210,210,210)", //数值
},
DialogSelectRect:
{
BGColor:'rgb(20,20,20)', //背景色
BorderColor:'rgb(170,170,170)', //边框颜色
TitleColor:'rgb(210,210,210)', //标题颜色
VolColor:"rgb(255, 185, 15)", //标题成交量
AmountColor:"rgb(210,210,210)", //成交金额
TextColor:"rgb(210,210,210)", //数值名称
ValueColor:"rgb(210,210,210)", //数值
TurnoverRateColor:'rgb(43,54,69)', //换手率
PositionColor:"rgb(255,0,255)" //持仓
},
DialogSearchIndex:
{
BGColor:'rgb(20,20,20)', //背景色
BorderColor:'rgb(170,170,170)', //边框颜色
TitleColor:'rgb(230,230,230)', //标题颜色
IndexNameColor:"rgb(210,210,210)",
GroupNameColor:"rgb(210,210,210)",
InputTextColor:"rgb(210,210,210)",
},
DialogPopKeyboard:
{
BGColor:'rgb(20,20,20)', //背景色
BorderColor:'rgb(170,170,170)', //边框颜色
TitleColor:'rgb(240,240,240)', //标题颜色
Input:
{
BGColor:"rgb(20,20,20)",
TextColor:"rgb(250,250,250)",
}
},
//走势图 信息地雷
MinuteInfo:
{
TextColor: 'rgb(84,143,255)',
Font: 14*GetDevicePixelRatio() +'px 微软雅黑',
PointColor:'rgb(38,113,254)',
LineColor:'rgb(120,167,255)',
TextBGColor:'rgba(255,255,255,1)'
},
DepthMapPaint:
{
LineColor:"rgba(255,185,15)",
AreaColor:"rgba(255,185,15,0.8)",
TextColor:"rgba(255,255,255)",
TextBGColor:'rgb(43,54,69)'
},
KLineYAxisBGPaint:
{
Font:12*GetDevicePixelRatio() +'px 微软雅黑',
TextColor:"rgb(255,255,255)",
LineColor:"rgb(255,255,255)"
},
//筹码分布图
StockChip:
{
InfoColor:'rgb(255,255,255)', //文字颜色
DayInfoColor:'rgb(0,0,0)' //周期颜色内文字颜色
},
//深度图
DepthChart:
{
BidColor: { Line:"rgb(82,176,123)", Area:"rgba(82,176,123,0.5)"}, //卖
AskColor: { Line:"rgb(207,76,89)", Area:"rgba(207,76,89, 0.5)"}, //买
LineWidth:4
},
DepthCorss:
{
BidColor: { Line:"rgb(82,176,123)" }, //卖
AskColor: { Line:"rgb(207,76,89)" }, //买
LineWidth:2, //线段宽度
LineDash:[3,3],
Tooltip:
{
BGColor:'rgba(54,54,54, 0.8)', TextColor:"rgb(203,215,224)",
Border:{ Top:5, Left:20, Bottom:5, Center: 5},
Font:14*GetDevicePixelRatio() +"px 微软雅黑",
LineHeight:16 //单行高度
}
},
ChartDrawVolProfile:
{
BGColor:"rgba(244,250,254,0.3)",
BorderColor:"rgba(255,255,255)",
VolLineColor:"rgb(232,5,9)",
UpVolColor:"rgba(103,179,238, 0.24)",
DownVolColor:"rgba(237,208,105,0.24)",
AreaUpColor:"rgb(103,179,238,0.7)",
AreaDonwColor:"rgba(237,208,105,0.7)",
Text:{ Color: "rgb(0,0,0)" , Family:'Arial', FontMaxSize:18, FontMinSize:6 }, //文字
},
//区间选择
RectSelect:
{
LineColor:"rgb(115,83,64)", //竖线
LineWidth:1*GetDevicePixelRatio(),
LineDotted:[3,3],
AreaColor:"rgba(26,13,7,0.5)", //面积
},
RectDrag:
{
LineColor:"rgb(220,220,220)",
LineWidth:1*GetDevicePixelRatio(),
BGColor:"rgba(220,220,220,0.2)", //面积
},
SelectedChart:
{
LineWidth:1,
LineColor:'rgb(55,100,100)',
Radius:4,
MinSpace:200, //点和点间最小间距
BGColor:"rgb(255,255,255)"
},
DragMovePaint:
{
TextColor:"rgb(255,255,255)",
//Font:14*GetDevicePixelRatio() +"px 微软雅黑"
},
SessionBreaksPaint:
{
BGColor:[null, "rgb(42,46,57)"],
SplitLine:{ Color:'rgb(73,133,231)', Width:1*GetDevicePixelRatio(), Dash:[5*GetDevicePixelRatio(),5*GetDevicePixelRatio()] }
},
//成交明细
DealList:
{
BorderColor:'rgb(38,38,41)', //边框线
Header:
{
Color:"RGB(245,245,245)",
Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
Font:{ Size:12, Name:"微软雅黑" }
},
Row:
{
Mergin:{ Top:2, Bottom:2 },
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 }
},
FieldColor:
{
Vol:"rgb(192,192,0)", //成交量
Time:"rgb(245,245,245)", //时间
Deal:"rgb(111,128,112)", //成交笔数
Index:"rgb(245,245,245)", //序号
BarTitle:'rgb(245,245,245)', //柱子文字
Text:"rgb(245,245,245)", //默认文本
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchagneTextColor:"rgb(228,228,228)" //平盘文字颜色
},
//报价列表
Report:
{
BorderColor:'rgb(38,38,41)', //边框线
SelectedColor:"rgb(49,48,56)", //选中行
Header:
{
Color:"RGB(245,245,245)",
SortColor:"rgb(255,0,0)",
//Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
Font:{ Size:12, Name:"微软雅黑" }
},
Item:
{
Mergin:{ Top:2, Bottom:4,Left:5, Right:5 },
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 },
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" }
},
//固定行
FixedItem:
{
Font:{ Size:15, Name:"微软雅黑"},
},
LimitBorder:
{
Color:"rgb(64,64,64)",
Mergin:{ Top:1, Bottom:1,Left:0, Right:0 },
},
FieldColor:
{
Index:"rgb(245,245,245)", //序号
Symbol:"rgb(255,255,255)",
Name:"rgb(255,255,255)",
Amount:"rgb(2,226,244)", //成交金额
Vol:"rgb(192,192,0)", //成交量
BarTitle:'rgb(245,245,245)', //柱子文字
Text:"rgb(245,245,245)", //默认文本
},
NameSymbolV2:
{
Name:{ Size:14, Name:"微软雅黑", Color: "rgb(250,250,250)"},
Symbol:{ Size:12, Name:"微软雅黑", Color: "rgb(190, 190, 190)"},
},
CloseLine:
{
CloseColor:"rgb(30,144,255)",
YCloseColor:"rgba(220,220,220,0.5)", //昨收线
AreaColor:'rgba(220,220,220,0.2)',
},
KLine:
{
UpColor:"rgb(255,0,0)",
DownColor:"rgb(0,128,0)",
UnchagneColor:'rgb(240,240,240)',
DataWidth:16,
DistanceWidth:3
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchagneTextColor:"rgb(228,228,228)", //平盘文字颜色
Tab:
{
Font:{ Size:12, Name:"微软雅黑" },
ScrollBarWidth:100,
ButtonColor:"rgb(13,12,15)",
BarColor:"rgb(48,48,48)",
BorderColor:'rgb(48,48,48)',
TabTitleColor:'rgb(153,153,153)',
TabSelectedTitleColor:'rgb(255,255,255)',
TabSelectedBGColor:"rgb(234,85,4)",
TabMoveOnTitleColor:"rgb(255,255,255)",
TabBGColor:"rgb(28,28,31)"
},
PageInfo:
{
Font:{ Size:15, Name:"微软雅黑"},
TextColor:"rgb(255,255,255)",
BGColor:"rgba(49,48,56,0.8)",
Mergin:{ Left:5, Right:5, Top:4, Bottom:2 },
},
DragRow:
{
Color:"rgba(255,250, 250,0.8)",
TextColor:'rgba(0,0, 0, 0.8)',
MoveRowColor:'rgb(135,206,250)',
SrcRowColor:'rgb(49,48,56)',
},
VScrollbar:
{
BarWidth:40,
ScrollBarHeight:60,
ButtonColor:"rgba(13,12,15,0.8)",
BarColor:"rgba(48,48,48,0.9)",
BorderColor:'rgba(48,48,48,0.9)',
BGColor:"rgba(211,211,211,0.5)",
},
CheckBox:
{
Family:"iconfont", Size:15,
Checked:{ Color:"rgb(69,147,238)", Symbol:"\ue6b3", DisableColor:"rgb(120,120,120)", MouseOnColor:"rgb(69,147,238)" },
Unchecked:{ Color:"rgb(210,210,210)", Symbol:"\ue6b4", DisableColor:"rgb(120,120,120)", MouseOnColor:"rgb(69,147,238)" },
},
Link:
{
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
TextColor:"rgb(0,144,255)",
Disable:{ TextColor:"rgb(211,211,211)" },
MouseOn:{ TextColor:"rgb(0,144,255)" },
},
ProgressBar:
{
BGColor:"rgb(20,24,28)",
BarColor:"rgb(47,124,197)",
Margin:{ Left:2, Right:2, Bottom:2, Top:2 },
BarMargin:{ Left:2, Right:2, Bottom:2, Top:2 },
TextColor:"rgb(230,230,230)",
Font:`${12*GetDevicePixelRatio()}px 微软雅黑`,
TextMargin:{ Left:40, Right:2, Bottom:2, Top:2},
Disable:{ BGColor:"rgb(61,61,61)", BarColor:"rgb(131,131,131)", TextColor:"rgb(159,161,159)"}
}
},
//T型报价
TReport:
{
BorderColor:'rgb(38,38,41)', //边框线
SelectedColor:"rgb(180,180,180)", //选中行
Header:
{
Color:"rgb(187,187,187)", //表头文字颜色
SortColor:"rgb(255,0,0)", //排序箭头颜色
Mergin:{ Left:5, Right:5, Top:4, Bottom:2}, //表头四周间距
Font:{ Size:14, Name:"微软雅黑" } //表头字体
},
Item:
{
Mergin:{ Top:2, Bottom:0,Left:5, Right:5 }, //单元格四周间距
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:3, Right:3, Bottom:2 },//单元格字体
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" }
},
CenterItem:
{
TextColor:"rgb(16,226,217)",
BaseTextColor:"rgb(60,60,83)",
BGColor:"rgb(65,65,65)"
},
FieldColor:
{
Index:"rgb(250,250,250)", //序号
Symbol:"rgb(60,60,60)",
Name:"rgb(250,250,250)",
Vol:"rgb(192,165,3)", //成交量
Position:"rgb(250,250,250)", //持仓量
Amount:"rgb(16,226,217)", //成交金额
Text:"rgb(250,250,250)", //默认文本
},
UpTextColor:"rgb(238,21,21)", //上涨文字颜色
DownTextColor:"rgb(25,158,0)", //下跌文字颜色
UnchangeTextColor:"rgb(187,187,187)", //平盘文字颜色
UpBGColor:"rgb(35,5,5)",
DownBGColor:"rgb(5,35,5)",
MarkBorder:
{
MaxPositionColor:"rgb(192,192,0)"
},
},
//键盘精灵
Keyboard:
{
BorderColor:'rgb(38,38,41)', //边框线
SelectedColor:"rgb(49,48,56)", //选中行
TextColor:"rgb(245,245,245)",
Item:
{
Mergin:{ Top:2, Bottom:0,Left:1, Right:1 }, //单元格四周间距
Font:{ Size:15, Name:"微软雅黑"},
BarMergin:{ Top:2, Left:0, Right:0, Bottom:2 },//单元格字体
NameFont:{ Size:14, Name:"微软雅黑" },
SymbolFont:{ Size:12, Name:"微软雅黑" }
},
VScrollbar:
{
ScrollBarHeight:50,
ButtonColor:"rgba(13,12,15,0.8)",
BarColor:"rgba(48,48,48,0.9)",
BorderColor:'rgba(48,48,48,0.9)',
BGColor:"rgba(211,211,211,0.5)",
BarWidth:{ Size:8 }
},
},
ScrollBar:
{
BorderColor:'rgb(38,38,41)', //边框线
XSplitTextColor:"rgb(240,240,240)",
XSplitLineColor:'rgb(38,38,41)',
Slider:
{
DateFont:`${14*GetDevicePixelRatio()}px 微软雅黑`,
DateColor:'rgb(240,240,240)',
BarColor:"rgb(105,105,105)",
BarAreaColor:"rgba(128,128,128,0.65)"
},
BGChart:
{
Color:"rgb(105,113,125)",
LineWidth:1,
AreaColor:"rgba(24,28,42,0.5)",
},
},
FrameButtomToolbar:
{
BGColor:"rgb(25,25,25)",
BorderColor:"rgb(60,60,60)",
Button:
{
Font:{ Family:"微软雅黑" },
TitleColor: { Selected:"rgb(255,255,255)", Default:"rgb(140,140,140)", MoveOn:"rgb(255,255,255)" },
BGColor: { Selected:"rgb(234,85,4)", Default:"rgb(25,25,25)", MoveOn:"rgb(59,59,59)" },
BorderColor:"rgb(60,60,60)",
}
}
};
return BLACK_STYLE;
}
var STYLE_TYPE_ID=
{
BLACK_ID:1, //黑色风格
WHITE_ID:0, //白色风格
}
function HQChartStyle()
{
}
HQChartStyle.GetStyleConfig=function(styleid) //获取一个风格的配置变量
{
switch (styleid)
{
case STYLE_TYPE_ID.BLACK_ID:
return GetBlackStyle();
case STYLE_TYPE_ID.WHITE_ID:
return new JSChartResource();
default:
return null;
}
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
封装成交明细表格控件 (H5版本)
*/
function JSDealChart(divElement)
{
this.DivElement=divElement;
this.JSChartContainer; //表格控件
//h5 canvas
this.CanvasElement=document.createElement("canvas");
this.CanvasElement.className='jsdeallist-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("[JSDealChart::JSDealList] divElement hasChildNodes", divElement.childNodes);
}
divElement.appendChild(this.CanvasElement);
this.OnSize=function()
{
//画布大小通过div获取
var height=parseInt(this.DivElement.style.height.replace("px",""));
this.CanvasElement.height=height;
this.CanvasElement.width=parseInt(this.DivElement.style.width.replace("px",""));
this.CanvasElement.style.width=this.CanvasElement.width+'px';
this.CanvasElement.style.height=this.CanvasElement.height+'px';
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.CanvasElement.height*=pixelTatio;
this.CanvasElement.width*=pixelTatio;
JSConsole.Chart.Log(`[JSDealChart::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.CreateJSDealChartContainer(option);
if (!chart) return false;
if (option.OnCreatedCallback) option.OnCreatedCallback(chart);
this.JSChartContainer=chart;
this.DivElement.JSChart=this; //div中保存一份
if (!option.Symbol)
{
chart.Draw();
}
else
{
chart.ChangeSymbol(option.Symbol);
}
}
this.CreateJSDealChartContainer=function(option)
{
var chart=new JSDealChartContainer(this.CanvasElement);
chart.Create(option);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) chart.SetColumn(option.Column);
if (IFrameSplitOperator.IsNumber(option.ShowOrder)) chart.ChartPaint[0].ShowOrder=option.ShowOrder;
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.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.EnableFilter=function(bEnable, option) //启动|关闭筛选
{
if (this.JSChartContainer) this.JSChartContainer.EnableFilter(bEnable, option);
}
//事件回调
this.AddEventCallback=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function')
{
JSConsole.Chart.Log('[JSDealChart:AddEventCallback] obj=', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSDealChart:ReloadResource] ');
this.JSChartContainer.ReloadResource(option);
}
}
}
JSDealChart.Init=function(divElement)
{
var jsChartControl=new JSDealChart(divElement);
jsChartControl.OnSize();
return jsChartControl;
}
function JSDealChartContainer(uielement)
{
this.ClassName='JSDealChartContainer';
this.Frame; //框架画法
this.ChartPaint=[]; //图形画法
this.ChartSplashPaint=null; //等待提示
this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息
this.Canvas=uielement.getContext("2d"); //画布
this.ShowCanvas=null;
this.Symbol;
this.Name;
this.TradeDate;
this.NetworkFilter; //数据回调接口
this.Data={ DataOffset:0, Data:[] }; //分笔数据
this.SourceData={DataOffset:0, Data:[] }; //原始分笔数据
this.IsShowLastPage=true; //显示最后一页
//事件回调
this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,}
this.AutoUpdateTimer=null;
this.AutoUpdateFrequency=15000; //更新频率
this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息
this.UIElement=uielement;
this.LastPoint=new Point(); //鼠标位置
this.IsDestroy=false; //是否已经销毁了
this.ChartDestory=function() //销毁
{
this.IsDestroy=true;
this.StopAutoUpdate();
}
this.EnableFilterData=false; //是否启动筛选
//筛选数据
this.FilterData=function(aryDeal)
{
if (!this.EnableFilterData) return aryDeal;
//过滤由外部处理
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FILTER_DEAL_DATA);
if (!event || !event.Callback) return aryDeal;
var sendData={ Data:aryDeal, Result:[] }; //{ Data:原始数据, Result:[] 过滤以后的数据 }
event.Callback(event,sendData,this);
return sendData.Result;
}
this.EnableFilter=function(bEnable, option) //启动|关闭筛选
{
this.EnableFilterData=bEnable;
this.Data.Data=this.FilterData(this.SourceData.Data);
this.Data.DataOffset=0;
if (option)
{
if (option.GotoLastPage==true) this.GotoLastPage();
if (option.Redraw==true) this.Draw();
}
}
this.CloneArray=function(aryData)
{
var data=[];
if (!IFrameSplitOperator.IsNonEmptyArray(aryData)) return data;
for(var i=0;i<aryData.length;++i)
{
data.push(aryData[i]);
}
return data;
}
//创建
//windowCount 窗口个数
this.Create=function(option)
{
this.UIElement.JSChartContainer=this;
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
//创建框架
this.Frame=new JSDealFrame();
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 ChartDealList();
chart.Frame=this.Frame;
chart.ChartBorder=this.Frame.ChartBorder;
chart.Canvas=this.Canvas;
chart.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartPaint[0]=chart;
if (option)
{
if (IFrameSplitOperator.IsBool(option.IsSingleTable)) chart.IsSingleTable=option.IsSingleTable; //单表模式
if (IFrameSplitOperator.IsBool(option.IsShowHeader)) chart.IsShowHeader=option.IsShowHeader; //是否显示表头
if (IFrameSplitOperator.IsBool(option.IsShowLastPage)) this.IsShowLastPage=option.IsShowLastPage; //是否显示最后一页
if (IFrameSplitOperator.IsNumber(option.BorderLine)) this.Frame.BorderLine=option.BorderLine; //边框
}
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.Draw=function()
{
if (this.UIElement.width<=0 || this.UIElement.height<=0) return;
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash)
{
this.Frame.Draw( { 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();
}
}
this.ChangeSymbol=function(symbol, option)
{
this.Symbol=symbol;
this.Data=null;
this.SourceData=null;
var chart=this.ChartPaint[0];
if (chart) chart.Data=null;
if (option && IFrameSplitOperator.IsNumber(option.TradeDate))
this.TradeDate=option.TradeDate;
if (!this.Symbol)
{
this.Draw();
return;
}
this.RequestDealData();
}
this.CancelAutoUpdate=function() //关闭停止更新
{
if (typeof (this.AutoUpdateTimer) == 'number')
{
clearTimeout(this.AutoUpdateTimer);
this.AutoUpdateTimer = null;
}
}
this.AutoUpdateEvent=function(bStart, explain) //自定更新事件, 是给websocket使用
{
var eventID=bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE:JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE;
if (!this.mapEvent.has(eventID)) return;
var self=this;
var event=this.mapEvent.get(eventID);
var data={ Stock:{ Symbol:this.Symbol, Name:this.Name, DayCount:this.DayCount }, Explain: explain };
if (bStart)
{
data.Callback=function(data) //数据到达更新回调
{
self.RecvDealUpdateData(data);
}
}
event.Callback(event,data,this);
}
//全量数据下载
this.RequestDealData=function()
{
this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
this.ChartSplashPaint.EnableSplash(true);
this.Draw();
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSDealChartContainer::RequestDealData', //类名::
Explain:'成交明细',
Request:{ Data: { symbol:self.Symbol, tradeDate:self.TradeDate } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvDealData(data);
self.AutoUpdateEvent(true,'JSDealChartContainer::RequestDealData');
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
var cacheUrl=`${g_JSChartResource.CacheDomain}/cache/dealday/today/${this.Symbol}.json`;
JSNetwork.HttpRequest({
url: cacheUrl,
type:"get",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvDealData(data);
self.AutoUpdate(1);
},
error: function(http,e)
{
self.ChartSplashPaint.EnableSplash(false);
self.AutoUpdate();
//self.RecvError(http,e,param);;
}
});
}
this.RecvDealData=function(data)
{
var aryDeal=JSDealChartContainer.JsonDataToDealData(data);
this.SourceData={ DataOffset:0, Data:aryDeal };
this.Data={ DataOffset:0, Data:this.FilterData(this.CloneArray(aryDeal)) };
this.Symbol=data.symbol;
this.Name=data.name;
var chart=this.ChartPaint[0];
chart.Data=this.Data;
chart.Symbol=this.Symbol;
chart.YClose=data.yclose;
chart.Open=data.open;
if (this.IsShowLastPage) //显示最后一屏
{
var pageSize=chart.GetPageSize(true);
var offset=aryDeal.length-pageSize;
if (offset<0) offset=0;
this.Data.DataOffset=offset;
}
this.Draw();
}
//增量数据下载
this.RequestDealUpdateData=function()
{
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSDealChartContainer::RequestDealUpdateData', //类名::函数名
Explain:'增量成交明细',
Request:{ Data: { symbol: self.Symbol } },
Self:this,
PreventDefault:false
};
if (this.Data && IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
var lastItem=this.Data.Data[this.Data.Data.length-1]; //最后一条数据
obj.LastItem=lastItem;
}
this.NetworkFilter(obj, function(data)
{
self.RecvDealUpdateData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return;
}
}
this.RecvDealUpdateData=function(data)
{
var aryDeal=JSDealChartContainer.JsonDataToDealData(data);
if (!IFrameSplitOperator.IsNonEmptyArray(aryDeal)) return;
if (data.UpdateType===1) //全量更新
{
this.SourceData.Data=aryDeal;
this.Data.Data=this.FilterData(this.CloneArray(aryDeal));
if (this.Data.DataOffset>= this.Data.Data.length) this.Data.DataOffset=0;
}
else
{
this.AddDealData(this.SourceData, aryDeal);
this.AddDealData(this.Data,this.FilterData(aryDeal));
}
this.Draw();
}
this.AddDealData=function(dealData, aryNewData)
{
if (!dealData.Data) //原来是空的
{
dealData.Data=aryNewData;
}
else
{
var pageSize=0;
var chart=this.ChartPaint[0];
if (chart) pageSize=chart.GetPageSize();
for(var i=0;i<aryNewData.length;++i)
{
dealData.Data.push(aryNewData[i]);
if (dealData.DataOffset+pageSize<dealData.Data.length)
++dealData.DataOffset;
}
}
}
this.AutoUpdate=function(waitTime) //waitTime 更新时间
{
this.CancelAutoUpdate();
if (!this.IsAutoUpdate) return;
if (!this.Symbol) return;
var self = this;
var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol);
if (marketStatus==0 || marketStatus==3) return; //闭市,盘后
var frequency=this.AutoUpdateFrequency;
if (marketStatus==1) //盘前
{
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},frequency);
}
else if (marketStatus==2) //盘中
{
this.AutoUpdateTimer=setTimeout(function()
{
self.RequestDealUpdateData();
},frequency);
}
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
this.AutoUpdateEvent(false,'JSDealChartContainer::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);
var chart=this.ChartPaint[0];
if (chart && this.Data && this.Data.DataOffset>0 && IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
var pageSize=chart.GetPageSize(true);
if (pageSize+this.Data.DataOffset>=this.Data.Data.length) //当前屏不能显示满,调整
this.GotoLastPage();
}
this.Draw();
}
this.SetSizeChange=function(bChanged)
{
var chart=this.ChartPaint[0];
if (chart) chart.SizeChange=bChanged;
}
this.OnWheel=function(e) //滚轴
{
JSConsole.Chart.Log('[JSDealChartContainer::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.ChartPaint[0];
if (!chart) return;
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
if (wheelValue<0) //下一页
{
if (this.GotoNextPage()) this.Draw();
}
else if (wheelValue>0) //上一页
{
if (this.GotoPreviousPage()) this.Draw();
}
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnKeyDown=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var keyID = e.keyCode ? e.keyCode :e.which;
switch(keyID)
{
case 38: //up
if (this.GotoPreviousPage()) this.Draw();
break;
case 40: //down
if (this.GotoNextPage()) this.Draw();
break;
}
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.GotoNextPage=function()
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
if (pageSize>this.Data.Data.length) return false;
var offset=this.Data.DataOffset+pageSize;
if (offset+pageSize==this.Data.Data.length-1) return false;
if (offset+pageSize>this.Data.Data.length) //最后一页不够一屏调整到满屏
{
this.Data.DataOffset=this.Data.Data.length-pageSize;
}
else
{
this.Data.DataOffset=offset;
}
return true;
}
this.GotoPreviousPage=function()
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
if (this.Data.DataOffset<=0) return false;
var pageSize=chart.GetPageSize();
var offset=this.Data.DataOffset;
offset-=pageSize;
if (offset<0) offset=0;
this.Data.DataOffset=offset;
return true;
}
this.GotoLastPage=function()
{
var chart=this.ChartPaint[0];
if (!chart) return;
//显示最后一屏
var pageSize=chart.GetPageSize(true);
var offset=this.Data.Data.length-pageSize;
if (offset<0) offset=0;
this.Data.DataOffset=offset;
}
this.SetColumn=function(aryColunm, option)
{
var chart=this.ChartPaint[0];
if (chart)
{
chart.SetColumn(aryColunm);
chart.SizeChange=true;
if (option && option.Redraw) this.Draw();
}
}
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)
{
this.SetSizeChange(true);
this.Draw();
}
}
}
JSDealChartContainer.JsonDataToDealData=function(data)
{
var symbol=data.symbol;
var result=[];
if (!IFrameSplitOperator.IsNonEmptyArray(data.detail)) return result;
//0=时间 1=价格 2=成交量 3=成交金额 4=BS 5=字符串时间 6=ID
for(var i=0;i<data.detail.length;++i)
{
var item=data.detail[i];
var dealItem={ Time:item[0], Price:item[1], Vol:item[2], BS:item[4], Amount:item[3] };
dealItem.Source=item;
if (item[5]) dealItem.StrTime=item[5];
if (item[6]) dealItem.ID=item[6];
result.push(dealItem);
}
return result;
}
function JSDealFrame()
{
this.ChartBorder;
this.Canvas; //画布
this.BorderColor=g_JSChartResource.DealList.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.DealList.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
}
this.Draw=function(option)
{
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 = 'left';
this.Canvas.textBaseline = 'bottom';
var x=this.ChartBorder.GetLeft()+5;
var y=this.ChartBorder.GetBottom()-5;
this.Canvas.fillText(text,x,y);
}
}
var DEAL_COLUMN_ID=
{
TIME_ID:0, //时间
PRICE_ID:1, //成交价格
VOL_ID:2, //成交量
DEAL_ID:3, //成交笔数
BS_ID:4,
UPDOWN_ID:5, //涨跌
STRING_TIME_ID:6, //字符串时间
INDEX_ID:7, //序号 从1开始
MULTI_BAR_ID:8, //多颜色柱子
CENTER_BAR_ID:9, //中心柱子
CUSTOM_TEXT_ID:10 //自定义文本
}
function ChartDealList()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartDealList'; //类名
this.IsDrawFirst=false;
this.GetEventCallback;
this.Data; //数据 { Data:[ { Time:, Price:, Vol:, BS:, StrTime } ], Offset: }
//this.Data={Offset:0, Data:[ {Time:925, Price:20.1, Vol:10000050, BS:1, Deal:45 }, {Time:925, Price:18.2, Vol:1150, BS:1, Deal:5 }] };
this.Symbol;
this.YClose; //昨收
this.Open; //开盘价
this.Decimal=2; //小数位数
this.IsSingleTable=false; //单表模式
this.IsShowHeader=true; //是否显示表头
this.ShowOrder=1; //0=顺序 1=倒序
this.SizeChange=true;
//涨跌颜色
this.UpColor=g_JSChartResource.DealList.UpTextColor;
this.DownColor=g_JSChartResource.DealList.DownTextColor;
this.UnchagneColor=g_JSChartResource.DealList.UnchagneTextColor;
this.BorderColor=g_JSChartResource.DealList.BorderColor; //边框线
//表头配置
this.HeaderFontConfig={ Size:g_JSChartResource.DealList.Header.Font.Size, Name:g_JSChartResource.DealList.Header.Font.Name };
this.HeaderColor=g_JSChartResource.DealList.Header.Color;
this.HeaderMergin=
{
Left:g_JSChartResource.DealList.Header.Mergin.Left,
Right:g_JSChartResource.DealList.Header.Mergin.Right,
Top:g_JSChartResource.DealList.Header.Mergin.Top,
Bottom:g_JSChartResource.DealList.Header.Mergin.Bottom
};
//表格内容配置
this.ItemFontConfig={ Size:g_JSChartResource.DealList.Row.Font.Size, Name:g_JSChartResource.DealList.Row.Font.Name };
this.RowMergin={ Top:g_JSChartResource.DealList.Row.Mergin.Top, Bottom:g_JSChartResource.DealList.Row.Mergin.Bottom };
this.BarMergin=
{
Top:g_JSChartResource.DealList.Row.BarMergin.Top,
Left:g_JSChartResource.DealList.Row.BarMergin.Left,
Right:g_JSChartResource.DealList.Row.BarMergin.Right,
Bottom:g_JSChartResource.DealList.Row.BarMergin.Bottom
};
//缓存
this.HeaderFont=12*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.RowCount=0;
this.TableWidth=0;
this.TableCount=0;
this.HeaderHeight=0;
this.Column=
[
{ Type:DEAL_COLUMN_ID.TIME_ID, Title:"时间", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Time, MaxText:"88:88:88" , Foramt:"HH:MM:SS"},
{ Type:DEAL_COLUMN_ID.PRICE_ID, Title:"价格", TextAlign:"center", Width:null, MaxText:"888888.88"},
{ Type:DEAL_COLUMN_ID.VOL_ID, Title:"成交", TextAlign:"right", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Vol, MaxText:"888888"},
{ Type:DEAL_COLUMN_ID.BS_ID, Title:"", TextAlign:"right", Width:null, MaxText:"擎" }
];
this.RectClient={};
this.ReloadResource=function(resource)
{
this.UpColor=g_JSChartResource.DealList.UpTextColor;
this.DownColor=g_JSChartResource.DealList.DownTextColor;
this.UnchagneColor=g_JSChartResource.DealList.UnchagneTextColor;
this.BorderColor=g_JSChartResource.DealList.BorderColor; //边框线
//表头配置
this.HeaderFontConfig={ Size:g_JSChartResource.DealList.Header.Font.Size, Name:g_JSChartResource.DealList.Header.Font.Name };
this.HeaderColor=g_JSChartResource.DealList.Header.Color;
this.HeaderMergin=
{
Left:g_JSChartResource.DealList.Header.Mergin.Left,
Right:g_JSChartResource.DealList.Header.Mergin.Right,
Top:g_JSChartResource.DealList.Header.Mergin.Top,
Bottom:g_JSChartResource.DealList.Header.Mergin.Bottom
};
//表格内容配置
this.ItemFontConfig={ Size:g_JSChartResource.DealList.Row.Font.Size, Name:g_JSChartResource.DealList.Row.Font.Name };
this.RowMergin={ Top:g_JSChartResource.DealList.Row.Mergin.Top, Bottom:g_JSChartResource.DealList.Row.Mergin.Bottom };
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
if (item.Type==DEAL_COLUMN_ID.TIME_ID || item.Type==DEAL_COLUMN_ID.STRING_TIME_ID)
item.TextColor=g_JSChartResource.DealList.FieldColor.Time;
else if (item.Type==DEAL_COLUMN_ID.VOL_ID)
item.TextColor=g_JSChartResource.DealList.FieldColor.Vol;
else if (item.Type==DEAL_COLUMN_ID.DEAL_ID)
item.TextColor=g_JSChartResource.DealList.FieldColor.Deal;
else if (item.Type==DEAL_COLUMN_ID.INDEX_ID)
item.TextColor=g_JSChartResource.DealList.FieldColor.Index;
}
}
this.SetColumn=function(aryColumn)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryColumn)) return;
this.Column=[];
for(var i=0;i<aryColumn.length;++i)
{
var item=aryColumn[i];
var colItem=this.GetDefaultColunm(item.Type);
if (!colItem) continue;
if (item.Title) colItem.Title=item.Title;
if (item.TextAlign) colItem.TextAlign=item.TextAlign;
if (item.TextColor) colItem.TextColor=item.TextColor;
if (item.MaxText) colItem.MaxText=item.MaxText;
if (item.Type==DEAL_COLUMN_ID.MULTI_BAR_ID || item.Type==DEAL_COLUMN_ID.CENTER_BAR_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex)) continue;
colItem.DataIndex=item.DataIndex; //柱子数据所在原始数据索引列
}
else if (item.Type==DEAL_COLUMN_ID.TIME_ID)
{
if (IFrameSplitOperator.IsString(item.Foramt)) colItem.Foramt=item.Foramt; //设置时间格式
}
this.Column.push(colItem);
}
}
this.GetDefaultColunm=function(id)
{
var DEFAULT_COLUMN=
[
{ Type:DEAL_COLUMN_ID.TIME_ID, Title:"时间", TextAlign:"center", Width:null , TextColor:g_JSChartResource.DealList.FieldColor.Time, MaxText:"88:88:88", Foramt:"HH:MM:SS" },
{ Type:DEAL_COLUMN_ID.PRICE_ID, Title:"价格", TextAlign:"center", Width:null, MaxText:"888888.88"},
{ Type:DEAL_COLUMN_ID.VOL_ID, Title:"成交", TextAlign:"right", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Vol, MaxText:"888888"},
{ Type:DEAL_COLUMN_ID.BS_ID, Title:"", TextAlign:"right", Width:null,MaxText:"擎" },
{ Type:DEAL_COLUMN_ID.DEAL_ID, Title:"笔数", TextAlign:"right", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Deal , MaxText:"8888"},
{ Type:DEAL_COLUMN_ID.UPDOWN_ID, Title:"涨跌", TextAlign:"right", Width:null, MaxText:"-8888.88"},
{ Type:DEAL_COLUMN_ID.STRING_TIME_ID, Title:"时间", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Time, MaxText:"88:88:88" },
{ Type:DEAL_COLUMN_ID.INDEX_ID, Title:"序号", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Index, MaxText:"88888" },
{ Type:DEAL_COLUMN_ID.MULTI_BAR_ID, Title:"柱子", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.BarTitle, MaxText:"888888" },
{ Type:DEAL_COLUMN_ID.CENTER_BAR_ID, Title:"柱子2", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.BarTitle, MaxText:"888888" },
{ Type:DEAL_COLUMN_ID.CUSTOM_TEXT_ID, Title:"自定义", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.Text, MaxText:"擎擎擎擎擎" },
];
for(var i=0;i<DEFAULT_COLUMN.length;++i)
{
var item=DEFAULT_COLUMN[i];
if (item.Type==id) return item;
}
return null;
}
this.Draw=function()
{
if (this.SizeChange) this.CalculateSize();
else this.UpdateCacheData();
this.DrawBorder();
this.DrawHeader();
this.DrawBody();
this.SizeChange=false;
}
//更新缓存变量
this.UpdateCacheData=function()
{
this.RectClient.Left=this.ChartBorder.GetLeft();
this.RectClient.Right=this.ChartBorder.GetRight();
this.RectClient.Top=this.ChartBorder.GetTop();
this.RectClient.Bottom=this.ChartBorder.GetBottom();
this.Decimal=GetfloatPrecision(this.Symbol);
}
this.GetPageSize=function(recalculate) //recalculate 是否重新计算
{
if (recalculate) this.CalculateSize();
var size=this.TableCount*this.RowCount;
return size;
}
this.CalculateSize=function() //计算大小
{
this.UpdateCacheData();
var pixelRatio=GetDevicePixelRatio();
this.HeaderFont=`${this.HeaderFontConfig.Size*pixelRatio}px ${ this.HeaderFontConfig.Name}`;
this.ItemFont=`${this.ItemFontConfig.Size*pixelRatio}px ${ this.ItemFontConfig.Name}`;
this.Canvas.font=this.ItemFont;
var sumWidth=0, itemWidth=0;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
itemWidth=this.Canvas.measureText(item.MaxText).width;
item.Width=itemWidth+4;
sumWidth+=item.Width;
}
var clientWidth=this.RectClient.Right-this.RectClient.Left;
this.TableCount=parseInt(clientWidth/sumWidth);
if (this.IsSingleTable) this.TableCount=1;
this.TableWidth=clientWidth/this.TableCount;
this.HeaderHeight=this.GetFontHeight(this.HeaderFont,"擎")+ this.HeaderMergin.Top+ this.HeaderMergin.Bottom;
if (!this.IsShowHeader) this.HeaderHeight=0;
this.RowHeight=this.GetFontHeight(this.ItemFont,"擎")+ this.HeaderMergin.Top+ this.HeaderMergin.Bottom;
this.RowCount=parseInt((this.RectClient.Bottom-this.RectClient.Top-this.HeaderHeight)/this.RowHeight);
}
this.DrawHeader=function()
{
if (!this.IsShowHeader) return;
var left=this.RectClient.Left+this.HeaderMergin.Left;
var top=this.RectClient.Top;
var y=top+this.HeaderMergin.Top+(this.HeaderHeight-this.HeaderMergin.Top-this.HeaderMergin.Bottom)/2;
this.Canvas.font=this.HeaderFont;
this.Canvas.fillStyle=this.HeaderColor;
for(var i=0, j=0;i<this.TableCount;++i)
{
var tableLeft=left+(this.TableWidth*i);
var textLeft=tableLeft;
for(j=0;j<this.Column.length;++j)
{
var item=this.Column[j];
var itemWidth=item.Width;
if (j==this.Column.length-1) itemWidth=this.TableWidth-(textLeft-tableLeft)-this.HeaderMergin.Right-this.HeaderMergin.Left;
var x=textLeft;
if (item.TextAlign=='center')
{
x=textLeft+itemWidth/2;
this.Canvas.textAlign="center";
}
else if (item.TextAlign=='right')
{
x=textLeft+itemWidth;
this.Canvas.textAlign="right";
}
else
{
this.Canvas.textAlign="left";
}
this.Canvas.textBaseline="middle";
this.Canvas.fillText(item.Title,x,y);
textLeft+=item.Width;
}
}
}
this.DrawBorder=function()
{
var left=ToFixedPoint(this.RectClient.Left);
var right=ToFixedPoint(this.RectClient.Right);
var top=ToFixedPoint(this.RectClient.Top);
var bottom=ToFixedPoint(this.RectClient.Bottom);
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.beginPath();
if (this.IsShowHeader)
{
this.Canvas.moveTo(left,top+this.HeaderHeight);
this.Canvas.lineTo(right,top+this.HeaderHeight);
}
var tableLeft=ToFixedPoint(left+this.TableWidth);
for(var i=1;i<this.TableCount;++i)
{
this.Canvas.moveTo(tableLeft,top);
this.Canvas.lineTo(tableLeft,bottom);
tableLeft=ToFixedPoint(tableLeft+this.TableWidth);
}
this.Canvas.stroke();
}
this.DrawBody=function()
{
if (!this.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.Canvas.font=this.ItemFont;
var top=this.RectClient.Top+this.HeaderHeight;
var left=this.RectClient.Left+this.HeaderMergin.Left;
var dataCount=this.Data.Data.length;
var index=this.Data.DataOffset;
if (this.ShowOrder==1)
{
var index=this.Data.DataOffset+(this.TableCount*this.RowCount);
if (index>=dataCount) index=dataCount-1;
for(var i=0,j=0;i<this.TableCount;++i)
{
var tableLeft=left+(this.TableWidth*i);
var textLeft=tableLeft;
var textTop=top;
for(j=0;j<this.RowCount && index>=0;++j, --index)
{
var dataItem=this.Data.Data[index];
this.DrawRow(dataItem, textLeft, textTop, index);
textTop+=this.RowHeight;
}
}
}
else
{
for(var i=0,j=0;i<this.TableCount;++i)
{
var tableLeft=left+(this.TableWidth*i);
var textLeft=tableLeft;
var textTop=top;
for(j=0;j<this.RowCount && index<dataCount;++j, ++index)
{
var dataItem=this.Data.Data[index];
this.DrawRow(dataItem, textLeft, textTop, index);
textTop+=this.RowHeight;
}
}
}
}
this.DrawRow=function(data, left, top, dataIndex, colIndex)
{
var tableLeft=left;
var tableRight=left+this.TableWidth;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
var textColor=item.TextColor;
var text=null;
var itemWidth=item.Width;
var textAlign=item.TextAlign;
if (left+itemWidth>tableRight) break;
if (i==this.Column.length-1) itemWidth=this.TableWidth-(left-tableLeft)-this.HeaderMergin.Right-this.HeaderMergin.Left;
if (item.Type==DEAL_COLUMN_ID.TIME_ID)
{
text=IFrameSplitOperator.FormatTimeString(data.Time,item.Foramt);
}
else if (item.Type==DEAL_COLUMN_ID.STRING_TIME_ID)
{
text=data.StrTime;
}
else if (item.Type==DEAL_COLUMN_ID.PRICE_ID)
{
if (data.Price>this.YClose) textColor=this.UpColor;
else if (data.Price<this.YClose) textColor=this.DownColor;
else textColor=this.UnchagneColor;
text=data.Price.toFixed(this.Decimal);
}
else if (item.Type==DEAL_COLUMN_ID.VOL_ID)
{
text=IFrameSplitOperator.FormatValueString(data.Vol,0);
textColor=this.GetVolColor(item, data);
}
else if (item.Type==DEAL_COLUMN_ID.DEAL_ID)
{
text=IFrameSplitOperator.FormatValueString(data.Deal,0);
}
else if (item.Type==DEAL_COLUMN_ID.BS_ID)
{
if (data.BS==1)
{
text="B";
textColor=this.UpColor;
}
else if (data.BS==2)
{
text="S";
textColor=this.DownColor;
}
}
else if (item.Type==DEAL_COLUMN_ID.UPDOWN_ID)
{
if (IFrameSplitOperator.IsNumber(this.YClose))
{
var value=data.Price-this.YClose;
text=value.toFixed(2);
if (value>0) textColor=this.UpColor;
else if (value<0) textColor=this.DownColor;
else textColor=this.UnchagneColor;
}
}
else if (item.Type==DEAL_COLUMN_ID.INDEX_ID)
{
text=(dataIndex+1).toString();
}
else if (item.Type==DEAL_COLUMN_ID.MULTI_BAR_ID)
{
var rtItem={Left:left, Top:top, Width:itemWidth, Height:this.RowHeight};
this.DrawMultiBar(item, data, rtItem);
}
else if (item.Type==DEAL_COLUMN_ID.CENTER_BAR_ID)
{
var rtItem={Left:left, Top:top, Width:itemWidth, Height:this.RowHeight};
this.DrawCenterBar(item, data, rtItem);
}
else if (item.Type==DEAL_COLUMN_ID.CUSTOM_TEXT_ID)
{
var out={ Text:null, TextColor:null, TextAlign:null }; //输出
var rtItem={Left:left, Top:top, Width:itemWidth, Height:this.RowHeight};
if (this.DrawCustomText(item, data, rtItem, dataIndex, i, out))
{
if (out.Text) text=out.Text;
if (out.TextColor) textColor=out.TextColor;
if (out.TextAlign) textAlign=out.TextAlign;
}
}
this.DrawItemText(text, textColor, textAlign, left, top, itemWidth);
left+=item.Width;
}
}
this.DrawItemText=function(text, textColor, textAlign, left, top, width)
{
var x=left;
if (textAlign=='center')
{
x=left+width/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=left+width;
this.Canvas.textAlign="right";
}
else
{
this.Canvas.textAlign="left";
}
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=textColor;
if (text) this.Canvas.fillText(text,x,top+this.RowHeight/2);
}
this.DrawMultiBar=function(colunmInfo, data, rtItem)
{
if (!data.Source || !IFrameSplitOperator.IsNonEmptyArray(data.Source)) return false;
var barData=data.Source[colunmInfo.DataIndex]; //{ Value:[0.4,0,2], Color:[0,1] };
if (!barData) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(barData.Value)) return false;
var width=rtItem.Width-this.BarMergin.Left-this.BarMergin.Right;
var left=rtItem.Left+this.BarMergin.Left;
var top=rtItem.Top+this.RowMergin.Top+this.BarMergin.Top;
var height=rtItem.Height-this.RowMergin.Top-this.RowMergin.Bottom-this.BarMergin.Top-this.BarMergin.Bottom;
var right=left+width;
for(var i=0;i<barData.Value.length;++i)
{
var value=barData.Value[i];
if (value<=0) continue;
if (left>=right) break;
var barWidth=width*value;
if (barWidth<1) barWidth=1;
if (left+barWidth>right) barWidth=right-left;
var colorIndex=i;
if (IFrameSplitOperator.IsNonEmptyArray(barData.Color) && i<barData.Color.length) colorIndex= barData.Color[i];
this.Canvas.fillStyle=g_JSChartResource.DealList.FieldColor.Bar[colorIndex];
this.Canvas.fillRect(left,top,barWidth,height);
left+=barWidth;
}
return true;
}
this.DrawCenterBar=function(colunmInfo, data, rtItem)
{
if (!data.Source || !IFrameSplitOperator.IsNonEmptyArray(data.Source)) return false;
var barData=data.Source[colunmInfo.DataIndex]; //{ Value:[0.4,0,2], Color:[0,1] };
if (!barData) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(barData.Value)) return false;
var width=(rtItem.Width-this.BarMergin.Left-this.BarMergin.Right)/2;
var left=rtItem.Left+this.BarMergin.Left;
var center=left+width;
var top=rtItem.Top+this.RowMergin.Top+this.BarMergin.Top;
var height=rtItem.Height-this.RowMergin.Top-this.RowMergin.Bottom-this.BarMergin.Top-this.BarMergin.Bottom;
var right=left+width;
for(var i=0;i<barData.Value.length && i<2;++i)
{
var value=barData.Value[i];
if (value<=0) continue;
if (value>1) value=1;
var barWidth=width*value;
if (barWidth<1) barWidth=1;
var colorIndex=i;
if (IFrameSplitOperator.IsNonEmptyArray(barData.Color) && i<barData.Color.length) colorIndex= barData.Color[i];
this.Canvas.fillStyle=g_JSChartResource.DealList.FieldColor.Bar[colorIndex];
if (i==0) //左边
{
this.Canvas.fillRect(center,top,-barWidth,height);
}
else //右边
{
this.Canvas.fillRect(center,top,barWidth,height);
}
}
}
this.DrawCustomText=function(columnInfo, data, rtItem, dataIndex, colid, out)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_DEAL_TEXT);
if (!event || !event.Callback) return false;
var sendData={ Data:data, DataIndex:dataIndex, ColumnIndex:colid, ColumnInfo: columnInfo , Out:{ Text:null, TextColor:null,TextAlign:null } };
event.Callback(event,sendData,this);
if (!sendData.Out.Text) return false;
out.Text=sendData.Out.Text;
if (sendData.Out.TextColor) out.TextColor=sendData.Out.TextColor;
if (sendData.Out.TextAlign) out.TextAlign=sendData.Out.TextAlign;
return true;
}
this.GetVolColor=function(colunmInfo, data)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_DEAL_VOL_COLOR);
if (event && event.Callback)
{
var sendData={ Data:data, TextColor:null };
event.Callback(event,sendData,this);
if (sendData.TextColor) return sendData.TextColor;
}
return colunmInfo.TextColor;
}
this.GetFontHeight=function(font,word)
{
return GetFontHeight(this.Canvas, font, word);
}
}
/*
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.EnableTooltip)
{
this.CreateExtraCanvasElement(JSReportChart.TooltipCursorCanvasKey, { ZIndex:99 });
}
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.WheelPageType=option.WheelPageType;
if (IFrameSplitOperator.IsBool(option.PageUpDownCycle)) chart.PageUpDownCycle=option.PageUpDownCycle;
if (option.VScrollbar) chart.SetVScrollbar(option.VScrollbar);
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;
}
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;
}
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("[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.EnableFilter=function(bEnable, option) //启动|关闭筛选
{
if (this.JSChartContainer) this.JSChartContainer.EnableFilter(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.ChartDestory=function()
{
if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestory) == 'function')
{
this.JSChartContainer.ChartDestory();
}
}
this.Draw=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function')
{
JSConsole.Chart.Log('[JSReportChart:Draw] ');
this.JSChartContainer.Draw();
}
}
}
JSReportChart.TooltipCursorCanvasKey="hq_report_tooltip"; //提示信息
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.TooltipCanvas;
this.ChartTooltip;
this.Tooltip=document.createElement("div");
this.Tooltip.className='jsreport-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:[], 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.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=一条一条翻
//拖拽滚动条
this.DragXScroll=null; //{Start:{x,y}, End:{x, y}}
this.DragYScroll=null;
this.IsShowVScrollbar=false;
this.IsDestroy=false; //是否已经销毁了
this.JSPopMenu; //内置菜单
this.IsShowRightMenu=true;
//MouseOnStatus:{ RowIndex:行, ColumnIndex:列}
this.LastMouseStatus={ MoveStatus:null, TooltipStatus:null, MouseOnStatus:null };
this.ChartDestory=function() //销毁
{
this.IsDestroy=true;
this.StopAutoUpdate();
}
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.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;
//提示信息
var chartTooltip=new ChartCellTooltip();
chartTooltip.Frame=this.Frame;
chartTooltip.ChartBorder=this.Frame.ChartBorder;
this.ChartTooltip=chartTooltip;
//页脚
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.IsBool(option.ItemBorder)) chart.IsDrawBorder=option.ItemBorder; //单元格边框
if (IFrameSplitOperator.IsNumber(option.SelectedModel)) chart.SelectedModel=option.SelectedModel;
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;
}
}
}
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.DrawTooltip(this.LastMouseStatus.TooltipStatus);
}
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 (IFrameSplitOperator.IsNumber(item.Field)) this.SortInfo.Field=item.Field;
if (IFrameSplitOperator.IsNumber(item.Sort)) this.SortInfo.Sort=item.Sort;
}
if (IFrameSplitOperator.IsBool(option.IsReloadStockList))
{
var requestOption={ Callback:null };
if (this.Symbol) requestOption.Callback=()=>{ this.RequestMemberListData(); };
this.MapStockData=new Map();
this.RequestStockListData(requestOption);
return;
}
}
this.RequestMemberListData();
}
//更新数据
this.UpdateFullData=function(data)
{
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]);
}
}
this.Draw();
}
//设置全部的数据
this.SetFullData=function(data)
{
this.ClearMapStockData();
this.ClearData();
this.ResetReportStatus();
this.ResetSortStatus();
this.ResetReportSelectStatus();
this.UpdateFullData(data);
/*
//缓存所有数据
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()
{
//this.ChartSplashPaint.SetTitle(this.SplashTitle.MemberList);
//this.ChartSplashPaint.EnableSplash(true);
//this.Draw();
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.Draw();
this.UpdateStockData();
}
this.AutoUpdateEvent=function(bStart, explain) //自定更新事件, 是给websocket使用
{
var eventID=bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE:JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE;
if (!this.mapEvent.has(eventID)) return;
var self=this;
var event=this.mapEvent.get(eventID);
var data={ Stock:{ Symbol:this.Symbol, Name:this.Name, DayCount:this.DayCount }, Explain: explain };
if (bStart)
{
data.Callback=function(data) //数据到达更新回调
{
self.RecvDealUpdateData(data);
}
}
event.Callback(event,data,this);
}
//下载码表
this.RequestStockListData=function(option)
{
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);
}
}
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()
{
if (this.DelayUpdateTimer!=null)
{
clearTimeout(this.DelayUpdateTimer);
this.DelayUpdateTimer = null;
}
var frequency=this.DelayUpdateFrequency;
this.DelayUpdateTimer=setTimeout(()=>
{
this.UpdateStockData();
},frequency);
}
this.UpdateStockData=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
var chart=this.ChartPaint[0];
if (!chart) return;
if (this.Data.Virtual && this.Data.Virtual.Enable)
{
this.RequestVirtualStockData(); //虚拟表格 全部取后台
return;
}
if (this.SortInfo && this.SortInfo.Field>=0 && this.SortInfo.Sort>0)
{
var column=chart.Column[this.SortInfo.Field];
if (column.Sort==2)
{
this.RequestStockSortData(column, this.SortInfo.Field, this.SortInfo.Sort); //远程排序
return;
}
}
var arySymbol=chart.ShowSymbol;
if (!IFrameSplitOperator.IsNonEmptyArray(arySymbol)) return;
this.RequestStockData(arySymbol);
}
//下载股票数据
this.RequestStockData=function(arySymbol)
{
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSDealChartContainer::RequestStockData', //类名::函数名
Explain:'报价列表股票数据',
Request:{ Data: { stocks: arySymbol } , symbol:this.Symbol, name:this.Name },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvStockData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return;
}
//throw { Name:'JSReportChartContainer::RequestStockData', Error:'(报价列表股票数据)不提供内置测试数据' };
}
this.RecvStockData=function(data)
{
var setUpdateSymbol=new Set(); //更新的股票列表
if (IFrameSplitOperator.IsNonEmptyArray(data.data))
{
//0=证券代码 1=股票名称 2=昨收 3=开 4=高 5=低 6=收 7=成交量 8=成交金额, 9=买价 10=买量 11=卖价 12=卖量 13=均价 14=流通股 15=总股本
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
var symbol=item[0];
if (!symbol) continue;
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
stock.Symbol=this.GetSymbolNoSuffix(symbol);
this.MapStockData.set(symbol, stock);
}
this.ReadStockJsonData(stock, item);
if (!setUpdateSymbol.has(symbol)) setUpdateSymbol.add(symbol);
}
}
var chart=this.ChartPaint[0];
if (!chart) return;
var bUpdate=false;
//实时本地数据排序
var chart=this.ChartPaint[0];
if (chart && this.SortInfo.Sort==1 && IFrameSplitOperator.IsNumber(this.SortInfo.Field) && this.SortInfo.Field>=0)
{
var column=chart.Column[this.SortInfo.Field];
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_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); });
}
bUpdate=true; //排序暂时每次都刷新
}
else
{
//更新的股票在当前页面,需要重绘
var aryStock=chart.ShowSymbol;
for(var i=0;i<aryStock.length;++i)
{
if (setUpdateSymbol.has(aryStock[i].Symbol))
{
bUpdate=true;
break;
}
}
}
if (bUpdate) this.Draw();
}
//读取单条股票json数据
this.ReadStockJsonData=function(stock, item)
{
//0=证券代码 1=股票名称 2=昨收 3=开 4=高 5=低 6=收 7=成交量 8=成交金额, 9=买价 10=买量 11=卖价 12=卖量 13=均价 14=流通股 15=总股本 16=涨停价 17=跌停价
//18=内盘 19=外盘 20=现量 21=涨幅% 22=涨跌 23=换手率% 24=振幅% 25=流通市值 26=总市值
//30=全局扩展数据 31=当前板块扩展数据 36=日期字段
//88=价格颜色类型
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.OutShares=item[14]; //流通股
if (IFrameSplitOperator.IsNumber(item[15])) stock.TotalShares=item[15]; //总股本
if (IFrameSplitOperator.IsNumber(item[16])) stock.LimitHigh=item[16]; //涨停价
if (IFrameSplitOperator.IsNumber(item[17])) stock.LimitLow=item[17]; //跌停价
if (IFrameSplitOperator.IsNumber(item[18])) stock.VolIn=item[18]; //内盘
if (IFrameSplitOperator.IsNumber(item[19])) stock.VolOut=item[19]; //外盘
if (IFrameSplitOperator.IsNumber(item[20])) stock.DealNum=item[20]; //现量
if (IFrameSplitOperator.IsNumber(item[21])) stock.Increase=item[21]; //涨幅%
if (IFrameSplitOperator.IsNumber(item[22])) stock.UpDown=item[22]; //涨跌
if (IFrameSplitOperator.IsNumber(item[23])) stock.Exchange=item[23]; //换手率%
if (IFrameSplitOperator.IsNumber(item[24])) stock.Amplitude=item[24]; //振幅%
if (IFrameSplitOperator.IsNumber(item[25])) stock.CircMarketValue=item[25]; //流通市值
if (IFrameSplitOperator.IsNumber(item[26])) stock.MarketValue=item[26]; //总市值
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[23])) //换手率%
{
if (IFrameSplitOperator.IsNumber(stock.Vol) && IFrameSplitOperator.IsNumber(stock.OutShares) && stock.OutShares>0)
stock.Exchange=stock.Vol/stock.OutShares*100;
}
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 (!IFrameSplitOperator.IsNumber(item[25])) //流通市值
{
if (IFrameSplitOperator.IsNumber(stock.OutShares) && IFrameSplitOperator.IsNumber(stock.Price))
stock.CircMarketValue=stock.OutShares*stock.Price;
}
if (!IFrameSplitOperator.IsNumber(item[26])) //总市值
{
if (IFrameSplitOperator.IsNumber(stock.TotalShares) && IFrameSplitOperator.IsNumber(stock.Price))
stock.MarketValue=stock.TotalShares*stock.Price;
}
if (item[30])
stock.ExtendData=item[30]; //30=全局扩展数据
if (item[31])
this.BlockData.set(stock.OriginalSymbol,item[31]); //31=当前板块数据
if (item[32]) stock.CloseLine=item[32]; //32=收盘价线
if (item[33]) stock.KLine=item[33]; //33=K线
if (IFrameSplitOperator.IsNumber(item[35])) stock.Time=item[35]; //时间 hhmm / hhmmss / hhmmss.fff
if (IFrameSplitOperator.IsNumber(item[36])) stock.Date=item[36]; //日期
if (IFrameSplitOperator.IsBool(item[37])) stock.Checked=item[37];
if (IFrameSplitOperator.IsNumber(item[38])) stock.Position=item[38]; //持仓量
if (IFrameSplitOperator.IsNumber(item[39])) stock.FClose=item[39]; //结算价
if (IFrameSplitOperator.IsNumber(item[40])) stock.YFClose=item[40]; //昨结算价
if (IFrameSplitOperator.IsNumber(item[41])) stock.OpenPosition=item[41]; //开仓量
if (IFrameSplitOperator.IsNumber(item[42])) stock.ClosePosition=item[42]; //平仓量
//1,3,5,10,15 涨速%
if (IFrameSplitOperator.IsNumber(item[43])) stock.RSpeed1M=item[43];
if (IFrameSplitOperator.IsNumber(item[44])) stock.RSpeed3M=item[44];
if (IFrameSplitOperator.IsNumber(item[45])) stock.RSpeed5M=item[45];
if (IFrameSplitOperator.IsNumber(item[46])) stock.RSpeed10M=item[46];
if (IFrameSplitOperator.IsNumber(item[47])) stock.RSpeed15M=item[47];
//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])) stock.ReserveString1=item[201];
if (IFrameSplitOperator.IsString(item[202])) stock.ReserveString2=item[202];
if (IFrameSplitOperator.IsString(item[203])) stock.ReserveString3=item[203];
if (IFrameSplitOperator.IsString(item[204])) stock.ReserveString4=item[204];
if (IFrameSplitOperator.IsString(item[205])) stock.ReserveString5=item[205];
if (IFrameSplitOperator.IsString(item[206])) stock.ReserveString6=item[206];
if (IFrameSplitOperator.IsString(item[207])) stock.ReserveString7=item[207];
if (IFrameSplitOperator.IsString(item[208])) stock.ReserveString8=item[208];
if (IFrameSplitOperator.IsString(item[209])) stock.ReserveString9=item[209];
if (IFrameSplitOperator.IsString(item[210])) stock.ReserveString10=item[210];
//10个进度条 301-350 { Value:, BGColor: }
if (IFrameSplitOperator.IsNumber(item[301]) || IFrameSplitOperator.IsObject(item[301])) stock.ReserveProgressBar1=item[301];
if (IFrameSplitOperator.IsNumber(item[302]) || IFrameSplitOperator.IsObject(item[302])) stock.ReserveProgressBar2=item[302];
if (IFrameSplitOperator.IsNumber(item[303]) || IFrameSplitOperator.IsObject(item[303])) stock.ReserveProgressBar3=item[303];
if (IFrameSplitOperator.IsNumber(item[304]) || IFrameSplitOperator.IsObject(item[304])) stock.ReserveProgressBar4=item[304];
if (IFrameSplitOperator.IsNumber(item[305]) || IFrameSplitOperator.IsObject(item[305])) stock.ReserveProgressBar5=item[305];
if (IFrameSplitOperator.IsNumber(item[306]) || IFrameSplitOperator.IsObject(item[306])) stock.ReserveProgressBar6=item[306];
if (IFrameSplitOperator.IsNumber(item[307]) || IFrameSplitOperator.IsObject(item[307])) stock.ReserveProgressBar7=item[307];
if (IFrameSplitOperator.IsNumber(item[308]) || IFrameSplitOperator.IsObject(item[308])) stock.ReserveProgressBar8=item[308];
if (IFrameSplitOperator.IsNumber(item[309]) || IFrameSplitOperator.IsObject(item[309])) stock.ReserveProgressBar9=item[309];
if (IFrameSplitOperator.IsNumber(item[310]) || IFrameSplitOperator.IsObject(item[310])) stock.ReserveProgressBar10=item[310];
}
this.GetSymbolNoSuffix=function(symbol)
{
var index=symbol.lastIndexOf(".");
if (index>0)
return symbol.substring(0,index);
else
return symbol;
}
this.CancelAutoUpdate=function() //关闭停止更新
{
if (typeof (this.AutoUpdateTimer) == 'number')
{
clearTimeout(this.AutoUpdateTimer);
this.AutoUpdateTimer = null;
}
}
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_REPORT_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);
}
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
this.AutoUpdateEvent(false,'JSDealChartContainer::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.OnWheel=function(e) //滚轴
{
JSConsole.Chart.Log('[JSReportChartContainer::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.ChartPaint[0];
if (!chart) return;
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
if (this.WheelPageType==1)
{
console.log(`[OnWheel] wheelValue=${wheelValue}`);
if (wheelValue<0) //下
{
this.LastMouseStatus.TooltipStatus=null;
if (this.GotoNextItem(1))
{
this.Draw();
this.DelayUpdateStockData();
}
}
else if (wheelValue>0) //上
{
this.LastMouseStatus.TooltipStatus=null;
if (this.GotoNextItem(-1))
{
this.Draw();
this.DelayUpdateStockData();
}
}
}
else
{
if (wheelValue<0) //下一页
{
this.LastMouseStatus.TooltipStatus=null;
if (this.GotoNextPage(this.PageUpDownCycle))
{
this.Draw();
this.DelayUpdateStockData();
}
}
else if (wheelValue>0) //上一页
{
this.LastMouseStatus.TooltipStatus=null;
if (this.GotoPreviousPage(this.PageUpDownCycle))
{
this.Draw();
this.DelayUpdateStockData();
}
}
}
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnKeyDown=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var reportChart=this.GetReportChart();
if (!reportChart) return;
var keyID = e.keyCode ? e.keyCode :e.which;
if (keyID==116) return; //F15刷新不处理
switch(keyID)
{
case 33: //page up
if (this.GotoPreviousPage(this.PageUpDownCycle))
{
this.Draw();
this.DelayUpdateStockData();
}
break;
case 34: //page down
if (this.GotoNextPage(this.PageUpDownCycle))
{
this.Draw();
this.DelayUpdateStockData();
}
break;
case 38: //up
var result=this.MoveSelectedRow(-1);
if (result)
{
if (result.Redraw) this.Draw();
if (result.Update) this.DelayUpdateStockData();
}
break;
case 40: //down
var result=this.MoveSelectedRow(1)
if (result)
{
if (result.Redraw) this.Draw();
if (result.Update) this.DelayUpdateStockData();
}
break;
case 37: //left
if (this.MoveXOffset(-1)) this.Draw();
break
case 39: //right
if (this.MoveXOffset(1)) this.Draw();
break;
}
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
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.ChartPaint[0];
if (chart) chart.OnDblClick(x,y,e);
}
this.UIOnMouseDown=function(e)
{
this.DragXScroll=null;
this.DragYScroll=null;
this.DragHeader=null;
this.DragColumnWidth=null;
this.DragMove={ Click:{ X:e.clientX, Y:e.clientY }, Move:{X:e.clientX, Y:e.clientY}, PreMove:{X:e.clientX, Y:e.clientY } };
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)
{
var dragColumnWidth=chart.PtInHeaderDragBorder(x,y)
if (dragColumnWidth)
{
this.DragColumnWidth=
{
ClickPoint:{ X:x, Y:y },
LastPoint:{ X:x, Y:y },
//Click:{ X:e.clientX, Y:e.clientY },
//LastMove:{ X:e.clientX, Y:e.clientY},
ClickData:dragColumnWidth,
ColumnWidth:dragColumnWidth.Column.Width
};
}
else
{
var clickData=chart.OnMouseDown(x,y,e);
if (!clickData) return;
//if (e.button!=0) return;
if ((clickData.Type==2 || clickData.Type==4) && (e.button==0 || e.button==2)) //点击行|固定行
{
if (e.button==0 && clickData.Type==2)
{
if (this.EnableDragRow && this.SortInfo.Sort<=0)
{
this.DragRow={ Click:{ X:e.clientX, Y:e.clientY }, LastMove:{ X:e.clientX, Y:e.clientY} , Data:clickData };
}
}
if (clickData.Redraw==true)
this.Draw();
}
else if (clickData.Type==3 && e.button==0) //表头
{
this.DragHeader={
ClickPoint:{ X:x, Y:y }, Click:{ X:e.clientX, Y:e.clientY },
ClickData:clickData,
LastMove:{ X:e.clientX, Y:e.clientY}, MovePoint:null,
MoveToData:null
};
}
else if (clickData.Type==1 && e.button==0) //底部工具栏
{
var tabData=clickData.Tab;
if (tabData.Type==1) //左按钮
{
if (this.MoveXOffset(-1)) this.Draw();
}
else if (tabData.Type==2) //右按钮
{
if (this.MoveXOffset(1)) this.Draw();
}
else if (tabData.Type==3) //滚动条
{
this.DragXScroll={ Click:{X:x, Y:y}, LastMove:{X:x, Y:y} };
}
else if (tabData.Type==4) //滚动条内部
{
if (this.SetXOffset(tabData.Pos)) this.Draw();
}
else if (tabData.Type==5) //标签
{
this.OnClickTab(tabData, e);
}
}
else if (clickData.Type==5 && e.button==0) //右侧滚动条
{
var scroll=clickData.VScrollbar;
if (scroll.Type==1) //顶部按钮
{
if (this.MoveYOffset(-1))
{
this.Draw();
this.DelayUpdateStockData();
}
}
else if (scroll.Type==2) //底部按钮
{
if (this.MoveYOffset(1))
{
this.Draw();
this.DelayUpdateStockData();
}
}
else if (scroll.Type==3) //滚动条
{
this.DragYScroll={ Click:{X:x, Y:y}, LastMove:{X:x, Y:y} };
}
else if (scroll.Type==4) //滚动条内部
{
if (this.SetYOffset(scroll.Pos))
{
this.Draw();
this.DelayUpdateStockData();
}
}
}
}
}
document.onmousemove=(e)=>{ this.DocOnMouseMove(e); }
document.onmouseup=(e)=> { this.DocOnMouseUp(e); }
}
this.UIOnMounseUp=function(e)
{
console.log('"UIOnMounseUp');
}
//去掉右键菜单
this.UIOnContextMenu=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
if (!this.IsShowRightMenu) return;
var x = e.clientX-this.UIElement.getBoundingClientRect().left;
var y = e.clientY-this.UIElement.getBoundingClientRect().top;
if(typeof(this.OnRightMenu)=='function') this.OnRightMenu(x,y,e); //右键菜单事件
}
this.OnRightMenu=function(x,y,e)
{
e.preventDefault();
}
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 bDrawTooltip=false;
if (this.LastMouseStatus.TooltipStatus) bDrawTooltip=true;
this.LastMouseStatus.TooltipStatus=null;
if (this.DragRow) return;
if (this.DrawHeader) return;
if (this.DragColumnWidth) return;
var tabChart=this.GetTabChart();
var bDrawTab=false;
if (tabChart)
{
var tabData=tabChart.PtInTab(x,y);
if (tabData)
{
var index=tabData.Index;
if (tabChart.MoveOnTabIndex!=index)
{
tabChart.MoveOnTabIndex=index;
bDrawTab=true;
}
}
else
{
if (tabChart.MoveOnTabIndex>=0)
{
tabChart.MoveOnTabIndex=-1;
bDrawTab=true;
}
}
}
this.LastMouseStatus.OnMouseMove={ X:x, Y:y };
var mouseStatus={ Cursor:"default", Name:"Default"};; //鼠标状态
var report=this.GetReportChart();
var bDraw=false;
if (report)
{
var dragHeaderWidth=report.PtInHeaderDragBorder(x,y);
if (dragHeaderWidth)
{
mouseStatus={ Cursor:"col-resize", Name:"DragHeaderWidth"};
JSConsole.Chart.Log("[JSReportChartContainer::UIOnMouseMove] drag column width ",dragHeaderWidth);
}
else
{
var buttonData=report.GetButtonData(x,y);
var mouseOnStatus=null;
if (buttonData)
{
mouseStatus={ Cursor:"pointer", Name:"Botton"};
if (buttonData.Type==1 || buttonData.Type==0 || buttonData.Type==2)
{
mouseOnStatus={ Index:buttonData.Index, ColumnIndex:buttonData.ColumnIndex };
}
}
//console.log("[UIOnMouseMove] ", oldMouseOnStatus, mouseOnStatus)
if ((!oldMouseOnStatus && mouseOnStatus) || (oldMouseOnStatus && !mouseOnStatus))
{
bDraw=true;
}
else if (oldMouseOnStatus && mouseOnStatus)
{
if (oldMouseOnStatus.Index!=mouseOnStatus.Index || oldMouseOnStatus.ColumnIndex!=mouseOnStatus.ColumnIndex)
bDraw=true;
}
var tooltipData=report.GetTooltipData(x,y); //单元格提示信息
if (tooltipData)
{
this.LastMouseStatus.TooltipStatus={ X:e.clientX, Y:e.clientY, Data:tooltipData };
bDrawTooltip=true;
}
}
var scrollbar=report.VScrollbar;
if (scrollbar.Enable)
{
var bShowScrollbar=report.PtInClient(x,y);
this.IsShowVScrollbar=bShowScrollbar;
if (!this.DragYScroll)
{
if (bShowScrollbar && !scrollbar.LastStatus.Draw) bDraw=true;
else if (!bShowScrollbar && scrollbar.LastStatus.Draw) bDraw=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 (bDraw || bDrawTab) this.Draw();
else if (bDrawTooltip) this.DrawTooltip(this.LastMouseStatus.TooltipStatus);
}
this.UIOnMounseOut=function(e)
{
var bDraw=false;
var tabChart=this.GetTabChart();
if (tabChart && tabChart.MoveOnTabIndex>=0)
{
tabChart.MoveOnTabIndex=-1;
bDraw=true;
this.Draw();
}
var scrollbar=this.GetVScrollbarChart();
if (scrollbar.Enable)
{
this.IsShowVScrollbar=false;
if (!this.DragYScroll)
{
if (scrollbar.LastStatus.Draw) bDraw=true;
}
}
if (bDraw) this.Draw();
}
this.UIOnMouseleave=function(e)
{
var tabChart=this.GetTabChart();
if (tabChart && tabChart.MoveOnTabIndex>=0)
{
tabChart.MoveOnTabIndex=-1;
this.Draw();
}
}
this.DocOnMouseMove=function(e)
{
this.DragMove.PreMove.X=this.DragMove.Move.X;
this.DragMove.PreMove.Y=this.DragMove.Move.Y;
this.DragMove.Move.X=e.clientX;
this.DragMove.Move.Y=e.clientX;
if (this.DragMove.Move.X!=this.DragMove.PreMove.X || this.DragMove.Move.Y!=this.DragMove.PreMove.Y)
this.StopAutoDragScrollTimer();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
//JSConsole.Chart.Log(`[JSReportChartContainer::DocOnMouseMove] x=${x}, y=${y}`);
if (this.DragRow)
{
var drag=this.DragRow;
var moveSetpY=drag.LastMove.Y-e.clientY;
if (Math.abs(moveSetpY)<2) return;
var reportChart=this.GetReportChart();
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
drag.Inside={X:x, Y:y};
if (reportChart)
{
var moveRow=reportChart.OnDrawgRow(x,y,e);
if (moveRow )
{
if (moveRow.Type==2)
{
if (moveRow.Data.DataIndex!=drag.Data.Row.DataIndex)
{
drag.MoveRow=moveRow;
}
}
else if (moveRow.Type==7)
{
var pageStatus=reportChart.GetCurrentPageStatus();
if (!pageStatus.IsEnd)
{
this.MoveYOffset(1, false);
drag.MoveRow=null;
this.EnablePageScroll=true;
this.AutoScrollPage(2);
}
}
else if (moveRow.Type==5)
{
if (this.Data.YOffset>0)
{
this.MoveYOffset(-1, false);
drag.MoveRow=null;
this.EnablePageScroll=true;
this.AutoScrollPage(-2);
}
}
}
reportChart.DragRow=drag;
}
this.Draw();
}
else if (this.DragXScroll)
{
var chart=this.ChartPaint[0];
if (!chart || !chart.Tab) return;
this.DragXScroll.LastMove.X=x;
this.DragXScroll.LastMove.Y=y;
var pos=chart.Tab.GetScrollPostionByPoint(x,y);
if (this.SetXOffset(pos)) this.Draw();
}
else if (this.DragYScroll)
{
var chart=this.ChartPaint[0];
if (!chart || !chart.VScrollbar) return;
this.DragYScroll.LastMove.X=x;
this.DragYScroll.LastMove.Y=y;
var pos=chart.VScrollbar.GetScrollPostionByPoint(x,y);
if (this.SetYOffset(pos))
{
this.Draw();
this.DelayUpdateStockData();
}
}
else if (this.DragHeader && this.DragHeader.ClickData) //表头拖拽
{
if (this.DragHeader.ClickData.Header.IsFixed) return;
if (!this.EnableDragHeader) return;
var xMove=e.clientX-this.DragHeader.Click.X;
var yMove=e.clientY-this.DragHeader.Click.Y;
if ( Math.abs(yMove)<=1 && Math.abs(xMove)<=1) return;
this.DragHeader.LastMove.X=e.clientX;
this.DragHeader.LastMove.Y=e.clientY;
if (!this.DragHeader.MovePoint)
{
this.DragHeader.MovePoint={ X:x, Y:y };
}
else
{
this.DragHeader.MovePoint.X=x;
this.DragHeader.MovePoint.Y=y;
}
this.OnMoveDragHeader(x,y,e);
this.ShowDragHeaderTooltip(x,y,e);
}
else if (this.DragColumnWidth && this.DragColumnWidth.ClickData) //列宽度拖拽
{
var xMove=x-this.DragColumnWidth.ClickPoint.X;
if (Math.abs(xMove)<1) return;
var fixedWidth=this.DragColumnWidth.ColumnWidth+xMove;
if (fixedWidth<=10) return;
var index=this.DragColumnWidth.ClickData.Index;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_DRAG_COLUMN_WIDTH);
if (event && event.Callback)
{
var sendData={ Index:index, Width:fixedWidth, PreventDefault:false };
if (this.DragColumnWidth && this.DragColumnWidth.ClickData) sendData.Column=this.DragColumnWidth.ClickData.Column
event.Callback(event, sendData, this);
if (sendData.PreventDefault) return;
}
this.SetColumnFixedWidth(index, fixedWidth);
this.DragColumnWidth.LastPoint.X=x;
this.DragColumnWidth.LastPoint.Y=y;
}
}
this.SetColumnFixedWidth=function(index, width)
{
var chart=this.ChartPaint[0];
if (!chart) return;
var item=chart.Column[index];
if (!item) return;
item.FixedWidth=width;
this.SetSizeChange(true);
this.Draw();
}
this.OnMoveDragHeader=function(x, y,e)
{
var chart=this.ChartPaint[0];
if (!chart) return;
var clickData=this.DragHeader.ClickData;
this.DragHeader.MoveToData=null;
if (!clickData.Header.IsFixed) //固定列不能拖
{
var yHeader=this.DragHeader.ClickPoint.Y;
var moveData=chart.OnMouseDown(x,yHeader,e);
if (!moveData || !moveData.Header) return;
if (moveData.Header.IsFixed) return;
if (moveData.Header.Index== clickData.Header.Index) return;
this.DragHeader.MoveToData=moveData;
console.log(`[JSReportChartContainer::OnMoveDragHeader] Click[Index=${clickData.Header.Index}, Title=${clickData.Header.Column.Title}] => Move[Index=${moveData.Header.Index}, Title=${moveData.Header.Column.Title}]`);
}
}
this.ShowDragHeaderTooltip=function(x,y,e)
{
if (!this.DragHeader) return;
var drag=this.DragHeader;
if (!drag.ClickData || !drag.MovePoint) return;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_DRAG_HEADER_TOOLTIP);
if (event)
{
var sendData={ PreventDefault:false, e, X:x, Y:y, DragHeader:this.DragHeader, Tooltip:this.Tooltip };
event.Callback(event,sendData,this);
if (sendData.PreventDefault) return;
}
var title=drag.ClickData.Header.Column.Title;
this.Tooltip.className='jchart-chartdrawsvg-tooltip'; //ChartDrawSVG指标数据
this.Tooltip.style.position = "absolute";
this.Tooltip.style.left = e.clientX + "px";
this.Tooltip.style.top = e.clientY+ "px";
this.Tooltip.style.width = 100+"px";
this.Tooltip.style.height =null;
this.Tooltip.innerHTML=title;
this.Tooltip.style.display = "block";
}
this.HideTooltip=function()
{
if (this.Tooltip.style.display!="none") this.Tooltip.style.display = "none";
}
this.DocOnMouseUp=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
this.StopAutoDragScrollTimer();
this.HideTooltip();
var reportChart=this.GetReportChart();
var mouseStatus={ Cursor:"default", Name:"Default"};; //鼠标状态
var bRedraw=false;
if (this.DragRow)
{
if (reportChart)
{
this.OnDragRow();
reportChart.DragRow=null;
}
bRedraw=true;
}
var dragHeader=this.DragHeader;
this.DragHeader=null;
this.DragXScroll=null;
if (this.DragYScroll)
{
bRedraw=true;
this.DragYScroll=null;
}
this.DragRow=null;
this.DragMove=null;
this.DragColumnWidth=null;
if (bRedraw) this.Draw();
if (dragHeader)
{
var clickData=dragHeader.ClickData;
var moveToData=dragHeader.MoveToData;
if (clickData && moveToData)
{
this.SwapColumn(clickData.Header.Index, moveToData.Header.Index, { Redraw:true });
}
else
{
this.OnClickHeader(clickData, e);
}
}
if (mouseStatus) this.UIElement.style.cursor=mouseStatus.Cursor;
}
this.OnDragRow=function()
{
if (!this.SourceData || !IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data)) return;
if (!this.DragRow || !this.DragRow.MoveRow) return;
var drag=this.DragRow;
var srcIndex=drag.Data.Row.DataIndex;
var moveIndex=drag.MoveRow.Data.DataIndex;
if (srcIndex==moveIndex || srcIndex<0 || moveIndex<0) return;
var data=this.SourceData.Data;
if (srcIndex>=data.length || moveIndex>=data.length) return;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_DRAG_ROW);
if (event)
{
var sendData=
{
Symbol:this.Symbol,
Src:{ Index:srcIndex, Symbol:data[srcIndex] },
To:{ Index:moveIndex, Symbol:data[moveIndex] },
PreventDefault:false //PreventDefault 是否阻止内置的点击处理
};
event.Callback(event,sendData,this);
if (sendData.PreventDefault) return;
}
if (this.DragRowType==1)
{
//原始数据交换顺序
var temp=data[srcIndex];
data[srcIndex]=data[moveIndex];
data[moveIndex]=temp;
this.Data.Data=data.slice(0);
}
else
{
//插入模式
var srcItem=data[srcIndex];
data.splice(srcIndex,1);
data.splice(moveIndex, 0, srcItem);
this.Data.Data=data.slice(0);
}
//更新选中行
var reportChart=this.GetReportChart();
if (reportChart)
{
if (reportChart.SelectedModel==0) reportChart.SelectedRow=drag.MoveRow.Data.Index;
else reportChart.SelectedRow=drag.MoveRow.Data.DataIndex;
}
}
//判断是单个手指
this.IsPhoneDragging=function(e)
{
// JSConsole.Chart.Log(e);
var changed=e.changedTouches.length;
var touching=e.touches.length;
return changed==1 && touching==1;
}
this.GetTouchData=function(e)
{
var touches=[];
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
for(var i=0; i<e.touches.length; ++i)
{
var item=e.touches[i];
var toucheItem=
{
clientX:item.clientX*pixelTatio,
clientY:item.clientY*pixelTatio,
pageX:item.pageX*pixelTatio,
pageY:item.pageY*pixelTatio,
//内部相对坐标
InsideX:(item.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio,
InsideY:(item.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio
};
touches.push(toucheItem);
}
return touches;
}
this.GetMoveAngle=function(pt,pt2) //计算角度
{
var xMove=Math.abs(pt.X-pt2.X);
var yMove=Math.abs(pt.Y-pt2.Y);
var angle=Math.atan(xMove/yMove)*180/Math.PI;
return angle;
}
this.PreventTouchEvent=function(e)
{
if (e.cancelable) e.preventDefault();
e.stopPropagation();
}
//手势事件
this.OnTouchStart=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.IsOnTouch=true;
var reportChart=this.GetReportChart();
if (!reportChart) return;
if (this.IsPhoneDragging(e))
{
var drag= { "Click":{}, "LastMove":{}, "InsideClick":{} }; //LastMove 最后移动的位置
var touches=this.GetTouchData(e);
drag.Click.X=touches[0].clientX;
drag.Click.Y=touches[0].clientY;
drag.InsideClick.X=touches[0].InsideX;
drag.InsideClick.Y=touches[0].InsideY;
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
drag.IsXMove=false;
drag.IsYMove=false;
if (reportChart.IsPtInBody(drag.InsideClick.X,drag.InsideClick.Y))
{
this.TouchDrag=drag;
}
this.TouchInfo={ InsideClick:{ X:touches[0].InsideX, Y:touches[0].InsideY }, Click:{ X:touches[0].clientX, Y:touches[0].clientY } };
this.PreventTouchEvent(e);
}
}
this.OnDragYOffset=function(drag, touches, moveUpDown, e)
{
if (moveUpDown<5) return false
var isUp=true;
if (drag.LastMove.Y<touches[0].clientY) isUp=false; //Down
var oneStep=this.YStepPixel;
if (oneStep<=0) oneStep=5;
var step=parseInt(moveUpDown/oneStep);
if (step<=0) return false
if (isUp==false) step*=-1;
if (this.MoveYOffset(step, this.DragPageCycle))
{
drag.IsYMove=true;
this.Draw();
this.DelayUpdateStockData();
}
return true;
}
this.OnDragXOffset=function(drag, touches, moveLeftRight, e)
{
if (moveLeftRight<5) return false;
var isLeft=true;
if (drag.LastMove.X<touches[0].clientX) isLeft=false;//右移数据
var oneStep=this.XStepPixel;
if (oneStep<=0) oneStep=5;
var step=parseInt(moveLeftRight/oneStep); //除以4个像素
if (step<=0) return false;
if (!isLeft) step*=-1;
if (this.MoveXOffset(step))
{
drag.IsXMove=true;
this.Draw();
}
return true;
}
this.OnTouchMove=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var reportChart=this.GetReportChart();
if (!reportChart) return;
var touches=this.GetTouchData(e);
if (this.IsPhoneDragging(e))
{
var drag=this.TouchDrag;
this.TouchInfo.Move={ X:touches[0].clientX, Y:touches[0].clientY };
if (drag)
{
this.PreventTouchEvent(e);
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveLeftRight=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
if (drag.IsYMove==true)
{
this.ShowPageInfo(true);
if (!this.OnDragYOffset(drag, touches,moveUpDown, e)) return;
}
else if (drag.IsXMove==true)
{
if (!this.OnDragXOffset(drag, touches,moveLeftRight, e)) return;
}
else if (moveUpDown>0 && moveAngle<this.TouchMoveMinAngle)
{
this.ShowPageInfo(true);
if (!this.OnDragYOffset(drag, touches,moveUpDown, e)) return;
}
else if (moveLeftRight>0 && moveAngle>=this.TouchMoveMinAngle)
{
if (!this.OnDragXOffset(drag, touches,moveLeftRight, e)) return;
}
else
{
return;
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
}
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[JSReportChartContainer:OnTouchEnd]',e);
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
this.ShowPageInfo(false);
this.OnTouchClick(this.TouchInfo, e);
this.IsOnTouch=false;
this.TouchDrag=null;
this.TouchInfo=null;
}
this.OnTouchClick=function(touchInfo, e)
{
if (!touchInfo || !touchInfo.Click) return false;
if (touchInfo.Move) return false;
var clickPoint=touchInfo.InsideClick;
var reportChart=this.GetReportChart();
if (!reportChart) return false;
var clickData=reportChart.OnMouseDown(clickPoint.X,clickPoint.Y,e);
if (!clickData) return false;
if (clickData.Type==2 || clickData.Type==4) //点击行
{
if (clickData.Redraw==true)
this.Draw();
}
else if (clickData.Type==3) //表头
{
this.OnClickHeader(clickData, e);
}
JSConsole.Chart.Log('[JSReportChartContainer:OnTouchClick] clickData', clickData);
}
this.GetTabChart=function()
{
var chart=this.ChartPaint[0];
if (!chart) return null;
return chart.Tab;
}
this.GetVScrollbarChart=function()
{
var chart=this.ChartPaint[0];
if (!chart) return null;
return chart.VScrollbar;
}
this.GetReportChart=function()
{
var chart=this.ChartPaint[0];
return chart;
}
this.GotoNextItem=function(step)
{
if (step==0) return false;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
if (pageSize>this.Data.Data.length) return false;
var moveCount=0;
if (step>0)
{
for(var i=0;i<step;++i)
{
if (this.Data.YOffset+pageSize>=this.Data.Data.length)
break;
++this.Data.YOffset;
++moveCount;
}
}
else if (step<0)
{
step=Math.abs(step);
for(var i=0;i<step;++i)
{
if (this.Data.YOffset<=0)
break;
--this.Data.YOffset;
++moveCount;
}
}
return moveCount>0
}
this.GotoNextPage=function(bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
var dataCount=chart.GetAllRowCount();
if (pageSize>dataCount) return false;
if (this.Data.YOffset+pageSize>=dataCount)
{
if (bCycle===true)
{
this.Data.YOffset=0; //循环到第1页
return true;
}
else
{
return false;
}
}
this.Data.YOffset+=pageSize;
var showDataCount=dataCount-this.Data.YOffset;
if (chart.SelectedModel==0)
{
if (chart.SelectedRow>showDataCount-1) chart.SelectedRow=showDataCount-1;
}
return true;
}
this.GotoPreviousPage=function(bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
var dataCount=chart.GetAllRowCount();
if (pageSize>dataCount) return false;
if (this.Data.YOffset<=0)
{
if (bCycle===true)
{
this.Data.YOffset=dataCount-pageSize; //循环到最后一页
return true;
}
else
{
return false;
}
}
var offset=this.Data.YOffset;
offset-=pageSize;
if (offset<0) offset=0;
this.Data.YOffset=offset;
return true;
}
this.MoveYOffset=function(setp, bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageStatus=chart.GetCurrentPageStatus();
if (pageStatus.IsSinglePage) return false;
if (setp>0) //向上
{
var count=this.Data.Data.length;
var pageSize=pageStatus.PageSize;
var offset=this.Data.YOffset;
if (bCycle)
{
for(var i=0;i<setp;++i)
{
++offset;
if (offset+pageSize>count) offset=0;
}
}
else
{
if (offset+pageSize>=count) return false;
for(var i=0;i<setp;++i)
{
if (offset+pageSize+1>count) break;
++offset;
}
}
this.Data.YOffset=offset;
return true;
}
else if (setp<0) //向下
{
setp=Math.abs(setp);
var offset=this.Data.YOffset;
if (bCycle)
{
var pageSize=pageStatus.PageSize;
for(var i=0;i<setp;++i)
{
--offset;
if (offset<0) offset=this.Data.Data.length-pageSize;
}
}
else
{
if (this.Data.YOffset<=0) return false;
for(var i=0;i<setp;++i)
{
if (offset-1<0) break;
--offset;
}
}
this.Data.YOffset=offset;
return true;
}
return false;
}
this.MoveSelectedRow=function(step)
{
var chart=this.ChartPaint[0];
if (!chart) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var result={ Redraw:false, Update:false }; //Redraw=重绘, Update=更新数据
if (chart.MultiSelectModel==1)
{
var pageStatus=chart.GetCurrentPageStatus();
if (IFrameSplitOperator.IsNonEmptyArray(pageStatus.MultiSelectedRow))
{
var selected=pageStatus.MultiSelectedRow[0];
if (step>0)
{
if (selected==this.Data.Data.length-1) return result;
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.MultiSelectedRow=[pageStatus.Start];
result.Redraw=true;
return result;
}
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
++selected;
if (selected>pageStatus.End) ++offset;
if (selected>=this.Data.Data.length)
{
selected=0;
offset=0;
}
}
result.Redraw=true;
result.Update=(offset!=this.Data.YOffset);
chart.MultiSelectedRow=[selected];
this.Data.YOffset=offset;
return result;
}
else if (step<0)
{
if (selected==0) return result;
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.MultiSelectedRow=[pageStatus.End];
result.Redraw=true;
return result;
}
step=Math.abs(step);
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
--selected;
if (selected<pageStatus.Start) --offset;
if (selected<0)
{
selected=this.Data.Data.length-1;
offset=this.Data.Data.length-pageSize;
if (offset<0) offset=0;
}
}
result.Redraw=true;
result.Update=(offset!=this.Data.YOffset);
chart.MultiSelectedRow=[selected];
this.Data.YOffset=offset;
return result;
}
else
{
return null;
}
return result;
}
else
{
var selected=-1;
if (step>0) selected=pageStatus.Start;
else if (step<0) selected=pageStatus.End;
else return null;
chart.MultiSelectedRow=[selected];
result.Redraw=true;
}
return result;
}
if (chart.SelectedModel==0) //不可翻页模式, 只能在当前页移动
{
var pageStatus=chart.GetCurrentPageStatus();
var pageSize=pageStatus.End-pageStatus.Start+1;
var selected=pageStatus.SelectedRow;
if (step>0)
{
selected+=step;
selected=selected%pageSize;
chart.SelectedRow=selected;
chart.SelectedFixedRow=-1;
result.Redraw=true;
return result;
}
else if (step<0)
{
selected+=step;
if (selected<0)
{
selected=selected%pageSize;
selected=pageSize+selected;
}
chart.SelectedRow=selected;
chart.SelectedFixedRow=-1;
result.Redraw=true;
return result;
}
}
else if (chart.SelectedModel==1) //可翻页模式
{
var pageStatus=chart.GetCurrentPageStatus();
var pageSize=pageStatus.PageSize;
var selected=pageStatus.SelectedRow;
if (step>0)
{
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.SelectedRow=pageStatus.Start;
result.Redraw=true;
return result;
}
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
++selected;
if (selected>pageStatus.End) ++offset;
if (selected>=this.Data.Data.length)
{
selected=0;
offset=0;
}
}
result.Redraw=true;
result.Update=(offset!=this.Data.YOffset);
chart.SelectedRow=selected;
this.Data.YOffset=offset;
return result;
}
else if (step<0)
{
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.SelectedRow=pageStatus.End;
result.Redraw=true;
return result;
}
step=Math.abs(step);
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
--selected;
if (selected<pageStatus.Start) --offset;
if (selected<0)
{
selected=this.Data.Data.length-1;
offset=this.Data.Data.length-pageSize;
if (offset<0) offset=0;
}
}
result.Redraw=true;
result.Update=(offset!=this.Data.YOffset);
chart.SelectedRow=selected;
this.Data.YOffset=offset;
return result;
}
}
return null;
}
//左右移动
this.MoveXOffset=function(step)
{
var chart=this.ChartPaint[0];
if (!chart) return false;
var maxOffset=chart.GetXScrollRange();
if (maxOffset<=0) return false;
if (step>0)
{
if (this.Data.XOffset>=maxOffset) return false;
for(var i=0;i<step;++i)
{
if (this.Data.XOffset>=maxOffset) break;
++this.Data.XOffset;
}
return true;
}
else if (step<0)
{
if (this.Data.XOffset<=0) return false;
step=Math.abs(step);
for(var i=0;i<step;++i)
{
if (this.Data.XOffset-1<0) break;
--this.Data.XOffset;
}
return true;
}
return false;
}
this.SetXOffset=function(pos)
{
if (!IFrameSplitOperator.IsNumber(pos)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var maxOffset=chart.GetXScrollRange();
if (pos<0) pos=0;
if (pos>maxOffset) pos=maxOffset;
this.Data.XOffset=pos;
return true;
}
this.SetYOffset=function(pos)
{
if (!IFrameSplitOperator.IsNumber(pos)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var maxOffset=chart.GetYScrollRange();
if (pos<0) pos=0;
if (pos>maxOffset) pos=maxOffset;
this.Data.YOffset=pos;
return true;
}
this.GotoLastPage=function()
{
var chart=this.ChartPaint[0];
if (!chart) return;
//显示最后一屏
var pageSize=chart.GetPageSize(true);
var offset=this.Data.Data.length-pageSize;
if (offset<0) offset=0;
this.Data.DataOffset=offset;
}
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.SetTab=function(aryTab, option)
{
var chart=this.ChartPaint[0];;
if (!chart) return;
var chartTab=chart.Tab;
if (!chartTab) return;
chartTab.SetTabList(aryTab);
if (option && option.Redraw) this.Draw();
}
this.SetVScrollbar=function(option)
{
var chart=this.GetReportChart();
if (!chart) return;
var scrollbar=chart.VScrollbar;
if (!scrollbar) return;
scrollbar.SetOption(option);
}
this.SetSelectedTab=function(index, opiton)
{
var chart=this.ChartPaint[0];;
if (!chart) return;
var chartTab=chart.Tab;
if (!chartTab) return;
chartTab.SelectedTabIndex=index;
}
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)
{
this.SetSizeChange(true);
this.Draw();
}
}
//列排序
this.SortColumn=function(index, sortType)
{
if (index<0) return false;
var reportChart=this.GetReportChart();
if (!reportChart) return false;
var column=reportChart.Column[index];
if (!column) return false;
if (column.Sort!=1 && column.Sort!=2) return false;
var sortInfo={ Field:index, Sort:sortType };
if (this.Data.Virtual && this.Data.Virtual.Enable)
{
this.SortInfo.Field=sortInfo.Field;
this.SortInfo.Sort=sortInfo.Sort;
this.Data.YOffset=0;
this.ResetReportSelectStatus();
this.RequestVirtualStockData(); //虚拟表格
return true;
}
else if (sortInfo.Sort==0) //不排序还原
{
this.Data.Data=[];
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
this.Data.Data=this.SourceData.Data.slice();
}
else if (sortInfo.Sort==1 || sortInfo.Sort==2)
{
if (column.Sort==1) //本地排序
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_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); });
}
}
else if (column.Sort==2) //远程排序
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.SortInfo.Field=sortInfo.Field;
this.SortInfo.Sort=sortInfo.Sort;
this.Data.YOffset=0;
this.ResetReportSelectStatus();
this.RequestStockSortData(column, sortInfo.Field, sortInfo.Sort); //远程排序
return true;
}
}
this.Data.YOffset=0;
this.ResetReportSelectStatus();
this.SortInfo.Field=sortInfo.Field;
this.SortInfo.Sort=sortInfo.Sort;
this.Draw();
this.DelayUpdateStockData();
return true;
}
//点表头
this.OnClickHeader=function(clickData, e)
{
var header=clickData.Header;
if (header.Column && header.Column.EnablePopupHeaderMenu)
{
this.PopupHeaderMenu(clickData, e);
return;
}
if (header.Column && (header.Column.Sort==1 || header.Column.Sort==2))
{
var index=header.Index;
var sortInfo={Field:this.SortInfo.Field, Sort:this.SortInfo.Sort };
var arySortType=header.Column.SortType;
if (sortInfo.Field!=index)
{
sortInfo.Field=index;
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 (header.Column.Sort==1 || header.Column.Sort==2)
{
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
{
if (header.Column.Sort==1) //本地排序
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_LOCAL_SORT);
if (event && event.Callback)
{
var sendData={ Column:header.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, header.Column, sortInfo.Sort); });
}
}
else if (header.Column.Sort==2) //远程排序
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.SortInfo.Field=sortInfo.Field;
this.SortInfo.Sort=sortInfo.Sort;
this.Data.YOffset=0;
this.ResetReportSelectStatus();
this.RequestStockSortData(header.Column, sortInfo.Field, sortInfo.Sort); //远程排序
return;
}
}
this.Data.YOffset=0;
this.ResetReportSelectStatus();
this.SortInfo.Field=sortInfo.Field;
this.SortInfo.Sort=sortInfo.Sort;
this.Draw();
this.DelayUpdateStockData();
}
}
}
this.PopupHeaderMenu=function(clickData, e)
{
if (!this.JSPopMenu) return;
if (!this.GetEventCallback) return;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CREATE_REPORT_HEADER_MENU);
if (!event || !event.Callback) return;
var header=clickData.Header;
var column=header.Column;
var menuData={ Menu:null, Position:JSPopMenu.POSITION_ID.DROPDOWN_MENU_ID };
menuData.ClickCallback=(data)=>{ this.OnClickHeaderMenu(column, data); }
var sendData={ MenuData:menuData, Column:column, Index:header.Index, PreventDefault:false, e:e };
event.Callback(event, sendData, this);
if (sendData.PreventDefault==true) return;
if (!menuData.Menu) return;
this.PopupMenuByDrapdown(menuData, header.Rect);
}
//下拉菜单
this.PopupMenuByDrapdown=function(menuData, rtButton)
{
if (!this.JSPopMenu) return;
var pixelRatio=GetDevicePixelRatio();
var rtCell={ Left:rtButton.Left/pixelRatio, Right:rtButton.Right/pixelRatio, Bottom:rtButton.Bottom/pixelRatio, Top:rtButton.Top/pixelRatio };
rtCell.Width=rtCell.Right-rtCell.Left;
rtCell.Height=rtCell.Bottom-rtCell.Top;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var offsetLeft=rtClient.left+rtScroll.Left;
var offsetTop=rtClient.top+rtScroll.Top;
rtCell.Left+=offsetLeft;
rtCell.Right+=offsetLeft;
rtCell.Top+=offsetTop;
rtCell.Bottom+=offsetTop;
this.JSPopMenu.CreatePopMenu(menuData);
this.JSPopMenu.PopupMenuByDrapdown(rtCell);
}
this.GetTabPopMenu=function(tabItem)
{
var aryMenu=[ ];
if (IFrameSplitOperator.IsNonEmptyArray(tabItem.ArySubMenu))
{
for(var i=0;i<tabItem.ArySubMenu.length;++i)
{
var item=tabItem.ArySubMenu[i];
var menuItem={ Name:item.Title, Data:{ ID:item.CommandID, Args:[item.ID]} };
if (item.Text) menuItem.Text=item.Text;
aryMenu.push(menuItem);
}
}
return aryMenu;
}
this.PopupTabMenu=function(menuData, tab, e)
{
if (!this.JSPopMenu) return;
var rtTab=tab.Rect;
var pixelRatio=GetDevicePixelRatio();
var rtCell={ Left:rtTab.Left/pixelRatio, Right:rtTab.Right/pixelRatio, Bottom:rtTab.Bottom/pixelRatio, Top:rtTab.Top/pixelRatio };
rtCell.Width=rtCell.Right-rtCell.Left;
rtCell.Height=rtCell.Bottom-rtCell.Top;
var rtClient=this.UIElement.getBoundingClientRect();
var rtScroll=GetScrollPosition();
var offsetLeft=rtClient.left+rtScroll.Left;
var offsetTop=rtClient.top+rtScroll.Top;
rtCell.Left+=offsetLeft;
rtCell.Right+=offsetLeft;
rtCell.Top+=offsetTop;
rtCell.Bottom+=offsetTop;
this.JSPopMenu.CreatePopMenu(menuData);
this.JSPopMenu.PopupMenuByTab(rtCell);
if(e.preventDefault) e.preventDefault();
if(e.stopPropagation) e.stopPropagation();
}
//点击标签
this.OnClickTab=function(tabData, e)
{
if (!tabData.Tab) return;
var redraw=false;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
var uiElement={Left:this.UIElement.getBoundingClientRect().left, Top:this.UIElement.getBoundingClientRect().top};
if (tabData.Tab.IsMenu)
{
var menuData={ Menu:this.GetTabPopMenu(tabData.Tab), Position:JSPopMenu.POSITION_ID.TAB_MENU_ID };
menuData.ClickCallback=(data)=>{ this.OnClickTabPopMenu(tabData, data); }
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_REPORT_TABMENU);
if (event && event.Callback)
{
var sendData={ MenuData:menuData, Tab:tabData, PreventDefault:false, e:e };
event.Callback(event, sendData, this);
if (sendData.PreventDefault==true) return;
}
this.PopupTabMenu(menuData, tabData.Tab, e);
}
else
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_REPORT_TAB);
if (event && event.Callback)
{
var sendData={ Data:tabData, IsSide:{X:x, Y:x}, UIElement:uiElement, e:e , Redraw:redraw, PreventDefault:false };
event.Callback(event, sendData, this);
if (IFrameSplitOperator.IsBool(sendData.Redraw)) redraw=sendData.Redraw;
if (sendData.PreventDefault==true) return;
}
if (tabData.Tab.CommandID==JSCHART_MENU_ID.CMD_REPORT_CHANGE_BLOCK_ID)
{
this.ExecuteMenuCommand(tabData.Tab.CommandID, [tabData.Tab.ID]);
this.SetSelectedTab(tabData.Index);
redraw=true;
}
}
if (redraw) this.Draw();
}
this.OnClickTabPopMenu=function(tabData, data)
{
JSConsole.Chart.Log('[JSReportChartContainer::OnClickTabPopMenu] ',tabData, data);
var cmdID=data.Data.ID; //命令ID
var aryArgs=data.Data.Args; //参数
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MENU_COMMAND); //回调通知外部
if (event && event.Callback)
{
var data={ PreventDefault:false, CommandID:cmdID, Args:aryArgs, SrcData:data, TabData:tabData };
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
this.ExecuteMenuCommand(cmdID,aryArgs);
this.SetSelectedTab(tabData.Index);
this.Draw();
}
this.OnClickHeaderMenu=function(menuData, data)
{
JSConsole.Chart.Log('[JSReportChartContainer::OnClickHeaderMenu] ',menuData, data);
var cmdID=data.Data.ID;
var aryArgs=data.Data.Args;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_MENU_COMMAND); //回调通知外部
if (event && event.Callback)
{
var data={ PreventDefault:false, CommandID:cmdID, Args:aryArgs, SrcData:data, MenuData:menuData };
event.Callback(event,data,this);
if (data.PreventDefault) return;
}
this.ExecuteMenuCommand(cmdID,aryArgs);
}
this.ExecuteMenuCommand=function(cmdID, aryArgs)
{
JSConsole.Chart.Log('[JSReportChartContainer::ExecuteMenuCommand] cmdID=, aryArgs=', cmdID,aryArgs);
var param=null, srcParam=null; //原始值
if (IFrameSplitOperator.IsNonEmptyArray(aryArgs))
{
srcParam=aryArgs[0];
if (IFrameSplitOperator.IsNumber(aryArgs[0])) param=aryArgs[0];
}
switch(cmdID)
{
case JSCHART_MENU_ID.CMD_REPORT_CHANGE_BLOCK_ID:
if (srcParam) this.ChangeSymbol(srcParam);
break;
case JSCHART_MENU_ID.CMD_REPORT_COLUMN_SORT_ID:
if (IFrameSplitOperator.IsNumber(param) && IFrameSplitOperator.IsNumber(aryArgs[1]))
this.SortColumn(param, aryArgs[1]);
break;
case JSCHART_MENU_ID.CMD_REPORT_COLUMN_MOVE_ID:
if (IFrameSplitOperator.IsNumber(param) && IFrameSplitOperator.IsNumber(aryArgs[1]))
{
var leftIndex=param;
var rightIndex=param+aryArgs[1];
this.SwapColumn(leftIndex, rightIndex, {Redraw:true});
}
break;
case JSCHART_MENU_ID.CMD_REPORT_COLUMN_DEL_ID:
if (IFrameSplitOperator.IsNumber(param))
this.DeleteColumn(param, {Redraw:true});
break;
}
}
this.SwapColumn=function(leftIndex, rightIndex, option)
{
var reportChart=this.GetReportChart();
if (!reportChart) return;
if (!reportChart.SwapColumn(leftIndex, rightIndex)) return;
if (option && option.Redraw)
{
this.SetSizeChange(true);
this.Draw();
}
}
this.DeleteColumn=function(index, option)
{
var reportChart=this.GetReportChart();
if (!reportChart) return;
if (!reportChart.DeleteColumn(index)) return;
if (option && option.Redraw)
{
this.SetSizeChange(true);
this.Draw();
}
}
//本地排序
this.LocalSort=function(left, right, column, sortType)
{
switch(column.Type)
{
case REPORT_COLUMN_ID.SYMBOL_ID:
case REPORT_COLUMN_ID.NAME_ID:
return this.LocalStringSort(left, right, column, sortType);
case REPORT_COLUMN_ID.NAME_EX_ID:
return this.LocalNameExSort(left, right, column, sortType);
case REPORT_COLUMN_ID.PRICE_ID:
case REPORT_COLUMN_ID.VOL_ID:
case REPORT_COLUMN_ID.INCREASE_ID:
case REPORT_COLUMN_ID.UPDOWN_ID:
case REPORT_COLUMN_ID.BUY_PRICE_ID:
case REPORT_COLUMN_ID.SELL_PRICE_ID:
case REPORT_COLUMN_ID.AMOUNT_ID:
case REPORT_COLUMN_ID.BUY_VOL_ID:
case REPORT_COLUMN_ID.SELL_VOL_ID:
case REPORT_COLUMN_ID.YCLOSE_ID:
case REPORT_COLUMN_ID.OPEN_ID:
case REPORT_COLUMN_ID.HIGH_ID:
case REPORT_COLUMN_ID.LOW_ID:
case REPORT_COLUMN_ID.AVERAGE_PRICE_ID:
case REPORT_COLUMN_ID.OUTSTANDING_SHARES_ID:
case REPORT_COLUMN_ID.TOTAL_SHARES_ID:
case REPORT_COLUMN_ID.CIRC_MARKET_VALUE_ID:
case REPORT_COLUMN_ID.MARKET_VALUE_ID:
case REPORT_COLUMN_ID.EXCHANGE_RATE_ID:
case REPORT_COLUMN_ID.AMPLITUDE_ID:
case REPORT_COLUMN_ID.LIMIT_HIGH_ID:
case REPORT_COLUMN_ID.LIMIT_LOW_ID:
//期货字段
case REPORT_COLUMN_ID.FUTURES_POSITION_ID:
case REPORT_COLUMN_ID.FUTURES_CLOSE_ID:
case REPORT_COLUMN_ID.FUTURES_YCLOSE_ID:
case REPORT_COLUMN_ID.FUTURES_OPEN_POSITION_ID:
case REPORT_COLUMN_ID.FUTURES_CLOSE_POSITION_ID:
case REPORT_COLUMN_ID.VOL_IN_ID:
case REPORT_COLUMN_ID.VOL_OUT_ID:
case REPORT_COLUMN_ID.DATE_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);
case REPORT_COLUMN_ID.CUSTOM_NUMBER_TEXT_ID: //自定义数值字段
return this.LoacCustomNumberSort(left, right, column, sortType);
case REPORT_COLUMN_ID.CUSTOM_STRING_TEXT_ID: //自定义字符串字段
return this.LoacCustomStringSort(left, right, column, sortType);
case REPORT_COLUMN_ID.CUSTOM_DATETIME_TEXT_ID:
return this.LoacCustomDateTimeSort(left, right, column, sortType);
default:
return 0;
}
}
this.GetStockExtendData=function(symbol,column)
{
if (IFrameSplitOperator.IsNumber(column.DataIndex))
{
if (column.DataIndex<0) return null;
var stock=this.GetStockData(symbol);
if (!stock || !stock.ExtendData) return null;
return stock.ExtendData[column.DataIndex];
}
if (IFrameSplitOperator.IsNumber(column.BlockIndex))
{
if (column.BlockIndex<0) return null;
var stock=this.GetBlockData(symbol);
if (!stock) return null;
return stock[column.BlockIndex];
}
return null;
}
this.LocalNameExSort=function(left, right, column, sortType)
{
var leftStock=this.GetStockData(left);
var rightStock=this.GetStockData(right);
var leftValue="", rightValue="";
if (sortType==2)
{
leftValue="啊啊啊啊啊";
rightValue="啊啊啊啊啊";
}
if (leftStock && leftStock.Name) leftValue=leftStock.Name;
if (rightStock && rightStock.Name) rightValue=rightStock.Name;
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.LocalStringSort=function(left, right, column, sortType)
{
var leftStock=this.GetStockData(left);
var rightStock=this.GetStockData(right);
var leftValue="", rightValue="";
if (sortType==2)
{
leftValue="啊啊啊啊啊";
rightValue="啊啊啊啊啊";
}
var filedName=MAP_COLUMN_FIELD.get(column.Type);
if (leftStock && leftStock[filedName]) leftValue=leftStock[filedName];
if (rightStock && rightStock[filedName]) rightValue=rightStock[filedName];
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.LocalNumberSort=function(left, right, column, sortType)
{
var leftStock=this.GetStockData(left);
var rightStock=this.GetStockData(right);
var leftValue=-99999999999999, rightValue=-99999999999999;
if (sortType==2) leftValue=rightValue=99999999999999;
var filedName=MAP_COLUMN_FIELD.get(column.Type);
if (leftStock && IFrameSplitOperator.IsNumber(leftStock[filedName])) leftValue=leftStock[filedName];
if (rightStock && IFrameSplitOperator.IsNumber(rightStock[filedName])) rightValue=rightStock[filedName];
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.LoacCustomNumberSort=function(left, right, column, sortType)
{
var leftValue=-99999999999999, rightValue=-99999999999999;
if (sortType==2) leftValue=rightValue=99999999999999;
var value=this.GetStockExtendData(left, column);
if (IFrameSplitOperator.IsNumber(value)) leftValue=value;
var value=this.GetStockExtendData(right, column);
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.LoacCustomDateTimeSort=function(left, right, column, sortType)
{
var leftValue=-99999999999999, rightValue=-99999999999999;
if (sortType==2) leftValue=rightValue=99999999999999;
var value=this.GetStockExtendData(left, column);
if (IFrameSplitOperator.IsNumber(value)) leftValue=value;
var value=this.GetStockExtendData(right, column);
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.LoacCustomStringSort=function(left, right, column, sortType)
{
var leftValue="", rightValue="";
if (sortType==2) rightValue=leftValue="啊啊啊啊啊";
var value=this.GetStockExtendData(left, column);
if (IFrameSplitOperator.IsString(value)) leftValue=value;
var value=this.GetStockExtendData(right, column);
if (IFrameSplitOperator.IsString(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.RequestStockSortData=function(column, filedid, sortType)
{
var chart=this.ChartPaint[0];
if (!chart) return;
var self=this;
var startIndex=this.Data.YOffset;
var pageSize=chart.GetPageSize();
var endIndex=startIndex+pageSize;
if (endIndex>=this.Data.Data.length) endIndex=this.Data.Data.length-1;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSDealChartContainer::RequestStockSortData', //类名::函数名
Explain:'报价列表股票排序数据',
Request:
{
Data:
{
range:{ start:startIndex, end:endIndex, count:this.Data.Data.length },
column:{ name: column.Title, type: column.Type, index:filedid, ID:column.ID },
sort:sortType, symbol:this.Symbol, name:this.Name,
pageSize:pageSize
}
},
Self:this,
PreventDefault:false
};
if (chart.FixedRowCount>0 && chart.FixedRowData.Type==1)
{
var arySymbol=[];
for(var i=0;i<chart.FixedRowData.Symbol.length;++i)
{
var item=chart.FixedRowData.Symbol[i];
if (item) arySymbol.push(item);
}
obj.Request.FixedSymbol=arySymbol;
}
this.NetworkFilter(obj, function(data)
{
self.RecvStockSortData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return;
}
//throw { Name:'JSReportChartContainer::RequestStockSortData', Error:'(报价列表股票排序数据)不提供内置测试数据' };
}
this.RecvStockSortData=function(data)
{
//更新股票数据
var arySymbol=[];
if (IFrameSplitOperator.IsNonEmptyArray(data.data))
{
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i]; //数据
var symbol=item[0];
if (!symbol) continue;
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
stock.Symbol=this.GetSymbolNoSuffix(symbol);
this.MapStockData.set(symbol, stock);
}
this.ReadStockJsonData(stock, item);
arySymbol.push(symbol);
}
}
//更新股票顺序
if (IFrameSplitOperator.IsNonEmptyArray(data.index))
{
for(var i=0;i<data.index.length;++i)
{
var index=data.index[i];
var newSymbol=arySymbol[i];
var oldSymbol=this.Data.Data[index];
if (newSymbol==oldSymbol) continue;
this.Data.Data[index]=newSymbol;
}
}
if (data.Virtual)
{
var item=data.Virtual;
if (IFrameSplitOperator.IsNumber(item.Count)) this.Data.Virtual.Count=item.Count;
}
var chart=this.ChartPaint[0];
if (!chart) return;
//更新的股票在当前页面,需要重绘
var bUpdate=true;
if (bUpdate) this.Draw();
}
//虚拟表格 请求序号 所有数据后台返回
this.RequestVirtualStockData=function()
{
var chart=this.ChartPaint[0];
if (!chart) return;
var self=this;
var startIndex=this.Data.YOffset;
var pageSize=chart.GetPageSize();
var endIndex=startIndex+pageSize;
var dataCount=chart.GetAllRowCount();
if (endIndex>=dataCount) endIndex=dataCount-1;
if (!this.NetworkFilter) return;
var requestData=
{
range:{ start:startIndex, end:endIndex, count:chart.GetAllRowCount() },
column:null,
sort:0, symbol:this.Symbol, name:this.Name,
pageSize:pageSize
}
if (this.SortInfo && this.SortInfo.Field>=0 && this.SortInfo.Sort>0) //排序
{
var column=chart.Column[this.SortInfo.Field];
requestData.column={ name: column.Title, type: column.Type, index:this.SortInfo.Field, ID:column.ID };
requestData.sort=this.SortInfo.Sort;
}
var obj=
{
Name:'JSDealChartContainer::RequestVirtualStockData', //类名::函数名
Explain:'报价列表股票数据(虚拟表格)',
Request:
{
Data: requestData
},
Self:this,
PreventDefault:false
};
if (chart.FixedRowCount>0 && chart.FixedRowData.Type==1)
{
var arySymbol=[];
for(var i=0;i<chart.FixedRowData.Symbol.length;++i)
{
var item=chart.FixedRowData.Symbol[i];
if (item) arySymbol.push(item);
}
obj.Request.FixedSymbol=arySymbol;
}
this.NetworkFilter(obj, function(data)
{
self.RecvStockSortData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return;
}
//底部标签
this.ShowPageInfo=function(bShow)
{
var chart=this.ChartPaint[1];
if (!chart) return false;
chart.IsShow=bShow;
return true;
}
this.DrawTooltip=function(tooltipStatus)
{
if (!this.GetExtraCanvas) return;
if (!this.TooltipCanvas)
{
var finder=this.GetExtraCanvas(JSReportChart.TooltipCursorCanvasKey);
if (!finder) return;
this.TooltipCanvas=finder.Canvas;
}
if (!this.TooltipCanvas) return;
this.ClearCanvas(this.TooltipCanvas);
if (!this.ChartTooltip) return;
if (!tooltipStatus || !tooltipStatus.Data) return;
this.ChartTooltip.Canvas=this.TooltipCanvas;
this.ChartTooltip.Point={ X:tooltipStatus.X, Y:tooltipStatus.Y };
this.ChartTooltip.Data=tooltipStatus.Data.Data;
this.ChartTooltip.Draw();
}
}
function JSReportFrame()
{
this.ChartBorder;
this.Canvas; //画布
this.BorderLine=null; //1=上 2=下 4=左 8=右
this.BorderColor=g_JSChartResource.Report.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.Report.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);
}
}
var REPORT_COLUMN_ID=
{
SYMBOL_ID:0,
NAME_ID:1,
PRICE_ID:2, //成交价格
VOL_ID:3, //成交量
INCREASE_ID:4, //涨幅
UPDOWN_ID:5, //涨跌
BUY_PRICE_ID:6, //买价
SELL_PRICE_ID:7, //卖价
AMOUNT_ID:8, //总金额
BUY_VOL_ID:9, //买量
SELL_VOL_ID:10, //卖量
YCLOSE_ID:11, //昨收
OPEN_ID:12,
HIGH_ID:13,
LOW_ID:14,
AVERAGE_PRICE_ID:15,//均价
INDEX_ID:16, //序号 从1开始
OUTSTANDING_SHARES_ID:17, //流通股本
TOTAL_SHARES_ID:18, //总股本
CIRC_MARKET_VALUE_ID:19, //流通市值
MARKET_VALUE_ID:20, //总市值
EXCHANGE_RATE_ID:21, //换手率 成交量/流通股本
AMPLITUDE_ID:22, //振幅
LIMIT_HIGH_ID:23, //涨停价
LIMIT_LOW_ID:24, //跌停价
VOL_IN_ID:25, //内盘
VOL_OUT_ID:26, //外盘
NAME_EX_ID:27, //扩展名字
CLOSE_LINE_ID:28, //收盘价线
KLINE_ID:29, //K线
TIME_ID:31, //时间 hhmmss / hhmm / hhmmss.fff
DATE_ID:32, //日期
CHECKBOX_ID:33, //单选框
FUTURES_POSITION_ID:34, //期货持仓量
FUTURES_CLOSE_ID:35, //期货结算价
FUTURES_YCLOSE_ID:36, //期货昨结算
FUTURES_OPEN_POSITION_ID:37, //期货开仓量
FUTURES_CLOSE_POSITION_ID:38, //期货平仓量
//1,3,5,10,15分钟涨速
RISING_SPEED_1M_ID:60,
RISING_SPEED_3M_ID:61,
RISING_SPEED_5M_ID:62,
RISING_SPEED_10M_ID:63,
RISING_SPEED_15M_ID:64,
SYMBOL_NAME_V2_ID:98, //单行
SYMBOL_NAME_ID:99, //两行
CUSTOM_STRING_TEXT_ID:100, //自定义字符串文本
CUSTOM_NUMBER_TEXT_ID:101, //自定义数值型
CUSTOM_DATETIME_TEXT_ID:102, //自定义日期类型
CUSTOM_ICON_ID:103, //自定义图标
CUSTOM_CHECKBOX_ID:104, //自定义checkbox
CUSTOM_BUTTON_ID:105, //自定义按钮
CUSTOM_PROGRESS_ID:106, //进度条
CUSTOM_LINK_ID:107, //链接
//预留数值类型 10个
RESERVE_NUMBER1_ID:201, //ReserveNumber1:
RESERVE_NUMBER2_ID:202,
RESERVE_NUMBER3_ID:203,
RESERVE_NUMBER4_ID:204,
RESERVE_NUMBER5_ID:205,
RESERVE_NUMBER6_ID:206,
RESERVE_NUMBER7_ID:207,
RESERVE_NUMBER8_ID:208,
RESERVE_NUMBER9_ID:209,
RESERVE_NUMBER10_ID:210,
//预留字符串类型 10个 301-399
RESERVE_STRING1_ID:301, //ReserveString1:
RESERVE_STRING2_ID:302,
RESERVE_STRING3_ID:303,
RESERVE_STRING4_ID:304,
RESERVE_STRING5_ID:305,
RESERVE_STRING6_ID:306,
RESERVE_STRING7_ID:307,
RESERVE_STRING8_ID:308,
RESERVE_STRING9_ID:309,
RESERVE_STRING10_ID:310,
//预留进度条类型 10个 401-450
RESERVE_PROGRESS_BAR1_ID:401, //ReserveProgressBar1:
RESERVE_PROGRESS_BAR2_ID:402,
RESERVE_PROGRESS_BAR3_ID:403,
RESERVE_PROGRESS_BAR4_ID:404,
RESERVE_PROGRESS_BAR5_ID:405,
RESERVE_PROGRESS_BAR6_ID:406,
RESERVE_PROGRESS_BAR7_ID:407,
RESERVE_PROGRESS_BAR8_ID:408,
RESERVE_PROGRESS_BAR9_ID:409,
RESERVE_PROGRESS_BAR10_ID:410,
}
//数据对应字段名对照表
var MAP_COLUMN_FIELD=new Map([
[REPORT_COLUMN_ID.SYMBOL_ID, "Symbol"],
[REPORT_COLUMN_ID.NAME_ID, "Name"],
[REPORT_COLUMN_ID.PRICE_ID, "Price"],
[REPORT_COLUMN_ID.INCREASE_ID, "Increase"],
[REPORT_COLUMN_ID.UPDOWN_ID, "UpDown"],
[REPORT_COLUMN_ID.VOL_ID, "Vol"],
[REPORT_COLUMN_ID.BUY_PRICE_ID, "BuyPrice"],
[REPORT_COLUMN_ID.SELL_PRICE_ID, "SellPrice"],
[REPORT_COLUMN_ID.AMOUNT_ID, "Amount"],
[REPORT_COLUMN_ID.BUY_VOL_ID, "BuyVol"],
[REPORT_COLUMN_ID.SELL_VOL_ID, "SellVol"],
[REPORT_COLUMN_ID.YCLOSE_ID, "YClose"],
[REPORT_COLUMN_ID.OPEN_ID, "Open"],
[REPORT_COLUMN_ID.HIGH_ID, "High"],
[REPORT_COLUMN_ID.LOW_ID, "Low"],
[REPORT_COLUMN_ID.AVERAGE_PRICE_ID,"AvPrice"],
[REPORT_COLUMN_ID.OUTSTANDING_SHARES_ID,"OutShares"],
[REPORT_COLUMN_ID.TOTAL_SHARES_ID,"TotalShares"],
[REPORT_COLUMN_ID.CIRC_MARKET_VALUE_ID,"CircMarketValue"],
[REPORT_COLUMN_ID.MARKET_VALUE_ID,"MarketValue"],
[REPORT_COLUMN_ID.EXCHANGE_RATE_ID, "Exchange"],
[REPORT_COLUMN_ID.AMPLITUDE_ID, "Amplitude"],
[REPORT_COLUMN_ID.LIMIT_HIGH_ID, "LimitHigh"],
[REPORT_COLUMN_ID.LIMIT_LOW_ID,"LimitLow"],
[REPORT_COLUMN_ID.VOL_IN_ID, "VolIn"],
[REPORT_COLUMN_ID.VOL_OUT_ID,"VolOut"],
[REPORT_COLUMN_ID.NAME_EX_ID, "NameEx"],
[REPORT_COLUMN_ID.DATE_ID, "Date"],
[REPORT_COLUMN_ID.FUTURES_POSITION_ID, "Position"],
[REPORT_COLUMN_ID.FUTURES_CLOSE_ID, "FClose"],
[REPORT_COLUMN_ID.FUTURES_YCLOSE_ID, "YFClose"],
[REPORT_COLUMN_ID.FUTURES_OPEN_POSITION_ID, "OpenPosition"],
[REPORT_COLUMN_ID.FUTURES_CLOSE_POSITION_ID, "ClosePosition"],
[REPORT_COLUMN_ID.RISING_SPEED_1M_ID, "RSpeed1M"],
[REPORT_COLUMN_ID.RISING_SPEED_3M_ID, "RSpeed3M"],
[REPORT_COLUMN_ID.RISING_SPEED_5M_ID, "RSpeed5M"],
[REPORT_COLUMN_ID.RISING_SPEED_10M_ID, "RSpeed10M"],
[REPORT_COLUMN_ID.RISING_SPEED_15M_ID, "RSpeed15M"],
[REPORT_COLUMN_ID.RESERVE_NUMBER1_ID,"ReserveNumber1"],
[REPORT_COLUMN_ID.RESERVE_NUMBER2_ID,"ReserveNumber2"],
[REPORT_COLUMN_ID.RESERVE_NUMBER3_ID,"ReserveNumber3"],
[REPORT_COLUMN_ID.RESERVE_NUMBER4_ID,"ReserveNumber4"],
[REPORT_COLUMN_ID.RESERVE_NUMBER5_ID,"ReserveNumber5"],
[REPORT_COLUMN_ID.RESERVE_NUMBER6_ID,"ReserveNumber6"],
[REPORT_COLUMN_ID.RESERVE_NUMBER7_ID,"ReserveNumber7"],
[REPORT_COLUMN_ID.RESERVE_NUMBER8_ID,"ReserveNumber8"],
[REPORT_COLUMN_ID.RESERVE_NUMBER9_ID,"ReserveNumber9"],
[REPORT_COLUMN_ID.RESERVE_NUMBER10_ID,"ReserveNumber10"],
[REPORT_COLUMN_ID.RESERVE_STRING1_ID,"ReserveString1"],
[REPORT_COLUMN_ID.RESERVE_STRING2_ID,"ReserveString2"],
[REPORT_COLUMN_ID.RESERVE_STRING3_ID,"ReserveString3"],
[REPORT_COLUMN_ID.RESERVE_STRING4_ID,"ReserveString4"],
[REPORT_COLUMN_ID.RESERVE_STRING5_ID,"ReserveString5"],
[REPORT_COLUMN_ID.RESERVE_STRING6_ID,"ReserveString6"],
[REPORT_COLUMN_ID.RESERVE_STRING7_ID,"ReserveString7"],
[REPORT_COLUMN_ID.RESERVE_STRING8_ID,"ReserveString8"],
[REPORT_COLUMN_ID.RESERVE_STRING9_ID,"ReserveString9"],
[REPORT_COLUMN_ID.RESERVE_STRING10_ID,"ReserveString10"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR1_ID,"ReserveProgressBar1"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR2_ID,"ReserveProgressBar2"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR3_ID,"ReserveProgressBar3"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR4_ID,"ReserveProgressBar4"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR5_ID,"ReserveProgressBar5"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR6_ID,"ReserveProgressBar6"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR7_ID,"ReserveProgressBar7"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR8_ID,"ReserveProgressBar8"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR9_ID,"ReserveProgressBar9"],
[REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR10_ID,"ReserveProgressBar10"],
]);
function ChartReport()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartReport'; //类名
this.UIElement;
this.IsDrawFirst=false;
this.GetEventCallback; //获取事件
this.GetStockDataCallback; //获取股票数据
this.GetFlashBGDataCallback; //获取闪烁背景
this.GetBlockDataCallback; //获取当前板块的数据
this.Data; //数据 { XOffset:0, YOffset:0, Data:['600000.sh', '000001.sz'] }
this.FixedRowData; //固定行
this.SortInfo; //排序信息 {Field:排序字段id, Sort:0 不排序 1升序 2降序 }
this.FixedColumn=2; //固定列
this.FixedRowCount=0; //固定行
this.IsShowHeader=true; //是否显示表头
this.SizeChange=true;
this.SelectedModel=0; //选中模式 0=SelectedRow表示当前屏索引
this.SelectedRow=-1; //选中行ID
this.SelectedFixedRow=-1; //选中固定行ID
this.IsDrawBorder=1; //是否绘制单元格边框
//多选模式
this.MultiSelectModel=0; //0=禁用 1=开启
this.MultiSelectedRow=[]; //选中行
this.ShowSymbol=[]; //显示的股票列表 { Index:序号(排序用), Symbol:股票代码 }
this.DragRow; //拖拽行
this.Tab;
this.VScrollbar;
this.GlobalOption;
this.TextOverflowStyle=0; //输出内容比单元格长度大 0=裁剪 1=输出"####"
//涨跌颜色
this.UpColor=g_JSChartResource.Report.UpTextColor;
this.DownColor=g_JSChartResource.Report.DownTextColor;
this.UnchagneColor=g_JSChartResource.Report.UnchagneTextColor;
this.BorderColor=g_JSChartResource.Report.BorderColor; //边框线
this.SelectedColor=g_JSChartResource.Report.SelectedColor; //选中行
//表头配置
this.HeaderFontConfig={ Size:g_JSChartResource.Report.Header.Font.Size, Name:g_JSChartResource.Report.Header.Font.Name };
this.HeaderColor=g_JSChartResource.Report.Header.Color;
this.HeaderMergin=
{
Left:g_JSChartResource.Report.Header.Mergin.Left,
Right:g_JSChartResource.Report.Header.Mergin.Right,
Top:g_JSChartResource.Report.Header.Mergin.Top,
Bottom:g_JSChartResource.Report.Header.Mergin.Bottom
};
//排序图标
this.SortConfig=
{
Size:g_JSChartResource.Report.SortIcon.Size,
Family:g_JSChartResource.Report.SortIcon.Family,
Arrow:g_JSChartResource.Report.SortIcon.Arrow.slice(),
Color:g_JSChartResource.Report.SortIcon.Color.slice(),
Margin:
{
Left:g_JSChartResource.Report.SortIcon.Margin.Left,
Bottom:g_JSChartResource.Report.SortIcon.Margin.Bottom
}
}
//表格内容配置
this.ItemFontConfig={ Size:g_JSChartResource.Report.Item.Font.Size, Name:g_JSChartResource.Report.Item.Font.Name };
this.ItemFixedFontConfg={ Size:g_JSChartResource.Report.FixedItem.Font.Size, Name:g_JSChartResource.Report.FixedItem.Font.Name }; //固定行
this.ItemMergin=
{
Left:g_JSChartResource.Report.Item.Mergin.Left,
Right:g_JSChartResource.Report.Item.Mergin.Right,
Top:g_JSChartResource.Report.Item.Mergin.Top,
Bottom:g_JSChartResource.Report.Item.Mergin.Bottom,
};
this.BarMergin=
{
Top:g_JSChartResource.Report.Item.BarMergin.Top,
Left:g_JSChartResource.Report.Item.BarMergin.Left,
Right:g_JSChartResource.Report.Item.BarMergin.Right,
Bottom:g_JSChartResource.Report.Item.BarMergin.Bottom,
};
this.LimitDrawType=0; //0=绘制边框 1=背景色
this.LimitBorderColor=g_JSChartResource.Report.LimitBorder.Color;
this.LimitUpBGColor=g_JSChartResource.Report.LimitColor.UpColor;
this.LimitDownBGColor=g_JSChartResource.Report.LimitColor.DownColor;
this.LimitTextColor=g_JSChartResource.Report.LimitColor.TextColor;
this.LimitMergin=
{
Top:g_JSChartResource.Report.LimitBorder.Mergin.Top,
Left:g_JSChartResource.Report.LimitBorder.Mergin.Left,
Right:g_JSChartResource.Report.LimitBorder.Mergin.Right,
Bottom:g_JSChartResource.Report.LimitBorder.Mergin.Bottom
}
this.DragRowColor=g_JSChartResource.Report.DragRow.Color;
this.DragRowTextColor=g_JSChartResource.Report.DragRow.TextColor;
this.DragMoveRowColor=g_JSChartResource.Report.DragRow.MoveRowColor;
this.DragSrcRowColor=g_JSChartResource.Report.DragRow.SrcRowColor;
//走势图
this.CloseLineConfig=
{
CloseColor:g_JSChartResource.Report.CloseLine.CloseColor,
YCloseColor:g_JSChartResource.Report.CloseLine.YCloseColor,
AreaColor:g_JSChartResource.Report.CloseLine.AreaColor
}
//K线配置
this.KLineConfig=
{
UpColor:g_JSChartResource.Report.KLine.UpColor,
DownColor:g_JSChartResource.Report.KLine.DownColor,
UnchagneColor:g_JSChartResource.Report.KLine.UnchagneColor,
DataWidth:g_JSChartResource.Report.KLine.DataWidth,
DistanceWidth:g_JSChartResource.Report.KLine.DistanceWidth
}
this.CheckBoxConfig=CloneData(g_JSChartResource.Report.CheckBox);
this.LinkConfig=CloneData(g_JSChartResource.Report.Link);
this.ProgressBarConfig=CloneData(g_JSChartResource.Report.ProgressBar);
this.ButtonConfig=CloneData(g_JSChartResource.Report.Button);
//股票代码+股票名称
this.ItemSymbolFontConfig={Size:g_JSChartResource.Report.Item.SymbolFont.Size, Name:g_JSChartResource.Report.Item.SymbolFont.Name};
this.ItemNameFontConfg={Size:g_JSChartResource.Report.Item.NameFont.Size, Name:g_JSChartResource.Report.Item.NameFont.Name};
//名称+代码
this.NameSymbolV2Config=CloneData(g_JSChartResource.Report.NameSymbolV2);
//缓存
this.HeaderFont=12*GetDevicePixelRatio() +"px 微软雅黑";
this.SortFont=null,
this.ItemFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemFontHeight=0;
this.ItemFixedFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemSymbolFont=12*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemNameFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemNameHeight=0;
this.ItemSymbolHeight=0;
this.NameSymbolFont={ Symbol:null, Name:null };
this.RowCount=0; //一屏显示行数
this.HeaderHeight=0; //表头高度
this.FixedRowHeight=0; //固定行高度
this.RowHeight=0; //行高度
this.ItemTextLines=1; //单元格输出行数
this.BottomToolbarHeight=0; //底部工具条高度
this.IsShowAllColumn=false; //是否已显示所有列
this.DevicePixelRatio=GetDevicePixelRatio(); //分辨率
//{
// Type:列id, Title:标题, TextAlign:文字对齐方式, MaxText:文字最大宽度 , TextColor:文字颜色, Sort:0=不支持排序 1=本地排序 0=远程排序,
// Icon:{ Family:"iconfont", Size:12, Symbol:"", Margin: { Left:, Bottom }}
//}
this.Column=
[
{ Type:REPORT_COLUMN_ID.INDEX_ID, Title:"序号", TextAlign:"center", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Index, MaxText:"8888"},
{ Type:REPORT_COLUMN_ID.SYMBOL_ID, Title:"代码", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Symbol, MaxText:"888888"},
{ Type:REPORT_COLUMN_ID.NAME_ID, Title:"名称", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Name, MaxText:"擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.INCREASE_ID, Title:"涨幅%", TextAlign:"right", Width:null, MaxText:"-888.88" },
];
this.RectClient={};
//{ Rect:rtItem, Stock:stock, Index:index, Column:column, RowType:rowType, Type:drawInfo.Tooltip.Type, Data:{ AryText:[ {Text:xx} ]} };
//Type:1=数据截断
// { Text, Color, Title:, TitleColor, Space, Margin:{ Left, Top, Right, Bottom }}
this.TooltipRect=[];
//{ Rect:rtItem, Type: 0=checkedbox, 1=button, 2=link , Stock, Index:index, Column:column }
this.ButtonRect=[];
this.LastMouseStatus;
this.ReloadResource=function(resource)
{
this.DevicePixelRatio=GetDevicePixelRatio()
this.UpColor=g_JSChartResource.Report.UpTextColor;
this.DownColor=g_JSChartResource.Report.DownTextColor;
this.UnchagneColor=g_JSChartResource.Report.UnchagneTextColor;
this.BorderColor=g_JSChartResource.Report.BorderColor; //边框线
this.SelectedColor=g_JSChartResource.Report.SelectedColor; //选中行
//表头配置
this.HeaderFontConfig={ Size:g_JSChartResource.Report.Header.Font.Size, Name:g_JSChartResource.Report.Header.Font.Name };
this.HeaderColor=g_JSChartResource.Report.Header.Color;
this.HeaderMergin=
{
Left:g_JSChartResource.Report.Header.Mergin.Left,
Right:g_JSChartResource.Report.Header.Mergin.Right,
Top:g_JSChartResource.Report.Header.Mergin.Top,
Bottom:g_JSChartResource.Report.Header.Mergin.Bottom
};
//表格内容配置
this.ItemFontConfig={ Size:g_JSChartResource.Report.Item.Font.Size, Name:g_JSChartResource.Report.Item.Font.Name };
this.ItemMergin=
{
Left:g_JSChartResource.Report.Item.Mergin.Left,
Right:g_JSChartResource.Report.Item.Mergin.Right,
Top:g_JSChartResource.Report.Item.Mergin.Top,
Bottom:g_JSChartResource.Report.Item.Mergin.Bottom
};
this.BarMergin=
{
Top:g_JSChartResource.Report.Item.BarMergin.Top,
Left:g_JSChartResource.Report.Item.BarMergin.Left,
Right:g_JSChartResource.Report.Item.BarMergin.Right,
Bottom:g_JSChartResource.Report.Item.BarMergin.Bottom
};
this.LimitBorderColor=g_JSChartResource.Report.LimitBorder.Color;
this.LimitMergin=
{
Top:g_JSChartResource.Report.LimitBorder.Mergin.Top,
Left:g_JSChartResource.Report.LimitBorder.Mergin.Left,
Right:g_JSChartResource.Report.LimitBorder.Mergin.Right,
Bottom:g_JSChartResource.Report.LimitBorder.Mergin.Bottom
}
//排序图标
this.SortConfig=
{
Size:g_JSChartResource.Report.SortIcon.Size,
Family:g_JSChartResource.Report.SortIcon.Family,
Arrow:g_JSChartResource.Report.SortIcon.Arrow.slice(),
Color:g_JSChartResource.Report.SortIcon.Color.slice(),
Margin:
{
Left:g_JSChartResource.Report.SortIcon.Margin.Left,
Bottom:g_JSChartResource.Report.SortIcon.Margin.Bottom
}
}
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
if (item.Type==REPORT_COLUMN_ID.INDEX_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Index;
else if (item.Type==REPORT_COLUMN_ID.SYMBOL_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Symbol;
else if (item.Type==REPORT_COLUMN_ID.NAME_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Name;
else if (item.Type==REPORT_COLUMN_ID.VOL_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Vol;
else if (item.Type==REPORT_COLUMN_ID.BUY_VOL_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Vol;
else if (item.Type==REPORT_COLUMN_ID.SELL_VOL_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Vol;
else if (item.Type==REPORT_COLUMN_ID.AMOUNT_ID)
item.TextColor=g_JSChartResource.Report.FieldColor.Amount;
else if (item.Type==REPORT_COLUMN_ID.VOL_IN_ID)
item.TextColor=g_JSChartResource.Report.DownTextColor;
else if (item.Type==REPORT_COLUMN_ID.VOL_OUT_ID)
item.TextColor=g_JSChartResource.Report.UpTextColor;
else
item.TextColor=g_JSChartResource.Report.FieldColor.Text;
}
if (this.Tab) this.Tab.ReloadResource(resource);
if (this.VScrollbar) this.VScrollbar.ReloadResource(resource);
this.CheckBoxConfig=CloneData(g_JSChartResource.Report.CheckBox);
this.LinkConfig=CloneData(g_JSChartResource.Report.Link);
this.ProgressBarConfig=CloneData(g_JSChartResource.Report.ProgressBar);
}
this.SetColumn=function(aryColumn)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryColumn)) return;
this.Column=[];
for(var i=0;i<aryColumn.length;++i)
{
var item=aryColumn[i];
var colItem=this.GetDefaultColunm(item.Type);
if (!colItem) continue;
if (item.Title) colItem.Title=item.Title;
if (item.TextAlign) colItem.TextAlign=item.TextAlign;
if (item.TextColor) colItem.TextColor=item.TextColor;
if (item.HeaderColor) colItem.HeaderColor=item.HeaderColor;
if (item.MaxText) colItem.MaxText=item.MaxText;
if (item.MaxText2) colItem.MaxText=item.MaxText2;
if (IFrameSplitOperator.IsNumber(item.Space)) colItem.Space=item.Space;
if (item.ID) colItem.ID=item.ID;
if (item.FullColBGColor) colItem.FullColBGColor=item.FullColBGColor; //整列背景色
if (item.HeaderBGColor) colItem.HeaderBGColor=item.HeaderBGColor; //表头背景色
if (IFrameSplitOperator.IsNumber(item.Sort)) colItem.Sort=item.Sort;
if (IFrameSplitOperator.IsNumber(item.FixedWidth)) colItem.FixedWidth=item.FixedWidth;
if (IFrameSplitOperator.IsBool(item.EnableDragWidth)) colItem.EnableDragWidth=item.EnableDragWidth;
if (IFrameSplitOperator.IsBool(item.IsDrawCallback)) colItem.IsDrawCallback=item.IsDrawCallback;
if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) colItem.FloatPrecision=item.FloatPrecision; //小数位数
if (IFrameSplitOperator.IsNumber(item.ColorType)) colItem.ColorType=item.ColorType; //0=默认 1=(>0, =0, <0) 2=(>=0, <0)
else colItem.IsDrawCallback=false;
if (item.Icon) colItem.Icon=item.Icon;
//点击表头弹出菜单
if (IFrameSplitOperator.IsBool(item.EnablePopupHeaderMenu)) colItem.EnablePopupHeaderMenu=item.EnablePopupHeaderMenu;
if (item.Sort==1 || item.Sort==2) //1本地排序 2=远程排序
{
colItem.SortType=[1,2]; //默认 降序 ,升序
if (IFrameSplitOperator.IsNonEmptyArray(item.SortType)) colItem.SortType=item.SortType.slice();
}
if (item.Type==REPORT_COLUMN_ID.CUSTOM_STRING_TEXT_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
colItem.FormatType=0; //0=默认格式 1=长度不够使用...
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
if (IFrameSplitOperator.IsNumber(item.FormatType)) colItem.FormatType=item.FormatType; //输出样式
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_NUMBER_TEXT_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
colItem.Decimal=2;
colItem.FormatType=0; //0=默认格式化 1=原始输出 2=科学计数 3=成交量格式化
colItem.ColorType=0; //0=默认使用TextColor, 1=(>0涨,<0跌)2=(>昨收涨,<昨收跌)
if (IFrameSplitOperator.IsNumber(item.Decimal)) colItem.Decimal=item.Decimal; //小数位数
if (IFrameSplitOperator.IsNumber(item.FormatType)) colItem.FormatType=item.FormatType; //输出样式
if (IFrameSplitOperator.IsNumber(item.ColorType)) colItem.ColorType=item.ColorType; //颜色属性
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_DATETIME_TEXT_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
colItem.FormatType=0; //0=yyyy-mm-dd 1=YYYY/MM/DD
colItem.ValueType=0; //0=yyyymmdd 1=hhmmss
if (IFrameSplitOperator.IsNumber(item.FormatType)) colItem.FormatType=item.FormatType; //输出样式
if (IFrameSplitOperator.IsNumber(item.ValueType)) colItem.FormatType=item.ValueType; //输出样式
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_CHECKBOX_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
if (item.CheckBox) colItem.CheckBox=CloneData(item.CheckBox);
else colItem.CheckBox=this.CheckBoxConfig;
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_BUTTON_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
if (item.Button) colItem.Button=CloneData(item.Button);
else colItem.Button=this.ButtonConfig;
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_PROGRESS_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
if (item.ProgressBar) colItem.ProgressBar=CloneData(item.ProgressBar);
else colItem.ProgressBar=this.ProgressBarConfig;
}
else if (this.IsReserveProgressBarColumn(item.Type))
{
if (item.ProgressBar) colItem.ProgressBar=CloneData(item.ProgressBar);
else colItem.ProgressBar=this.ProgressBarConfig;
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_LINK_ID)
{
if (!IFrameSplitOperator.IsNumber(item.DataIndex) && !IFrameSplitOperator.IsNumber(item.BlockIndex)) continue;
if (IFrameSplitOperator.IsNumber(item.DataIndex)) colItem.DataIndex=item.DataIndex; //数据在扩展数据索引列
if (IFrameSplitOperator.IsNumber(item.BlockIndex)) colItem.BlockIndex=item.BlockIndex;
if (item.Link) colItem.Link=CloneData(item.Link);
else colItem.Link=this.LinkConfig;
}
else if (item.Type==REPORT_COLUMN_ID.CUSTOM_ICON_ID)
{
}
else if (item.Type==REPORT_COLUMN_ID.CLOSE_LINE_ID)
{
if (IFrameSplitOperator.IsBool(item.IsDrawArea)) colItem.IsDrawArea=item.IsDrawArea;
}
else if(item.Type==REPORT_COLUMN_ID.TIME_ID)
{
if (IFrameSplitOperator.IsNumber(item.ValueType)) colItem.ValueType=item.ValueType;
}
else if (item.Type==REPORT_COLUMN_ID.DATE_ID)
{
if (IFrameSplitOperator.IsNumber(item.FormatType)) colItem.FormatType=item.FormatType;
}
this.Column.push(colItem);
}
}
this.SwapColumn=function(leftIndex, rightIndex)
{
if (!IFrameSplitOperator.IsNumber(leftIndex) || !IFrameSplitOperator.IsNumber(rightIndex)) return false;
var count=this.Column.length;
if (leftIndex<0 || leftIndex>=count) return false;
if (rightIndex<0 || rightIndex>=count) return false;
if (leftIndex==rightIndex) return;
var tempItem=this.Column[leftIndex];
this.Column[leftIndex]=this.Column[rightIndex];
this.Column[rightIndex]=tempItem;
return true;
}
this.DeleteColumn=function(index)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Column)) return false;
if (index<0 || index>=this.Column.length) return false;
this.Column.splice(index,1);
return true;
}
this.GetXScrollPos=function()
{
return this.Data.XOffset;
}
this.GetXScrollRange=function()
{
var maxOffset=this.Column.length-this.FixedColumn-3;
if (maxOffset<0) return 0;
return maxOffset;
}
this.GetYScrollRange=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return 0;
var dataCount=this.GetAllRowCount();
var maxOffset=dataCount-this.RowCount;
return maxOffset;
}
this.GetDefaultColunm=function(id)
{
var DEFAULT_COLUMN=
[
{ Type:REPORT_COLUMN_ID.INDEX_ID, Title:"序号", TextAlign:"center", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Index, MaxText:"8888"},
{ Type:REPORT_COLUMN_ID.SYMBOL_ID, Title:"代码", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Symbol, MaxText:"888888"},
{ Type:REPORT_COLUMN_ID.NAME_ID, Title:"名称", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Name, MaxText:"擎擎擎擎0" },
{ Type:REPORT_COLUMN_ID.NAME_EX_ID, Title:"名称", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Name, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.SYMBOL_NAME_ID, Title:"股票名称", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Name, MaxText:"擎擎擎擎0"},
{ Type:REPORT_COLUMN_ID.SYMBOL_NAME_V2_ID, Title:"名称/代码", TextAlign:"left", Width:null, TextColor:g_JSChartResource.Report.NameSymbolV2.Name.Color, MaxText:"擎擎擎擎*", MaxText2:"999999", Space:5, TextColor2:g_JSChartResource.Report.NameSymbolV2.Symbol.Color },
{ Type:REPORT_COLUMN_ID.INCREASE_ID, Title:"涨幅%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.PRICE_ID, Title:"现价", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.UPDOWN_ID, Title:"涨跌", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.AMPLITUDE_ID, Title:"振幅%", TextAlign:"right", Width:null, MaxText:"888.88" },
{ Type:REPORT_COLUMN_ID.BUY_PRICE_ID, Title:"买价", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.SELL_PRICE_ID, Title:"卖价", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.AVERAGE_PRICE_ID, Title:"均价", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.OPEN_ID, Title:"今开", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.HIGH_ID, Title:"最高", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.LOW_ID, Title:"最低", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.YCLOSE_ID, Title:"昨收", TextAlign:"right", Width:null, MaxText:"88888.88" },
{ Type:REPORT_COLUMN_ID.VOL_ID, Title:"总量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Vol, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.AMOUNT_ID, Title:"总金额", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Amount, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.EXCHANGE_RATE_ID, Title:"换手%", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"88.88擎" },
{ Type:REPORT_COLUMN_ID.OUTSTANDING_SHARES_ID, Title:"流通股本", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.TOTAL_SHARES_ID, Title:"总股本", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.CIRC_MARKET_VALUE_ID, Title:"流通市值", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.MARKET_VALUE_ID, Title:"总市值", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.VOL_IN_ID, Title:"内盘", TextAlign:"right", TextColor:g_JSChartResource.Report.DownTextColor, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.VOL_OUT_ID, Title:"外盘", TextAlign:"right", TextColor:g_JSChartResource.Report.UpTextColor, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.CLOSE_LINE_ID, Title:"走势", TextAlign:"center", TextColor:g_JSChartResource.Report.CloseLineColor, Width:null, MaxText:"88888.88888" },
{ Type:REPORT_COLUMN_ID.BUY_VOL_ID, Title:"买量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Vol, Width:null, MaxText:"8888.8擎" },
{ Type:REPORT_COLUMN_ID.SELL_VOL_ID, Title:"卖量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Vol, Width:null, MaxText:"8888.8擎" },
//{ Type:REPORT_COLUMN_ID.MULTI_BAR_ID, Title:"柱子", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.BarTitle, MaxText:"888888" },
//{ Type:REPORT_COLUMN_ID.CENTER_BAR_ID, Title:"柱子2", TextAlign:"center", Width:null, TextColor:g_JSChartResource.DealList.FieldColor.BarTitle, MaxText:"888888" },
{ Type:REPORT_COLUMN_ID.CUSTOM_STRING_TEXT_ID, Title:"自定义", TextAlign:"center", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.CUSTOM_NUMBER_TEXT_ID, Title:"自定义", TextAlign:"center", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.CUSTOM_DATETIME_TEXT_ID, Title:"自定义", TextAlign:"center", Width:null, TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999-99-99" },
{ Type:REPORT_COLUMN_ID.CUSTOM_ICON_ID, Title:" ", TextAlign:"left", FixedWidth:20, TextColor:g_JSChartResource.Report.FieldColor.Text },
{ Type:REPORT_COLUMN_ID.KLINE_ID, Title:"K线", TextAlign:"left", FixedWidth:50, TextColor:g_JSChartResource.Report.FieldColor.Text },
{ Type:REPORT_COLUMN_ID.TIME_ID, Title:"时间", TextAlign:"left", ValueType:0, TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"99:99:99.999" },
{ Type:REPORT_COLUMN_ID.DATE_ID, Title:"日期", TextAlign:"left", FormatType:0, TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999-99-99" },
{ Type:REPORT_COLUMN_ID.CHECKBOX_ID, Title:"", TextAlign:"center", FixedWidth:20*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.CUSTOM_CHECKBOX_ID, Title:"", TextAlign:"center", FixedWidth:20*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.CUSTOM_BUTTON_ID, Title:"", TextAlign:"center", FixedWidth:50*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.CUSTOM_PROGRESS_ID, Title:"进度条", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.CUSTOM_LINK_ID, Title:"链接地址", TextAlign:"center", MaxText:"擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.FUTURES_POSITION_ID, Title:"持仓量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Vol, Width:null, MaxText:"8888888" },
{ Type:REPORT_COLUMN_ID.FUTURES_CLOSE_ID, Title:"结算价", TextAlign:"right", Width:null, MaxText:"8888888" },
{ Type:REPORT_COLUMN_ID.FUTURES_YCLOSE_ID, Title:"昨结算价", TextAlign:"right", Width:null, MaxText:"8888888" },
{ Type:REPORT_COLUMN_ID.FUTURES_OPEN_POSITION_ID, Title:"开仓量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888888" },
{ Type:REPORT_COLUMN_ID.FUTURES_CLOSE_POSITION_ID, Title:"平仓量", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, Width:null, MaxText:"8888888" },
{ Type:REPORT_COLUMN_ID.RISING_SPEED_1M_ID, Title:"涨速%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.RISING_SPEED_3M_ID, Title:"3分涨速%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.RISING_SPEED_5M_ID, Title:"5分涨速%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.RISING_SPEED_10M_ID, Title:"10分涨速%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.RISING_SPEED_15M_ID, Title:"15分涨速%", TextAlign:"right", Width:null, MaxText:"-888.88" },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER1_ID, Title:"数值1", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER2_ID, Title:"数值2", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER3_ID, Title:"数值3", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER4_ID, Title:"数值4", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER5_ID, Title:"数值5", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER6_ID, Title:"数值6", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER7_ID, Title:"数值7", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER8_ID, Title:"数值8", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER9_ID, Title:"数值9", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_NUMBER10_ID, Title:"数值10", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"9999.99", FloatPrecision:2 },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING1_ID, Title:"文字1", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING2_ID, Title:"文字2", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING3_ID, Title:"文字3", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING4_ID, Title:"文字4", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING5_ID, Title:"文字5", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING6_ID, Title:"文字6", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING7_ID, Title:"文字7", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING8_ID, Title:"文字8", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING9_ID, Title:"文字9", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_STRING10_ID, Title:"文字10", TextAlign:"right", TextColor:g_JSChartResource.Report.FieldColor.Text, MaxText:"擎擎擎擎擎擎" },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR1_ID, Title:"进度条1", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR2_ID, Title:"进度条2", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR3_ID, Title:"进度条3", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR4_ID, Title:"进度条4", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR5_ID, Title:"进度条5", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR6_ID, Title:"进度条6", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR7_ID, Title:"进度条7", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR8_ID, Title:"进度条8", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR9_ID, Title:"进度条9", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
{ Type:REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR10_ID, Title:"进度条10", TextAlign:"center", FixedWidth:100*GetDevicePixelRatio() },
];
for(var i=0;i<DEFAULT_COLUMN.length;++i)
{
var item=DEFAULT_COLUMN[i];
if (item.Type==id) return item;
}
return null;
}
this.ClipClient=function()
{
this.Canvas.save();
this.Canvas.beginPath();
this.Canvas.rect(this.RectClient.Left,this.RectClient.Top,(this.RectClient.Right-this.RectClient.Left),(this.RectClient.Bottom-this.RectClient.Top));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
}
this.Draw=function(lastMouseStatus)
{
this.ShowSymbol=[];
this.TooltipRect=[];
this.ButtonRect=[];
this.DevicePixelRatio=GetDevicePixelRatio()
this.LastMouseStatus=lastMouseStatus;
if (this.GlobalOption) this.GlobalOption.FlashBGCount=0;
if (this.SizeChange) this.CalculateSize();
else this.UpdateCacheData();
this.ClipClient();
this.DrawHeader();
this.DrawBody();
this.Canvas.restore();
if (this.Tab && this.BottomToolbarHeight>0)
{
var bottom=this.ChartBorder.GetBottom();
this.Tab.DrawTab(this.RectClient.Left,bottom-this.BottomToolbarHeight, this.RectClient.Right, bottom)
this.Tab.DrawScrollbar(this.RectClient.Left,bottom-this.BottomToolbarHeight, this.RectClient.Right, bottom);
}
this.ClipClient();
this.DrawBorder();
this.Canvas.restore();
this.DrawDragRow();
if (this.VScrollbar)
{
var bottom=this.ChartBorder.GetBottom();
this.VScrollbar.DrawScrollbar(this.RectClient.Left,this.RectClient.Top+this.HeaderHeight, this.RectClient.Right, bottom-this.BottomToolbarHeight-4);
}
this.LastMouseStatus=null;
this.SizeChange=false;
}
//更新缓存变量
this.UpdateCacheData=function()
{
this.RectClient.Left=this.ChartBorder.GetLeft();
this.RectClient.Right=this.ChartBorder.GetRight();
this.RectClient.Top=this.ChartBorder.GetTop();
this.RectClient.Bottom=this.ChartBorder.GetBottom()-this.BottomToolbarHeight;
}
this.GetPageSize=function(recalculate) //recalculate 是否重新计算
{
if (recalculate) this.CalculateSize();
var size=this.RowCount;
return size;
}
this.GetCurrentPageStatus=function() //{ Start:起始索引, End:结束索引(数据), PageSize:页面可以显示几条记录, IsEnd:是否是最后一页, IsSinglePage:是否只有一页数据}
{
var result={ Start:this.Data.YOffset, PageSize:this.RowCount, IsEnd:false, SelectedRow:this.SelectedRow, IsSinglePage:false, DataCount:0, MultiSelectModel:this.MultiSelectModel };
if (this.MultiSelectModel==1)
{
result.SelectedRow=-1;
result.MultiSelectedRow=this.MultiSelectedRow.slice();
result.MultiSelectedRow.sort((left, right)=>{ return left>right; });
}
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
result.End=this.Data.YOffset+this.RowCount-1;
result.IsSinglePage=this.Data.Data.length<=this.RowCount;
result.DataCount=this.Data.Data.length;
if (result.End>=this.Data.Data.length-1) result.IsEnd=true;
if (result.End>=this.Data.Data.length) result.End=this.Data.Data.length-1;
}
else
{
result.Start=0;
result.End=0;
result.IsEnd=true;
result.IsSinglePage=true;
}
return result;
}
this.CalculateSize=function() //计算大小
{
if (this.Tab && this.Tab.IsShow)
{
this.Tab.CalculateSize();
this.BottomToolbarHeight=this.Tab.Height;
}
else
{
this.BottomToolbarHeight=0;
}
if (this.VScrollbar && this.VScrollbar.Enable) this.VScrollbar.CalculateSize();
this.UpdateCacheData();
var pixelRatio=GetDevicePixelRatio();
this.HeaderFont=`${this.HeaderFontConfig.Size*pixelRatio}px ${ this.HeaderFontConfig.Name}`;
this.ItemFont=`${this.ItemFontConfig.Size*pixelRatio}px ${ this.ItemFontConfig.Name}`;
this.ItemFixedFont=`${this.ItemFixedFontConfg.Size*pixelRatio}px ${ this.ItemFixedFontConfg.Name}`;
this.ItemSymbolFont=`${this.ItemSymbolFontConfig.Size*pixelRatio}px ${ this.ItemSymbolFontConfig.Name}`;
this.ItemNameFont=`${this.ItemNameFontConfg.Size*pixelRatio}px ${ this.ItemNameFontConfg.Name}`;
this.NameSymbolFont.Symbol=`${this.NameSymbolV2Config.Symbol.Size*pixelRatio}px ${this.NameSymbolV2Config.Symbol.Name}`;
this.NameSymbolFont.Name=`${this.ItemSymbolFontConfig.Name.Size*pixelRatio}px ${this.NameSymbolV2Config.Name.Name}`;
this.ItemFontHeight=this.GetFontHeight(this.ItemFont,"擎");
this.RowHeight=this.ItemFontHeight+ this.ItemMergin.Top+ this.ItemMergin.Bottom;
this.ItemTextLines=1;
this.FixedRowHeight=this.GetFontHeight(this.ItemFixedFont,"擎")+ this.ItemMergin.Top+ this.ItemMergin.Bottom;
this.SortFont=`${this.SortConfig.Size*pixelRatio}px ${ this.SortConfig.Family}`;
this.Canvas.font=this.ItemFont;
var itemWidth=0;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
if (item.Type==REPORT_COLUMN_ID.SYMBOL_NAME_ID)
{
this.Canvas.font=this.ItemNameFont;
var nameWidth=this.Canvas.measureText(item.MaxText).width;
var nameHeight=this.GetFontHeight(this.ItemNameFont,"擎");
this.ItemNameHeight=nameHeight;
this.Canvas.font=this.ItemSymbolFont;
var symbolWidth=this.Canvas.measureText(item.MaxText).width;
var symboHeight=this.GetFontHeight(this.ItemSymbolFont,"擎");
this.ItemSymbolHeight=symboHeight;
this.Canvas.font=this.ItemFont;
itemWidth=Math.max(nameWidth, symbolWidth);
item.Width=itemWidth+4+this.ItemMergin.Left+this.ItemMergin.Right;
var rowHeight=nameHeight+symboHeight+this.ItemMergin.Top+ this.ItemMergin.Bottom;
this.ItemTextLines=2;
if (rowHeight>this.RowHeight) this.RowHeight=rowHeight;
if (rowHeight>this.FixedRowHeight) this.FixedRowHeight=rowHeight;
}
else if (item.Type==REPORT_COLUMN_ID.SYMBOL_NAME_V2_ID) //单行显示
{
this.Canvas.font==this.NameSymbolFont.Name;
var nameWidth=this.Canvas.measureText(item.MaxText).width;
var nameHeight=this.GetFontHeight(this.ItemNameFont,"擎");
this.Canvas.font==this.NameSymbolFont.Symbol;
var symbolWidth=this.Canvas.measureText(item.MaxText2).width;
var symboHeight=this.GetFontHeight(this.ItemSymbolFont,"擎");
this.ItemNameHeight=Math.abs(nameHeight,symboHeight);
var space=2;
if (IFrameSplitOperator.IsNumber(item.Space)) space=item.Space;
itemWidth=nameWidth+symbolWidth+space;
item.Width=itemWidth+4+this.ItemMergin.Left+this.ItemMergin.Right;
}
else
{
if (IFrameSplitOperator.IsNumber(item.FixedWidth)) itemWidth=item.FixedWidth;
else itemWidth=this.Canvas.measureText(item.MaxText).width;
item.Width=itemWidth+4+this.ItemMergin.Left+this.ItemMergin.Right;
}
if (item.Icon && item.Icon.Symbol)
{
item.Width+=item.Icon.Size;
if (item.Icon.Margin)
{
var margin=item.Icon.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) item.Width+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) item.Width+=margin.Right;
}
}
}
this.Canvas.font=this.HeaderFont;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
if (!item.Title || item.Title.length<=0) continue;
var text=item.Title;
itemWidth=this.Canvas.measureText(text).width;
if (item.Sort>0) itemWidth+this.SortConfig.Size*pixelRatio;
itemWidth+=(4+this.HeaderMergin.Left+this.HeaderMergin.Right);
if (item.Width<itemWidth) item.Width=itemWidth;
}
this.HeaderHeight=this.GetFontHeight(this.HeaderFont,"擎")+ this.HeaderMergin.Top+ this.HeaderMergin.Bottom;
if (!this.IsShowHeader) this.HeaderHeight=0;
if (this.FixedRowCount<=0) this.FixedRowHeight=0;
this.RowCount=parseInt((this.RectClient.Bottom-this.RectClient.Top-this.HeaderHeight-(this.FixedRowHeight*this.FixedRowCount))/this.RowHeight);
var subWidth=0;
var reportWidth=this.RectClient.Right-this.RectClient.Left;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
subWidth+=item.Width;
}
this.IsShowAllColumn=(subWidth<reportWidth);
}
this.DrawHeader=function()
{
if (!this.IsShowHeader) return;
var left=this.RectClient.Left;
var top=this.RectClient.Top;
var y=top+this.HeaderMergin.Top+(this.HeaderHeight-this.HeaderMergin.Top-this.HeaderMergin.Bottom)/2;
var yBottom=top+this.HeaderHeight;
this.Canvas.font=this.HeaderFont;
var textLeft=left;
//固定列
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
var itemWidth=item.Width;
var textWidth=itemWidth-this.HeaderMergin.Left-this.HeaderMergin.Right;
var x=textLeft+this.HeaderMergin.Left;
if (item.HeaderBGColor)
{
var rtBG={Left:textLeft, Top:top, Width:itemWidth, Height:this.HeaderHeight };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
this.DrawItemBG({ Rect:rtBG, BGColor:item.HeaderBGColor });
}
var iconWidth=0;
if (item.Icon && item.Icon.Symbol) //图标
{
var iconWidth=item.Icon.Size;
if (item.Icon.Margin)
{
var margin=item.Icon.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) iconWidth+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) iconWidth+=margin.Right;
}
}
textWidth-=iconWidth;
if (item.HeaderColor) this.Canvas.fillStyle=item.HeaderColor;
else this.Canvas.fillStyle=this.HeaderColor;
var textSize={ }
if (this.SortInfo && this.SortInfo.Field==i && this.SortInfo.Sort>0)
{
this.DrawSortHeader(item.Title,item.TextAlign,x,yBottom,textWidth,this.SortInfo.Sort, textSize);
}
else
{
this.DrawText(item.Title,item.TextAlign,x,yBottom,textWidth,textSize);
}
if (iconWidth>0)
{
this.DrawHeaderIcon(item.Icon, textSize.Right, yBottom, i, item);
this.Canvas.font=this.HeaderFont;
}
this.Canvas.fillStyle=this.HeaderColor;
textLeft+=item.Width;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
var itemWidth=item.Width;
var textWidth=itemWidth-this.HeaderMergin.Left-this.HeaderMergin.Right;
var x=textLeft+this.HeaderMergin.Left;
if (item.HeaderBGColor)
{
var rtBG={Left:textLeft, Top:top, Width:itemWidth, Height:this.HeaderHeight };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
this.DrawItemBG({ Rect:rtBG, BGColor:item.HeaderBGColor });
}
var iconWidth=0;
if (item.Icon && item.Icon.Symbol) //图标
{
var iconWidth=item.Icon.Size;
if (item.Icon.Margin)
{
var margin=item.Icon.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) iconWidth+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) iconWidth+=margin.Right;
}
}
textWidth-=iconWidth;
if (item.HeaderColor) this.Canvas.fillStyle=item.HeaderColor;
else this.Canvas.fillStyle=this.HeaderColor;
var textSize={ }
if (this.SortInfo && this.SortInfo.Field==i && this.SortInfo.Sort>0)
{
this.DrawSortHeader(item.Title,item.TextAlign,x,yBottom,textWidth,this.SortInfo.Sort,textSize);
}
else
{
this.DrawText(item.Title,item.TextAlign,x,yBottom,textWidth,textSize);
}
if (iconWidth>0)
{
this.DrawHeaderIcon(item.Icon, textSize.Right, yBottom, i, item);
this.Canvas.font=this.HeaderFont;
}
textLeft+=item.Width;
}
}
this.DrawText=function(text, textAlign, x, yBottom, cellWidth, textSize)
{
var textWidth=this.Canvas.measureText(text).width;
if (textAlign=='center')
{
x=x+(cellWidth-textWidth)/2;
}
else if (textAlign=='right')
{
x=x+cellWidth-textWidth;
}
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.fillText(text,x,yBottom-this.HeaderMergin.Bottom);
if (textSize)
{
textSize.Right=x+textWidth;
textSize.Width=textWidth;
}
}
this.DrawHeaderIcon=function(icon, x, yBottom, index, column)
{
var iconFont=`${icon.Size}px ${icon.Family}`;
this.Canvas.font=iconFont;
this.Canvas.textAlign="left";
if (icon.Color) this.Canvas.fillStyle=icon.Color;
var xIcon=x;
var yIcon=yBottom;
if (icon.Margin && IFrameSplitOperator.IsNumber(icon.Margin.Left)) xIcon+=icon.Margin.Left;
if (icon.Margin && IFrameSplitOperator.IsNumber(icon.Margin.Bottom)) yIcon-=icon.Margin.Bottom;
this.Canvas.fillText(icon.Symbol, xIcon, yIcon);
if (icon.Tooltip)
{
var rtIcon={ Left:xIcon, Bottom:yIcon, Width:icon.Size, Height:icon.Size };
rtIcon.Right=rtIcon.Left+rtIcon.Width;
rtIcon.Top=rtIcon.Bottom-rtIcon.Height;
var tooltipData={ Rect:rtIcon, Type:2, Column:column, Index:index, Data:icon.Tooltip.Data };
this.TooltipRect.push(tooltipData);
}
}
this.DrawSortHeader=function(text, textAlign, x, yBottom, width, sortType,textSize)
{
var pixelRatio=GetDevicePixelRatio();
var sortText=this.SortConfig.Arrow[sortType];
this.Canvas.font=this.HeaderFont;
var textWidth=this.Canvas.measureText(text).width;
var sortTextWidth=this.SortConfig.Size*pixelRatio+this.SortConfig.Margin.Left;
if (textAlign=='center')
{
x=x+width/2-(sortTextWidth+textWidth)/2;
}
else if (textAlign=='right')
{
x=(x+width)-sortTextWidth-textWidth;
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
var xText=x;
this.Canvas.font=this.HeaderFont;
this.Canvas.fillStyle=this.HeaderColor;
this.Canvas.fillText(text,xText,yBottom-this.HeaderMergin.Bottom);
xText+=(textWidth+this.SortConfig.Margin.Left);
this.Canvas.font=this.SortFont;
this.Canvas.fillStyle=this.SortConfig.Color[sortType];
this.Canvas.fillText(sortText,xText,yBottom-this.SortConfig.Margin.Bottom);
this.Canvas.font=this.HeaderFont;
this.Canvas.fillStyle=this.HeaderColor;
if (textSize)
{
textSize.Right=x+textWidth+sortTextWidth;
textSize.Width=textWidth+sortTextWidth;
}
}
this.DrawBorder=function()
{
if (!this.IsDrawBorder) return;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var top=this.RectClient.Top;
var bottom=this.RectClient.Bottom;
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(top+this.HeaderHeight));
this.Canvas.lineTo(right,ToFixedPoint(top+this.HeaderHeight));
var rowTop=top+this.HeaderHeight+this.RowHeight;
var rotBottom=rowTop;
for(var i=0;i<this.FixedRowCount;++i)
{
var drawTop=ToFixedPoint(rowTop);
this.Canvas.moveTo(left,drawTop);
this.Canvas.lineTo(right,drawTop);
rotBottom=rowTop;
rowTop+=this.FixedRowHeight;
}
var rowTop=top+this.HeaderHeight+this.RowHeight+this.FixedRowHeight*this.FixedRowCount;
var rotBottom=rowTop;
//横线
for(var i=0;i<this.RowCount;++i)
{
var drawTop=ToFixedPoint(rowTop);
this.Canvas.moveTo(left,drawTop);
this.Canvas.lineTo(right,drawTop);
rotBottom=rowTop;
rowTop+=this.RowHeight;
}
//竖线
var columnLeft=left;
for(var i=0;i<this.FixedColumn && i<this.Column.length; ++i)
{
var item=this.Column[i];
var drawLeft=ToFixedPoint(columnLeft+item.Width);
this.Canvas.moveTo(drawLeft,top);
this.Canvas.lineTo(drawLeft,rotBottom);
columnLeft+=item.Width;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
var drawLeft=ToFixedPoint(columnLeft+item.Width);
this.Canvas.moveTo(drawLeft,top);
this.Canvas.lineTo(drawLeft,rotBottom);
columnLeft+=item.Width;
}
this.Canvas.stroke();
}
//获取一共多少行
this.GetAllRowCount=function()
{
var count=this.Data.Data.length;
if (this.Data.Virtual && this.Data.Virtual.Enable) count=this.Data.Virtual.Count;
return count;
}
this.DrawBody=function()
{
if (!this.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data) && !this.Data.Virtual.Enable) return;
this.Canvas.font=this.ItemFont;
var top=this.RectClient.Top+this.HeaderHeight;
var left=this.RectClient.Left;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
//固定行
var textTop=top;
this.Canvas.font=this.ItemFixedFont;
for(var i=0; i<this.FixedRowCount; ++i)
{
if (this.SelectedFixedRow==i)
{
this.Canvas.fillStyle=this.SelectedColor;;
this.Canvas.fillRect(left,textTop,rowWidth,this.FixedRowHeight);
}
if (this.FixedRowData.Type==1)
this.DrawFixedSymbolRow(textTop,i);
else
this.DrawFixedRow(textTop, i);
textTop+=this.FixedRowHeight;
}
textTop=top+this.FixedRowHeight*this.FixedRowCount;
this.Canvas.font=this.ItemFont;
var eventDrawBG=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_REPORT_ROW_BG);
var selectedSymbol=this.GetSelectedSymbol();
var setSelected;
if (this.MultiSelectModel==1) setSelected=new Set(this.MultiSelectedRow);
var dataCount=this.GetAllRowCount();
for(var i=this.Data.YOffset, j=0; i<dataCount && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var bFillRow=false;
if (this.MultiSelectModel==1)
{
if (setSelected.has(i)) bFillRow=true;
}
else
{
if (this.SelectedModel==0)
{
if (j==this.SelectedRow) bFillRow=true; //选中行
}
else
{
if (i==this.SelectedRow) bFillRow=true; //选中行
}
}
if (this.DragRow)
{
if (this.DragRow.Data)
{
var dataIndex=this.DragRow.Data.Row.DataIndex;
if (dataIndex==i)
{
this.Canvas.fillStyle=this.DragSrcRowColor;
this.Canvas.fillRect(left,textTop,rowWidth,this.RowHeight);
}
}
if (this.DragRow.MoveRow)
{
var dataIndex=this.DragRow.MoveRow.Data.DataIndex;
if (dataIndex==i)
{
this.Canvas.fillStyle=this.DragMoveRowColor;
this.Canvas.fillRect(left,textTop,rowWidth,this.RowHeight);
}
}
bFillRow=false;
}
if (eventDrawBG && eventDrawBG.Callback)
{
//Out:{ BGColor: }
var sendData={ RowIndex:i, Symbol:symbol, Out:null, Selected:selectedSymbol, MultiSelectModel:this.MultiSelectModel };
eventDrawBG.Callback(eventDrawBG,sendData,this);
if (sendData.Out && sendData.Out.BGColor)
{
this.Canvas.fillStyle=sendData.Out.BGColor;
this.Canvas.fillRect(left,textTop,rowWidth,this.RowHeight);
}
}
if (bFillRow)
{
this.Canvas.fillStyle=this.SelectedColor;
this.Canvas.fillRect(left,textTop,rowWidth,this.RowHeight);
}
this.DrawRow(symbol, textTop, i);
this.ShowSymbol.push( { Index:i, Symbol:symbol } );
textTop+=this.RowHeight;
}
}
this.GetSelectedSymbol=function()
{
if (this.MultiSelectModel==1)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.MultiSelectedRow)) return null;
var aryData=[];
for(var i=0;i<this.MultiSelectedRow.length;++i)
{
var item=this.Data.Data[this.MultiSelectedRow[i]];
if (!item) continue;
aryData.push(item);
}
return aryData;
}
else
{
if (this.SelectedRow<0) return null;
var index=this.SelectedRow;
if (this.SelectedModel==0) //当前屏选中
index=this.Data.YOffset+this.SelectedRow;
var symbol=this.Data.Data[index];
return [symbol];
}
}
this.DrawFixedSymbolRow=function(top, dataIndex)
{
var left=this.RectClient.Left;
var chartRight=this.RectClient.Right;
if (!this.FixedRowData || !IFrameSplitOperator.IsNonEmptyArray(this.FixedRowData.Symbol)) return;
var symbol=this.FixedRowData.Symbol[dataIndex];
if (!symbol) return;
this.DrawRow(symbol, top, dataIndex, 1);
this.ShowSymbol.push( { Index:dataIndex, Symbol:symbol, RowType:1 } );
}
this.DrawFixedRow=function(top, dataIndex)
{
var left=this.RectClient.Left;
var chartRight=this.RectClient.Right;
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawFixedItem(dataIndex, i, item, left, top);
left+=item.Width;
if (left>=chartRight) break;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawFixedItem(dataIndex, i, item, left, top);
left+=item.Width;
if (left>=chartRight) break;
}
}
this.DrawFixedItem=function(dataIndex, colIndex, column, left, top)
{
var x=left+this.ItemMergin.Left;
var textWidth=column.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var drawInfo={ Text:null, TextColor:column.TextColor , TextAlign:column.TextAlign };
if (this.GetFixedRowTextDrawInfo(dataIndex, colIndex, column, drawInfo))
{
this.DrawItemText(drawInfo.Text, drawInfo.TextColor, drawInfo.TextAlign, x, top, textWidth);
return;
}
if (!this.FixedRowData || !IFrameSplitOperator.IsNonEmptyArray(this.FixedRowData.Data)) return;
var data=this.FixedRowData.Data;
var rowData=data[dataIndex];
if (!IFrameSplitOperator.IsNonEmptyArray(rowData)) return;
var itemData=rowData[colIndex];
if (!itemData || !itemData.Text) return;
drawInfo.Text=itemData.Text;
if (itemData.Color) drawInfo.TextColor=itemData.Color;
if (itemData.TextAlign) drawInfo.TextAlign=itemData.TextAlign;
this.DrawItemText(drawInfo.Text, drawInfo.TextColor, drawInfo.TextAlign, x, top, textWidth);
}
this.DrawRow=function(symbol, top, dataIndex, rowType) //rowType 0=表格行 1=顶部固定行 2=拖拽行
{
var left=this.RectClient.Left;
var chartRight=this.RectClient.Right;
var data= { Symbol:symbol , Stock:null, Block:null };
if (this.GetStockDataCallback) data.Stock=this.GetStockDataCallback(symbol);
if (this.GetBlockDataCallback) data.Block=this.GetBlockDataCallback(symbol);
if (this.GetFlashBGDataCallback) data.FlashBG=this.GetFlashBGDataCallback(symbol, Date.now());
data.Decimal=GetfloatPrecision(symbol); //小数位数
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawItem(dataIndex, data, item, left, top, rowType, i);
left+=item.Width;
if (left>=chartRight) break;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawItem(dataIndex, data, item, left, top, rowType, i);
left+=item.Width;
if (left>=chartRight) break;
}
}
this.DrawItem=function(index, data, column, left, top, rowType, columnIndex)
{
var itemWidth=column.Width;
var x=left+this.ItemMergin.Left;
var textWidth=column.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var stock=data.Stock;
var drawInfo=
{
Text:null, TextColor:column.TextColor , TextAlign:column.TextAlign, Tooltip:null,
Index:index, ColumnIndex:columnIndex
};
var rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
drawInfo.Rect=rtItem;
if (column.FullColBGColor)
{
this.DrawItemBG({ Rect:rtItem, BGColor:column.FullColBGColor });
}
if (column.Type==REPORT_COLUMN_ID.INDEX_ID)
{
if (rowType==1) return; //固定行序号空
drawInfo.Text=(index+1).toString();
}
else if (column.Type==REPORT_COLUMN_ID.SYMBOL_ID)
{
if (stock && stock.Symbol) drawInfo.Text=stock.Symbol;
else drawInfo.Text=data.Symbol;
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.SYMBOL_NAME_ID)
{
this.DrawSymbolName(data, column, left, top, rowType);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.SYMBOL_NAME_V2_ID)
{
this.DrawSymbolNameV2(data, column, left, top, rowType);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.NAME_ID)
{
if (stock && stock.Name)
{
if (IFrameSplitOperator.IsString(stock.Name))
{
drawInfo.Text=this.TextEllipsis(stock.Name, textWidth, column.MaxText);
drawInfo.TextColor=this.GetNameColor(column,data.Symbol, rowType);
}
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.NAME_EX_ID)
{
//复杂格式 { Text:, Symbol:{ Family:'iconfont', Size:, Data:[ { Text:'\ue631', Color:'#1c65db'}, ...] } ]}
if (stock && stock.NameEx)
{
var nameEx=stock.NameEx;
drawInfo.Text=this.TextEllipsis(nameEx.Text, textWidth, column.MaxText);
drawInfo.TextColor=this.GetNameColor(column,data.Symbol, rowType);
if (nameEx.Symbol) drawInfo.Symbol=nameEx.Symbol;
}
}
else if (column.Type==REPORT_COLUMN_ID.PRICE_ID)
{
if (stock) this.GetPriceDrawInfo(stock.Price, stock, data, drawInfo, { LimitBG:true });
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.OPEN_ID)
{
//如果行情开盘价为涨停价或跌停价,则对内容加灰框
if (stock)
{
this.DrawLimitPriceBorder(stock.Open, stock, left, top, column.Width);
this.GetPriceDrawInfo(stock.Open, stock, data, drawInfo, { LimitBG:true });
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.HIGH_ID)
{
//如果行情最高价为涨停价,则对内容加灰框
if (stock)
{
this.DrawLimitPriceBorder(stock.High, stock, left, top, column.Width);
this.GetPriceDrawInfo(stock.High, stock, data, drawInfo, { LimitBG:true });
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.LOW_ID)
{
//如果行情最低价为跌停价,则对内容加灰框
if (stock)
{
this.DrawLimitPriceBorder(stock.Low, stock, left, top, column.Width);
this.GetPriceDrawInfo(stock.Low, stock, data, drawInfo, { LimitBG:true });
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.YCLOSE_ID)
{
if (stock) this.GetPriceDrawInfo(stock.YClose, stock, data, drawInfo);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.BUY_PRICE_ID)
{
if (stock) this.GetPriceDrawInfo(stock.BuyPrice, stock, data, drawInfo);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.FUTURES_CLOSE_ID || column.Type==REPORT_COLUMN_ID.FUTURES_YCLOSE_ID)
{
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (stock && IFrameSplitOperator.IsNumber(stock[fieldName]))
{
var value=stock[fieldName];
this.GetPriceDrawInfo(value, stock, data, drawInfo);
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.SELL_PRICE_ID)
{
if (stock) this.GetPriceDrawInfo(stock.SellPrice, stock, data, drawInfo);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.AVERAGE_PRICE_ID)
{
if (stock) this.GetPriceDrawInfo(stock.AvPrice, stock, data, drawInfo);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.EXCHANGE_RATE_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.Exchange))
drawInfo.Text=stock.Exchange.toFixed(2);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.BUY_VOL_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.BuyVol)) drawInfo.Text=this.FormatVolString(stock.BuyVol);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.SELL_VOL_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.SellVol)) drawInfo.Text=this.FormatVolString(stock.SellVol);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.VOL_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.Vol)) drawInfo.Text=this.FormatVolString(stock.Vol);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.VOL_IN_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.VolIn)) drawInfo.Text=this.FormatVolString(stock.VolIn);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.VOL_OUT_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.VolOut)) drawInfo.Text=this.FormatVolString(stock.VolOut);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.TOTAL_SHARES_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.TotalShares)) drawInfo.Text=this.FormatVolString(stock.TotalShares);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.OUTSTANDING_SHARES_ID)
{
if (stock && IFrameSplitOperator.IsNumber(stock.OutShares)) drawInfo.Text=this.FormatVolString(stock.OutShares);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.CIRC_MARKET_VALUE_ID || column.Type==REPORT_COLUMN_ID.MARKET_VALUE_ID || column.Type==REPORT_COLUMN_ID.AMOUNT_ID)
{
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (stock && IFrameSplitOperator.IsNumber(stock[fieldName]))
drawInfo.Text=this.FormatVolString(stock[fieldName]);
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.INCREASE_ID || column.Type==REPORT_COLUMN_ID.AMPLITUDE_ID || column.Type==REPORT_COLUMN_ID.UPDOWN_ID ||
column.Type==REPORT_COLUMN_ID.RISING_SPEED_1M_ID || column.Type==REPORT_COLUMN_ID.RISING_SPEED_3M_ID || column.Type==REPORT_COLUMN_ID.RISING_SPEED_5M_ID ||
column.Type==REPORT_COLUMN_ID.RISING_SPEED_10M_ID || column.Type==REPORT_COLUMN_ID.RISING_SPEED_15M_ID )
{
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (stock && IFrameSplitOperator.IsNumber(stock[fieldName]))
{
var value=stock[fieldName];
drawInfo.Text=value.toFixed(2);
drawInfo.TextColor=this.GetUpDownColor(value,0);
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.FUTURES_POSITION_ID || column.Type==REPORT_COLUMN_ID.FUTURES_OPEN_POSITION_ID || column.Type==REPORT_COLUMN_ID.FUTURES_CLOSE_POSITION_ID)
{
//持仓量原始值输出
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (stock && IFrameSplitOperator.IsNumber(stock[fieldName]))
{
var value=stock[fieldName];
drawInfo.Text=value.toFixed(0);
}
this.FormatDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_STRING_TEXT_ID)
{
this.GetCustomStringDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_NUMBER_TEXT_ID)
{
this.GetCustomNumberDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_DATETIME_TEXT_ID)
{
this.GetCustomDateTimeDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_ICON_ID)
{
this.GetCustomIconDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CLOSE_LINE_ID)
{
var rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
if (stock) this.DrawLine(stock.CloseLine, column, rtItem);
}
else if (column.Type==REPORT_COLUMN_ID.KLINE_ID)
{
var rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
this.DrawKLine(stock.KLine, column, rtItem, data);
}
else if (column.Type==REPORT_COLUMN_ID.TIME_ID)
{
this.FormaTimeDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.DATE_ID)
{
this.FormaDateDrawInfo(column, stock, drawInfo, data);
}
else if (column.Type==REPORT_COLUMN_ID.CHECKBOX_ID)
{
rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
drawInfo.Rect=rtItem;
drawInfo.Checked=false;
drawInfo.Enable=true;
drawInfo.CheckBox=this.CheckBoxConfig;
drawInfo.Data=stock;
if (stock && IFrameSplitOperator.IsBool(stock.Checked))
drawInfo.Checked=stock.Checked;
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_CHECKBOX_ID)
{
rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
drawInfo.Rect=rtItem;
this.GetCustomCheckBoxDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_BUTTON_ID)
{
rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
drawInfo.Rect=rtItem;
this.GetCustomButtonDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_PROGRESS_ID)
{
rtItem={ Left:left, Top:top, Width:column.Width, Height:this.RowHeight };
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
drawInfo.Rect=rtItem;
this.GetCustomProgressBarDrawInfo(data, column, drawInfo);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_LINK_ID)
{
this.GetCustomLinkDrawInfo(data, column, drawInfo);
}
else if ([REPORT_COLUMN_ID.RESERVE_NUMBER1_ID,REPORT_COLUMN_ID.RESERVE_NUMBER2_ID,REPORT_COLUMN_ID.RESERVE_NUMBER3_ID,
REPORT_COLUMN_ID.RESERVE_NUMBER4_ID,REPORT_COLUMN_ID.RESERVE_NUMBER5_ID,REPORT_COLUMN_ID.RESERVE_NUMBER6_ID,REPORT_COLUMN_ID.RESERVE_NUMBER7_ID,
REPORT_COLUMN_ID.RESERVE_NUMBER8_ID,REPORT_COLUMN_ID.RESERVE_NUMBER9_ID,REPORT_COLUMN_ID.RESERVE_NUMBER10_ID].includes(column.Type))
{
this.FormatReserveNumber(column, stock, drawInfo);
}
else if ([REPORT_COLUMN_ID.RESERVE_STRING1_ID,REPORT_COLUMN_ID.RESERVE_STRING2_ID,REPORT_COLUMN_ID.RESERVE_STRING3_ID,REPORT_COLUMN_ID.RESERVE_STRING4_ID,
REPORT_COLUMN_ID.RESERVE_STRING5_ID,REPORT_COLUMN_ID.RESERVE_STRING6_ID,REPORT_COLUMN_ID.RESERVE_STRING7_ID,REPORT_COLUMN_ID.RESERVE_STRING8_ID,
REPORT_COLUMN_ID.RESERVE_STRING9_ID,REPORT_COLUMN_ID.RESERVE_STRING10_ID].includes(column.Type))
{
this.FormatReserveString(column, stock, drawInfo);
}
else if (this.IsReserveProgressBarColumn(column.Type))
{
this.FormatReserveProgressBar(column, stock, drawInfo);
}
//拖拽行颜色
if (rowType==3)
drawInfo.TextColor=this.DragRowTextColor;
if (drawInfo.Symbol)
{
this.DrawItemTextEx(drawInfo, x, top, textWidth);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_ICON_ID)
{
this.DrawIconItem(drawInfo, x, top, textWidth);
}
else if (column.Type==REPORT_COLUMN_ID.CHECKBOX_ID || column.Type==REPORT_COLUMN_ID.CUSTOM_CHECKBOX_ID)
{
this.DrawCheckbox(drawInfo, left, top, itemWidth);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_BUTTON_ID)
{
this.DrawButton(drawInfo, left, top, itemWidth);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_PROGRESS_ID || this.IsReserveProgressBarColumn(column.Type))
{
this.DrawProgressBar(drawInfo, left, top, itemWidth);
}
else if (column.Type==REPORT_COLUMN_ID.CUSTOM_LINK_ID)
{
this.DrawLinkText(drawInfo, x, top, textWidth);
}
else
{
if (data.FlashBG && data.FlashBG.Data && column.ID!=undefined)
{
if (data.FlashBG.Data.has(column.ID))
{
var flashItem=data.FlashBG.Data.get(column.ID);
var drawBG={ Rect:drawInfo.Rect , BGColor:flashItem.Color };
--flashItem.Count;
this.DrawItemBG(drawBG);
if (this.GlobalOption) ++this.GlobalOption.FlashBGCount;
}
}
this.DrawItemBG(drawInfo);
if (column.Type==REPORT_COLUMN_ID.CUSTOM_STRING_TEXT_ID)
this.DrawCustomText(drawInfo,column, x, top, textWidth);
else
this.DrawItemText(drawInfo.Text, drawInfo.TextColor, drawInfo.TextAlign, x, top, textWidth, drawInfo.BGColor);
}
//tooltip提示
if (drawInfo.Tooltip)
{
//Type:1=数据截断
var tooltipData={ Rect:rtItem, Stock:stock, Index:index, Column:column, RowType:rowType, Type:drawInfo.Tooltip.Type, Data:drawInfo.Tooltip.Data };
this.TooltipRect.push(tooltipData);
}
if (drawInfo.Botton)
{
var buttonData={ Stock:stock, Index:index, ColumnIndex:columnIndex, Column:column, Rect:drawInfo.Botton.Rect, Type:drawInfo.Botton.Type, Data:drawInfo.Data };
this.ButtonRect.push(buttonData);
}
}
this.IsReserveProgressBarColumn=function(value)
{
var ARARY_TYPE=
[
REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR1_ID, REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR2_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR3_ID,
REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR4_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR5_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR6_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR7_ID,
REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR8_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR9_ID,REPORT_COLUMN_ID.RESERVE_PROGRESS_BAR10_ID
];
return ARARY_TYPE.includes(value);
}
this.DrawCustomText=function(drawInfo, column, left, top, cellWidth)
{
if (!drawInfo.Text) return;
var text=drawInfo.Text;
var x=left;
if (drawInfo.TextAlign=='center')
{
x=left+cellWidth/2;
this.Canvas.textAlign="center";
}
else if (drawInfo.TextAlign=='right')
{
x=left+cellWidth-2;
this.Canvas.textAlign="right";
}
else
{
x+=2;
this.Canvas.textAlign="left";
}
var textWidth=this.Canvas.measureText(text).width+1;
var bClip=false;
if (textWidth>=cellWidth) //长度超过单元格 裁剪
{
if (column.FormatType==2)
{
var count=text.length+5;
text="";
for(var i=0;i<count;++i)
text+="#";
}
else if (column.FormatType==1)
{
text=this.TextEllipsis(text, cellWidth, column.MaxText);
}
this.Canvas.save();
bClip=true;
var rtCell={ Left:left, Top:top+this.ItemMergin.Top, Width:cellWidth, Height:this.RowHeight };
this.Canvas.beginPath();
this.Canvas.rect(rtCell.Left, rtCell.Top, rtCell.Width, rtCell.Height);
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
//数据截断提示信息
drawInfo.Tooltip=
{
Type:1,
Data:{ AryText:[ {Text:drawInfo.Text} ] }
}
}
this.Canvas.textBaseline="bottom";
this.Canvas.fillStyle=drawInfo.TextColor;
this.Canvas.fillText(text,x,top+this.RowHeight-this.ItemMergin.Bottom);
if (bClip) this.Canvas.restore();
}
this.DrawSymbolName=function(data, column, left, top, rowType)
{
var stock=data.Stock;
var symbol=data.Symbol;
var name;
if (stock)
{
symbol=stock.Symbol;
name=stock.Name;
}
if (!symbol && !name) return;
var y=top+this.ItemMergin.Top+this.ItemNameHeight;
var textLeft=left+this.ItemMergin.Left;
var x=textLeft;
var width=column.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var textAlign=column.TextAlign;
if (textAlign=='center')
{
x=textLeft+width/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=textLeft+width-2;
this.Canvas.textAlign="right";
}
else
{
x+=2;
this.Canvas.textAlign="left";
}
var textColor=this.GetNameColor(column,symbol,rowType);
var text=name;
if (text)
{
this.Canvas.textBaseline="bottom";
this.Canvas.fillStyle=textColor;
this.Canvas.font=this.ItemNameFont;
text=this.TextEllipsis(text, width, column.MaxText);
if (text) this.Canvas.fillText(text,x,y);
}
text=symbol;
if (text)
{
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.ItemSymbolFont;
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(text,x,y+this.ItemSymbolHeight);
}
this.Canvas.font=this.ItemFont; //还原字体
}
this.DrawSymbolNameV2=function(data, column, left, top, rowType)
{
var stock=data.Stock;
var symbol=data.Symbol;
var name;
if (stock)
{
symbol=stock.Symbol;
name=stock.Name;
}
if (!symbol && !name) return;
var y=top+this.ItemMergin.Top+this.ItemNameHeight;
var textLeft=left+this.ItemMergin.Left;
var x=textLeft;
var width=column.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var textAlign=column.TextAlign;
if (textAlign=='center')
{
x=textLeft+width/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=textLeft+width-2;
this.Canvas.textAlign="right";
}
else
{
x+=2;
this.Canvas.textAlign="left";
}
this.Canvas.textBaseline="bottom";
var textColor=column.TextColor;
var text=name;
if (text)
{
this.Canvas.fillStyle=textColor;
this.Canvas.font=this.NameSymbolFont.Name;
text=this.TextEllipsis(text, width, column.MaxText);
if (text)
{
this.Canvas.fillText(text,x,y);
var textWidth=this.Canvas.measureText(text).width;
var space=2;
if (IFrameSplitOperator.IsNumber(column.Space)) space=column.Space;
x+=(textWidth+space);
}
}
var textColor=column.TextColor2;
text=symbol;
if (text)
{
this.Canvas.font=this.NameSymbolFont.Symbol;
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(text,x,y);
}
this.Canvas.font=this.ItemFont; //还原字体
}
this.DrawLimitPriceBorder=function(value, stock, left, top, itemWidth)
{
if (!IFrameSplitOperator.IsNumber(value) || !stock) return;
var bDraw=false;
if (IFrameSplitOperator.IsNumber(stock.LimitHigh))
{
if (value>=stock.LimitHigh) bDraw=true;
}
if (IFrameSplitOperator.IsNumber(stock.LimitLow))
{
if (value<=stock.LimitLow) bDraw=true;
}
if (!bDraw) return;
var x=left+this.ItemMergin.Left+this.LimitMergin.Left;
var width=itemWidth-this.ItemMergin.Left-this.ItemMergin.Right-this.LimitMergin.Left-this.LimitMergin.Right;
var y=top+this.ItemMergin.Top+this.LimitMergin.Top;
var height=this.RowHeight-this.ItemMergin.Top-this.ItemMergin.Bottom-this.LimitMergin.Top-this.LimitMergin.Bottom;
this.Canvas.strokeStyle=this.LimitBorderColor;
this.Canvas.strokeRect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(width),ToFixedRect(height));
}
this.GetExtendData=function(data, column)
{
if (IFrameSplitOperator.IsNumber(column.DataIndex))
{
if (!data.Stock || !data.Stock.ExtendData) return null;
if (column.DataIndex<0) return;
return data.Stock.ExtendData[column.DataIndex];
}
if (IFrameSplitOperator.IsNumber(column.BlockIndex))
{
if (!data.Block) return;
if (column.BlockIndex<0) return;
return data.Block[column.BlockIndex];
}
return null;
}
this.GetCustomStringDrawInfo=function(data, column, drawInfo)
{
var value=this.GetExtendData(data, column);
if (column.IsDrawCallback) //外部处理输出格式
{
this.GetCustomTextDrawInfo(column, data.Symbol, value, drawInfo, data);
return;
}
if (!IFrameSplitOperator.IsString(value)) return;
drawInfo.Text=value;
}
this.GetCustomNumberDrawInfo=function(data, column, drawInfo)
{
var value=this.GetExtendData(data, column);
if (column.IsDrawCallback) //外部处理输出格式
{
this.GetCustomTextDrawInfo(column, data.Symbol, value, drawInfo, data);
return;
}
if (!IFrameSplitOperator.IsNumber(value)) return;
//格式化输出
switch(column.FormatType)
{
case 1:
drawInfo.Text=value.toFixed(column.Decimal);
break;
case 2:
drawInfo.Text=IFrameSplitOperator.FormatValueThousandsString(value, column.Decimal);
break;
case 3:
drawInfo.Text=this.FormatVolString(value);
break;
default:
drawInfo.Text=IFrameSplitOperator.FormatValueString(value, column.Decimal);
break;
}
//颜色
switch(column.ColorType)
{
case 1:
drawInfo.TextColor=this.GetUpDownColor(value,0);
break;
case 2:
if (!IFrameSplitOperator.IsNumber(data.Stock.YClose))
drawInfo.TextColor=this.UnchagneColor;
else
drawInfo.TextColor=this.GetUpDownColor(value, data.Stock.YClose);
break;
default:
break;
}
}
this.GetCustomDateTimeDrawInfo=function(data, column, drawInfo)
{
var value=this.GetExtendData(data, column);
if (!IFrameSplitOperator.IsNumber(value)) return;
if (column.IsDrawCallback) //外部处理输出格式
{
this.GetCustomTextDrawInfo(column, data.Symbol, value, drawInfo, data);
return;
}
if (column.ValueType==0)
{
if (column.FormatType==1)
drawInfo.Text=IFrameSplitOperator.FormatDateString(value,"YYYY/MM/DD");
else
drawInfo.Text=IFrameSplitOperator.FormatDateString(value);
}
}
this.GetCustomIconDrawInfo=function(data, column, drawInfo)
{
if (column.IsDrawCallback) //外部处理输出格式
{
this.GetCustomIconData(column, data.Symbol, drawInfo, data);
return;
}
}
this.GetCustomCheckBoxDrawInfo=function(data, column, drawInfo)
{
var checkData=this.GetExtendData(data, column);
if (!checkData) return;
if (!IFrameSplitOperator.IsBool(checkData.Checked)) return;
drawInfo.Checked=checkData.Checked;
drawInfo.Enable=true;
drawInfo.Data=checkData;
if (IFrameSplitOperator.IsBool(checkData.DisableCheckBox)) drawInfo.Enable=!checkData.DisableCheckBox;
drawInfo.CheckBox=column.CheckBox;
}
this.GetCustomButtonDrawInfo=function(data, column, drawInfo)
{
var buttonData=this.GetExtendData(data, column);
if (!buttonData) return;
drawInfo.Text=buttonData.Title;
drawInfo.Button=column.Button;
drawInfo.Font=column.Button.Font;
drawInfo.Enable=true;
drawInfo.Data=buttonData;
if (IFrameSplitOperator.IsBool(buttonData.Enable)) drawInfo.Enable=buttonData.Enable;
}
this.GetCustomProgressBarDrawInfo=function(data, column, drawInfo)
{
var barData=this.GetExtendData(data, column);
if (!barData) return;
drawInfo.Text=barData.Title;
drawInfo.ProgressBar=column.ProgressBar;
drawInfo.Enable=true;
drawInfo.Value=barData.Value; //占比
drawInfo.Data=barData;
if (IFrameSplitOperator.IsBool(barData.Enable)) drawInfo.Enable=barData.Enable;
if (barData.TextColor) drawInfo.TextColor=barData.TextColor;
if (barData.BarColor) drawInfo.BarColor=barData.BarColor;
if (barData.BGColor) drawInfo.BGColor=barData.BGColor;
}
this.GetCustomLinkDrawInfo=function(data, column, drawInfo)
{
var linkData=this.GetExtendData(data, column);
if (!linkData) return;
drawInfo.Text=linkData.Title;
drawInfo.Link=column.Link;
drawInfo.Enable=true;
drawInfo.Data=linkData;
drawInfo.MaxText=column.MaxText;
if (IFrameSplitOperator.IsBool(linkData.Enable)) drawInfo.Enable=linkData.Enable;
if (linkData.TextColor) drawInfo.TextColor=linkData.TextColor;
}
this.FormatReserveNumber=function(column, data, drawInfo)
{
if (column.DefaultText) drawInfo.Text=column.DefaultText;
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (!data || !fieldName) return;
var value=data[fieldName];
if (!IFrameSplitOperator.IsNumber(value)) return;
if (IFrameSplitOperator.IsNumber(column.ColorType))
{
if (column.ColorType==1)
{
drawInfo.TextColor=this.GetUpDownColor(value,0);
}
else if (column.ColorType==2)
{
drawInfo.TextColor=this.GetUpDownColorV2(value,0);
}
}
//TODO: 不同类型的 格式化输出
drawInfo.Text=value.toFixed(column.FloatPrecision);
}
this.FormatReserveString=function(column, data, drawInfo)
{
if (column.DefaultText) drawInfo.Text=column.DefaultText;
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (!data || !fieldName) return;
var item=data[fieldName];
if (IFrameSplitOperator.IsObject(item))
{
if (item.Text) drawInfo.Text=item.Text;
if (item.TextColor) drawInfo.TextColor=item.TextColor;
if (item.BGColor) drawInfo.BGColor=item.BGColor;
}
else if (IFrameSplitOperator.IsString(item))
{
drawInfo.Text=item;
}
}
this.FormatReserveProgressBar=function(column, data, drawInfo)
{
var fieldName=MAP_COLUMN_FIELD.get(column.Type);
if (!data || !fieldName) return;
var item=data[fieldName];
if (IFrameSplitOperator.IsNumber(item))
{
drawInfo.ProgressBar=column.ProgressBar;
drawInfo.Enable=true;
drawInfo.Value=item; //占比
drawInfo.Data={ Value:item };
}
else if (IFrameSplitOperator.IsObject(item))
{
if (item.Title) drawInfo.Text=item.Title;
drawInfo.ProgressBar=column.ProgressBar;
drawInfo.Enable=true;
drawInfo.Value=item.Value; //占比
drawInfo.Data=item;
if (IFrameSplitOperator.IsBool(item.Enable)) drawInfo.Enable=item.Enable;
if (item.TextColor) drawInfo.TextColor=item.TextColor;
if (item.BarColor) drawInfo.BarColor=item.BarColor;
if (item.BGColor) drawInfo.BGColor=item.BGColor;
}
}
this.FormaTimeDrawInfo=function(column, stock, drawInfo, data)
{
if (!IFrameSplitOperator.IsNumber(stock.Time)) return;
if (column.ValueType==0) //0=hhmm 1=hhmmss 2=hhmmss.fff
{
drawInfo.Text=IFrameSplitOperator.FormatTimeString(stock.Time,"HH:MM");
}
else if (column.ValueType==1)
{
drawInfo.Text=IFrameSplitOperator.FormatTimeString(stock.Time,"HH:MM:SS");
}
else if (column.ValueType==2)
{
drawInfo.Text=IFrameSplitOperator.FormatTimeString(stock.Time,"HH:MM:SS.fff");
}
}
this.FormaDateDrawInfo=function(column, stock, drawInfo, data)
{
if (!IFrameSplitOperator.IsNumber(stock.Date)) return;
if (column.FormatType==0)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"YYYY-MM-DD");
else if (column.FormatType==1)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"YYYY/MM/DD");
else if (column.FormatType==2)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"YYYY/MM/DD/W");
else if (column.FormatType==3)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"YYYY-MM");
else if (column.FormatType==4)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"MM/DD");
else if (column.FormatType==4)
drawInfo.Text=IFrameSplitOperator.FormatDateString(stock.Date,"MM-DD");
}
//自定义图标
this.GetCustomIconData=function(columnInfo, symbol, drawInfo, data)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_DRAW_CUSTOM_ICON);
if (!event || !event.Callback) return false;
var sendData=
{
Symbol:symbol, Column:columnInfo, Data:data,
Out:{ Text:null, TextColor:null, TextAlign:null, Font:null }
};
event.Callback(event,sendData,this);
if (sendData.Out.Text) drawInfo.Text=sendData.Out.Text;
if (sendData.Out.TextColor) drawInfo.TextColor=sendData.Out.TextColor;
if (sendData.Out.TextAlign) drawInfo.TextAlign=sendData.Out.TextAlign;
if (sendData.Out.BGColor) drawInfo.BGColor=sendData.Out.BGColor;
if (sendData.Out.Font) drawInfo.Font=sendData.Out.Font;
return true;
}
this.GetPriceDrawInfo=function(price, stock, data, drawInfo, option)
{
if (!IFrameSplitOperator.IsNumber(price)) return false;
drawInfo.Text=price.toFixed(data.Decimal);
var yClose=null;
if (stock.PriceColorType===1) //昨结算价 计算颜色
{
if (IFrameSplitOperator.IsNumber(stock.YFClose)) yClose=stock.YFClose;
}
else //昨收价 计算颜色
{
if (IFrameSplitOperator.IsNumber(stock.YClose)) yClose=stock.YClose;
}
if (!IFrameSplitOperator.IsNumber(yClose))
drawInfo.TextColor=this.UnchagneColor;
else
drawInfo.TextColor=this.GetUpDownColor(price, yClose);
if (option && option.LimitBG)
{
if (IFrameSplitOperator.IsNumber(stock.LimitHigh))
{
if (price>=stock.LimitHigh)
{
drawInfo.BGColor=this.LimitUpBGColor;
drawInfo.TextColor=this.LimitTextColor;
}
}
if (IFrameSplitOperator.IsNumber(stock.LimitLow))
{
if (price<=stock.LimitLow)
{
drawInfo.BGColor=this.LimitDownBGColor;
drawInfo.TextColor=this.LimitTextColor;
}
}
}
}
this.GetUpDownColor=function(price, price2)
{
if (price>price2) return this.UpColor;
else if (price<price2) return this.DownColor;
else return this.UnchagneColor;
}
this.GetUpDownColorV2=function(price, price2)
{
if (price>=price2) return this.UpColor;
else return this.DownColor;
}
//单独处理成交量显示
this.FormatVolString=function(value,languageID)
{
return IFrameSplitOperator.FormatVolString(value, languageID);
}
this.DrawItemBG=function(drawInfo)
{
if (drawInfo.BGColor && drawInfo.Rect)//绘制背景色
{
var rtItem=drawInfo.Rect;
this.Canvas.fillStyle=drawInfo.BGColor;
this.Canvas.fillRect(rtItem.Left,rtItem.Top,rtItem.Width,rtItem.Height); //画一个背景色, 不然是一个黑的背景
}
}
this.DrawItemText=function(text, textColor, textAlign, left, top, width, bgColor)
{
if (!text) return;
var x=left;
if (textAlign=='center')
{
x=left+width/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=left+width-2;
this.Canvas.textAlign="right";
}
else
{
x+=2;
this.Canvas.textAlign="left";
}
var textWidth=this.Canvas.measureText(text).width+1;
var bClip=false;
if (textWidth>=width) //长度超过单元格 裁剪
{
this.Canvas.save();
bClip=true;
var rtCell={ Left:left, Top:top+this.ItemMergin.Top, Width:width, Height:this.RowHeight };
this.Canvas.beginPath();
this.Canvas.rect(rtCell.Left, rtCell.Top, rtCell.Width, rtCell.Height);
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
if (this.TextOverflowStyle==1)
{
var count=text.length+5;
text="";
for(var i=0;i<count;++i)
{
text+="#";
}
}
}
this.Canvas.textBaseline="bottom";
this.Canvas.fillStyle=textColor;
if (this.ItemTextLines>1) //多行模式要上下居中
{
var yOffset=(this.RowHeight-this.ItemMergin.Bottom-this.ItemMergin.Top-this.ItemFontHeight)/2;
var yBottom=top+this.RowHeight-this.ItemMergin.Bottom-yOffset;
this.Canvas.fillText(text,x,yBottom);
}
else
{
this.Canvas.fillText(text,x,top+this.RowHeight-this.ItemMergin.Bottom);
}
if (bClip) this.Canvas.restore();
}
//{ Text:, Symbol:{ Family:'iconfont', Size:, Data:[ { Text:'\ue631', Color:'#1c65db'}, ...] } ]}
this.DrawItemTextEx=function(drawInfo, left, top, width)
{
var text=drawInfo.Text;
var clrText=drawInfo.TextColor;
var symbol=drawInfo.Symbol; //符号
var textAlign=drawInfo.TextAlign;
var textWidth=this.Canvas.measureText(text).width+1;;
var totalWidth=textWidth;
var font= `${symbol.Size*GetDevicePixelRatio()}px ${symbol.Family}`;
this.Canvas.font=font;
var aryIconWidth=[];
for(var i=0;i<symbol.Data.length;++i)
{
var item=symbol.Data[i];
var iconWidth=this.Canvas.measureText(item.Text).width+1;
if (totalWidth+iconWidth>width)
break;
totalWidth+=iconWidth;
aryIconWidth[i]=iconWidth;
}
var x=left;
var y=top+this.ItemMergin.Top+this.RowHeight/2;
if (textAlign=='center')
{
x=left+(width-totalWidth)/2;
}
else if (textAlign=='right')
{
x=left+(width-totalWidth);
}
else
{
x+=2;
}
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
this.Canvas.font=this.ItemFont;
this.Canvas.fillStyle=clrText;
this.Canvas.fillText(text,x,y);
x+=textWidth;
this.Canvas.font=font;
for(var i=0;i<aryIconWidth.length;++i)
{
var item=symbol.Data[i];
this.Canvas.fillStyle=item.Color;
this.Canvas.fillText(item.Text,x,y);
x+=aryIconWidth[i];
}
this.Canvas.font=this.ItemFont;
}
this.DrawIconItem=function(drawInfo, left, top, width)
{
if (!drawInfo || !drawInfo.Font || !drawInfo.Text) return;
var text=drawInfo.Text;
var clrText=drawInfo.TextColor;
var textAlign=drawInfo.TextAlign;
this.Canvas.font=drawInfo.Font;
var textWidth=this.Canvas.measureText(text).width+1;;
var x=left;
var y=top+this.ItemMergin.Top+this.RowHeight/2;
if (textAlign=='center')
{
x=left+(width-textWidth)/2;
}
else if (textAlign=='right')
{
x=left+(width-textWidth);
}
else
{
x+=2;
}
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=clrText;
this.Canvas.fillText(text,x,y);
this.Canvas.font=this.ItemFont;
}
this.DrawCheckbox=function(drawInfo, left, top, width)
{
if (!IFrameSplitOperator.IsBool(drawInfo.Checked)) return;
if (!drawInfo.CheckBox) return;
var config=drawInfo.CheckBox;
drawInfo.Font=`${config.Size*this.DevicePixelRatio}px ${config.Family}`;
var textAlign=drawInfo.TextAlign;
var size=drawInfo.CheckBox.Size*this.DevicePixelRatio;
var x=left+drawInfo.CheckBox.Margin.Left;
var y=top+this.RowHeight-drawInfo.CheckBox.Margin.Bottom;
if (textAlign=='center') x=left+width/2-size/2;
else if (textAlign=='right') x=left+width-config.Margin.Right;
var rtBox={ Left:x, Bottom:y, Width:size, Height:size };
rtBox.Right=rtBox.Left+rtBox.Width;
rtBox.Top=rtBox.Bottom-rtBox.Height;
//鼠标在上面
var bMouseOn=false;
if (drawInfo.Enable && this.LastMouseStatus && this.LastMouseStatus.OnMouseMove)
{
var xMouse=this.LastMouseStatus.OnMouseMove.X;
var yMouse=this.LastMouseStatus.OnMouseMove.Y;
if (xMouse>rtBox.Left && xMouse<rtBox.Right && yMouse>rtBox.Top && yMouse<rtBox.Bottom)
{
bMouseOn=true;
this.LastMouseStatus.MouseOnStatus={ Index:drawInfo.Index, ColumnIndex:drawInfo.ColumnIndex, Type:0 };
}
}
this.Canvas.font=drawInfo.Font;
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
if (drawInfo.Checked===true)
{
var textColor=config.Checked.Color;
if (drawInfo.Enable===false) textColor=config.Checked.DisableColor;
else if (bMouseOn) textColor=config.Checked.MouseOnColor;
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(config.Checked.Symbol,x,y);
}
else if (drawInfo.Checked===false)
{
var textColor=config.Unchecked.Color;
if (drawInfo.Enable===false) textColor=config.Unchecked.DisableColor;
else if (bMouseOn) textColor=config.Unchecked.MouseOnColor;
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(config.Unchecked.Symbol,x,y);
}
if (drawInfo.Enable)
{
drawInfo.Botton={ Rect:rtBox, Type:0 };
}
}
this.DrawButton=function(drawInfo, left, top, width)
{
if (!drawInfo.Button) return;
var config=drawInfo.Button;
var rtBG=
{
Left:left+drawInfo.Button.Margin.Left, Top:top+drawInfo.Button.Margin.Top,
Height:this.RowHeight-drawInfo.Button.Margin.Top-drawInfo.Button.Margin.Bottom,
Width:width-drawInfo.Button.Margin.Left-drawInfo.Button.Margin.Right
}
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
var bgColor=config.BGColor, textColor=config.TextColor;
if (drawInfo.Enable===false)
{
bgColor=config.Disable.BGColor;
textColor=config.Disable.TextColor;
}
else
{
if (this.LastMouseStatus && this.LastMouseStatus.OnMouseMove && config.MouseOn)
{
var x=this.LastMouseStatus.OnMouseMove.X;
var y=this.LastMouseStatus.OnMouseMove.Y;
if (x>rtBG.Left && x<rtBG.Right && y>rtBG.Top && y<rtBG.Bottom)
{
bgColor=config.MouseOn.BGColor;
textColor=config.MouseOn.TextColor;
this.LastMouseStatus.MouseOnStatus={ Index:drawInfo.Index, ColumnIndex:drawInfo.ColumnIndex, Type:1 };
}
}
}
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top,rtBG.Width,rtBG.Height);
this.Canvas.font=drawInfo.Font;
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=textColor;
var textWidth=this.Canvas.measureText(drawInfo.Text).width;
var x=rtBG.Left;
if (textWidth<rtBG.Width) x+=(rtBG.Width-textWidth)/2;
var y=rtBG.Bottom-drawInfo.Button.TextMargin.Bottom;
this.Canvas.fillText(drawInfo.Text,x,y);
if (drawInfo.Enable)
{
drawInfo.Botton={ Rect:rtBG, Type:1 };
}
}
this.DrawProgressBar=function(drawInfo, left, top, width)
{
if (!drawInfo.ProgressBar) return;
var config=drawInfo.ProgressBar;
var rtBG=
{
Left:left+config.Margin.Left, Top:top+config.Margin.Top,
Height:this.RowHeight-config.Margin.Top-config.Margin.Bottom,
Width:width-config.Margin.Left-config.Margin.Right
}
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
var bgColor=config.BGColor;
var barColor=config.BarColor;
var textColor=config.TextColor;
if (drawInfo.Enable===false)
{
bgColor=config.Disable.BGColor;
barColor=config.Disable.BarColor;
textColor=config.Disable.TextColor;
}
if (drawInfo.BGColor) bgColor=drawInfo.BGColor;
if (drawInfo.TextColor) textColor=drawInfo.TextColor;
if (drawInfo.BarColor) barColor=drawInfo.BarColor;
if (bgColor)
{
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtBG.Left, rtBG.Top,rtBG.Width,rtBG.Height);
}
var fullBarWidth=rtBG.Width-config.BarMargin.Left-config.BarMargin.Right;
var value=drawInfo.Value; // 0-1 进度条
var rtBar={ Left:rtBG.Left+config.BarMargin.Left, Top:rtBG.Top+config.BarMargin.Top, Bottom:rtBG.Bottom-config.BarMargin.Bottom, Width:0 };
if (value>0)
{
if (value>1) value=1;
rtBar.Width=fullBarWidth*value;
rtBar.Height=rtBar.Bottom-rtBar.Top;
if (rtBar.Width<1) rtBG.Width=1;
this.Canvas.fillStyle=barColor;
this.Canvas.fillRect(rtBar.Left, rtBar.Top,rtBar.Width,rtBar.Height);
}
if (textColor && drawInfo.Text)
{
this.Canvas.font=config.Font;
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=textColor;
var xText=rtBar.Left+config.TextMargin.Left;
var yText=rtBar.Bottom-config.TextMargin.Bottom;
this.Canvas.fillText(drawInfo.Text, xText, yText);
}
}
this.DrawLinkText=function(drawInfo, left, top, width)
{
if (!drawInfo.Link || !drawInfo.Text) return;
var config=drawInfo.Link;
var text=drawInfo.Text;
var textAlign=drawInfo.TextAlign;
var font=config.Font;
var color=config.TextColor;
this.Canvas.font=font;
var textWidth=this.Canvas.measureText(text).width;
var textHeight=this.Canvas.measureText("擎").width;
var x=left;
if (width>=textWidth)
{
if (textAlign=='center') x=left+(width-textWidth)/2;
else if (textAlign=='right') x=left+width-textWidth;
}
else
{
text=this.TextEllipsis(text, width, drawInfo.MaxText);
textWidth=this.Canvas.measureText(text).width;
//数据截断提示信息
drawInfo.Tooltip=
{
Type:2,
Data:{ AryText:[ {Text:drawInfo.Text} ] }
}
}
var rtText={Left:x, Bottom:top+this.RowHeight-this.ItemMergin.Bottom, Height:textHeight, Width:textWidth };
rtText.Right=rtText.Left+rtText.Width;
rtText.Top=rtText.Bottom-rtText.Height;
var drawLine=false; //下划线
if (drawInfo.Enable===false)
{
color=config.Disable.TextColor;
}
else if (this.LastMouseStatus && this.LastMouseStatus.OnMouseMove && config.MouseOn)
{
var x=this.LastMouseStatus.OnMouseMove.X;
var y=this.LastMouseStatus.OnMouseMove.Y;
if (x>rtText.Left && x<rtText.Right && y>rtText.Top && y<rtText.Bottom)
{
color=config.MouseOn.TextColor;
drawLine=true;
this.LastMouseStatus.MouseOnStatus={ Index:drawInfo.Index, ColumnIndex:drawInfo.ColumnIndex, Type:2 };
}
}
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="left";
this.Canvas.fillStyle=color;
this.Canvas.fillText(text,rtText.Left, rtText.Bottom);
if (drawLine)
{
this.Canvas.strokeStyle=color;
this.Canvas.beginPath();
this.Canvas.moveTo(rtText.Left,rtText.Bottom);
this.Canvas.lineTo(rtText.Right,rtText.Bottom);
this.Canvas.stroke();
}
if (drawInfo.Enable)
{
drawInfo.Botton={ Rect:rtText, Type:2 };
}
}
//字体由外面设置
this.TextEllipsis=function(text, maxWidth, maxText)
{
if (!text) return null;
if (text.length<maxText.length) return text;
var start=maxText.length-3;
if (start<0) return null;
var newText=text.slice(0,start);
for(var i=start;i<text.length;++i)
{
var value=newText + text[i] + "...";
var width=this.Canvas.measureText(value).width;
if (width>maxWidth)
{
newText+="...";
break;
}
newText+=text[i];
}
return newText;
}
this.DrawMultiBar=function(colunmInfo, data, rtItem)
{
if (!data.Source || !IFrameSplitOperator.IsNonEmptyArray(data.Source)) return false;
var barData=data.Source[colunmInfo.DataIndex]; //{ Value:[0.4,0,2], Color:[0,1] };
if (!barData) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(barData.Value)) return false;
var width=rtItem.Width-this.BarMergin.Left-this.BarMergin.Right;
var left=rtItem.Left+this.BarMergin.Left;
var top=rtItem.Top+this.RowMergin.Top+this.BarMergin.Top;
var height=rtItem.Height-this.RowMergin.Top-this.RowMergin.Bottom-this.BarMergin.Top-this.BarMergin.Bottom;
var right=left+width;
for(var i=0;i<barData.Value.length;++i)
{
var value=barData.Value[i];
if (value<=0) continue;
if (left>=right) break;
var barWidth=width*value;
if (barWidth<1) barWidth=1;
if (left+barWidth>right) barWidth=right-left;
var colorIndex=i;
if (IFrameSplitOperator.IsNonEmptyArray(barData.Color) && i<barData.Color.length) colorIndex= barData.Color[i];
this.Canvas.fillStyle=g_JSChartResource.DealList.FieldColor.Bar[colorIndex];
this.Canvas.fillRect(left,top,barWidth,height);
left+=barWidth;
}
return true;
}
this.DrawCenterBar=function(colunmInfo, data, rtItem)
{
if (!data.Source || !IFrameSplitOperator.IsNonEmptyArray(data.Source)) return false;
var barData=data.Source[colunmInfo.DataIndex]; //{ Value:[0.4,0,2], Color:[0,1] };
if (!barData) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(barData.Value)) return false;
var width=(rtItem.Width-this.BarMergin.Left-this.BarMergin.Right)/2;
var left=rtItem.Left+this.BarMergin.Left;
var center=left+width;
var top=rtItem.Top+this.RowMergin.Top+this.BarMergin.Top;
var height=rtItem.Height-this.RowMergin.Top-this.RowMergin.Bottom-this.BarMergin.Top-this.BarMergin.Bottom;
var right=left+width;
for(var i=0;i<barData.Value.length && i<2;++i)
{
var value=barData.Value[i];
if (value<=0) continue;
if (value>1) value=1;
var barWidth=width*value;
if (barWidth<1) barWidth=1;
var colorIndex=i;
if (IFrameSplitOperator.IsNonEmptyArray(barData.Color) && i<barData.Color.length) colorIndex= barData.Color[i];
this.Canvas.fillStyle=g_JSChartResource.DealList.FieldColor.Bar[colorIndex];
if (i==0) //左边
{
this.Canvas.fillRect(center,top,-barWidth,height);
}
else //右边
{
this.Canvas.fillRect(center,top,barWidth,height);
}
}
}
//绘制线段
this.DrawLine=function(lineData, column, rtItem)
{
if (!lineData) return false;
if (!IFrameSplitOperator.IsNonEmptyArray(lineData.Data)) return false;
var width=rtItem.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var left=rtItem.Left+this.ItemMergin.Left;
var top=rtItem.Top+this.ItemMergin.Top;
var height=rtItem.Height-this.ItemMergin.Top-this.ItemMergin.Bottom;
var right=left+width;
var bottom=top+height;
var Temp_GetXFromIndex=function(index)
{
var count=lineData.Count;
if (count==1)
{
if (index==0) return left;
else return right;
}
else if (count<=0)
{
return left;
}
else if (index>=count)
{
return right;
}
else
{
var offset=left+width*index/count;
return offset;
}
}
var priceMax=lineData.Max, priceMin=lineData.Min;
if (IFrameSplitOperator.IsNumber(lineData.YClose)) //前收盘价
{
if (lineData.YClose==priceMax && lineData.YClose==priceMin)
{
priceMax=lineData.YClose+lineData.YClose*0.1;
priceMin=lineData.YClose-lineData.YClose*0.1
}
else
{
var distanceValue=Math.max(Math.abs(lineData.YClose-priceMax),Math.abs(lineData.YClose-priceMin));
priceMax=lineData.YClose+distanceValue;
priceMin=lineData.YClose-distanceValue;
}
}
var Temp_GetYFromData=function(value)
{
if(value<=priceMin) return bottom;
if(value>=priceMax) return top;
var value=height*(value-priceMin)/(priceMax-priceMin);
return bottom-value;
}
this.Canvas.save();
var yCenter=null;
if (IFrameSplitOperator.IsNumber(lineData.YClose))
{
var y=Temp_GetYFromData(lineData.YClose);
y=ToFixedPoint(y);
yCenter=y;
this.Canvas.setLineDash([2,2]);
this.Canvas.strokeStyle=this.CloseLineConfig.YCloseColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,y);
this.Canvas.lineTo(right,y);
this.Canvas.stroke();
this.Canvas.setLineDash([]);
}
if (lineData.Color) this.Canvas.strokeStyle=lineData.Color;
else this.Canvas.strokeStyle=this.CloseLineConfig.CloseColor;
var bFirstPoint=true;
var ptFirst={}; //第1个点
var drawCount=0, x,y;
for(var i=0; i<lineData.Data.length; ++i)
{
var value=lineData.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
x=Temp_GetXFromIndex(i);
y=Temp_GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.beginPath();
this.Canvas.moveTo(x,y);
bFirstPoint=false;
ptFirst={ X:x, Y:y };
}
else
{
this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0)
{
this.Canvas.stroke();
if (column.IsDrawArea && IFrameSplitOperator.IsNumber(yCenter))
{
this.Canvas.lineTo(x,yCenter);
this.Canvas.lineTo(ptFirst.X,yCenter);
this.Canvas.closePath();
this.SetFillStyle(this.CloseLineConfig.AreaColor,left,top, left,bottom);
this.Canvas.fill();
}
}
this.Canvas.restore();
}
//klineData={ Data:[ open, high, low, close ] }
this.DrawKLine=function(klineData, column, rtItem, data)
{
if (column.IsDrawCallback) //外部处理输出格式
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_DRAW_KLINE);
if (event || event.Callback)
{
var sendData=
{
Column:column, Data:data, KLineData:klineData, Rect:rtItem, PreventDefault:false
};
event.Callback(event,sendData,this);
if (sendData.PreventDefault) return;
}
}
if (!klineData) return;
if (!IFrameSplitOperator.IsNonEmptyArray(klineData.Data)) return;
var high=klineData.Data[1];
var low=klineData.Data[2];
var aryKLine=
[
{ Open:klineData.Data[0], High:high, Low:low, Close:klineData.Data[3]},
//{ Open:klineData.Data[0], High:high, Low:low, Close:klineData.Data[3]}
];
this.DrawKLineBar(aryKLine, high, low, rtItem);
}
this.DrawKLineBar=function(aryKLine, high, low, rtItem)
{
var yMergin=4;
var left=rtItem.Left+this.ItemMergin.Left;
var width=rtItem.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var left=rtItem.Left+this.ItemMergin.Left;
var top=rtItem.Top+this.ItemMergin.Top+yMergin;
var height=rtItem.Height-this.ItemMergin.Top-this.ItemMergin.Bottom-yMergin*2;
var right=left+width;
var bottom=top+height;
var Temp_GetYFromData=function(value)
{
if(value<=low) return bottom;
if(value>=high) return top;
var value=height*(value-low)/(high-low);
return bottom-value;
}
var dataWidth=this.KLineConfig.DataWidth;
var distanceWidth=this.KLineConfig.DistanceWidth;
var xOffset=left;
var x, xLeft, xRight;
for(var i=0;i<aryKLine.length;++i,xOffset+=(dataWidth+distanceWidth))
{
var item=aryKLine[i];
xLeft=xOffset;
xRight=xOffset+dataWidth;
x=xLeft+(xRight-xLeft)/2;
if (xRight>right) break;
var yLow=Temp_GetYFromData(item.Low, false);
var yHigh=Temp_GetYFromData(item.High, false);
var yOpen=Temp_GetYFromData(item.Open, false);
var yClose=Temp_GetYFromData(item.Close, false);
var y=yHigh;
if (item.Open<item.Close) //阳线
{
this.DrawKBarItem(item,dataWidth, this.KLineConfig.UpColor, 1, xLeft, xRight, yLow, yHigh, yOpen, yClose);
}
else if (item.Open>item.Close) //阴线
{
this.DrawKBarItem(item,dataWidth, this.KLineConfig.DownColor, 0, xLeft, xRight, yLow, yHigh, yOpen, yClose);
}
else //平线
{
this.DrawKBarItem(item,dataWidth, this.KLineConfig.UnchagneColor, 0, xLeft, xRight, yLow, yHigh, yOpen, yClose);
}
}
}
this.DrawKBarItem=function(data, dataWidth, barColor, drawType, left, right, yLow, yHigh, yOpen, yClose)
{
var isEmptyBar=false;
if (drawType==1) isEmptyBar=true;
var yBarTop=Math.min(yOpen, yClose);
var yBarBottom=Math.max(yOpen, yClose);
var barTopValue=Math.max(data.Open, data.Close);
var barBottomValue=Math.min(data.Open, data.Close);
this.Canvas.fillStyle=barColor;
this.Canvas.strokeStyle=barColor;
var x=left+(right-left)/2;
if (isEmptyBar)
{
if ((dataWidth%2)!=0) dataWidth-=1;
}
if (dataWidth>=4)
{
if (data.High>barTopValue)
{
this.Canvas.beginPath();
var xBar=x;
if (isEmptyBar) xBar=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xBar),ToFixedPoint(yBarTop));
this.Canvas.lineTo(ToFixedPoint(xBar),ToFixedPoint(yHigh));
this.Canvas.stroke();
}
if (Math.abs(yBarBottom-yBarTop)<1)
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(yBarTop),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1
}
else
{
if (isEmptyBar)
{
this.Canvas.beginPath();
this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(yBarTop),ToFixedRect(dataWidth),ToFixedRect(yBarBottom-yBarTop));
this.Canvas.stroke();
}
else
{
this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(yBarTop),ToFixedRect(dataWidth),ToFixedRect(yBarBottom-yBarTop));
}
}
if (data.Low<barBottomValue)
{
this.Canvas.beginPath();
var xBar=x;
if (isEmptyBar) xBar=left+dataWidth/2;
this.Canvas.moveTo(ToFixedPoint(xBar),ToFixedPoint(yBarBottom));
this.Canvas.lineTo(ToFixedPoint(xBar),ToFixedPoint(yLow));
this.Canvas.stroke();
}
}
else
{
}
}
this.SetFillStyle=function(color, x0, y0, x1, y1)
{
if (Array.isArray(color))
{
let gradient = this.Canvas.createLinearGradient(x0, y0, x1, y1);
var offset=1/(color.length);
for(var i in color)
{
gradient.addColorStop(i*offset, color[i]);
}
this.Canvas.fillStyle=gradient;
}
else
{
this.Canvas.fillStyle=color;
}
}
//外部配置显示格式 颜色 对齐方式
this.GetCustomTextDrawInfo=function(columnInfo, symbol, value, drawInfo, data)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_CUSTOM_TEXT);
if (!event || !event.Callback) return false;
var sendData=
{
Symbol:symbol, Column:columnInfo, Value:value, Data:data,
Out:{ Text:null, TextColor:null, TextAlign:null }
};
event.Callback(event,sendData,this);
if (sendData.Out.Text) drawInfo.Text=sendData.Out.Text;
if (sendData.Out.TextColor) drawInfo.TextColor=sendData.Out.TextColor;
if (sendData.Out.TextAlign) drawInfo.TextAlign=sendData.Out.TextAlign;
if (sendData.Out.BGColor) drawInfo.BGColor=sendData.Out.BGColor;
return true;
}
this.FormatDrawInfo=function(column, stock, drawInfo, data)
{
if (!column.IsDrawCallback) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_FORMAT_DRAW_INFO);
if (!event || !event.Callback) return false;
var sendData=
{
Stock:stock, Column:column, Data:data,
DrawInfo:drawInfo
};
event.Callback(event,sendData,this);
}
this.GetFixedRowTextDrawInfo=function(rowIndex, colIndex, columnInfo, drawInfo)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_REPORT_FIXEDROW_TEXT);
if (!event || !event.Callback) return false;
var sendData=
{
RowIndex:rowIndex, ColIndex:colIndex, Column:columnInfo, Data:this.FixedRowData,
Out:{ Text:null, TextColor:null, TextAlign:null }
};
event.Callback(event,sendData,this);
if (sendData.Out.Text) drawInfo.Text=sendData.Out.Text;
if (sendData.Out.TextColor) drawInfo.TextColor=sendData.Out.TextColor;
if (sendData.Out.TextAlign) drawInfo.TextAlign=sendData.Out.TextAlign;
return true;
}
this.GetVolColor=function(colunmInfo, data)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_DEAL_VOL_COLOR);
if (event && event.Callback)
{
var sendData={ Data:data, TextColor:null };
event.Callback(event,sendData,this);
if (sendData.TextColor) return sendData.TextColor;
}
return colunmInfo.TextColor;
}
//获取股票名称颜色
this.GetNameColor=function(colunmInfo, symbol, rowType)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_REPORT_NAME_COLOR);
if (event && event.Callback)
{
var sendData={ Symbol:symbol, TextColor:null, RowType:rowType };
event.Callback(event,sendData,this);
if (sendData.TextColor) return sendData.TextColor;
}
return colunmInfo.TextColor;
}
this.GetFontHeight=function(font,word)
{
return GetFontHeight(this.Canvas, font, word);
}
this.OnMouseDown=function(x,y,e) //Type: 1=tab 4=固定行 2=行 3=表头 5=右侧滚动条
{
if (!this.Data) return null;
if (this.Tab)
{
var tab=this.Tab.OnMouseDown(x,y,e);
if (tab) return { Type:1, Tab: tab }; //底部工具栏
}
if (this.VScrollbar)
{
var item=this.VScrollbar.OnMouseDown(x,y,e);
if (item) return { Type:5, VScrollbar:item }; //右侧滚动条
}
var pixelTatio = GetDevicePixelRatio();
var insidePoint={X:x/pixelTatio, Y:y/pixelTatio};
if (this.UIElement)
var uiElement={Left:this.UIElement.getBoundingClientRect().left, Top:this.UIElement.getBoundingClientRect().top};
else
var uiElement={Left:null, Top:null};
var row=this.PtInFixedBody(x,y)
if (row)
{
var bRedraw=true;
var eventID=JSCHART_EVENT_ID.ON_CLICK_REPORT_FIXEDROW;
if (e.button==2) eventID=JSCHART_EVENT_ID.ON_RCLICK_REPORT_FIXEDROW;
this.SendClickEvent(eventID, { Data:row, X:x, Y:y, e:e, Inside:insidePoint, UIElement:uiElement });
this.SelectedFixedRow=row.Index;
this.SelectedRow=-1;
this.MultiSelectedRow=[];
return { Type:4, Redraw:bRedraw, Row:row }; //行
}
var row=this.PtInBody(x,y);
if (row)
{
var btnStatus={ Redraw:false };
this.OnClickButton(x, y, e, btnStatus);
var bRedraw=true;
if (this.MultiSelectModel==1)
{
if (e && e.ctrlKey) //多选
{
var pos=this.MultiSelectedRow.indexOf(row.DataIndex);
if (pos>=0) this.MultiSelectedRow.splice(pos,1);
else this.MultiSelectedRow.push(row.DataIndex);
}
else if (e && e.shiftKey) //批量多选
{
this.OnShiftClickRow(row);
}
else
{
if (this.MultiSelectedRow.length==1 && this.MultiSelectedRow[0]==row.DataIndex) bRedraw=false;
else this.MultiSelectedRow=[row.DataIndex];
}
this.SelectedFixedRow=-1;
}
else
{
if (this.SelectedModel==0)
{
if (this.SelectedRow==row.Index) bRedraw=false;
this.SelectedRow=row.Index;
this.SelectedFixedRow=-1;
}
else
{
if (this.SelectedRow==row.DataIndex) bRedraw=false;
this.SelectedRow=row.DataIndex;
this.SelectedFixedRow=-1;
}
}
var eventID=JSCHART_EVENT_ID.ON_CLICK_REPORT_ROW;
if (e.button==2) eventID=JSCHART_EVENT_ID.ON_RCLICK_REPORT_ROW;
this.SendClickEvent(eventID, { Data:row, X:x, Y:y, e:e, Inside:insidePoint, UIElement:uiElement });
return { Type:2, Redraw:bRedraw || btnStatus.Redraw, Row:row }; //行
}
var header=this.PtInHeader(x,y);
if (header)
{
var eventID=JSCHART_EVENT_ID.ON_CLICK_REPORT_HEADER;
if (e.button==2)
{
eventID=JSCHART_EVENT_ID.ON_RCLICK_REPORT_HEADER;
}
else if (e.button==0)
{
eventID=JSCHART_EVENT_ID.ON_CLICK_REPORT_HEADER;
}
this.SendClickEvent(eventID, { Data:row, X:x, Y:y , e:e, Inside:insidePoint, UIElement:uiElement});
return { Type:3, Redraw:bRedraw, Header:header }; //表头
}
return null;
}
this.OnShiftClickRow=function(row)
{
if (this.MultiSelectedRow.length<=0)
{
this.MultiSelectedRow.push(row.DataIndex);
return;
}
var max=null, min=null;
for(var i=0;i<this.MultiSelectedRow.length;++i)
{
var value=this.MultiSelectedRow[i];
if (max==null || max<value) max=value;
if (min==null || min>value) min=value;
if (value==row.DataIndex) //移除
{
this.MultiSelectedRow.splice(i,1);
return;
}
}
if (max==min)
{
var start=row.DataIndex, end=max;
if (start>end)
{
start=max;
end=row.DataIndex;
}
this.MultiSelectedRow=[];
for(var i=start;i<=end;++i)
{
this.MultiSelectedRow.push(i);
}
}
else
{
if (row.DataIndex<=max && row.DataIndex>=min)
{
this.MultiSelectedRow.push(row.DataIndex);
}
else
{
var start=Math.min(row.DataIndex, min);
var end=Math.max(row.DataIndex, max);
this.MultiSelectedRow=[];
for(var i=start;i<=end;++i)
{
this.MultiSelectedRow.push(i);
}
}
}
}
this.OnDrawgRow=function(x, y, e) //Type: 5=顶部 6=空白行 2=行 7=底部
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var topOffset=this.RowHeight/2;
var top=this.RectClient.Top+this.HeaderHeight;
var right=this.ChartBorder.GetChartWidth();
var textTop=top+this.FixedRowHeight*this.FixedRowCount;
if (y<textTop+topOffset) return { Type:5 };
for(var i=this.Data.YOffset, j=0; i<this.Data.Data.length && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var rtRow={ Left:0, Top:textTop, Right:right, Bottom: textTop+this.RowHeight };
rtRow.Top+=topOffset;
rtRow.Bottom+=topOffset;
if (x>=rtRow.Left && x<=rtRow.Right && y>=rtRow.Top && y<=rtRow.Bottom)
{
var data={ DataIndex:i, Index:j , Symbol:symbol, Pos:0 };
if (j==0) data.Pos=1;
else if (j==this.RowCount-1) data.Pos=2;
return { Type: 2, Data:data };
}
textTop+=this.RowHeight;
}
if (j<this.RowCount) return { Type:6 };
return { Type:7 };
}
this.OnClickButton=function(x, y, e, status)
{
if (e.button!=0) return false;
var buttonData=this.GetButtonData(x,y);
if (!buttonData) return true;
if (buttonData.Type===0) //checkbox
{
var sendData=
{
Column:buttonData.Column, Index:buttonData.Index, Stock:buttonData.Stock, ColumnIndex:buttonData.ColumnIndex,
Data:buttonData.Data, Value:true,
PreventDefault: false
};
if (IFrameSplitOperator.IsBool(buttonData.Data.Checked)) sendData.Value=!buttonData.Data.Checked;
this.SendClickEvent(JSCHART_EVENT_ID.ON_CLICK_REPORT_CHECKBOX, sendData)
if (!sendData.PreventDefault)
{
if (IFrameSplitOperator.IsBool(buttonData.Data.Checked))
buttonData.Data.Checked=!buttonData.Data.Checked;
else
buttonData.Data.Checked=true;
}
status.Redraw=true;
return true;
}
else if (buttonData.Type===1) //button
{
var sendData={ Column:buttonData.Column, Index:buttonData.Index, Stock:buttonData.Stock, ColumnIndex:buttonData.ColumnIndex, Data:buttonData.Data };
this.SendClickEvent(JSCHART_EVENT_ID.ON_CLICK_REPORT_BUTTON, sendData)
status.Redraw=true;
return true;
}
else if (buttonData.Type===2) //link
{
var sendData={ Column:buttonData.Column, Index:buttonData.Index, Stock:buttonData.Stock, ColumnIndex:buttonData.ColumnIndex, Data:buttonData.Data };
this.SendClickEvent(JSCHART_EVENT_ID.ON_CLICK_REPORT_LINK, sendData)
status.Redraw=true;
return true;
}
return false;
}
this.OnDblClick=function(x,y,e)
{
if (!this.Data) return false;
var header=this.PtInHeaderDragBorder(x,y);
if (header)
{
this.SendClickEvent(JSCHART_EVENT_ID.ON_DBCLICK_REPORT_DRAG_COLUMN_WIDTH, { Data:header, X:x, Y:y });
return true;
}
var row=this.PtInBody(x,y);
if (row)
{
this.SendClickEvent(JSCHART_EVENT_ID.ON_DBCLICK_REPORT_ROW, { Data:row, X:x, Y:y });
return true;
}
return false;
}
this.PtInClient=function(x,y)
{
if (x>this.RectClient.Left && x<this.RectClient.Right && y>this.RectClient.Top && y<this.RectClient.Bottom) return true;
return false;
}
this.PtInBody=function(x,y)
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var top=this.RectClient.Top+this.HeaderHeight;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
var textTop=top+this.FixedRowHeight*this.FixedRowCount;
for(var i=this.Data.YOffset, j=0; i<this.Data.Data.length && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var rtRow={ Left:left, Top:textTop, Right:right, Bottom: textTop+this.RowHeight };
if (x>=rtRow.Left && x<=rtRow.Right && y>=rtRow.Top && y<=rtRow.Bottom)
{
var data={ Rect:rtRow, DataIndex:i, Index:j , Symbol:symbol };
data.Item=this.PtInItem(x,y, rtRow.Top, rtRow.Bottom);
return data;
}
textTop+=this.RowHeight;
}
return null;
}
this.PtInFixedBody=function(x,y)
{
if (this.FixedRowCount<=0) return null;
var top=this.RectClient.Top+this.HeaderHeight;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
var textTop=top;
for(var i=0; i<this.FixedRowCount; ++i)
{
var rtRow={ Left:left, Top:textTop, Right:right, Bottom: textTop+this.FixedRowHeight };
if (x>=rtRow.Left && x<=rtRow.Right && y>=rtRow.Top && y<=rtRow.Bottom)
{
var data={ Rect:rtRow, Index:i};
data.Item=this.PtInItem(x,y, rtRow.Top, rtRow.Bottom);
return data;
}
textTop+=this.FixedRowHeight;
}
return null;
}
this.PtInItem=function(x,y, top, bottom)
{
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var textLeft=left;
//固定列
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
var header={Left:textLeft, Right:textLeft+item.Width, Top:top, Bottom:bottom };
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i, IsFixed:true };
}
textLeft+=item.Width;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
if (textLeft>=right) break;
var header={Left:textLeft, Right:textLeft+item.Width, Top:top, Bottom:bottom };
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i, IsFixed:false };
}
textLeft+=item.Width;
}
return null;
}
this.PtInHeader=function(x,y)
{
if (!this.IsShowHeader) return null;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var top=this.RectClient.Top;
var bottom=top+this.HeaderHeight;
if (!(x>=left && x<=right && y>=top && y<=bottom)) return null;
return this.PtInItem(x,y,top,bottom);
}
this.IsPtInBody=function(x,y)
{
var top=this.RectClient.Top+this.HeaderHeight;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var bottom=this.RectClient.Bottom;
if (x>=left && x<=right && y>=top && y<=bottom) return true;
return false;
}
this.IsPtInHeader=function(x,y)
{
if (!this.IsShowHeader) return false;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var top=this.RectClient.Top;
var bottom=top+this.HeaderHeight;
if (x>=left && x<=right && y>=top && y<=bottom) return true;
return false;
}
this.SendClickEvent=function(id, data)
{
var event=this.GetEventCallback(id);
if (event && event.Callback)
{
event.Callback(event,data,this);
}
}
this.DrawDragRow=function()
{
if (!this.DragRow) return;
var drag=this.DragRow;
if (!drag.Data || !drag.Inside || !drag.Data.Row) return;
var dataIndex=drag.Data.Row.DataIndex;
if (!IFrameSplitOperator.IsNumber(dataIndex) || dataIndex<0) return;
var textTop=drag.Inside.Y-(this.RowHeight/2);
var top=textTop;
var left=this.RectClient.Left;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
//背景
this.Canvas.fillStyle=this.DragRowColor;
this.Canvas.fillRect(left,textTop,rowWidth,this.RowHeight);
var symbol=this.Data.Data[dataIndex];
var data= { Symbol:symbol , Stock:null, Block:null };
if (this.GetStockDataCallback) data.Stock=this.GetStockDataCallback(symbol);
if (this.GetBlockDataCallback) data.Block=this.GetBlockDataCallback(symbol);
data.Decimal=GetfloatPrecision(symbol); //小数位数
var chartRight=this.RectClient.Right;
this.Canvas.font=this.ItemFont;
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawItem(dataIndex, data, item, left, top, 3);
left+=item.Width;
if (left>=chartRight) break;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawItem(dataIndex, data, item, left, top, 3);
left+=item.Width;
if (left>=chartRight) break;
}
}
this.GetTooltipData=function(x,y)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.TooltipRect)) return null;
for(var i=0;i<this.TooltipRect.length;++i)
{
var item=this.TooltipRect[i];
var rt=item.Rect;
if (!rt) continue;
if (x>=rt.Left && x<=rt.Right && y>=rt.Top && y<=rt.Bottom)
{
return { Rect:item.Rect, Stock:item.Stock, Column:item.Column, Index:item.Index, Type:item.Type, Data:item.Data };
}
}
return null;
}
this.GetButtonData=function(x,y)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.ButtonRect)) return null;
for(var i=0;i<this.ButtonRect.length;++i)
{
var item=this.ButtonRect[i];
var rt=item.Rect;
if (!rt) continue;
if (x>=rt.Left && x<=rt.Right && y>=rt.Top && y<=rt.Bottom)
{
return { Rect:item.Rect, Stock:item.Stock, Column:item.Column, Index:item.Index, Type:item.Type, Data:item.Data, ColumnIndex:item.ColumnIndex };
}
}
}
this.PtInHeaderDragBorder=function(x, y)
{
if (!this.IsShowHeader) return null;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var top=this.RectClient.Top;
var bottom=top+this.HeaderHeight;
if (!(x>=left && x<=right && y>=top && y<=bottom)) return null;
var textLeft=left;
var dragBarWidth=5*GetDevicePixelRatio();
//固定列
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
if (item.EnableDragWidth===true)
{
var header={ Right:textLeft+item.Width, Top:top, Bottom:bottom };
header.Left=header.Right-dragBarWidth;
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i, IsFixed:true };
}
}
textLeft+=item.Width;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
if (textLeft>=right) break;
if (item.EnableDragWidth===true)
{
var header={ Right:textLeft+item.Width, Top:top, Bottom:bottom };
header.Left=header.Right-dragBarWidth;
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i, IsFixed:false };
}
}
textLeft+=item.Width;
}
return null;
}
//设置选中行 data={ Symbol:, AutoYScroll:true/false Y滚动条自定定位 }
this.SetSelectedRow=function(option)
{
if (!option) return false;
if (this.SelectedModel===0) return false;
if (option.Symbol)
{
var symbol=option.Symbol;
var bFinder=false;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (symbol==item)
{
this.SelectedRow=i;
bFinder=true;
break;
}
}
if (!bFinder) return false;
if (option.AutoYScroll===true)
{
this.UpdatePageYOffset({ SelectedRow:this.SelectedRow });
}
return bFinder;
}
return false;
}
this.UpdatePageYOffset=function(option)
{
if (!option) return;
var selectedRow=option.SelectedRow;
if (selectedRow<0) return;
var pageStatus=this.GetCurrentPageStatus();
if (pageStatus.IsSinglePage) return;
if (selectedRow>=pageStatus.Start && selectedRow<=pageStatus.End) return;
this.Data.YOffset=selectedRow; //选中行不在当前屏 设置为第1行
}
}
//报价列表底部tab和横向滚动条
function ChartReportTab()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartReportTab'; //类名
this.IsDrawFirst=false;
this.GetEventCallback; //获取事件
this.Report;
this.IsShow=true; //是否显示
//Tab
this.TabList=[]; //{ Title:标题, ID:, IsMenu: 是否菜单, ArySubMenu:[ { Title:, ID: }] }
this.SelectedTabIndex=-1;
this.MoveOnTabIndex=-1;
//滚动条信息
this.MaxPos=15; //滚动条可移动长度
this.CurrentPos=15; //当前滚动条移动位置
this.Step=1; //滚动条移动步长
this.ScrollBarWidth=g_JSChartResource.Report.Tab.ScrollBarWidth;
this.ButtonColor=g_JSChartResource.Report.Tab.ButtonColor;
this.BarColor=g_JSChartResource.Report.Tab.BarColor;
this.BorderColor=g_JSChartResource.Report.Tab.BorderColor;
this.Mergin={ Left:2, Right:2, Top:2, Bottom:2 };
this.TabFontConfig={ Size:g_JSChartResource.Report.Tab.Font.Size, Name:g_JSChartResource.Report.Tab.Font.Name };
this.TabFont;
this.TabTitleColor=g_JSChartResource.Report.Tab.TabTitleColor;
this.TabSelectedTitleColor=g_JSChartResource.Report.Tab.TabSelectedTitleColor;
this.TabSelectedBGColor=g_JSChartResource.Report.Tab.TabSelectedBGColor;
this.TabMoveOnTitleColor=g_JSChartResource.Report.Tab.TabMoveOnTitleColor;
this.TabBGColor=g_JSChartResource.Report.Tab.TabBGColor;
this.TabMergin=
{
Top:g_JSChartResource.Report.Tab.Mergin.Top,
Left:g_JSChartResource.Report.Tab.Mergin.Left,
Right:g_JSChartResource.Report.Tab.Mergin.Right,
Bottom:g_JSChartResource.Report.Tab.Mergin.Bottom
};
this.Height;
this.ButtonSize=25;
this.TabWidth=0;
this.RectScroll={ Left:null, Right:null, Bar:null, Client:null }; //滚动条区域
this.ReloadResource=function(resource)
{
//滚动条
this.ScrollBarWidth=g_JSChartResource.Report.Tab.ScrollBarWidth;
this.ButtonColor=g_JSChartResource.Report.Tab.ButtonColor;
this.BarColor=g_JSChartResource.Report.Tab.BarColor;
this.BorderColor=g_JSChartResource.Report.Tab.BorderColor;
//tab
this.TabFontConfig={ Size:g_JSChartResource.Report.Tab.Font.Size, Name:g_JSChartResource.Report.Tab.Font.Name };
this.TabTitleColor=g_JSChartResource.Report.Tab.TabTitleColor;
this.TabSelectedTitleColor=g_JSChartResource.Report.Tab.TabSelectedTitleColor;
this.TabSelectedBGColor=g_JSChartResource.Report.Tab.TabSelectedBGColor;
this.TabMoveOnTitleColor=g_JSChartResource.Report.Tab.TabMoveOnTitleColor;
this.TabBGColor=g_JSChartResource.Report.Tab.TabBGColor;
this.TabMergin=
{
Top:g_JSChartResource.Report.Tab.Mergin.Top,
Left:g_JSChartResource.Report.Tab.Mergin.Left,
Right:g_JSChartResource.Report.Tab.Mergin.Right,
Bottom:g_JSChartResource.Report.Tab.Mergin.Bottom
};
}
this.SetTabList=function(aryTab)
{
this.TabList=[];
for(var i=0;i<aryTab.length;++i)
{
var item=aryTab[i];
if (!item.Title) continue;
var tabItem={ Title:item.Title, IsMenu:false, FixedSymbol:[], FixedRowCount:0 };
if (item.ID) tabItem.ID=item.ID;
if (item.CommandID) tabItem.CommandID=item.CommandID;
if (IFrameSplitOperator.IsBool(item.IsMenu)) tabItem.IsMenu=item.IsMenu;
if (IFrameSplitOperator.IsNonEmptyArray(item.FixedSymbol))
{
for(var j=0;j<item.FixedSymbol.length;++j)
{
var stockItem=item.FixedSymbol[j];
if (!stockItem || !stockItem.Symbol) continue;
tabItem.FixedSymbol.push(stockItem);
++tabItem.FixedRowCount;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(item.ArySubMenu))
tabItem.ArySubMenu=item.ArySubMenu.slice();
this.TabList.push(tabItem);
}
}
this.CalculateSize=function() //计算大小
{
var pixelRatio=GetDevicePixelRatio();
this.TabFont=`${this.TabFontConfig.Size*pixelRatio}px ${ this.TabFontConfig.Name}`;
this.Height=this.GetFontHeight(this.TabFont,"8")+ this.Mergin.Top+ this.Mergin.Bottom;
var buttonSize=Math.min(25, this.Height-this.Mergin.Top-this.Mergin.Bottom);
this.ButtonSize=buttonSize;
}
this.DrawScrollbar=function(left, top, right, bottom)
{
this.RectScroll={ Left:null, Right:null, Bar:null, Client:null };
var columnOffset = this.Report.GetXScrollPos();
var clolumCount =this.Report.GetXScrollRange();
if (clolumCount <= 0) return;
if (this.Report.IsShowAllColumn) return;
var left=left+this.TabWidth;
if (left+this.ScrollBarWidth*2>right) return;
this.MaxPos=clolumCount;
this.CurrentPos=columnOffset;
var buttonSize=this.ButtonSize;
var rtLeft={ Left:left+this.Mergin.Left, Top:bottom-buttonSize-this.Mergin.Bottom, Width:buttonSize, Height:buttonSize };
rtLeft.Right=rtLeft.Left+buttonSize;
rtLeft.Bottom=rtLeft.Top+buttonSize;
var rtRight={ Left:right-buttonSize-this.Mergin.Right, Top:rtLeft.Top, Width:buttonSize, Height:buttonSize };
rtRight.Right=rtRight.Left+buttonSize;
rtRight.Bottom=rtRight.Top+buttonSize;
this.Canvas.fillStyle=this.ButtonColor;
this.Canvas.fillRect(rtLeft.Left,rtLeft.Top,rtLeft.Width,rtLeft.Height);
this.Canvas.fillRect(rtRight.Left,rtRight.Top,rtRight.Width,rtRight.Height);
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(rtLeft.Left,rtLeft.Top,rtLeft.Width,rtLeft.Height);
this.Canvas.strokeRect(rtRight.Left,rtRight.Top,rtRight.Width,rtRight.Height);
var centerWidth = (rtRight.Left - 2) - (rtLeft.Right + 2);
var value = centerWidth - this.ScrollBarWidth;
var xOffset = (value * this.CurrentPos) / this.MaxPos;
var x = rtLeft.Right + 2 + xOffset;
var rtBar = {Left:x, Top:rtLeft.Top, Width:this.ScrollBarWidth, Height: rtLeft.Height };
rtBar.Right=rtBar.Left+this.ScrollBarWidth;
rtBar.Bottom=rtLeft.Bottom;
this.Canvas.fillStyle=this.BarColor;
this.Canvas.fillRect(rtBar.Left,rtBar.Top,rtBar.Width,rtBar.Height);
this.RectScroll.Left=rtLeft;
this.RectScroll.Right=rtRight;
this.RectScroll.Bar=rtBar;
this.RectScroll.Client={ Left:rtLeft.Right, Right: rtRight.Left, Top:rtLeft.Top, Bottom:rtLeft.Bottom };
}
this.DrawTab=function(left, top, right, bottom)
{
this.TabWidth=0;
this.Canvas.font=this.TabFont;
this.Canvas.textBaseline="bottom";
var tabHeight=bottom-top;
var itemLeft=left+1;
var y=bottom-this.TabMergin.Bottom, x=0;
var text;
var itemWidth=0;
var i=0;
for(i=0;i<this.TabList.length;++i)
{
var item=this.TabList[i];
text=item.Title;
if (item.IsMenu) text+="▲";
x=itemLeft+this.TabMergin.Left;
itemWidth=this.Canvas.measureText(text).width;
var rtItem={Left:itemLeft, Top:top, Width:itemWidth+this.TabMergin.Left+this.TabMergin.Right, Height:tabHeight};
rtItem.Right=rtItem.Left+rtItem.Width;
rtItem.Bottom=rtItem.Top+rtItem.Height;
if (rtItem.Right>right) break;
var bgColor=this.TabBGColor;
if (i==this.SelectedTabIndex) bgColor=this.TabSelectedBGColor
this.Canvas.fillStyle=bgColor;
this.Canvas.fillRect(rtItem.Left,rtItem.Top,rtItem.Width,rtItem.Height);
this.Canvas.textAlign="left";
var textColor=this.TabTitleColor;
if (i==this.MoveOnTabIndex) textColor=this.TabMoveOnTitleColor;
if (i==this.SelectedTabIndex) textColor=this.TabSelectedTitleColor;
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(text,x,y);
item.Rect=rtItem;
itemLeft+=rtItem.Width+1;
this.TabWidth+=rtItem.Width+1;
}
for(;i<this.TabList.length;++i)
{
var item=this.TabList[i];
item.Rect=null;
}
}
this.OnMouseDown=function(x,y, e)
{
var tab=this.PtInTab(x,y);
if (tab) return tab;
return this.PtInScroll(x,y);
}
// Type 1-4 滚动条
this.PtInScroll=function(x,y)
{
if (!this.RectScroll) return null;
if (this.RectScroll.Left)
{
var rtItem=this.RectScroll.Left;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 1, Rect: rtItem };
}
if (this.RectScroll.Right)
{
var rtItem=this.RectScroll.Right;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 2, Rect: rtItem };
}
if (this.RectScroll.Bar)
{
var rtItem=this.RectScroll.Bar;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 3, Rect: rtItem };
}
if (this.RectScroll.Client)
{
var rtItem=this.RectScroll.Client;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom)
{
return { Type: 4, Rect: rtItem , Pos: this.GetScrollPostionByPoint(x,y) };
}
}
return null;
}
// Type=5 标签 6=标签菜单
this.PtInTab=function(x,y)
{
for(var i=0;i<this.TabList.length;++i)
{
var item=this.TabList[i];
if (!item.Rect) continue;
var rtItem=item.Rect;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom)
{
var result= { Type: 5, Rect: rtItem, Tab:item, Index:i };
if (item.IsMenu==true) result.Type==6;
return result;
}
}
return null;
}
this.GetFontHeight=function(font,word)
{
return GetFontHeight(this.Canvas, font, word);
}
this.GetScrollPostionByPoint=function(x,y)
{
var rtItem=this.RectScroll.Client;
var value=rtItem.Right-rtItem.Left-this.ScrollBarWidth;
var pos =parseInt((this.MaxPos * (x - rtItem.Left)) / value);
return pos;
}
}
//页脚信息
function ChartReportPageInfo()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartPageInfo'; //类名
this.IsDrawFirst=false;
this.IsShow=false; //是否显示
this.SizeChange=true;
this.Report;
this.FontConfig={ Size:g_JSChartResource.Report.PageInfo.Font.Size, Name:g_JSChartResource.Report.PageInfo.Font.Name };
this.TextColor=g_JSChartResource.Report.PageInfo.TextColor;
this.BGColor=g_JSChartResource.Report.PageInfo.BGColor;
this.Mergin=
{
Top:g_JSChartResource.Report.PageInfo.Mergin.Top,
Left:g_JSChartResource.Report.PageInfo.Mergin.Left,
Right:g_JSChartResource.Report.PageInfo.Mergin.Right,
Bottom:g_JSChartResource.Report.PageInfo.Mergin.Bottom
}
this.Font;
this.TextHeight=0;
this.ReloadResource=function(resource)
{
this.FontConfig={ Size:g_JSChartResource.Report.PageInfo.Font.Size, Name:g_JSChartResource.Report.PageInfo.Font.Name };
this.TextColor=g_JSChartResource.Report.PageInfo.TextColor;
this.BGColor=g_JSChartResource.Report.PageInfo.BGColor;
this.Mergin=
{
Top:g_JSChartResource.Report.PageInfo.Mergin.Top,
Left:g_JSChartResource.Report.PageInfo.Mergin.Left,
Right:g_JSChartResource.Report.PageInfo.Mergin.Right,
Bottom:g_JSChartResource.Report.PageInfo.Mergin.Bottom
}
}
this.Draw=function()
{
if (!this.IsShow) return;
if (!this.Report) return;
var pageStatus=this.Report.GetCurrentPageStatus();
if (pageStatus.IsSinglePage) return;
if (this.SizeChange)
{
var pixelRatio=GetDevicePixelRatio();
this.Font=`${this.FontConfig.Size*pixelRatio}px ${ this.FontConfig.Name}`;
this.TextHeight=GetFontHeight(this.Canvas, this.Font, "擎")+this.Mergin.Top+this.Mergin.Bottom;
}
var left=this.ChartBorder.GetLeft();
var right=this.ChartBorder.GetRight();
var bottom=this.ChartBorder.GetBottom()-2;
var center=left+(right-left)/2;
var text=`${pageStatus.DataCount}/${pageStatus.DataCount}`;
this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(text).width+4;
var bgLeft=center-textWidth/2-this.Mergin.Left;
var bgTop=bottom-this.TextHeight;
this.Canvas.fillStyle=this.BGColor;;
this.Canvas.fillRect(bgLeft,bgTop,textWidth+(this.Mergin.Left+this.Mergin.Right),this.TextHeight);
text=`${pageStatus.Start+1}/${pageStatus.DataCount}`;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="bottom";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,center,bottom-this.Mergin.Bottom);
this.SizeChange=false;
}
}
function ChartVScrollbar()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartVScrollbar'; //类名
this.IsDrawFirst=false;
this.GetEventCallback; //获取事件
this.Report;
this.MaxPos=15; //滚动条可移动长度
this.CurrentPos=15; //当前滚动条移动位置
this.Step=1; //滚动条移动步长
this.ButtonSize=25;
this.Enable=false;
this.LastStatus={ Draw:false, };
this.GlobalOption;
this.Style=0; //0=滚动条+按钮 1=滚动条
this.ScrollBarHeight=g_JSChartResource.Report.VScrollbar.ScrollBarHeight;
this.ButtonColor=g_JSChartResource.Report.VScrollbar.ButtonColor;
this.BarColor=g_JSChartResource.Report.VScrollbar.BarColor;
this.BorderColor=g_JSChartResource.Report.VScrollbar.BorderColor;
this.BGColor=g_JSChartResource.Report.VScrollbar.BGColor;
this.Margin={ Left:2, Right:2, Top:2, Bottom:2 };
this.BarWithConfig={ Size:g_JSChartResource.Report.VScrollbar.BarWidth.Size };
this.RectScroll={ Top:null, Bottom:null, Bar:null, Client:null }; //滚动条区域
//this.BarWithConfig.Size=2;
//this.Mergin={ Left:1, Right:1, Top:1, Bottom:1 };
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsBool(option.Enable)) this.Enable=option.Enable;
if (IFrameSplitOperator.IsNumber(option.Style)) this.Style=option.Style;
if (IFrameSplitOperator.IsNumber(option.BarWidth)) this.BarWithConfig.Size=option.BarWidth;
if (option.Margin)
{
var item=option.Margin;
if (IFrameSplitOperator.IsNumber(item.Top)) this.Margin.Top=item.Top;
if (IFrameSplitOperator.IsNumber(item.Bottom)) this.Margin.Bottom=item.Bottom;
if (IFrameSplitOperator.IsNumber(item.Left)) this.Margin.Left=item.Left;
if (IFrameSplitOperator.IsNumber(item.Right)) this.Margin.Right=item.Right;
}
}
this.ReloadResource=function(resource)
{
this.ScrollBarHeight=g_JSChartResource.Report.VScrollbar.ScrollBarHeight;
this.ButtonColor=g_JSChartResource.Report.VScrollbar.ButtonColor;
this.BarColor=g_JSChartResource.Report.VScrollbar.BarColor;
this.BorderColor=g_JSChartResource.Report.VScrollbar.BorderColor;
this.BGColor=g_JSChartResource.Report.VScrollbar.BGColor;
this.BarWithConfig={ Size:g_JSChartResource.Report.VScrollbar.BarWidth.Size };
}
this.CalculateSize=function()
{
var pixelRatio=GetDevicePixelRatio();
var width=this.BarWithConfig.Size*pixelRatio+this.Margin.Left+this.Margin.Right;
this.ButtonSize=Math.min(25, width);
}
//不带上下按钮的滚动条样式
this.DrawScrollbarStyle2=function(left, top, right, bottom)
{
this.LastStatus.Draw=false;
this.RectScroll={ Left:null, Right:null, Bar:null, Client:null };
if (!this.Enable) return;
var isShow=this.IsShowCallback();
if (!isShow) return;
var pageInfo=this.Report.GetCurrentPageStatus();
if (pageInfo.IsSinglePage) return;
var xOffset=pageInfo.Start;
var dataCount=pageInfo.DataCount-pageInfo.PageSize;
var buttonSize=this.ButtonSize;
this.MaxPos=dataCount;
this.CurrentPos=xOffset;
var scrollTop=top+this.Margin.Top+2;
var scrollBottom=bottom-this.Margin.Bottom-2;
var centerHeight=scrollBottom-scrollTop;
var value = centerHeight - this.ScrollBarHeight;
var yOffset = (value * this.CurrentPos) / this.MaxPos;
var y = scrollTop + 2 + yOffset;
var rtBar = {Right:right-this.Margin.Right, Top:y, Width:buttonSize, Height: this.ScrollBarHeight };
rtBar.Left=rtBar.Right-buttonSize;
rtBar.Bottom=rtBar.Top+rtBar.Height;
if (rtBar.Bottom>scrollBottom-2)
{
rtBar.Bottom=scrollBottom-2;
rtBar.Top=rtBar.Bottom-rtBar.Height;
}
this.RectScroll.Bar=rtBar;
this.RectScroll.Client={ Left:rtBar.Left, Right: rtBar.Right, Top:scrollTop, Bottom:scrollBottom };
var rtBG={ Right:right, Top:top, Bottom:bottom, Width:buttonSize+this.Margin.Right+this.Margin.Left };
rtBG.Left=rtBG.Right-rtBG.Width;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
this.Canvas.fillStyle=this.BarColor;
this.Canvas.fillRect(rtBar.Left,rtBar.Top,rtBar.Width,rtBar.Height);
this.LastStatus.Draw=true;
}
this.DrawScrollbarStyle=function(left, top, right, bottom)
{
this.LastStatus.Draw=false;
this.RectScroll={ Left:null, Right:null, Bar:null, Client:null };
if (!this.Enable) return;
var isShow=this.IsShowCallback();
if (!isShow) return;
var pageInfo=this.Report.GetCurrentPageStatus();
if (pageInfo.IsSinglePage) return;
var xOffset=pageInfo.Start;
var dataCount=pageInfo.DataCount-pageInfo.PageSize;
var buttonSize=this.ButtonSize;
this.MaxPos=dataCount;
this.CurrentPos=xOffset;
var rtTop={ Right:right-this.Margin.Right, Top:top+this.Margin.Top, Width:buttonSize, Height:buttonSize };
rtTop.Left=rtTop.Right-buttonSize;
rtTop.Bottom=rtTop.Top+buttonSize;
var rtBottom={ Right:right-this.Margin.Right, Bottom:bottom-this.Margin.Bottom, Width:buttonSize, Height:buttonSize };
rtBottom.Left=rtBottom.Right-buttonSize;
rtBottom.Top=rtBottom.Bottom-buttonSize;
var centerHeight=(rtBottom.Top-2)-(rtTop.Bottom+2);
var value = centerHeight - this.ScrollBarHeight;
var yOffset = (value * this.CurrentPos) / this.MaxPos;
var y = rtTop.Bottom + 2 + yOffset;
var rtBar = {Right:right-this.Margin.Right, Top:y, Width:buttonSize, Height: this.ScrollBarHeight };
rtBar.Left=rtBar.Right-buttonSize;
rtBar.Bottom=rtBar.Top+rtBar.Height;
if (rtBar.Bottom>rtBottom.Top-2)
{
rtBar.Bottom=rtBottom.Top-2;
rtBar.Top=rtBar.Bottom-rtBar.Height;
}
this.RectScroll.Top=rtTop;
this.RectScroll.Bottom=rtBottom;
this.RectScroll.Bar=rtBar;
this.RectScroll.Client={ Left:rtTop.Left, Right: rtTop.Right, Top:rtTop.Bottom, Bottom:rtBottom.Top };
var rtBG={ Right:right, Top:top, Bottom:bottom, Width:buttonSize+this.Margin.Right+this.Margin.Left };
rtBG.Left=rtBG.Right-rtBG.Width;
rtBG.Height=rtBG.Bottom-rtBG.Top;
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
this.Canvas.fillStyle=this.ButtonColor;
this.Canvas.fillRect(rtTop.Left,rtTop.Top,rtTop.Width,rtTop.Height);
this.Canvas.fillRect(rtBottom.Left,rtBottom.Top,rtBottom.Width,rtBottom.Height);
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(rtTop.Left,rtTop.Top,rtTop.Width,rtTop.Height);
this.Canvas.strokeRect(rtBottom.Left,rtBottom.Top,rtBottom.Width,rtBottom.Height);
this.Canvas.fillStyle=this.BarColor;
this.Canvas.fillRect(rtBar.Left,rtBar.Top,rtBar.Width,rtBar.Height);
this.LastStatus.Draw=true;
}
this.DrawScrollbar=function(left, top, right, bottom)
{
if (this.Style==1)
this.DrawScrollbarStyle2(left, top, right, bottom);
else
this.DrawScrollbarStyle(left, top, right, bottom);
}
this.OnMouseDown=function(x,y, e)
{
return this.PtInScroll(x,y);
}
// Type 1-4 滚动条
this.PtInScroll=function(x,y)
{
if (!this.RectScroll) return null;
if (this.RectScroll.Top)
{
var rtItem=this.RectScroll.Top;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 1, Rect: rtItem };
}
if (this.RectScroll.Bottom)
{
var rtItem=this.RectScroll.Bottom;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 2, Rect: rtItem };
}
if (this.RectScroll.Bar)
{
var rtItem=this.RectScroll.Bar;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom) return { Type: 3, Rect: rtItem };
}
if (this.RectScroll.Client)
{
var rtItem=this.RectScroll.Client;
if (x>=rtItem.Left && x<=rtItem.Right && y>=rtItem.Top && y<=rtItem.Bottom)
{
return { Type: 4, Rect: rtItem , Pos: this.GetScrollPostionByPoint(x,y) };
}
}
return null;
}
this.GetScrollPostionByPoint=function(x,y)
{
var rtItem=this.RectScroll.Client;
var value=rtItem.Bottom-rtItem.Top-this.ScrollBarHeight;
var pos =parseInt((this.MaxPos * (y - rtItem.Top)) / value);
return pos;
}
}
function ChartCellTooltip()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartCellTooltip'; //类名
this.BGColor="rgba(255,255,225, 0.9)";
this.BorderColor="rgb(0,0,0)";
this.Margin={ Left:5, Right:5, Top:4, Bottom:5 };
this.Font=`${13*GetDevicePixelRatio()}px 微软雅黑`;
this.TextColor="rgb(0,0,0)";
this.YOffset=20;
this.XOffset=5;
this.Point; //{ X, Y}
this.Data; //{ AryText:[ { Text, Color, Title:, TitleColor, Space, Margin:{ Left, Top, Right, Bottom }} ]}
this.Draw=function()
{
if (!this.Canvas) return;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.AryText)) return;
if (!this.Point) return;
var size={ Width:0, Height:0, Text:[] };
this.CalculateTextSize(this.Data.AryText, size);
if (!IFrameSplitOperator.IsNonEmptyArray(size.Text)) return;
this.DrawTooltip(this.Data.AryText, size);
}
this.CalculateTextSize=function(aryText, size)
{
var width=0, height=0;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
var titleHeight=0, titleWidth=0;
if (!item.Title && !item.Text) continue;
if (item.Title)
{
if (item.TitleFont) this.Canvas.font=item.TitleFont;
else this.Canvas.font=this.Font;
titleWidth=this.Canvas.measureText(item.Title).width;
titleHeight=this.Canvas.measureText("擎").width;
}
var textWidth=0, textHeight=0;
if (item.Text)
{
if (item.Font) this.Canvas.font=item.Font;
else this.Canvas.font=this.Font;
textWidth=this.Canvas.measureText(item.Text).width;
textHeight=this.Canvas.measureText("擎").width;
}
var itemWidth=titleWidth+textWidth;
var itemHeight=Math.max(textHeight,titleHeight);
if (IFrameSplitOperator.IsNumber(item.Space)) itemWidth+=item.Space;
if (item.Margin)
{
var margin=item.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) itemWidth+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) itemWidth+=margin.Right;
if (IFrameSplitOperator.IsNumber(margin.Top)) itemHeight+=margin.Top;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) itemHeight+=margin.Bottom;
}
if (width<itemWidth) width=itemWidth;
height+=itemHeight;
size.Text[i]={ Width: itemWidth, Height:itemHeight, TitleWidth:titleWidth, TextWidth:textWidth };
}
if (this.Margin)
{
var margin=this.Margin;
if (IFrameSplitOperator.IsNumber(margin.Left)) width+=margin.Left;
if (IFrameSplitOperator.IsNumber(margin.Right)) width+=margin.Right;
if (IFrameSplitOperator.IsNumber(margin.Top)) height+=margin.Top;
if (IFrameSplitOperator.IsNumber(margin.Bottom)) height+=margin.Bottom;
}
size.Width=width;
size.Height=height;
}
this.DrawTooltip=function(aryText, size)
{
var rtBG={ Left:this.Point.X+this.XOffset, Top:this.Point.Y+this.YOffset, Width:size.Width, Height:size.Height };
rtBG.Right=rtBG.Left+rtBG.Width;
rtBG.Bottom=rtBG.Top+rtBG.Height;
var border=this.ChartBorder.GetBorder();
if (rtBG.Bottom>border.ChartHeight)
{
rtBG.Bottom=this.Point.Y;
rtBG.Top=rtBG.Bottom-rtBG.Height;
}
if (rtBG.Right>border.ChartWidth)
{
rtBG.Right=this.Point.X;
rtBG.Left=rtBG.Right-rtBG.Width;
}
if (this.BGColor)
{
this.Canvas.fillStyle=this.BGColor;
this.Canvas.fillRect(ToFixedPoint(rtBG.Left),ToFixedPoint(rtBG.Top),ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
}
if (this.BorderColor)
{
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.strokeRect(ToFixedPoint(rtBG.Left),ToFixedPoint(rtBG.Top),ToFixedRect(rtBG.Width),ToFixedRect(rtBG.Height));
}
var left=rtBG.Left;
var top=rtBG.Top;
if (this.Margin && IFrameSplitOperator.IsNumber(this.Margin.Left)) left+=this.Margin.Left;
if (this.Margin && IFrameSplitOperator.IsNumber(this.Margin.Top)) top+=this.Margin.Top;
var xText, yText=top;
for(var i=0;i<aryText.length;++i)
{
var item=aryText[i];
if (!item.Title && !item.Text) continue;
var itemSize=size.Text[i];
xText=left;
yText+=itemSize.Height;
if (item.Margin && IFrameSplitOperator.IsNumber(item.Margin.Left)) xText+=item.Margin.Left;
if (item.Margin && IFrameSplitOperator.IsNumber(item.Margin.Bottom)) yText-=item.Margin.Bottom;
if (item.Title)
{
if (item.TitleColor) this.Canvas.fillStyle=item.TitleColor;
else this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(item.Title,xText,yText,itemSize.TitleWidth);
xText+=itemSize.TitleWidth;
if (IFrameSplitOperator.IsNumber(item.Space)) xText+=item.Space;
}
if (item.Text)
{
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(item.Text,xText,yText,itemSize.TextWidth);
}
}
}
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
封装键盘精灵控件 (页面版 不支持手机)
*/
function JSKeyboardChart(divElement)
{
this.DivElement=divElement;
this.JSChartContainer; //表格控件
this.ResizeListener; //大小变动监听
//h5 canvas
this.CanvasElement=document.createElement("canvas");
this.CanvasElement.className='jskeyboard-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("[JSKeyboardChart::JSRepoJSKeyboardChartrtChart] divElement hasChildNodes", divElement.childNodes);
}
divElement.appendChild(this.CanvasElement);
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;
JSConsole.Chart.Log(`[JSKeyboardChart::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.CreateJSKeyboardChartContainer(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();
chart.Draw();
}
this.CreateJSKeyboardChartContainer=function(option)
{
var chart=new JSKeyboardChartContainer(this.CanvasElement);
chart.Create(option);
if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;
if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) chart.SetColumn(option.Column);
if (IFrameSplitOperator.IsNumber(option.BorderLine)) chart.Frame.BorderLine=option.BorderLine;
this.SetChartBorder(chart, option);
//注册事件
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("[JSKeyboardChart::OnDivResize] entries=", entries);
this.OnSize();
}
/////////////////////////////////////////////////////////////////////////////
//对外接口
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('[JSKeyboardChart:AddEventCallback] obj=', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:ReloadResource] ');
this.JSChartContainer.ReloadResource(option);
}
}
this.ChartDestory=function()
{
if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestory) == 'function')
{
this.JSChartContainer.ChartDestory();
}
}
this.Draw=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:Draw] ');
this.JSChartContainer.Draw();
}
}
this.SetSymbolData=function(arySymbol)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:SetSymbolData] ', arySymbol);
this.JSChartContainer.SetSymbolData(arySymbol);
}
}
this.Search=function(strText)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Search)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:Search] ', strText);
this.JSChartContainer.Search(strText);
}
}
this.OnKeyDown=function(event)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.OnKeyDown)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:OnKeyDown] ', event);
this.JSChartContainer.OnKeyDown(event);
}
}
this.ClearSearch=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ClearSearch)=='function')
{
JSConsole.Chart.Log('[JSKeyboardChart:ClearSearch] ', option);
this.JSChartContainer.ClearSearch(option);
}
}
}
JSKeyboardChart.Init=function(divElement)
{
var jsChartControl=new JSKeyboardChart(divElement);
jsChartControl.OnSize();
return jsChartControl;
}
//自定义风格
JSKeyboardChart.SetStyle=function(option)
{
if (option) g_JSChartResource.SetStyle(option);
}
function JSKeyboardChartContainer(uielement)
{
this.ClassName='JSKeyboardChartContainer';
this.Frame; //框架画法
this.ChartPaint=[]; //图形画法
this.Canvas=uielement.getContext("2d"); //画布
this.ShowCanvas=null;
this.NetworkFilter; //数据回调接口
this.Data={ XOffset:0, YOffset:0, Data:[] }; //股票列表
this.MapSymbol=new Map();
this.SourceData={ Data:[] } //码表数据 Data:[ { Symbol:, Spell, Name:, Color: TypeName:, TypeID } ]
this.FunctionKeyData=[]; //功能键 { Priority:, Data:[ { Symbol:, Spell, Name:, Color:, TypeName:, TypeID } ]
//事件回调
this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,}
this.UIElement=uielement;
this.LastPoint=new Point(); //鼠标位置
//拖拽滚动条
this.DragYScroll=null; //{Start:{x,y}, End:{x, y}}
this.IsDestroy=false; //是否已经销毁了
this.ChartDestory=function() //销毁
{
this.IsDestroy=true;
}
this.ClearSearch=function(option)
{
this.Data.Data=[];
this.Data.XOffset=0;
this.Data.YOffset=0;
if (option && option.Redraw==true) this.Draw();
}
this.SearchFunctionKeyData=function(strSearch)
{
if (strSearch.length<=0) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.FunctionKeyData)) return null;
var aryData=[];
for(var i=0; i<this.FunctionKeyData.length; ++i)
{
var groupData=this.FunctionKeyData[i];
if (!groupData) continue;
if (!IFrameSplitOperator.IsNonEmptyArray(groupData.Data)) continue;
var aryExactQuery=[]; //精确查询
var aryFuzzyQuery=[]; //模糊查询
var aryEqualQuery=[]; //相等
for(var j=0;j<groupData.Data.length;++j)
{
var item=groupData.Data[j];
if (this.SearchSymbol(item, strSearch, aryExactQuery, aryFuzzyQuery,aryEqualQuery)) continue;
}
if (IFrameSplitOperator.IsNonEmptyArray(aryEqualQuery)) aryData.push(...aryEqualQuery);
if (IFrameSplitOperator.IsNonEmptyArray(aryExactQuery)) aryData.push(...aryExactQuery);
if (IFrameSplitOperator.IsNonEmptyArray(aryFuzzyQuery)) aryData.push(...aryFuzzyQuery);
}
if (aryData.length>0) return aryData;
return null;
}
this.Search=function(strText)
{
var aryExactQuery=[]; //精确查询
var aryFuzzyQuery=[]; //模糊查询
var aryEqualQuery=[]; //相等
var aryFuncKeyQuery=null;
this.MapSymbol.clear();
this.Data.Data=[];
this.Data.XOffset=0;
this.Data.YOffset=0;
var strSearch=strText.trim();
if (strSearch.length>0)
{
aryFuncKeyQuery=this.SearchFunctionKeyData(strSearch);
for(var i=0;i<this.SourceData.Data.length;++i)
{
var item=this.SourceData.Data[i];
if (this.SearchSymbol(item, strSearch, aryExactQuery, aryFuzzyQuery, aryEqualQuery)) continue;
else if (this.SearchSpell(item, strSearch, aryExactQuery, aryFuzzyQuery)) continue;
}
}
if (IFrameSplitOperator.IsNonEmptyArray(aryFuncKeyQuery)) this.Data.Data.push(...aryFuncKeyQuery);
if (IFrameSplitOperator.IsNonEmptyArray(aryEqualQuery)) this.Data.Data.push(...aryEqualQuery);
if (IFrameSplitOperator.IsNonEmptyArray(aryExactQuery)) this.Data.Data.push(...aryExactQuery);
if (IFrameSplitOperator.IsNonEmptyArray(aryFuzzyQuery)) this.Data.Data.push(...aryFuzzyQuery);
this.ChartPaint[0].SelectedRow=0;
this.ChartPaint[0].SizeChange=true;
JSConsole.Chart.Log(`[JSKeyboardChart:Search] search=${strSearch}, source=${this.SourceData.Data.length} match=${this.Data.Data.length}`);
this.Draw();
}
this.SearchSymbol=function(item, strText, aryExactQuery, aryFuzzyQuery, aryEqualQuery)
{
var find=item.Symbol.indexOf(strText);
if (find<0) return false;
if (item.Symbol==strText) aryEqualQuery.push(item.Symbol);
else if (find==0) aryExactQuery.push(item.Symbol);
else aryFuzzyQuery.push(item.Symbol);
this.MapSymbol.set(item.Symbol, item);
return true;
}
this.SearchSpell=function(item, strText, aryExactQuery, aryFuzzyQuery)
{
if (!IFrameSplitOperator.IsString(item.Spell)) return false;
var find=item.Spell.indexOf(strText);
if (find!=0) return false;
aryExactQuery.push(item.Symbol);
this.MapSymbol.set(item.Symbol, item);
return true;
}
this.SetSymbolData=function(arySymbol)
{
this.SourceData.Data=[];
for(var i=0;i<arySymbol.length;++i)
{
var item=arySymbol[i];
if (IFrameSplitOperator.IsNumber(item.Priority))
{
if (!this.FunctionKeyData[item.Priority]) this.FunctionKeyData[item.Priority]={ Priority:item.Priority, Data:[] };
this.FunctionKeyData[item.Priority].Data.push(item);
}
else
{
this.SourceData.Data.push(item);
}
}
/*
//测试
this.MapSymbol.clear();
for(var i=0;i<this.SourceData.Data.length && i<3050 ;++i)
{
var item=this.SourceData.Data[i];
this.Data.Data.push(item.Symbol);
this.MapSymbol.set(item.Symbol, item);
}
this.ChartPaint[0].SelectedRow=0;
*/
}
//创建
this.Create=function(option)
{
this.UIElement.JSChartContainer=this;
//创建框架
this.Frame=new JSKeyboardFrame();
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 ChartSymbolList();
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.Data=this.Data;
this.ChartPaint[0]=chart;
chart.VScrollbar=new ChartKeyboardVScrollbar();
chart.VScrollbar.Frame=this.Frame;
chart.VScrollbar.Canvas=this.Canvas;
chart.VScrollbar.ChartBorder=this.Frame.ChartBorder;
chart.VScrollbar.Report=chart;
if (option)
{
}
var bRegisterKeydown=true;
var bRegisterWheel=true;
if (option)
{
if (option.KeyDown===false)
{
bRegisterKeydown=false;
JSConsole.Chart.Log('[JSKeyboardChartContainer::Create] not register keydown event.');
}
if (option.Wheel===false)
{
bRegisterWheel=false;
JSConsole.Chart.Log('[JSKeyboardChartContainer::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.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.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];
if (item.IsDrawFirst)
item.Draw();
}
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (!item.IsDrawFirst)
item.Draw();
}
}
this.GetStockData=function(symbol)
{
if (!this.MapSymbol.has(symbol)) return null;
return this.MapSymbol.get(symbol);
}
this.ResetStatus=function()
{
this.Data.XOffset=0;
this.Data.YOffset=0;
}
this.ResetSelectStatus=function()
{
var chart=this.GetReportChart();
if (chart)
{
chart.SelectedRow=-1;
chart.SelectedFixedRow=-1;
}
}
//设置事件回调
//{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.SetSizeChange=function(bChanged)
{
for(var i=0;i<this.ChartPaint.length;++i)
{
var chart=this.ChartPaint[i];
if (chart) chart.SizeChange=bChanged;
}
}
this.OnWheel=function(e) //滚轴
{
JSConsole.Chart.Log('[JSKeyboardChartContainer::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.ChartPaint[0];
if (!chart) return;
var wheelValue=e.wheelDelta;
if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
wheelValue=e.deltaY* -0.01;
if (wheelValue<0) //下一页
{
if (this.GotoNextPage(this.PageUpDownCycle))
{
this.Draw();
}
}
else if (wheelValue>0) //上一页
{
if (this.GotoPreviousPage(this.PageUpDownCycle))
{
this.Draw();
}
}
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnKeyDown=function(e)
{
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var reportChart=this.GetReportChart();
if (!reportChart) return;
var keyID = e.keyCode ? e.keyCode :e.which;
switch(keyID)
{
case 33: //page up
if (this.GotoPreviousPage(this.PageUpDownCycle))
{
this.Draw();
}
break;
case 34: //page down
if (this.GotoNextPage(this.PageUpDownCycle))
{
this.Draw();
}
break;
case 38: //up
var result=this.MoveSelectedRow(-1);
if (result)
{
if (result.Redraw) this.Draw();
}
break;
case 40: //down
var result=this.MoveSelectedRow(1)
if (result)
{
if (result.Redraw) this.Draw();
}
break;
case 37: //left
if (this.MoveXOffset(-1)) this.Draw();
break
case 39: //right
if (this.MoveXOffset(1)) this.Draw();
break;
case 13: //Enter
this.OnSelectedSymbol();
break;
}
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
this.OnSelectedSymbol=function()
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var data=chart.GetSelectedSymbol();
var selItem=this.MapSymbol.get(data.Symbol);
if (!selItem) return false;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYBOARD_SELECTED)
if (event && event.Callback)
{
event.Callback(event, { Data:data, RowData:selItem }, this);
}
}
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.ChartPaint[0];
if (chart)
{
if (chart.OnDblClick(x,y,e)) this.OnSelectedSymbol();
}
}
this.UIOnMouseDown=function(e)
{
this.DragYScroll=null;
this.DragMove={ Click:{ X:e.clientX, Y:e.clientY }, Move:{X:e.clientX, Y:e.clientY}, PreMove:{X:e.clientX, Y:e.clientY } };
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)
{
var clickData=chart.OnMouseDown(x,y,e);
if (!clickData) return;
//if (e.button!=0) return;
if ((clickData.Type==2) && (e.button==0 || e.button==2)) //点击行
{
if (clickData.Redraw==true)
this.Draw();
}
else if (clickData.Type==5 && e.button==0) //右侧滚动条
{
var scroll=clickData.VScrollbar;
if (scroll.Type==1) //顶部按钮
{
if (this.MoveYOffset(-1))
this.Draw();
}
else if (scroll.Type==2) //底部按钮
{
if (this.MoveYOffset(1))
this.Draw();
}
else if (scroll.Type==3) //滚动条
{
this.DragYScroll={ Click:{X:x, Y:y}, LastMove:{X:x, Y:y} };
}
else if (scroll.Type==4) //滚动条内部
{
if (this.SetYOffset(scroll.Pos))
this.Draw();
}
}
}
document.onmousemove=(e)=>{ this.DocOnMouseMove(e); }
document.onmouseup=(e)=> { this.DocOnMouseUp(e); }
}
//去掉右键菜单
this.UIOnContextMenu=function(e)
{
e.preventDefault();
}
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;
}
this.UIOnMounseOut=function(e)
{
}
this.UIOnMouseleave=function(e)
{
}
this.DocOnMouseMove=function(e)
{
this.DragMove.PreMove.X=this.DragMove.Move.X;
this.DragMove.PreMove.Y=this.DragMove.Move.Y;
this.DragMove.Move.X=e.clientX;
this.DragMove.Move.Y=e.clientX;
//if (this.DragMove.Move.X!=this.DragMove.PreMove.X || this.DragMove.Move.Y!=this.DragMove.PreMove.Y)
// this.StopAutoDragScrollTimer();
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.DragYScroll)
{
var chart=this.ChartPaint[0];
if (!chart || !chart.VScrollbar) return;
this.DragYScroll.LastMove.X=x;
this.DragYScroll.LastMove.Y=y;
var pos=chart.VScrollbar.GetScrollPostionByPoint(x,y);
if (this.SetYOffset(pos))
this.Draw();
}
}
this.DocOnMouseUp=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
this.DragYScroll=null;
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYBOARD_MOUSEUP)
if (event && event.Callback)
{
event.Callback(event, { }, this);
}
}
this.GetMoveAngle=function(pt,pt2) //计算角度
{
var xMove=Math.abs(pt.X-pt2.X);
var yMove=Math.abs(pt.Y-pt2.Y);
var angle=Math.atan(xMove/yMove)*180/Math.PI;
return angle;
}
this.PreventTouchEvent=function(e)
{
if (e.cancelable) e.preventDefault();
e.stopPropagation();
}
this.OnDragYOffset=function(drag, touches, moveUpDown, e)
{
if (moveUpDown<5) return false
var isUp=true;
if (drag.LastMove.Y<touches[0].clientY) isUp=false; //Down
var oneStep=this.YStepPixel;
if (oneStep<=0) oneStep=5;
var step=parseInt(moveUpDown/oneStep);
if (step<=0) return false
if (isUp==false) step*=-1;
if (this.MoveYOffset(step, this.DragPageCycle))
{
drag.IsYMove=true;
this.Draw();
this.DelayUpdateStockData();
}
return true;
}
this.OnDragXOffset=function(drag, touches, moveLeftRight, e)
{
if (moveLeftRight<5) return false;
var isLeft=true;
if (drag.LastMove.X<touches[0].clientX) isLeft=false;//右移数据
var oneStep=this.XStepPixel;
if (oneStep<=0) oneStep=5;
var step=parseInt(moveLeftRight/oneStep); //除以4个像素
if (step<=0) return false;
if (!isLeft) step*=-1;
if (this.MoveXOffset(step))
{
drag.IsXMove=true;
this.Draw();
}
return true;
}
this.GetReportChart=function()
{
var chart=this.ChartPaint[0];
return chart;
}
this.GotoNextPage=function(bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
if (pageSize>this.Data.Data.length) return false;
if (this.Data.YOffset+pageSize>=this.Data.Data.length)
{
if (bCycle===true)
{
this.Data.YOffset=0; //循环到第1页
return true;
}
else
{
return false;
}
}
this.Data.YOffset+=pageSize;
var showDataCount=this.Data.Data.length-this.Data.YOffset;
chart.SelectedRow=this.Data.YOffset;
return true;
}
this.GotoPreviousPage=function(bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageSize=chart.GetPageSize();
if (pageSize>this.Data.Data.length) return false;
if (this.Data.YOffset<=0)
{
if (bCycle===true)
{
this.Data.YOffset=this.Data.Data.length-pageSize; //循环到最后一页
return true;
}
else
{
return false;
}
}
var offset=this.Data.YOffset;
offset-=pageSize;
if (offset<0) offset=0;
this.Data.YOffset=offset;
chart.SelectedRow=this.Data.YOffset;
return true;
}
this.MoveYOffset=function(setp, bCycle) //bCycle 是否循环
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var pageStatus=chart.GetCurrentPageStatus();
if (pageStatus.IsSinglePage) return false;
if (setp>0) //向上
{
var count=this.Data.Data.length;
var pageSize=pageStatus.PageSize;
var offset=this.Data.YOffset;
if (bCycle)
{
for(var i=0;i<setp;++i)
{
++offset;
if (offset+pageSize>count) offset=0;
}
}
else
{
if (offset+pageSize>=count) return false;
for(var i=0;i<setp;++i)
{
if (offset+pageSize+1>count) break;
++offset;
}
}
this.Data.YOffset=offset;
return true;
}
else if (setp<0) //向下
{
setp=Math.abs(setp);
var offset=this.Data.YOffset;
if (bCycle)
{
var pageSize=pageStatus.PageSize;
for(var i=0;i<setp;++i)
{
--offset;
if (offset<0) offset=this.Data.Data.length-pageSize;
}
}
else
{
if (this.Data.YOffset<=0) return false;
for(var i=0;i<setp;++i)
{
if (offset-1<0) break;
--offset;
}
}
this.Data.YOffset=offset;
return true;
}
return false;
}
this.GotoLastPage=function()
{
var chart=this.ChartPaint[0];
if (!chart) return;
//显示最后一屏
var pageSize=chart.GetPageSize(true);
var offset=this.Data.Data.length-pageSize;
if (offset<0) offset=0;
this.Data.DataOffset=offset;
}
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.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)
{
this.SetSizeChange(true);
this.Draw();
}
}
this.MoveSelectedRow=function(step)
{
var chart=this.ChartPaint[0];
if (!chart) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var result={ Redraw:false }; //Redraw=重绘
//可翻页模式
var pageStatus=chart.GetCurrentPageStatus();
var pageSize=pageStatus.PageSize;
var selected=pageStatus.SelectedRow;
if (step>0)
{
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.SelectedRow=pageStatus.Start;
result.Redraw=true;
return result;
}
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
++selected;
if (selected>pageStatus.End) ++offset;
if (selected>=this.Data.Data.length)
break;
result.Redraw=true;
chart.SelectedRow=selected;
this.Data.YOffset=offset;
}
return result;
}
else if (step<0)
{
if (selected<0 || selected<pageStatus.Start || selected>pageStatus.End)
{
chart.SelectedRow=pageStatus.End;
result.Redraw=true;
return result;
}
step=Math.abs(step);
var offset=this.Data.YOffset;
for(var i=0;i<step;++i)
{
--selected;
if (selected<pageStatus.Start) --offset;
if (selected<0)
break;
result.Redraw=true;
chart.SelectedRow=selected;
this.Data.YOffset=offset;
}
return result;
}
}
this.SetYOffset=function(pos)
{
if (!IFrameSplitOperator.IsNumber(pos)) return false;
var chart=this.ChartPaint[0];
if (!chart) return false;
var maxOffset=chart.GetYScrollRange();
if (pos<0) pos=0;
if (pos>maxOffset) pos=maxOffset;
this.Data.YOffset=pos;
return true;
}
}
function JSKeyboardFrame()
{
this.ChartBorder;
this.Canvas; //画布
this.BorderLine=null; //1=上 2=下 4=左 8=右
this.BorderColor=g_JSChartResource.Keyboard.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
this.ReloadResource=function(option)
{
this.BorderColor=g_JSChartResource.Keyboard.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);
}
}
var KEYBOARD_COLUMN_ID=
{
SHORT_SYMBOL_ID:0, //不带后缀代码
SYMBOL_ID:1,
NAME_ID:2, //简称
TYPE_ID:3, //类型
TYPE_NAME_ID:4, //类型中文名字
}
function ChartSymbolList()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ChartSymbolList'; //类名
this.UIElement;
this.IsDrawFirst=false;
this.GetEventCallback; //获取事件
this.Data; //数据 { XOffset:0, YOffset:0, Data:['600000.sh', '000001.sz'] }
this.SizeChange=true;
this.SelectedRow=-1; //选中行ID
this.IsDrawBorder=false; //是否绘制单元格边框
this.ShowSymbol=[]; //显示的股票列表 { Index:序号(排序用), Symbol:股票代码 }
this.VScrollbar; //竖向滚动条
this.BorderColor=g_JSChartResource.Keyboard.BorderColor; //边框线
this.SelectedColor=g_JSChartResource.Keyboard.SelectedColor; //选中行
this.TextColor=g_JSChartResource.Keyboard.TextColor; //文字颜色
//表格内容配置
this.ItemFontConfig={ Size:g_JSChartResource.Keyboard.Item.Font.Size, Name:g_JSChartResource.Keyboard.Item.Font.Name };
this.ItemMergin=
{
Left:g_JSChartResource.Keyboard.Item.Mergin.Left,
Right:g_JSChartResource.Keyboard.Item.Mergin.Right,
Top:g_JSChartResource.Keyboard.Item.Mergin.Top,
Bottom:g_JSChartResource.Keyboard.Item.Mergin.Bottom
};
//缓存
this.ItemFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemSymbolFont=12*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemNameFont=15*GetDevicePixelRatio() +"px 微软雅黑";
this.ItemNameHeight=0;
this.RowCount=0; //一屏显示行数
this.RowHeight=0; //行高度
this.Column= //{ Type:列id, Title:标题, TextAlign:文字对齐方式, MaxText:文字最大宽度 , TextColor:文字颜色, Sort:0=不支持排序 1=本地排序 0=远程排序 }
[
{ Type:KEYBOARD_COLUMN_ID.SHORT_SYMBOL_ID, Title:"代码", TextAlign:"left", Width:null, MaxText:"888888" },
{ Type:KEYBOARD_COLUMN_ID.NAME_ID, Title:"名称", TextAlign:"left", Width:null, MaxText:"擎擎擎擎擎擎" },
//{ Type:KEYBOARD_COLUMN_ID.TYPE_ID, Title:"类型", TextAlign:"right", Width:null, MaxText:"擎擎擎擎" },
{ Type:KEYBOARD_COLUMN_ID.TYPE_NAME_ID, Title:"类型", TextAlign:"right", Width:null, MaxText:"擎擎擎擎" },
];
this.RectClient={ };
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.Keyboard.BorderColor; //边框线
this.SelectedColor=g_JSChartResource.Keyboard.SelectedColor; //选中行
this.TextColor=g_JSChartResource.Keyboard.TextColor; //文字颜色
if (this.VScrollbar) this.VScrollbar.ReloadResource(resource);
}
this.SetColumn=function(aryColumn)
{
if (!IFrameSplitOperator.IsNonEmptyArray(aryColumn)) return;
this.Column=[];
for(var i=0;i<aryColumn.length;++i)
{
var item=aryColumn[i];
var colItem=this.GetDefaultColunm(item.Type);
if (!colItem) continue;
if (item.Title) colItem.Title=item.Title;
if (item.TextAlign) colItem.TextAlign=item.TextAlign;
if (item.MaxText) colItem.MaxText=item.MaxText;
this.Column.push(colItem);
}
}
this.GetDefaultColunm=function(id)
{
var DEFAULT_COLUMN=
[
{ Type:KEYBOARD_COLUMN_ID.SHORT_SYMBOL_ID, Title:"代码", TextAlign:"left", Width:null, MaxText:"888888" },
{ Type:KEYBOARD_COLUMN_ID.NAME_ID, Title:"名称", TextAlign:"left", Width:null, MaxText:"擎擎擎擎擎擎" },
{ Type:KEYBOARD_COLUMN_ID.TYPE_NAME_ID, Title:"类型", TextAlign:"right", Width:null, MaxText:"擎擎擎擎" },
];
for(var i=0;i<DEFAULT_COLUMN.length;++i)
{
var item=DEFAULT_COLUMN[i];
if (item.Type==id) return item;
}
return null;
}
this.Draw=function()
{
this.ShowSymbol=[ ];
if (this.SizeChange) this.CalculateSize();
else this.UpdateCacheData();
var bShowVScrollbar=this.IsShowVScrollbar();
this.Canvas.save();
this.Canvas.beginPath();
this.Canvas.rect(this.RectClient.Left,this.RectClient.Top+1,(this.RectClient.Right-this.RectClient.Left),(this.RectClient.Bottom-(this.RectClient.Top+1)));
//this.Canvas.stroke(); //调试用
this.Canvas.clip();
this.DrawBody();
this.Canvas.restore();
this.DrawBorder();
if (this.VScrollbar && bShowVScrollbar)
{
var bottom=this.ChartBorder.GetBottom();
this.VScrollbar.DrawScrollbar(this.RectClient.Left,this.RectClient.Top+2, this.RectClient.Right+this.VScrollbar.ButtonSize+2, bottom-2);
}
this.SizeChange=false;
}
//更新缓存变量
this.UpdateCacheData=function()
{
this.RectClient.Left=this.ChartBorder.GetLeft();
this.RectClient.Right=this.ChartBorder.GetRight();
this.RectClient.Top=this.ChartBorder.GetTop();
this.RectClient.Bottom=this.ChartBorder.GetBottom();
var bShowVScrollbar=this.IsShowVScrollbar();
if (bShowVScrollbar && this.VScrollbar && this.VScrollbar.Enable)
{
this.RectClient.Right-=(this.VScrollbar.ButtonSize+2);
}
}
this.GetPageSize=function(recalculate) //recalculate 是否重新计算
{
if (recalculate) this.CalculateSize();
var size=this.RowCount;
return size;
}
this.GetCurrentPageStatus=function() //{ Start:起始索引, End:结束索引(数据), PageSize:页面可以显示几条记录, IsEnd:是否是最后一页, IsSinglePage:是否只有一页数据}
{
var result={ Start:this.Data.YOffset, PageSize:this.RowCount, IsEnd:false, SelectedRow:this.SelectedRow, IsSinglePage:false, DataCount:0 };
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
result.End=this.Data.YOffset+this.RowCount-1;
result.IsSinglePage=this.Data.Data.length<=this.RowCount;
result.DataCount=this.Data.Data.length;
if (result.End>=this.Data.Data.length-1) result.IsEnd=true;
if (result.End>=this.Data.Data.length) result.End=this.Data.Data.length-1;
}
else
{
result.Star=0;
result.End=0;
result.IsEnd=true;
result.IsSinglePage=true;
}
return result;
}
this.CalculateSize=function() //计算大小
{
if (this.VScrollbar && this.VScrollbar.Enable) this.VScrollbar.CalculateSize();
this.UpdateCacheData();
var pixelRatio=GetDevicePixelRatio();
this.ItemFont=`${this.ItemFontConfig.Size*pixelRatio}px ${ this.ItemFontConfig.Name}`;
this.RowHeight=this.GetFontHeight(this.ItemFont,"擎")+ this.ItemMergin.Top+ this.ItemMergin.Bottom;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
this.Canvas.font=this.ItemFont;
var itemWidth=0;
for(var i=0;i<this.Column.length;++i)
{
var item=this.Column[i];
itemWidth=this.Canvas.measureText(item.MaxText).width;
item.Width=itemWidth+4+this.ItemMergin.Left+this.ItemMergin.Right;
if (i==this.Column.length-1) //最后一列
{
if (left+item.Width<right) item.Width=right-left;
}
left+=item.Width;
}
this.RowCount=parseInt((this.RectClient.Bottom-this.RectClient.Top)/this.RowHeight);
}
this.DrawText=function(text, textAlign, x, y, textWidth)
{
if (textAlign=='center')
{
x=x+textWidth/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=x+textWidth;
this.Canvas.textAlign="right";
}
else
{
this.Canvas.textAlign="left";
}
this.Canvas.textBaseline="middle";
this.Canvas.fillText(text,x,y);
}
this.DrawBorder=function()
{
if (!this.IsDrawBorder) return;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var top=this.RectClient.Top;
var bottom=this.RectClient.Bottom;
this.Canvas.strokeStyle=this.BorderColor;
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(top));
this.Canvas.lineTo(right,ToFixedPoint(top));
var rowTop=top+this.RowHeight;
var rotBottom=rowTop;
//横线
for(var i=0;i<this.RowCount;++i)
{
var drawTop=ToFixedPoint(rowTop);
this.Canvas.moveTo(left,drawTop);
this.Canvas.lineTo(right,drawTop);
rotBottom=rowTop;
rowTop+=this.RowHeight;
}
//竖线
var columnLeft=left;
for(var i=this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
var drawLeft=ToFixedPoint(columnLeft+item.Width);
this.Canvas.moveTo(drawLeft,top);
this.Canvas.lineTo(drawLeft,rotBottom);
columnLeft+=item.Width;
}
this.Canvas.stroke();
}
this.GetSelectedSymbol=function()
{
if (this.SelectedRow<0 || this.SelectedRow>=this.Data.Data.length) return null;
return { Symbol: this.Data.Data[this.SelectedRow], RowID: this.SelectedRow };
}
this.DrawBody=function()
{
if (!this.Data) return;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.Canvas.font=this.ItemFont;
var top=this.RectClient.Top;
var left=this.RectClient.Left;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
var textTop=top;
this.Canvas.font=this.ItemFont;
for(var i=this.Data.YOffset, j=0; i<this.Data.Data.length && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var bFillRow=false;
if (i==this.SelectedRow) bFillRow=true; //选中行
if (bFillRow)
{
this.Canvas.fillStyle=this.SelectedColor;
this.Canvas.fillRect(left+1,textTop,rowWidth,this.RowHeight);
}
this.DrawRow(symbol, textTop, i);
this.ShowSymbol.push( { Index:i, Symbol:symbol } );
textTop+=this.RowHeight;
}
}
this.DrawRow=function(symbol, top, dataIndex, rowType) //rowType 0=表格行 1=顶部固定行 2=拖拽行
{
var left=this.RectClient.Left;
var chartRight=this.RectClient.Right;
var data= { Symbol:symbol , Stock:null, Block:null };
if (this.GetStockDataCallback) data.Stock=this.GetStockDataCallback(symbol);
for(var i=this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
this.DrawItem(dataIndex, data, item, left, top, rowType);
left+=item.Width;
if (left>=chartRight) break;
}
}
this.DrawItem=function(index, data, column, left, top, rowType)
{
var itemWidth=column.Width;
var x=left+this.ItemMergin.Left;
var textWidth=column.Width-this.ItemMergin.Left-this.ItemMergin.Right;
var stock=data.Stock;
var drawInfo={ Text:null, TextColor:this.TextColor , TextAlign:column.TextAlign };
if (column.Type==KEYBOARD_COLUMN_ID.SHORT_SYMBOL_ID)
{
if (stock && stock.ShortSymbol) drawInfo.Text=stock.ShortSymbol;
else drawInfo.Text=data.Symbol;
if (stock.Color) drawInfo.TextColor=stock.Color;
}
else if (column.Type==KEYBOARD_COLUMN_ID.NAME_ID)
{
if (stock && stock.Name)
{
drawInfo.Text=this.TextEllipsis(stock.Name, textWidth, column.MaxText);
if (stock.Color) drawInfo.TextColor=stock.Color;
}
}
else if (column.Type==KEYBOARD_COLUMN_ID.TYPE_NAME_ID)
{
if (stock && stock.TypeName)
{
drawInfo.Text=this.TextEllipsis(stock.TypeName, textWidth, column.MaxText);
if (stock.Color) drawInfo.TextColor=stock.Color;
}
}
this.DrawItemText(drawInfo.Text, drawInfo.TextColor, drawInfo.TextAlign, x, top, textWidth);
}
this.DrawItemText=function(text, textColor, textAlign, left, top, width)
{
if (!text) return;
var x=left;
if (textAlign=='center')
{
x=left+width/2;
this.Canvas.textAlign="center";
}
else if (textAlign=='right')
{
x=left+width-2;
if (left+width-2>this.RectClient.Right) x=this.RectClient.Right-2;
this.Canvas.textAlign="right";
}
else
{
x+=2;
this.Canvas.textAlign="left";
}
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=textColor;
this.Canvas.fillText(text,x,top+this.ItemMergin.Top+this.RowHeight/2);
}
//字体由外面设置
this.TextEllipsis=function(text, maxWidth, maxText)
{
if (!text) return null;
if (text.length<maxText.length) return text;
var start=maxText.length-3;
if (start<0) return null;
var newText=text.slice(0,start);
for(var i=start;i<text.length;++i)
{
var value=newText + text[i] + "...";
var width=this.Canvas.measureText(value).width;
if (width>maxWidth)
{
newText+="...";
break;
}
newText+=text[i];
}
return newText;
}
this.GetFontHeight=function(font,word)
{
return GetFontHeight(this.Canvas, font, word);
}
this.OnMouseDown=function(x,y,e) //Type: 2=行
{
if (!this.Data) return null;
var pixelTatio = GetDevicePixelRatio();
var insidePoint={X:x/pixelTatio, Y:y/pixelTatio};
if (this.UIElement)
var uiElement={Left:this.UIElement.getBoundingClientRect().left, Top:this.UIElement.getBoundingClientRect().top};
else
var uiElement={Left:null, Top:null};
if (this.VScrollbar)
{
var item=this.VScrollbar.OnMouseDown(x,y,e);
if (item) return { Type:5, VScrollbar:item }; //右侧滚动条
}
var row=this.PtInBody(x,y);
if (row)
{
var bRedraw=true;
if (this.SelectedModel==0)
{
if (this.SelectedRow==row.Index) bRedraw=false;
this.SelectedRow=row.Index;
this.SelectedFixedRow=-1;
}
else
{
if (this.SelectedRow==row.DataIndex) bRedraw=false;
this.SelectedRow=row.DataIndex;
this.SelectedFixedRow=-1;
}
var eventID=JSCHART_EVENT_ID.ON_CLICK_REPORT_ROW;
if (e.button==2) eventID=JSCHART_EVENT_ID.ON_RCLICK_REPORT_ROW;
this.SendClickEvent(eventID, { Data:row, X:x, Y:y, e:e, Inside:insidePoint, UIElement:uiElement });
return { Type:2, Redraw:bRedraw, Row:row }; //行
}
return null;
}
this.OnDrawgRow=function(x, y, e) //Type: 5=顶部 6=空白行 2=行 7=底部
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var topOffset=this.RowHeight/2;
var top=this.RectClient.Top+this.HeaderHeight;
var right=this.ChartBorder.GetChartWidth();
var textTop=top;
if (y<textTop+topOffset) return { Type:5 };
for(var i=this.Data.YOffset, j=0; i<this.Data.Data.length && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var rtRow={ Left:0, Top:textTop, Right:right, Bottom: textTop+this.RowHeight };
rtRow.Top+=topOffset;
rtRow.Bottom+=topOffset;
if (x>=rtRow.Left && x<=rtRow.Right && y>=rtRow.Top && y<=rtRow.Bottom)
{
var data={ DataIndex:i, Index:j , Symbol:symbol, Pos:0 };
if (j==0) data.Pos=1;
else if (j==this.RowCount-1) data.Pos=2;
return { Type: 2, Data:data };
}
textTop+=this.RowHeight;
}
if (j<this.RowCount) return { Type:6 };
return { Type:7 };
}
this.OnDblClick=function(x,y,e)
{
if (!this.Data) return false;
var row=this.PtInBody(x,y);
if (row) return true;
return false;
}
this.PtInBody=function(x,y)
{
if (!this.Data) return null;
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
var top=this.RectClient.Top;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var rowWidth=this.RectClient.Right-this.RectClient.Left;
var textTop=top;
for(var i=this.Data.YOffset, j=0; i<this.Data.Data.length && j<this.RowCount ;++i, ++j)
{
var symbol=this.Data.Data[i];
var rtRow={ Left:left, Top:textTop, Right:right, Bottom: textTop+this.RowHeight };
if (x>=rtRow.Left && x<=rtRow.Right && y>=rtRow.Top && y<=rtRow.Bottom)
{
var data={ Rect:rtRow, DataIndex:i, Index:j , Symbol:symbol };
data.Item=this.PtInItem(x,y, rtRow.Top, rtRow.Bottom);
return data;
}
textTop+=this.RowHeight;
}
return null;
}
this.PtInItem=function(x,y, top, bottom)
{
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var textLeft=left;
//固定列
for(var i=0;i<this.FixedColumn && i<this.Column.length;++i)
{
var item=this.Column[i];
var header={Left:textLeft, Right:textLeft+item.Width, Top:top, Bottom:bottom };
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i };
}
textLeft+=item.Width;
}
for(var i=this.FixedColumn+this.Data.XOffset;i<this.Column.length;++i)
{
var item=this.Column[i];
if (textLeft>=right) break;
var header={Left:textLeft, Right:textLeft+item.Width, Top:top, Bottom:bottom };
if (x>=header.Left && x<=header.Right && y>=header.Top && y<=header.Bottom)
{
return { Rect:header, Column:item, Index:i };
}
textLeft+=item.Width;
}
return null;
}
this.IsPtInBody=function(x,y)
{
var top=this.RectClient.Top;
var left=this.RectClient.Left;
var right=this.RectClient.Right;
var bottom=this.RectClient.Bottom;
if (x>=left && x<=right && y>=top && y<=bottom) return true;
return false;
}
this.SendClickEvent=function(id, data)
{
var event=this.GetEventCallback(id);
if (event && event.Callback)
{
event.Callback(event,data,this);
}
}
this.GetYScrollRange=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return 0;
var maxOffset=this.Data.Data.length-this.RowCount;
return maxOffset;
}
//大于1屏数据 显示滚动条
this.IsShowVScrollbar=function()
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
return this.Data.Data.length>this.RowCount;
}
}
//纵向滚动条
function ChartKeyboardVScrollbar()
{
this.newMethod=ChartVScrollbar; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartKeyboardVScrollbar';
this.Enable=true;
this.ScrollBarHeight=g_JSChartResource.Keyboard.VScrollbar.ScrollBarHeight;
this.ButtonColor=g_JSChartResource.Keyboard.VScrollbar.ButtonColor;
this.BarColor=g_JSChartResource.Keyboard.VScrollbar.BarColor;
this.BorderColor=g_JSChartResource.Keyboard.VScrollbar.BorderColor;
this.BGColor=g_JSChartResource.Keyboard.VScrollbar.BGColor;
this.Mergin={ Left:2, Right:2, Top:2, Bottom:2 };
this.BarWithConfig={ Size:g_JSChartResource.Keyboard.VScrollbar.BarWidth.Size };
this.ReloadResource=function(resource)
{
this.ScrollBarHeight=g_JSChartResource.Keyboard.VScrollbar.ScrollBarHeight;
this.ButtonColor=g_JSChartResource.Keyboard.VScrollbar.ButtonColor;
this.BarColor=g_JSChartResource.Keyboard.VScrollbar.BarColor;
this.BorderColor=g_JSChartResource.Keyboard.VScrollbar.BorderColor;
this.BGColor=g_JSChartResource.Keyboard.VScrollbar.BGColor;
this.BarWithConfig={ Size:g_JSChartResource.Keyboard.VScrollbar.BarWidth.Size };
}
this.IsShowCallback=function()
{
return true;
}
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
封装滚动条控件 (H5版本)
*/
function JSScrollBarChart(divElement)
{
this.DivElement=divElement;
this.JSChartContainer; //表格控件
this.ResizeListener;
//h5 canvas
this.CanvasElement=document.createElement("canvas");
this.CanvasElement.className='jsscrollbar-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("[JSScrollBarChart::JSScrollBarChart] divElement hasChildNodes", divElement.childNodes);
}
divElement.appendChild(this.CanvasElement);
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;
JSConsole.Chart.Log(`[JSScrollBarChart::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.CreateJSScrollBarChartContainer(option);
if (!chart) return false;
this.JSChartContainer=chart;
this.DivElement.JSChart=this; //div中保存一份
if (option.EnableResize==true) this.CreateResizeListener();
if (option.OnCreatedCallback) option.OnCreatedCallback(chart);
chart.Draw();
}
this.CreateJSScrollBarChartContainer=function(option)
{
var chart=new JSScrollBarChartContainer(this.CanvasElement);
chart.Create(option);
if (IFrameSplitOperator.IsNumber(option.DelayDragFrequency)) chart.DelayDragFrequency=option.DelayDragFrequency;
this.SetChartBorder(chart, option);
//注册事件
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;
if (IFrameSplitOperator.IsBool(item.AutoLeft)) chart.AutoMargin.Left=item.AutoLeft;
if (IFrameSplitOperator.IsBool(item.AutoRight)) chart.AutoMargin.Right=item.AutoRight;
}
this.CreateResizeListener=function()
{
this.ResizeListener = new ResizeObserver((entries)=>{ this.OnDivResize(entries); });
this.ResizeListener.observe(this.DivElement);
}
this.OnDivResize=function(entries)
{
JSConsole.Chart.Log("[JSScrollBarChart::OnDivResize] entries=", entries);
this.OnSize( );
}
/////////////////////////////////////////////////////////////////////////////
//对外接口
//事件回调
this.AddEventCallback=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:AddEventCallback] obj=', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:ReloadResource] ');
this.JSChartContainer.ReloadResource(option);
}
}
this.ChartDestory=function()
{
if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestory) == 'function')
{
this.JSChartContainer.ChartDestory();
}
}
this.Draw=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:Draw] ');
this.JSChartContainer.Draw();
}
}
this.RecvData=function(data, option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.RecvData)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:RecvData] ');
this.JSChartContainer.RecvData(data,option);
}
}
this.UpdateSlider=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.UpdateSlider)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:UpdateSlider] ');
this.JSChartContainer.UpdateSlider(obj);
}
}
this.Reset=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.Reset)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:Reset] ');
this.JSChartContainer.Reset(option);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSScrollBarChart:ReloadResource] ');
this.JSChartContainer.ReloadResource(option);
}
}
}
JSScrollBarChart.Init=function(divElement)
{
var jsChartControl=new JSScrollBarChart(divElement);
jsChartControl.OnSize();
return jsChartControl;
}
//自定义风格
JSScrollBarChart.SetStyle=function(option)
{
if (option) g_JSChartResource.SetStyle(option);
}
//获取颜色配置 (设置配必须啊在JSChart.Init()之前)
JSScrollBarChart.GetResource=function()
{
return g_JSChartResource;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
function JSScrollBarChartContainer(uielement)
{
this.ClassName='JSScrollBarChartContainer';
this.Frame; //框架画法
this.ChartPaint=[]; //图形画法
this.ChartSplashPaint=null; //等待提示
this.LoadDataSplashTitle="无数据"; //下载数据提示信息
this.Canvas=uielement.getContext("2d"); //画布
this.ShowCanvas=null;
this.XOffsetData={ Start:-1, End:-1, Count:0 }; //Count:一共的数据个数
this.SourceData// new ChartData(); //K线数据
this.SliderChart; //滑块
this.DragMove; //={ Click:{ 点击的点}, Move:{最后移动的点}, PreMove:{上一个点的位置} };
this.DragSlider;
this.DragTimer; //拖拽延迟定时器
this.DelayDragFrequency=150;
this.AutoMargin={ Left:false, Right:false }; //左右2边间距是否跟K线一致
//事件回调
this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,}
this.UIElement=uielement;
this.LastPoint=new Point(); //鼠标位置
//this.XStepPixel=10*GetDevicePixelRatio();
this.IsDestroy=false; //是否已经销毁了
this.HQChart=null;
this.ChartDestory=function() //销毁
{
this.IsDestroy=true;
}
this.GetHQChart=function()
{
return this.HQChart;
}
//设置事件回调
//{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.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 JSScrollBarFrame();
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 ScrollBarBGChart();
chart.ChartFrame=this.Frame;
chart.ChartBorder=this.Frame.ChartBorder;
chart.Canvas=this.Canvas;
chart.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.ChartPaint.push(chart);
//创建滑块
var chart=new SliderChart();
chart.ChartFrame=this.Frame;
chart.ChartBorder=this.Frame.ChartBorder;
chart.Canvas=this.Canvas;
chart.OffsetData=this.XOffsetData;
chart.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
this.SliderChart=chart;
this.ChartPaint.push(chart);
//this.UIElement.ondblclick=(e)=>{ this.UIOnDblClick(e); }
this.UIElement.onmousedown=(e)=> { this.UIOnMouseDown(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.CreateChartPaint=function(name)
{
var chart=g_ChartPaintFactory.Create(name);
if (!chart) return null;
chart.ChartFrame=this.Frame;
chart.ChartBorder=this.Frame.ChartBorder;
chart.Canvas=this.Canvas;
chart.Data=this.Frame.Data;
chart.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
chart.GetHQChartCallback=()=>{ return this.GetHQChart(); }
return chart;
}
this.GetChartPaintByClassName=function(name)
{
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (item.ClassName==name)
{
return { Chart:item, Index:i };
}
}
return null;
}
this.Draw=function()
{
if (this.UIElement.width<=0 || this.UIElement.height<=0) return;
this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash)
{
this.Frame.Draw( { 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();
}
}
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.UpdateFrameMaxMin=function()
{
var max=null, min=null;
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
if (!item.GetMaxMin) continue;
var range=item.GetMaxMin();
if (range==null || range.Max==null || range.Min==null) continue;
if (max==null || max<range.Max) max=range.Max;
if (min==null || min>range.Min) min=range.Min;
}
if (IFrameSplitOperator.IsNumber(max) && IFrameSplitOperator.IsNumber(min))
{
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
}
//未启动
this.UIOnDblClick=function(e)
{
}
this.CancelDragTimer=function()
{
if (this.DragTimer)
{
clearTimeout(this.DragTimer);
this.DragTimer=null;
}
}
this.UIOnMouseDown=function(e)
{
this.CancelDragTimer();
this.DragSlider=null;
this.DragMove={ Click:{ X:e.clientX, Y:e.clientY }, Move:{X:e.clientX, Y:e.clientY}, PreMove:{X:e.clientX, Y:e.clientY } };
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.SliderChart)
{
var clickData=this.SliderChart.PtInChart(x,y);
if (!clickData)
{
if (!this.Frame.PtInClient(x,y)) return;
//滚动块直接移动到鼠标点击的位置
var index=this.Frame.GetXData(x);
index=Math.round(index);
var pageRange=this.GetPageRange();
var showCount=pageRange.ShowCount;
var start=index-parseInt(showCount/2);
if (start<0) start=0;
var end=start+showCount;
if (end>=this.Frame.XPointCount)
{
end=this.Frame.XPointCount-1;
start=end-showCount;
}
var drag={ UpdateData:{ StartIndex:start, EndIndex:end, Type:3 } };
this.DragUpdate(drag);
return;
}
this.DragSlider={ Click:{ X:e.clientX, Y:e.clientY }, LastMove:{X:e.clientX, Y:e.clientY}, Data:clickData };
this.DragSlider.DrawCount=0; //重绘次数
}
document.onmousemove=(e)=>{ this.DocOnMouseMove(e); }
document.onmouseup=(e)=> { this.DocOnMouseUp(e); }
}
//去掉右键菜单
this.UIOnContextMenu=function(e)
{
e.preventDefault();
}
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;
if (this.DragSlider) return;
var mouseStatus= mouseStatus={ Cursor:"default" };; //鼠标状态
var item=this.SliderChart.PtInChart(x,y);
if (item)
{
switch(item.Data.Type)
{
case 0:
mouseStatus={ Cursor:"grab", Name:"SliderChart"};
break;
case 1:
case 2:
mouseStatus={ Cursor:"col-resize", Name:"SliderChart"};
break;
}
}
if (mouseStatus)
this.UIElement.style.cursor=mouseStatus.Cursor;
}
this.UIOnMounseOut=function(e)
{
}
this.UIOnMouseleave=function(e)
{
}
this.DocOnMouseMove=function(e)
{
this.DragMove.PreMove.X=this.DragMove.Move.X;
this.DragMove.PreMove.Y=this.DragMove.Move.Y;
this.DragMove.Move.X=e.clientX;
this.DragMove.Move.Y=e.clientX;
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
var pixelTatio = GetDevicePixelRatio();
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
JSConsole.Chart.Log(`[JSScrollBarChartContainer::DocOnMouseMove] x=${x}, y=${y}`);
if (this.DragSlider)
{
var drag=this.DragSlider;
var moveSetp=(e.clientX-drag.LastMove.X)*pixelTatio;
if (Math.abs(moveSetp)<1) return;
var pageRange=this.GetPageRange();
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
this.SliderChart.DragMode=true;
var type=drag.Data.Data.Type;
var xStart=this.SliderChart.XStart+moveSetp;
var xEnd=this.SliderChart.XEnd+moveSetp;
if (type==0) //整体移动
{
if (xStart<left) //第1页
{
xStart=pageRange.First.XStart;
xEnd=pageRange.First.XEnd;
}
else if (xEnd>=right)
{
xStart=pageRange.Last.XStart;
xEnd=pageRange.Last.XEnd;
}
this.SliderChart.XStart=xStart;
this.SliderChart.XEnd=xEnd;
}
else if (type==1) //左移动
{
if (xStart<=left)
{
xStart=pageRange.First.XStart;
}
else if (xStart>=right)
{
xStart=pageRange.Last.XEnd;
}
this.SliderChart.XStart=xStart;
}
else if (type==2)
{
if (xEnd>=right)
{
xEnd=pageRange.Last.XEnd;
}
else if (xEnd<=left)
{
xEnd=pageRange.First.XStart;
}
this.SliderChart.XEnd=xEnd;
}
drag.UpdateData={ XStart:xStart, XEnd:xEnd, Type:type };
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
if (drag.DrawCount==0)
{
this.DragUpdate(drag);
}
else
{
this.DragTimer=setTimeout(()=>
{
this.DragUpdate(this.DragSlider);
}, this.DelayDragFrequency);
}
}
}
this.DocOnMouseUp=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
this.CancelDragTimer();
var dragSlider=this.DragSlider;
this.DragMove=null;
this.DragSlider=null;
this.SliderChart.DragMode=false;
this.DragUpdate(dragSlider);
}
this.DragUpdate=function(dragData)
{
if (!dragData || !dragData.UpdateData) return;
this.UpdateXDataOffset(dragData.UpdateData);
this.Draw();
++dragData.DrawCount;
}
this.Reset=function(option)
{
this.SourceData=null;
this.XOffsetData.Start=-1;
this.XOffsetData.End=-1;
this.XOffsetData.Count=0;
this.Frame.Data=null;
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
item.Data=null;
}
if (this.ChartSplashPaint)
this.ChartSplashPaint.IsEnableSplash=true;
if (option.Draw) this.Draw();
}
//外部更新滑块 obj={ Start: , End: }
this.UpdateSlider=function(obj)
{
if (this.SliderChart.DragMode) return;
var bSizeChange=false;
if ((this.AutoMargin.Left || this.AutoMargin.Right) && obj.Border)
{
if (this.AutoMargin.Left)
{
if (this.Frame.ChartBorder.Left!=obj.Border.Left) bSizeChange=true;
}
if (this.AutoMargin.Right)
{
if (this.Frame.ChartBorder.Right!=obj.Border.Right) bSizeChange=true;
}
}
var data=obj.Data;
if (this.XOffsetData.Start==obj.Start && this.XOffsetData.End==obj.End && this.SourceData==data && !bSizeChange) return;
this.SourceData=data;
var count=data.Data.length;
if (IFrameSplitOperator.IsNumber(obj.RightSpaceCount)) count+=obj.RightSpaceCount;
this.Frame.XPointCount=count;
this.Frame.Data=data;
this.XOffsetData.Count=count;
this.XOffsetData.Start=obj.Start;
this.XOffsetData.End=obj.End;
for(var i=0;i<this.ChartPaint.length;++i)
{
var item=this.ChartPaint[i];
item.Data=data;
}
if (this.AutoMargin.Left && obj.Border)
{
if (IFrameSplitOperator.IsNumber(obj.Border.Left))
this.Frame.ChartBorder.Left=obj.Border.Left;
}
if (this.AutoMargin.Right && obj.Border)
{
if (IFrameSplitOperator.IsNumber(obj.Border.Right))
this.Frame.ChartBorder.Right=obj.Border.Right;
}
this.UpdateFrameMaxMin();
if (this.ChartSplashPaint)
this.ChartSplashPaint.IsEnableSplash=false;
if (obj.Draw) this.Draw();
}
//移动滑块
this.UpdateXDataOffset=function(obj)
{
if (!obj) return;
var type=obj.Type;
if (obj.Type==0)
{
var start=this.Frame.GetXData(obj.XStart);
start=parseInt(start+0.5); //四舍五入
var moveSetp=start-this.XOffsetData.Start;
this.XOffsetData.Start=start;
this.XOffsetData.End+=moveSetp;
}
else if (obj.Type==1)
{
var start=this.Frame.GetXData(obj.XStart);
start=parseInt(start);
this.XOffsetData.Start=start;
}
else if (obj.Type==2)
{
var end=this.Frame.GetXData(obj.XEnd);
end=parseInt(end);
this.XOffsetData.End=end;
}
else if (obj.Type==3)
{
this.XOffsetData.End=obj.EndIndex;
this.XOffsetData.Start=obj.StartIndex;
type=0;
}
var endItem=this.SourceData.Data[this.XOffsetData.End];
var startItem=this.SourceData.Data[this.XOffsetData.Start];
var sendData={ Type:type, Count:this.XOffsetData.Count };
if (this.XOffsetData.End>this.XOffsetData.Start)
{
sendData.Start={ Index:this.XOffsetData.Start, Item:startItem};
sendData.End={ Index:this.XOffsetData.End, Item:endItem};
}
else
{
sendData.Start={ Index:this.XOffsetData.End, Item:endItem };
sendData.End={ Index:this.XOffsetData.Start, Item:startItem };
}
if (this.HQChart && this.HQChart.JSChartContainer)
{
var internalChart=this.HQChart.JSChartContainer;
if (internalChart.ChartOperator)
{
var obj={ ID:JSCHART_OPERATOR_ID.OP_SCROOLBAR_SLIDER_CHANGED, Start:sendData.Start, End:sendData.End, Type:sendData.Type };
internalChart.ChartOperator(obj);
}
}
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SCROLLBAR_SLIDER_CHANGED);
if (event)
{
event.Callback(event,sendData,this);
}
}
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)
{
this.SetSizeChange(true);
this.Draw();
}
}
this.GetPageRange=function()
{
var result={};
var showCount=Math.abs(this.XOffsetData.Start-this.XOffsetData.End);
result.ShowCount=showCount;
//第1页
var xStart=this.Frame.GetXFromIndex(0);
var xEnd=this.Frame.GetXFromIndex(showCount);
result.First={ XStart:xStart, XEnd:xEnd };
//最后一页
var end=this.Frame.XPointCount-1;
var xEnd=this.Frame.GetXFromIndex(end);
var xStart=this.Frame.GetXFromIndex(end-showCount);
result.Last={ XStart:xStart, XEnd:xEnd };
return result;
}
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.Draw==true) this.Draw(); //是否立即重绘
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// 框子
//
//
/////////////////////////////////////////////////////////////////////////////////////////
function JSScrollBarFrame()
{
this.ChartBorder;
this.Canvas; //画布
this.BorderLine=null; //1=上 2=下 4=左 8=右
this.Data;
this.Count=0;
this.ClassName='JSScrollBarFrame'; //类名
this.HorizontalMax=10; //Y轴最大值
this.HorizontalMin=5; //Y轴最小值
this.XPointCount=0;
this.XSplitTextFont=g_JSChartResource.ScrollBar.XSplitTextFont;
this.XSplitTextColor=g_JSChartResource.ScrollBar.XSplitTextColor;
this.XSplitLineColor=g_JSChartResource.ScrollBar.XSplitLineColor;
this.BorderColor=g_JSChartResource.ScrollBar.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
this.ReloadResource=function(resource)
{
this.BorderColor=g_JSChartResource.ScrollBar.BorderColor; //边框线
this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor;
this.LogoTextFont=g_JSChartResource.FrameLogo.Font;
}
this.Draw=function()
{
this.DrawBorder();
this.DrawLogo();
this.DrawVertical();
}
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 = 'left';
this.Canvas.textBaseline = 'top';
var x=this.ChartBorder.GetLeft()+2;
var y=this.ChartBorder.GetTop()+2;
this.Canvas.fillText(text,x,y);
}
this.DrawBorder=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;
//JSConsole.Chart.Log(`[JSScrollBarFrame.DrawBorder] left=${left} `);
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.GetXFromIndex=function(index)
{
var count=this.XPointCount;
if (count==1)
{
if (index==0) return this.ChartBorder.GetLeft();
else return this.ChartBorder.GetRight();
}
else if (count<=0)
{
return this.ChartBorder.GetLeft();
}
else if (index>=count)
{
return this.ChartBorder.GetRight();
}
else
{
var offset=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*index/count;
return offset;
}
}
this.GetYFromData=function(value)
{
if(value<=this.HorizontalMin) return this.ChartBorder.GetBottomEx();
if(value>=this.HorizontalMax) return this.ChartBorder.GetTopEx();
var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
return this.ChartBorder.GetBottomEx()-height;
}
//X坐标转x轴数值
this.GetXData=function(x)
{
if (x<=this.ChartBorder.GetLeft()) return 0;
if (x>=this.ChartBorder.GetRight()) return this.XPointCount;
return (x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth());
}
this.GetPreSetpWidth=function()
{
return this.XPointCount*1.0/this.ChartBorder.GetWidth();
}
this.DrawVertical=function()
{
if (this.ChartBorder.Bottom<=5) return;
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return
var item=this.Data.Data[0];
var preYear=parseInt(item.Date/10000);
var preDay=item.Date%10000;
this.Canvas.font=this.XSplitTextFont;
this.Canvas.fillStyle=this.XSplitTextColor;
this.Canvas.textBaseline="top";
var yText=this.ChartBorder.GetBottom()+2;
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var preXText=0;
if (ChartData.IsMilliSecondPeriod(this.Data.Period))
{
var preHour=null;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
var day=item.Date%10000;
var time=parseInt(item.Time/1000);
var hour=parseInt(time/10000);
if (i==0)
{
var text=IFrameSplitOperator.FormatDateString(item.Date, "MM-DD");
var x=this.ChartBorder.GetLeft();
this.Canvas.textAlign="left";
this.Canvas.fillText(text,x,yText);
var textWidth=this.Canvas.measureText(text).width+2;
preXText=x+textWidth;
preDay=day;
preHour=hour;
continue;
}
if (hour!=preHour)
{
var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS.fff");
var x=this.GetXFromIndex(i);
var textWidth=this.Canvas.measureText(text).width+2;
if (x-textWidth/2>preXText)
{
this.Canvas.textAlign="center";
this.Canvas.fillText(text,x,yText);
preXText=x+textWidth/2;
}
x=ToFixedPoint(x);
this.Canvas.strokeStyle=this.XSplitLineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,top);
this.Canvas.lineTo(x,bottom);
this.Canvas.stroke();
preHour=hour;
}
}
}
else if (ChartData.IsMinutePeriod(this.Data.Period,true))
{
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
var day=item.Date%10000;
if (i==0)
{
var text=IFrameSplitOperator.FormatDateString(item.Date, "MM-DD");
var x=this.ChartBorder.GetLeft();
this.Canvas.textAlign="left";
this.Canvas.fillText(text,x,yText);
var textWidth=this.Canvas.measureText(text).width+2;
preXText=x+textWidth;
preDay=day;
continue;
}
if (day!=preDay)
{
var text=IFrameSplitOperator.FormatDateString(item.Date, "MM-DD");
var x=this.GetXFromIndex(i);
var textWidth=this.Canvas.measureText(text).width+2;
if (x-textWidth/2>preXText)
{
this.Canvas.textAlign="center";
this.Canvas.fillText(text,x,yText);
preXText=x+textWidth/2;
}
x=ToFixedPoint(x);
this.Canvas.strokeStyle=this.XSplitLineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,top);
this.Canvas.lineTo(x,bottom);
this.Canvas.stroke();
preDay=day;
}
}
}
else
{
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
var year=parseInt(item.Date/10000);
if (i==0)
{
var text=`${year}`;
var x=this.ChartBorder.GetLeft();
var textWidth=this.Canvas.measureText(text).width+2;
this.Canvas.textAlign="left";
this.Canvas.fillText(text,x,yText);
preXText=x+textWidth;
preYear=year;
continue;
}
if (year!=preYear)
{
var text=`${year}`;
var x=this.GetXFromIndex(i);
var textWidth=this.Canvas.measureText(text).width+2;
if (x-textWidth/2>preXText)
{
this.Canvas.textAlign="center";
this.Canvas.fillText(text,x,yText);
preXText=x+textWidth/2;
}
x=ToFixedPoint(x);
this.Canvas.strokeStyle=this.XSplitLineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(x,top);
this.Canvas.lineTo(x,bottom);
this.Canvas.stroke();
preYear=year;
}
}
}
}
this.PtInClient=function(x,y)
{
var left=ToFixedPoint(this.ChartBorder.GetLeft());
var top=ToFixedPoint(this.ChartBorder.GetTop());
var right=ToFixedPoint(this.ChartBorder.GetRight());
var bottom=ToFixedPoint(this.ChartBorder.GetBottom());
if (x>=left && x<=right && y>=top && y<=bottom) return true;
return false;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// 滑块
//
/////////////////////////////////////////////////////////////////////////////////////////////////
function SliderChart()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='SliderChart'; //类名
this.OffsetData;
this.Color=g_JSChartResource.ScrollBar.Slider.BarAreaColor;
this.BarColor=g_JSChartResource.ScrollBar.Slider.BarColor;
this.BarWidth=g_JSChartResource.ScrollBar.Slider.BarWidth;
this.BarPadding=g_JSChartResource.ScrollBar.Slider.BarPadding; //上下留白
this.MinCenterWidth=g_JSChartResource.ScrollBar.Slider.MinCenterWidth;
this.DateFont=g_JSChartResource.ScrollBar.Slider.DateFont;
this.DateColor=g_JSChartResource.ScrollBar.Slider.DateColor;
this.AryRect=[]; //[{ Rect:{Left, Top, Right:, Bottom:, Width, Height:}, Type:0中间 1=左 2=右 }]
this.XStart;
this.XEnd;
this.SizeChange=true;
this.DragMode=false;
this.ReloadResource=function(resource)
{
this.Color=g_JSChartResource.ScrollBar.Slider.BarAreaColor;
this.BarColor=g_JSChartResource.ScrollBar.Slider.BarColor;
this.DateFont=g_JSChartResource.ScrollBar.Slider.DateFont;
this.DateColor=g_JSChartResource.ScrollBar.Slider.DateColor;
}
this.Draw=function()
{
this.AryRect=[];
if (!this.OffsetData || !IFrameSplitOperator.IsPlusNumber(this.OffsetData.Count)) return;
if (!IFrameSplitOperator.IsNumber(this.OffsetData.Start) || !IFrameSplitOperator.IsNumber(this.OffsetData.End)) return;
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var startData, endData;
if (this.DragMode)
{
var xStart=this.XStart;
var xEnd=this.XEnd;
var startIndex=this.ChartFrame.GetXData(xStart);
var endIndx=this.ChartFrame.GetXData(xEnd);
startIndex=parseInt(startIndex);
endIndx=parseInt(endIndx);
startData={ Data:this.Data.Data[this.OffsetData.Start], X:xStart, Type:startIndex<endIndx?0:1 };
endData={Data:this.Data.Data[this.OffsetData.End], X:xEnd, Type:endIndx>startIndex?1:0 };
}
else
{
var start=this.OffsetData.Start, end=this.OffsetData.End;
var xStart=this.ChartFrame.GetXFromIndex(start);
var xEnd=this.ChartFrame.GetXFromIndex(end);
this.XStart=xStart;
this.XEnd=xEnd;
startData={ Data:this.Data.Data[this.OffsetData.Start], X:xStart, Type:xStart<xEnd?0:1 };
endData={Data:this.Data.Data[this.OffsetData.End], X:xEnd, Type:xEnd>xStart?1:0 };
}
this.Canvas.fillStyle=this.Color;
var rtBar={ Left:Math.min(xStart,xEnd), Top:top, Width:Math.abs(xEnd-xStart), Height: bottom-top};
rtBar.Right=rtBar.Left+rtBar.Width;
rtBar.Bottom=rtBar.Top+rtBar.Height;
if (rtBar.Width<this.MinCenterWidth)
{
rtBar.Left-=(this.MinCenterWidth-rtBar.Width)/2;
rtBar.Width=this.MinCenterWidth;
rtBar.Right=rtBar.Left+rtBar.Width;
}
this.Canvas.fillRect(rtBar.Left, rtBar.Top, rtBar.Width, rtBar.Height);
this.AryRect.push({ Rect:rtBar, Type:0});
//左右拖拽块
var pixelRatio=GetDevicePixelRatio();
var barWidth=this.BarWidth*pixelRatio;
var barHeight=bottom-top-(this.BarPadding*2)*pixelRatio;
var xBar=xStart-this.BarWidth/2;
var yBar=top+this.BarPadding*pixelRatio;
this.Canvas.fillStyle=this.BarColor;
var rtBar={Left:xBar, Top:yBar, Width:barWidth, Height:barHeight};
rtBar.Right=rtBar.Left+rtBar.Width;
rtBar.Bottom=rtBar.Top+rtBar.Height;
this.Canvas.fillRect(rtBar.Left, rtBar.Top, rtBar.Width, rtBar.Height);
this.AryRect.push({ Rect:rtBar, Type:1});
var xBar=xEnd-this.BarWidth/2;
var rtBar={Left:xBar, Top:yBar, Width:barWidth, Height:barHeight};
rtBar.Right=rtBar.Left+rtBar.Width;
rtBar.Bottom=rtBar.Top+rtBar.Height;
this.Canvas.fillRect(rtBar.Left, rtBar.Top, rtBar.Width, rtBar.Height);
this.AryRect.push({ Rect:rtBar, Type:2});
//最右边可能是空白区 要处理下
if (endData.Type==1)
{
var dataIndex=this.OffsetData.End;
if (dataIndex>=this.Data.Data.length) endData.Data=this.Data.Data[this.Data.Data.length-1];
}
this.DrawDateTime(startData);
this.DrawDateTime(endData);
}
this.DrawDateTime=function(data)
{
if (!data || !data.Data) return;
var text=IFrameSplitOperator.FormatDateString(data.Data.Date);
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var timeText=null;
if (ChartData.IsMilliSecondPeriod(this.Data.Period))
{
var time=parseInt(data.Data.Time/1000);
text=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
}
else if (ChartData.IsSecondPeriod(this.Data.Period))
{
text=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
}
else if (ChartData.IsMinutePeriod(this.Data.Period, true))
{
timeText=IFrameSplitOperator.FormatTimeString(data.Data.Time,"HH:MM");
}
if (data.Type==0)
{
this.Canvas.textAlign="right";
var x=data.X-this.BarWidth/2;
}
else if (data.Type==1)
{
this.Canvas.textAlign="left";
var x=data.X+this.BarWidth/2;
}
this.Canvas.font=this.DateFont;
var fontHeight=this.Canvas.measureText("擎").width;
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.DateColor;
var yText=top+(bottom-top)/2;
this.Canvas.fillText(text,x,yText);
if (timeText)
{
yText+=fontHeight;
this.Canvas.fillText(timeText,x,yText);
}
}
this.PtInChart=function(x,y)
{
if (!IFrameSplitOperator.IsNonEmptyArray(this.AryRect)) return null;
for(var i=this.AryRect.length-1; i>=0; --i)
{
var item=this.AryRect[i];
var rt=item.Rect;
if (x>=rt.Left && x<=rt.Right && y>=rt.Top && y<=rt.Bottom)
{
return { Data:item };
}
}
return null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// 滚动条K线背景色
//
//
/////////////////////////////////////////////////////////////////////////////////////////////////
function ScrollBarBGChart()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.ClassName='ScrollBarBGChart'; //类名
this.SizeChange=true;
this.Data;
this.Color=g_JSChartResource.ScrollBar.BGChart.Color; //线段颜色
this.LineWidth=g_JSChartResource.ScrollBar.BGChart.LineWidth; //线段宽度
this.AreaColor=g_JSChartResource.ScrollBar.BGChart.AreaColor; //面积图颜色
this.ReloadResource=function(resource)
{
this.Color=g_JSChartResource.ScrollBar.BGChart.Color; //线段颜色
this.LineWidth=g_JSChartResource.ScrollBar.BGChart.LineWidth; //线段宽度
this.AreaColor=g_JSChartResource.ScrollBar.BGChart.AreaColor; //面积图颜色
}
this.Draw=function()
{
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return;
this.Canvas.save();
if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
var bottom=this.ChartBorder.GetBottom();
this.Canvas.strokeStyle=this.Color;
var bFirstPoint=true;
var drawCount=0,x,y;
var firstPoint={ };
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
var value=item.Close;
if (!IFrameSplitOperator.IsNumber(value)) continue;
x=this.ChartFrame.GetXFromIndex(i);
y=this.ChartFrame.GetYFromData(value);
if (bFirstPoint)
{
this.Canvas.beginPath();
this.Canvas.moveTo(x,y);
bFirstPoint=false;
firstPoint={ X:x, Y:y };
}
else
{
this.Canvas.lineTo(x,y);
}
++drawCount;
}
if (drawCount>0)
{
this.Canvas.stroke();
this.Canvas.lineTo(x,bottom);
this.Canvas.lineTo(firstPoint.X,bottom);
this.Canvas.closePath();
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.fill();
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var range={ Max:null, Min:null };
if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return range;
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
var value=item.Close;
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (range.Max==null || range.Max<value) range.Max=value;
if (range.Min==null || range.Min>value) range.Min=value;
}
return range;
}
}
/********************************************************************************
* 版本信息输出
*
*/
var HQCHART_VERSION="1.1.14083";
function PrintHQChartVersion()
{
var logo=`
***************************************************************************************************************************************************************************
*
* :%@@-
* :@@@@-
* =@@@@ :#@@@ .:+#@@@#=: :=*@@@@@@#+-. *@@@@.
* :@@@@@ .@@@@@ .#@@@@@@@@@@@- +@@@@@@@@@@@@@+ @@@@@ -%@@*
* +@@@@% #@@@@# *@@@@@@@@@@@@@@%. =@@@@@@@@@@@@@@@- @@@@@ -@@@@+
* %@@@@* @@@@@+ .%@@@@@@@@@@@@@@@@%: #@@@@@@@@@@@@@@@% @@@@# *@@@@=
* @@@@@= @@@@@- .%@@@@@@@*++*%@@@@@@% .%@@@@@@@%*+==+**= -@@@@+ #@@@@-
* @@@@@. @@@@@. #@@@@@%= =@@@@@@* %@@@@@@#: *@@@@- :::. .-+*###+: ::: .+##+: -%%@@@@@%%%%
* .@@@@@ .@@@@@. +@@@@@% .@@@@@@ *@@@@@@: %@@@@: +@@@@@%. :%@@@@@@@@@@: *@@@ :@@@@@* @@@@@@@@@@@@
* :@@@@@ :@@@@@ @@@@@% :@@@@@+ @@@@@@: %@@@@-@@@@@@@@@. @@@@@@@@@@@@@. :@@@%-@@@@@@.:@@@@@@@@@@@#
* -@@@@% -@@@@@ =@@@@@. %@@@@% %@@@@@- %@@@@@@@@@@@@@@* %@@@@@@@@@@@@+ -@@@@@@@@@@# -@@@@@@@@@@@.
* +@@@@%=========#@@@@% @@@@@# :@@@@@ .@@@@@% @@@@@@@@%@@@@@@@ -%+:. .#@@@@* +@@@@@@@%%@. .::+@@@@#::
* #@@@@@@@@@@@@@@@@@@@# .@@@@@ .@@@@@ :@@@@@. @@@@@@#. #@@@@@. -@@@@* #@@@@@@: *@@@@+
* %@@@@@@@@@@@@@@@@@@@+ :@@@@@ .@@@@@ -@@@@@ @@@@@+ @@@@@. :@@@@* @@@@@% #@@@@-
* @@@@@@@@@@@@@@@@@@@@: :@@@@% :@@@@@ +@@@@% -@@@@+ @@@@@ -@@@@+ @@@@@. @@@@@.
* .@@@@@@@@@@@@@@@@@@@@ :@@@@% -@@@@% *@@@@% #@@@@. @@@@@ .=*#%%%@@@@@= :@@@@# @@@@@.
* -@@@@@:::::::::=@@@@@ :@@@@@ @@@@@* +@@@@% @@@@@ @@@@% -#@@@@@@@@@@@@: -@@@@* @@@@@
* =@@@@% =@@@@% .@@@@@ :@@@@@. -@@@@% @@@@@ .@@@@* +@@@@@@@@@@@@@@. =@@@@+ .@@@@@
* +@@@@# +@@@@# @@@@@# %@@@@% :@@@@@ .@@@@% =@@@@= -@@@@@*-:..%@@@@ +@@@@= :@@@@#
* *@@@@* *@@@@* +@@@@@: #@@@@@+ .@@@@@@ :@@@@% *@@@@- @@@@@. @@@@% #@@@@: =@@@@+
* %@@@@= %@@@@+ @@@@@@- .%@@@@@# #@@@@@# :@@@@% #@@@@: @@@@% @@@@* %@@@@. #@@@@-
* @@@@@- @@@@@= =@@@@@@#=...-*@@@@@@@: @@@@@@%=. :+**. :@@@@* %@@@@. .@@@@* *@@@@= @@@@@ %@@@@+
* .@@@@@: .@@@@@: *@@@@@@@@@@@@@@@@@@@# =@@@@@@@@%%%@@@@@@ +@@@@- @@@@@ .@@@@@: :%@@@@@- .@@@@% %@@@@@*+-
* :@@@@@ :@@@@@ +@@@@@@@@@@@@@@@@@@@# =@@@@@@@@@@@@@@@@% %@@@@ @@@@@ @@@@@@@@@@@@@@@: -@@@@* *@@@@@@@@-
* =@@@@@ -@@@@@ :@@@@@@@@@@@@@@@@@@@# :@@@@@@@@@@@@@@@% @@@@@ %@@@% #@@@@@@@@@#@@@@. +@@@@- .@@@@@@@@#
* *@@@@# =@@@@% :#@@@@@@@#: :@@@@@= =@@@@@@@@@@@+. @@@@@ :@@@+ *@@@@@@@- %@@@ *@@@= =@@@@@@@*
* =++++- -++++= .:::. .=*+: :-=+++=:. ****= .=+. .-++=: :+++ -+=: .-=+=:.
*
*
* HQChart
* Ver: ${HQCHART_VERSION}
* License: Apache License 2.0
* Source: https://github.com/jones2000/HQChart
*
**************************************************************************************************************************************************************************
`;
console.log(logo);
}
PrintHQChartVersion();
/*
单独的网络接口
*/
function JSNetwork() { }
JSNetwork.HttpRequest=function(obj) //使用uniapp 网络接口接口 !!每家平台都喜欢自定义接口, 低层不都是一样的嘛
{
let method=obj.type.toUpperCase();
uni.request({
url: obj.url,
data: obj.data,
method:method,
success: (res)=>
{
obj.success(res.data);
},
fail: obj.error,
});
}
//把给外界调用的方法暴露出来
export default {
//类导出
JSChart:JSChart, //行情图形库
ChartData:ChartData,
MARKET_SUFFIX_NAME:MARKET_SUFFIX_NAME, //判断股票属性
IFrameSplitOperator:IFrameSplitOperator, //格式化字符串方法
FrameSplitKLinePriceY:FrameSplitKLinePriceY,
FrameSplitKLineX:FrameSplitKLineX,
JSKLineInfoMap:JSKLineInfoMap,
JSCHART_EVENT_ID:JSCHART_EVENT_ID, //可以订阅的事件类型
JSCHART_OPERATOR_ID:JSCHART_OPERATOR_ID, //图形控制类型
JSAlgorithm:JSAlgorithm, //算法类
JSComplier:JSComplier, //指标编译器
JSIndexScript:JSIndexScript, //系统指标库
GetDevicePixelRatio,GetDevicePixelRatio,
ScriptIndexConsole:ScriptIndexConsole, //指标执行 无UI
//style.js相关
STYLE_TYPE_ID:STYLE_TYPE_ID,
HQChartStyle:HQChartStyle, //预定义全局的配色 黑
JSConsole:JSConsole, //日志输出
KLineTooltipPaint:KLineTooltipPaint, //K线tooltip
MinuteTooltipPaint:MinuteTooltipPaint, //走势图tooltip
CoordinateInfo:CoordinateInfo,
//图形基类导出
IChartPainting:IChartPainting, //图形
IExtendChartPainting:IExtendChartPainting, //扩展图形
IChartTitlePainting:IChartTitlePainting, //标题类
IChartDrawPicture:IChartDrawPicture, //画图工具
DynamicTitleData:DynamicTitleData, //指标标题数据
//成交明细
JSDealChart:JSDealChart,
DEAL_COLUMN_ID:DEAL_COLUMN_ID,
//报价列表
JSReportChart:JSReportChart,
REPORT_COLUMN_ID:REPORT_COLUMN_ID,
//键盘精灵
JSKeyboardChart:JSKeyboardChart,
KEYBOARD_COLUMN_ID:KEYBOARD_COLUMN_ID,
//X轴滚动条
JSScrollBarChart:JSScrollBarChart,
JSCHART_WORKER_MESSAGE_ID:JSCHART_WORKER_MESSAGE_ID,
}