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
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,
|
|
}
|