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
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+"  "+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}  ${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+"  "+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'> 前收: "+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}  ${value}`;
|
|
}
|
|
else if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期
|
|
{
|
|
value=IFrameSplitOperator.FormatTimeString(data.Time);
|
|
title=`${strDate}  ${value}`;
|
|
}
|
|
else if (ChartData.IsSecondPeriod(this.Value.ChartPaint.Data.Period) || isTickPeriod)
|
|
{
|
|
value=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS');
|
|
title=`${strDate}  ${value}`;
|
|
}
|
|
else if (ChartData.IsMilliSecondPeriod(this.Value.ChartPaint.Data.Period))
|
|
{
|
|
value=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS.fff');
|
|
title=
|
|
[
|
|
`${strDate}  ${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} ${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> <i class='tipBoxTitle'>成交价: "+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+
|
|
"</i><br/><i class='rate-discount tipBoxTitle'>溢折价率: <strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
|
|
showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股): "+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+" 上榜原因: </i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅: <strong style='color:"+
|
|
this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
|
|
"%</strong> 四周后涨幅: <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'>证券代表 </i>";
|
|
else if(levels[j]==1) recPerson+="<i>董秘 </i>";
|
|
else if(levels[j]==2) recPerson+="<i style='color:#00a0e9'>总经理 </i>";
|
|
else if(levels[j]==3) recPerson+="<i style='color:#00a0e9'>董事长 </i>";
|
|
}
|
|
|
|
recPerson='接待: '+recPerson;
|
|
}
|
|
|
|
var researchType='';
|
|
if (item.ExtendData.Type && item.ExtendData.Type!='其他')
|
|
{
|
|
researchType=' '+'<i>'+item.ExtendData.Type+'</i>';
|
|
if (levels.length==0) recPerson='';
|
|
}
|
|
|
|
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
|
|
var strText="<span>"+strDate+" "+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+=" 四周后涨幅:<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/> <i class='prorecast-week'>"+weekData+"</i>";
|
|
}
|
|
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
|
|
var strText="<span>"+strDate+" "+year+reportType+item.Title+" "+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,
|
|
}
|
|
|