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.
 
 
 
 
 

1191 lines
40 KiB

/*
copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
图形扩展画法
*/
//日志
import { JSConsole } from "./umychart.console.wechat.js"
//行情数据结构体 及涉及到的行情算法(复权,周期等)
import
{
ChartData, HistoryData,
SingleData, MinuteData,
Guid,
ToFixedPoint,
ToFixedRect,
} from "./umychart.data.wechat.js";
import
{
JSCommonCoordinateData,
MARKET_SUFFIX_NAME
} from "./umychart.coordinatedata.wechat.js";
import
{
g_JSChartResource,
JSCHART_LANGUAGE_ID,
g_JSChartLocalization,
} from './umychart.resource.wechat.js'
import
{
IFrameSplitOperator,
} from './umychart.framesplit.wechat.js'
function IExtendChartPainting()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.Data; // = new ChartData(); //数据区
this.ClassName = 'IExtendChartPainting';
this.IsDynamic = false;
this.IsEraseBG = false; //是否每次画的时候需要擦除K线图背景
this.IsAnimation=false;
this.DrawAfterTitle = false; //是否在动态标题画完以后再画,防止动态标题覆盖
this.ID=Guid(),
//上下左右间距
this.Left = 5;
this.Right = 5;
this.Top = 5;
this.Bottom = 5;
this.Draw = function () { } //画图接口
this.SetOption = function (option) { } //设置参数接口
}
//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.LatestPoint; //手势位置
this.ShowPosition=0; //显示位置 0=左 1=右
this.BorderColor = g_JSChartResource.TooltipPaint.BorderColor; //边框颜色
this.BGColor = g_JSChartResource.TooltipPaint.BGColor; //背景色
this.TitleColor = g_JSChartResource.TooltipPaint.TitleColor; //标题颜色
this.Font = [g_JSChartResource.TooltipPaint.TitleFont];
this.Mergin={ Left:2, Top:3, Bottom:5, Right:5 };
this.ExtendLineWidth=5;
this.Width = 50;
this.Height = 100;
this.LineHeight = 15; //行高
this.LineSpace=2; //行间距
this.Left = 1;
this.Top = 0;
this.HQChart;
this.KLineTitlePaint;
this.IsHScreen = false; //是否横屏
this.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
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.EnableClickModel)
{
if (this.HQChart.ClickModel.IsShowCorssCursor===false) return false;
}
else if (!this.HQChart.IsOnTouch)
{
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();
}
//[{ Text:, Color, Title:, TitleColor, }]
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 = JSCommonCoordinateData.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.TitleColor });
var period = this.HQChart.Period;
if (ChartData.IsMinutePeriod(period, true) && IFrameSplitOperator.IsNumber(item.Time))
{
text = this.HQChart.FormatTimeString(item.Time);
aryText.push({ Text:text, Color:this.TitleColor });
}
else if (ChartData.IsSecondPeriod(period) && IFrameSplitOperator.IsNumber(item.Time))
{
text = this.HQChart.FormatTimeString(item.Time,"HH:MM:SS");
aryText.push({ Text:text, Color:this.TitleColor });
}
if (IFrameSplitOperator.IsNumber(item.Open)) //开
{
title = g_JSChartLocalization.GetText('Tooltip-Open', this.LanguageID);
var 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 (item.YClose>0)
{
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);
text = this.HQChart.FormatValueString(item.Vol, 2, this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
if (IFrameSplitOperator.IsNumber(item.Amount))
{
title = g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID);
text = this.HQChart.FormatValueString(item.Amount, 2, this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
//持仓量
if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
{
title = g_JSChartLocalization.GetText('Tooltip-Position', this.LanguageID);
text = IFrameSplitOperator.FormatValueString(item.Position, 2, this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
return result;
}
this.CalculateTooltipSize=function(titleData)
{
this.Canvas.font=this.Font[0];
this.LineHeight=this.Canvas.measureText("擎").width;
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);
this.Width=(maxLineWidth)+(this.Mergin.Left+this.Mergin.Right)+this.ExtendLineWidth;
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.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(this.HQChart.ToFixedPoint(left), this.HQChart.ToFixedPoint(top),
this.HQChart.ToFixedRect(this.Height), this.HQChart.ToFixedRect(this.Width));
}
else
{
this.Canvas.strokeRect(this.HQChart.ToFixedPoint(left), this.HQChart.ToFixedPoint(top),
this.HQChart.ToFixedRect(this.Width), this.HQChart.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.DrawTooltipData = function (titleData)
{
//console.log('[KLineTooltipPaint::DrawKLineData] ', item);
var left = this.GetLeft();
var top = this.GetTop();
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 =0;
top = 0;
}
this.Canvas.textBaseline="top";
var right=left+this.Width-this.Mergin.Right;
left+=this.Mergin.Left;
top+=this.Mergin.Top;
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.SetOption = function (option)
{
if (option.LineHeight > 0) this.LineHeight = option.LineHeight;
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.IsShowAveragePrice=true;
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.GetTop()+this.Top;
}
}
this.GetLeft=function()
{
if (this.IsHScreen)
{
return this.ChartBorder.GetRight()-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.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 = JSCommonCoordinateData.GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //期货
this.YClose = this.KLineTitlePaint.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, value;
if (IFrameSplitOperator.IsNumber(item.Date))
{
text=IFrameSplitOperator.FormatDateString(item.Date);
aryText.push({ Text:text, Color:this.TitleColor });
}
if (IFrameSplitOperator.IsNumber(item.Time))
{
text=IFrameSplitOperator.FormatTimeString(item.Time);
aryText.push({ Text:text, Color:this.TitleColor });
}
if (IFrameSplitOperator.IsNumber(item.Close)) //最新
{
title = g_JSChartLocalization.GetText('Tooltip-Price', this.LanguageID);
color = this.KLineTitlePaint.GetColor(item.Close, this.YClose);
text = item.Close.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice==true) //均价
{
title = g_JSChartLocalization.GetText('Tooltip-AvPrice', this.LanguageID);
color = this.KLineTitlePaint.GetColor(item.AvPrice, this.YClose);
text = item.AvPrice.toFixed(defaultfloatPrecision);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.Close) && IFrameSplitOperator.IsNumber(this.YClose)) //涨幅
{
title = g_JSChartLocalization.GetText('Tooltip-Increase', this.LanguageID);
value = (item.Close - this.YClose) / this.YClose * 100;
color = this.KLineTitlePaint.GetColor(value, 0);
text = value.toFixed(2) + '%';
if (this.YClose===0)
{
text="--.--";
color=this.TitleColor;
}
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:color });
}
if (IFrameSplitOperator.IsNumber(item.Vol))
{
title = g_JSChartLocalization.GetText('Tooltip-Vol', this.LanguageID);
text = this.HQChart.FormatValueString(item.Vol, 2, this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
if (IFrameSplitOperator.IsNumber(item.Amount))
{
title = g_JSChartLocalization.GetText('Tooltip-Amount', this.LanguageID);
text = this.HQChart.FormatValueString(item.Amount, 2, this.LanguageID);
aryText.push({Title:title, TitleColor:this.TitleColor, Text:text, Color:this.TitleColor });
}
if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position)) //持仓量
{
title = g_JSChartLocalization.GetText('Tooltip-Position', this.LanguageID);
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)
{
//console.log('[KLineTooltipPaint::DrawKLineData] ', item);
var defaultfloatPrecision = JSCommonCoordinateData.GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var left = this.GetLeft() + 2;
var top = this.GetTop() + 3;
this.YClose = this.KLineTitlePaint.YClose;
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;
top = 3;
}
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 = this.HQChart.FormatDateString(aryDateTime[0]);
this.Canvas.fillStyle = this.TitleColor;
this.Canvas.fillText(text, left, top);
top += this.LineHeight;
text = this.HQChart.FormatTimeString(aryDateTime[1]);
this.Canvas.fillText(text, left, top);
}
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(item.Close, this.YClose);
text = item.Close.toFixed(defaultfloatPrecision);
this.Canvas.fillStyle = color;
this.Canvas.fillText(text, left + labelWidth, top);
if (IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice==true)
{
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 = (item.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(item.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 = this.HQChart.FormatValueString(item.Vol, 2, this.LanguageID);
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.fillText(text, left, top);
var text = this.HQChart.FormatValueString(item.Amount, 2, this.LanguageID);
this.Canvas.fillText(text, left + labelWidth, top);
}
//持仓量
var upperSymbol;
if (this.HQChart.Symbol) upperSymbol = this.HQChart.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsChinaFutures(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.FormatValueString(item.Position, 2, this.LanguageID);
this.Canvas.fillText(text, left + labelWidth, top);
}
if (this.IsHScreen) this.Canvas.restore();
}
*/
}
//////////////////////////////////////////////////////////////////////////////
// 弹幕
//弹幕数据 { X:X偏移, Y:Y偏移, Text:内容, Color:颜色 }
function BarrageList()
{
this.PlayList = []; //正在播放队列
this.Cache = []; //没有播放的弹幕数据
this.MinLineHeight = 40;
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) //单挑弹幕播放完毕
{
//监听事件
var event = hqChart.GetBarrageEvent();
if (!event || !event.Callback) return;
event.Callback(event, item, this);
}
this.Count = function () { return this.Cache.length; } //未播放的弹幕个数
}
//背景图 支持横屏
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)
{
var aryData = [];
for (var i in this.Data) {
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 (showItem.Start || showItem.End)
{
showItem.Color = item.Color;
aryData.push(showItem);
}
}
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() }; //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);
}
return mapKLine;
}
this.GetBGCoordinate = function (item, kLineMap)
{
var xLeft = null, xRight = null;
if (item.Start)
{
if (ChartData.IsMinutePeriod(this.Period, true))
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
{
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 (ChartData.IsMinutePeriod(this.Period, true))
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
{
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 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);
}
}
}
/*
扩展图形
*/
function ExtendChartPaintFactory()
{
this.DataMap=new Map(
[
//["FrameSplitPaint", { Create:function() { return new FrameSplitPaint(); } }],
]
);
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();
//导出统一使用JSCommon命名空间名
export
{
IExtendChartPainting,
KLineTooltipPaint,
BarragePaint,
MinuteTooltipPaint,
BackgroundPaint,
g_ExtendChartPaintFactory,
}
/*
module.exports =
{
JSCommonExtendChartPaint:
{
IExtendChartPainting: IExtendChartPainting,
KLineTooltipPaint: KLineTooltipPaint,
BarragePaint: BarragePaint,
MinuteTooltipPaint: MinuteTooltipPaint,
BackgroundPaint: BackgroundPaint,
},
//单个类导出
JSCommonExtendChartPaint_IExtendChartPainting: IExtendChartPainting,
JSCommonExtendChartPaint_KLineTooltipPaint: KLineTooltipPaint,
JSCommonExtendChartPaint_BarragePaint: BarragePaint,
JSCommonExtendChartPaint_MinuteTooltipPaint: MinuteTooltipPaint,
JSCommonExtendChartPaint_BackgroundPaint: BackgroundPaint,
};
*/