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.
 
 
 
 
 

2079 lines
64 KiB

import
{
IFrameSplitOperator,
} from './umychart.framesplit.wechat.js'
import
{
g_MinuteTimeStringData,
} from "./umychart.coordinatedata.wechat.js";
import
{
g_JSChartResource,
g_JSChartLocalization,
} from './umychart.resource.wechat.js'
import { JSConsole } from "./umychart.console.wechat.js";
function Guid()
{
function S4()
{
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
function Point()
{
this.X;
this.Y;
}
//修正线段有毛刺
function ToFixedPoint(value)
{
return parseInt(value) + 0.5;
}
function ToFixedRect(value)
{
//return value;
// With a bitwise or.
//rounded = (0.5 + somenum) | 0;
// A double bitwise not.
//rounded = ~~ (0.5 + somenum);
// Finally, a left bitwise shift.
var rounded;
return rounded = (0.5 + value) << 0;
}
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.width+2;
return textHeight;
}
//画图工具
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.TouchConfig={ Point:{ Radius:15 }, Line:{ Width:10 } },
this.PixelRatio=null; //分辨率
//接口函数
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.SelectPointColor=option.PointColor;
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;
}
}
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 in this.Point)
{
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 in this.Point)
{
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));
var yValue=this.Frame.GetYData(item.X);
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));
var yValue=this.Frame.GetYData(item.Y);
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 in aryDateTime)
{
var findItem=aryDateTime[i];
var valueItem=this.Value[i];
if (findItem.Index>=0) valueItem.XValue=findItem.Index;
}
}
//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];
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=1;
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=this.TouchConfig.Point.Radius;
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;
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=this.TouchConfig.Line.Width;
if (IFrameSplitOperator.IsPlusNumber(this.PixelRatio)) lineWidth=this.PixelRatio*this.TouchConfig.Line.Width
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();
//for debug
//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;
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="16px 微软雅黑";
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+'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) { }
}
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:"标价线2", ClassName:"ChartDrawPriceLineV2", Create:function() { return new ChartDrawPriceLineV2(); } },
];
IChartDrawPicture.GetDrawPictureByName=function(value)
{
for(var i=0; i<IChartDrawPicture.ArrayDrawPricture.length; ++i)
{
var item=IChartDrawPicture.ArrayDrawPricture[i];
if (item.Name==value) return item;
}
return null;
}
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: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();
}
this.GetYCoordinatePoint=function()
{
if (this.IsFrameMinSize()) 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 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 lineWidth=this.TouchConfig.Line.Width;
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 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;
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 ChartDrawPictureHorizontalLine()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.Super_SetOption=this.SetOption; //父类函数
this.Super_ExportStorageData=this.ExportStorageData;
this.Label; //{Text:文本, Position: 0=左, 1=右 }
this.SetOption=function(option)
{
if (this.Super_SetOption) this.Super_SetOption(option);
if (option)
{
if (option.Label) this.Label=option.Label;
}
}
this.ExportStorageData=function()
{
var storageData;
if (this.Super_ExportStorageData)
{
storageData=this.Super_ExportStorageData();
if (this.Label) storageData.Label=this.Label;
}
return storageData;
}
this.PointCount=1;
this.ClassName='ChartDrawPictureHorizontalLine';
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.Font=16+"px 微软雅黑";
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
{
this.Canvas.moveTo(left,drawPoint[0].Y);
this.Canvas.lineTo(right,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);
//画点
this.DrawPoint(drawPoint);
//显示价格
this.LineText(drawPoint[0])
/*
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
if (isHScreen)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var xText=drawPoint[0].X;
var yText=left;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
var yValue=this.Frame.GetYData(drawPoint[0].X);
var text=yValue.toFixed(2);
if (this.Label)
{
if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
}
this.Canvas.fillText(text,0,0);
}
else
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var yValue=this.Frame.GetYData(drawPoint[0].Y);
var text=yValue.toFixed(2);
if (this.Label)
{
if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
}
this.Canvas.fillText(text,left,drawPoint[0].Y);
}
*/
this.Canvas.restore();
}
this.LineText=function(point)
{
if (!point) return;
var isHScreen=this.Frame.IsHScreen;
var left=this.Frame.ChartBorder.GetLeft();
this.Canvas.fillStyle=this.LineColor;
this.Canvas.font=this.Font;
if (isHScreen)
{
left=this.Frame.ChartBorder.GetTop();
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var xText=point.X;
var yText=left;
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
var yValue=this.Frame.GetYData(point.X);
var text=yValue.toFixed(2);
if (this.Label)
{
if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
}
this.Canvas.fillText(text,2,0);
}
else
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
var yValue=this.Frame.GetYData(point.Y);
var text=yValue.toFixed(2);
if (this.Label)
{
if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
}
this.Canvas.fillText(text,left,point.Y);
}
}
}
//画图工具-标价线2 支持横屏
function ChartDrawPriceLineV2()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPriceLineV2';
this.Font="12px 微软雅黑";
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 =1;
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)
{
var rtBG={ Left:(xText-textHeight/2), Top:yText , Width: textHeight, Height:textWidth };
}
else //框架内部显示
{
yText=yText-textWidth;
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:bottom-textWidth-1*pixelTatio, Width:textHeight, Height:textWidth };
}
else
{
var rtTitle={Left:rtBG.Left, Top:rtBG.Top-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, 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;
}
else //框架内部显示
{
var rtBG={ Left:xText-textWidth, Top:(yText-textHeight/2-1*pixelTatio) , Width:textWidth, Height: textHeight};
}
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:right-textWidth-1*pixelTatio, Top:rtBG.Top, Width:textWidth, Height:textHeight };
if (rtBG.Left!=right) rtTitle.Left=rtBG.Left-textWidth-1*pixelTatio;
}
else
{
var rtTitle={Left:rtBG.Left-textWidth, Top:rtBG.Top, Width:textWidth, Height:textHeight}
}
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()
{
}
}
export
{
IChartDrawPicture,
ChartDrawPictureLine,
ChartDrawPictureHaflLine,
ChartDrawArrowLine,
ChartDrawPictureHorizontalLine,
ChartDrawPriceLineV2,
}