tslediter/funcext/tvclib/utvclgraphics.tsf

3169 lines
96 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

unit utvclgraphics;
interface
uses utslvclauxiliary;
//tsl绘图库
//20240126
//20240204 添加说明
{
tg_const 常量类型,作为所有类型的基类,提供常量别名
tg_canvas 绘图画布对象该对象以窗口中的canvas为父类并增加了辅助函数
axesclip() 限定到坐标系区域
axesunclip() 取消坐标系区域限定
axesrec 坐标系的范围
tg_line_info 画笔线型信息
Style 线型 tgc_PS_DOT tgc_PS_DASH tgc_PS_NULL tgc_PS_SOLID tgc_PS_DASHDOT tgc_PS_DASHDOTDOT
size 线宽度,像素
color 线颜色
bkcolor 线型封闭后的背景
tg_font_info 系统信息
size 字号,宽度的像素
color 字颜色
bkcolor 背景色
tg_mark_info 点标记信息
size 标记大小,像素
color 线颜色
bkcolor 背景色
tg_base 做个绘图类基类,提供一些基础功能,以及层次关系
层次关系:
parent: 设置或者父节点
nodecount 获取子节点数量
GetNodeByIndex 通过序号获取子节点
set_node_index(nd,idx) 设置子节点的序号
基础功能:
markinfo 标记信息 tg_mark_info 类型
lineinfo 画笔信息 tg_line_info 类型
line_mode 是否画线
mark_mode 是否画点的标记
clip_state 是否裁剪区域
Coordinate_Mapping(x,y,z,var _x,var _y) 通过坐标点计算画布点位置
Coordinate_unMapping(x,y,var x_,var y_,var z_) 通过画布点计算坐标点
set_lineinfo_to_canvas(cvs,peninfo) 设置当前画笔信息到画布
set_fontinfo_to_canvas(cvs,info) 设置当前字体信息到画布
paint(cvs);virtual;该函数由tg_figure的管理者在适当时候发起并送入tg_canvas对象
tg_figure //坐标容器类,可以在上面放坐标系,设置坐标系的位置信息
add_axes(axes) 添加坐标系
del_axes(axes) 删除坐标系
executecommand(cmd,p); //命令行执行
paint(cvs); 送入画布绘制各个图形如果是窗口在onpaint消息中调用该函数
属性:
rec_getter function() 返回画布区域 array(左上右下)
fresh_caller: function() //刷新回调
tg_axes 坐标系类型,作为绘图的基础载体,以及位置关系的基准
属性:
title 标题 tg_label 类型
y_label y轴标签 tg_label 类型
x_label x轴标签 tg_label 类型
axises(idx) 0,1,2 分别获取对应的xy轴 tg_axis 类型
axes_reverse(idx) 坐标轴是否反向,默认正向
auto_ticks(idx) 设置坐标轴刻度自动计算
margins 空白array(左上右下)设置上下左右空白tg_figure区域的百分比
axes_bounds(idx) 坐标系的大小 array((x,width),(y,heigt))以margins为基准点安百分比
data_bounds(idx) 获取或者设置数据范围 array((x0,x1),(y0,y1),(z0,z1))
zoom_box(idx) 设置显示的数据的区域 array((x0,x1),(y0,y1),(z0,z1))
x_location 坐标轴方向tgc_bottom tgc_top,tgc_middle ,tgc_origin
y_location 坐标轴方向tgc_left tgc_right,tgc_middle ,tgc_origin
box 是否有边框
grid(idx) 背景网格线属性 tg_line_info 对象size为0的时候网格线消失
tg_axis 坐标轴,可以在坐标系中放置任意多个坐标轴
tics_direction 坐标轴方向 tgc_left tgc_right tgc_bottom tgc_top
tics_style 刻度类型 tgc_tics_v (设置值) tgc_tics_r ([x0,x1,inteval])
xtics_coord 刻度根据tics_style 确定 [2,3,4,5,6,7] 计算 [start,end,interval]
ytics_coord 位置,设置在另一个方向的位置,相对坐标系的数据位置
tics_segment 是否有轴线
tics_color 刻度线颜色
sub_tics 子刻度个数
tics_labels 刻度值对应的标签,一维字符串数组
tg_label 标签以axes作为父节点
text 文本
position 坐标系位置
auto_position 自动位置,在坐标轴标签中使用
font_angle 设置角度
其他字体相关的通过 fontinfo设置
tg_graph_base 图基类
get_data_bounds();virtual; //获取数据边界
tg_graph 图类型
get_data_tips(); //获得数据提示对象
get_legend_size(var w,var h);virtual; 获取图例中的大小
paint_legend(cvs,rec);virtual; //绘制图例
get_graph_data_by_idx(idx); //通过数据序号获取数据
graph_data 绘图数据;
tg_Polyline 线图以tg_graph为父类
closed 是否封闭的图像
polyline_style 线类型, tgc_LS_interpolated tgc_LS_bar tgc_LS_filled tgc_LS_arrowed tgc_LS_barplot tgc_LS_staircase
bar_width 柱状图类型时候的宽度
tg_legend 图例
location 位置 tgc_in_upper_left tgc_in_lower_left ..... tgc_by_coordinates
postion 定位为tgc_by_coordinates设置具体位置 array(x,y)
line_mode 边框线
links 关联的绘图tg_graph 数组
text 文本内容,字符串数组
tg_tips 数据点提示父节点为tg_graph 对象
text 文本数组
data_idx 绑定数据序号
tg_text 文本展示
text 字符串数组
font_angle 角度
data array(x,y,z) 相对于坐标系的位置
tg_WinControl:绘图展示窗口对象,管理了一个 tg_figure 对象在paint消息的时候构造tg_canvas 对象并调用tg_figrue的paint函数实现图形的绘制
其仅仅作为一个案例,用户可以按照其原理构造自己的画布对象,驱动绘制,得到图形
}
{
//////////////////绘图范例//////////////////////////
uses tslvcl,utvclgraphics;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
fg := new tg_WinControl(self);
fg.Caption := "hello1";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "你好 plot ";
axs.title.fontinfo.size := 15;
axs.title.fontinfo.color := 0xff0000;
axs.x_label.text := "x fanli ";
axs.axises(1).tics_color := 0x0000ff;
axs.axises(1).fontinfo.size := 8;
axs.axises(1).lineinfo.color := 0x00ff00;
axs.grid(0).Width := 2;
axs.grid(0).color := 0x0ff0f0;
//设置线型属性
line := new tg_Polyline();
line.lineinfo.style := 4;
line.lineinfo.color := 0xff0000;
line.markinfo.bkcolor := 0x00ff00;
line.markinfo.color := 0x0000ff;
line.mark_mode := "on";
line.markinfo.size := 30;
line.markinfo.style := "pentagram";
line.polyline_style := "staircase";
d := array();
idx := 0;
for i:= -pi() to pi() step 0.2 do
begin
d[idx] := array(i,sin(i));
idx++;
end
line.graph_data := d;
line.parent := axs;
end
fg;
end
}
type tg_WinControl = class(tcustomcontrol,tg_const) //绘图窗口
function create(AOwner);
begin
inherited;
ffigure := new tg_figure();
fg_timer := new unit(utslvclstdctl).tcustomtimer(self);
fg_timer.Interval := 200;
fg_timer.Ontimer := thisfunction(figure_need_fresh);
ffigureprepared := false;
ffigure.rec_getter := function()begin
return clientrect;
end
ffigure.fresh_caller := thisfunction(flushfigure);
end
function flushfigure();
begin
if not ffigureprepared then return ;
if Fneed_invaliate then return ;
if not HandleAllocated() then return ;
Fneed_invaliate := true;
fg_timer.start();
end
function paint();override; //绘制
begin
cvs := canvas;
ffigure.paint(cvs);
ffigureprepared := true;
end
function DestroyHandle();override;
begin
ffigureprepared := false;
inherited;
end
function DoMouseWheel(o,e);override;
begin
p := ScreenToClient(e.xpos,e.ypos);
ffigure.executecommand("zoom_inc",array("delta":e.delta,"x":p[0],"y":p[1]));
end
function DoWMSIZE(o,e);override;
begin
inherited;
ffigure.executecommand("figure_changed");
end
function Recycling();override;
begin
ffigure:=nil;
inherited;
end
property figure read ffigure;
private
function figure_need_fresh(o,e); //定时刷新
begin
o.stop();
//echo "\r\ninvalidate time:",datetimetostr(now());
InvalidateRect(nil,false);
Fneed_invaliate := false;
end
private
ffigure;
fg_timer;
Fneed_invaliate;
ffigureprepared;
end
type tg_figure = class() /////////
function create();
begin
inherited;
faxeses := new tnumindexarray();
end
function paint(cvs); //绘制
begin
cvs := new tg_canvas(cvs.Handle);
for i,v in faxeses.data do
begin
v.paint_pre(cvs);
end
end
function executecommand(cmd,p);
begin
case cmd of
"figure_need_fresh":
begin
fresh();
return ;
end
"zoom_inc":
begin
for i,v in faxeses.data do
begin
v.executecommand("zoom_inc",p);
end
end
"figure_changed":
begin
for i,v in faxeses.data do
begin
v.executecommand("figure_changed");
end
end
end ;
end
function add_axes(axs);//添加
begin
if get_axes_idx(axs)>=0 then return ;
if fwilladdaxs and fwilladdaxs=axs then
begin
faxeses.unshift(axs);
fwilladdaxs := nil;
axs.figure := self(true);
return ;
end
if not(axs is class(tg_axes)) then return ;
fwilladdaxs := axs;
axs.figure := self(true);
end
function del_axes(axs); //移除
begin
idx := get_axes_idx(axs);
if not(idx>=0) then return ;
if fwilldelaxs and fwilldelaxs = axs then
begin
fwilldelaxs := nil;
faxeses.splice(idx,1);
axs.figure := nil;
return ;
end
fwilldelaxs := axs;
axs.figure := nil;
end
function fresh(); ///////////////////////////
begin
if ffresh_caller then call(ffresh_caller);
end
function rect(); //////////////////////////////////
begin
r := array(0,0,200,200);
if frect_getter then r := call(frect_getter);
return r;
end
property rec_getter read frect_getter write frect_getter; //区域获取
property fresh_caller read ffresh_caller write ffresh_caller; //刷新回调
private
function get_axes_idx(axs);
begin
for i ,v in faxeses.data do
begin
if v=axs then
begin
return i;
end
end
return -1;
end
private
[weakref] frect_getter;
[weakref] ffresh_caller;
fwilladdaxs;
fwilldelaxs;
faxeses;
end
type tg_axes = class(tg_base) //坐标系
private
[weakref]fFigure;
///////////////坐标辅助计算/////////////////////////
p_left;
p_top;
p_width;
p_height;
dx_min;
dx_max;
dx_len;
dy_min;
dy_max;
dy_len;
rt_x;
rt_y;
f_changed;
static const c_g_paint_rect=2;
static const c_g_data_changed=1;
static const c_g_data_zoombox=4;
///////////////////////////////////////////
public
function executecommand(cmd,pm);override;
begin
ochanged := f_changed;
case cmd of
"zoom_inc":
begin
if not ifarray(pm) then return ;
p0 := pm["x"];
p1 := pm["y"];
for i := 0 to 1 do
begin
a0 := fzoom_box[i,0];
b0 := fzoom_box[i,1];
if not xy_in_paint_rect(p0,p1) then
begin
continue;
end
if not Coordinate_unMapping(p0,p1,x,y,z) then continue ;
dx := ((pm["delta"]>0)?(1.05):(1/1.05));
if not zoom_bound_op(a0,b0,dx,array(x,y)[i],a,b) then continue ;
rt := 1;
cg := 0;
if a<fdata_bounds[i,0]*rt then
begin
cg++;
a := fdata_bounds[i,0]*rt ;
end
if b>fdata_bounds[i,1]*rt then
begin
cg++;
b := fdata_bounds[i,1]*rt;
end
if cg=2 then continue;
fzoom_box[i] := array(a,b);
f_changed .|= c_g_data_zoombox;
end
end
"node_add_in":
begin
if pm is class(tg_graph_base) then
begin
f_changed .|= c_g_data_changed;
f_changed .|= c_g_data_zoombox;
end
end
"figure_changed":
begin
f_changed .|= c_g_paint_rect;
f_changed .|= c_g_data_zoombox;
end
"data_changed":
begin
f_changed .|= c_g_data_changed;
f_changed .|= c_g_data_zoombox;
end
end ;
if ochanged<>f_changed then prop_changed("data_changed",f_changed);
end
function Coordinate_unMapping(x,y,_x,_y,_z);override; //画布到坐标
begin
if not(fFigure) then return 0;
if faxes_reverse[0]=tgc_on then //x轴
begin
_x := fzoom_box[0,0]-(x-p_left-p_width)/rt_x;
end else
begin
_x := (x-p_left)/rt_x+fzoom_box[0,0];
end
if faxes_reverse[1]=tgc_on then //y轴
begin
_y := (y-p_top)/rt_y +fzoom_box[1,0];
end else
begin
_y := fzoom_box[1,0]-(y-p_top-p_height)/rt_y;
end
return true;
end
function axes_mapping(x,y,z,_x,_y);override;//坐标系相对位置到画布
begin
if not(fFigure ) then return false;
_x := p_left+p_width*x ;
_y := p_top +p_height*y;
return true;
end
function axes_unmapping(x,y,_x,_y,_z);override;//画布位置到坐标系相对位置
begin
if not(fFigure ) then return false;
_x := (x-p_left)/p_width;
_y := (y-p_top)/p_height;
return true;
end
function Coordinate_Mapping(x,y,z,_x,_y);override; //坐标到画布
begin
if not(fFigure) then return 0;
if faxes_reverse[0]=tgc_on then //x轴
begin
_x := p_left+p_width-(x-fzoom_box[0,0])*rt_x;
end else
begin
_x := (x-fzoom_box[0,0])*rt_x+p_left;
end
if faxes_reverse[1]=tgc_on then //y轴
begin
_y := (y-fzoom_box[1,0])*rt_y+p_top;
end else
begin
_y := p_top+p_height-(y-fzoom_box[1,0])*rt_y;
end
return true;
end
function paint_pre(cvs);
begin
if not visible then return ;
axes_changed();
modify_coordinate_postion();
r := array(p_left-1,p_top-1,p_left+p_width+1,p_top+p_height+1);
cvs.axesrec := r;
paint(cvs);
cvs.axesunclip();
end
function paint(cvs);override;
begin
paint_grid(cvs);
inherited;
cvs.axesunclip();
for i,v in faxes_objects do //绘制坐标
begin
v.paint(cvs);
end
modify_label_postion();
for i,v in array(ftitle,fx_label,fy_label) do //标签
begin
v.paint(cvs);
end
if fbox = tgc_on then
begin
set_lineinfo_to_canvas(cvs);
cvs.moveto(array(p_left,p_top));
cvs.lineto(array(p_left+p_width,p_top));
cvs.lineto(array(p_left+p_width,p_top+p_height));
cvs.lineto(array(p_left,p_top+p_height));
cvs.lineto(array(p_left,p_top));
end
end
function axes_changed();//改变
begin
if not fFigure then return ;
if f_changed then
begin
fr := fFigure.rect();
w := fr[2]-fr[0];
h := fr[3]-fr[1];
p_left := fr[0]+w*fmargins[0]+faxes_bounds[0];
p_top := fr[1]+h*fmargins[1]+faxes_bounds[1];
p_width := w*(1-fmargins[0]-fmargins[2])*faxes_bounds[2];
p_height := h*(1-fmargins[1]-fmargins[3])*faxes_bounds[3];
if (f_changed .& c_g_data_changed)=c_g_data_changed then
begin
tbds := fdata_bounds;
for i,v in get_node_data_bounds(self(true)) do
begin
if not fdata_bounds_locked[i] then
begin
new_bounds(v[0],v[1],a_,b_);
tbds[i] := array(a_,b_);//v*1.05;
end
end
fdata_bounds := tbds;
fzoom_box := tbds;
end
if (f_changed .& c_g_data_zoombox)=c_g_data_zoombox then
begin
auto_set_axis();
end
dx_min := fzoom_box[0,0];
dx_max := fzoom_box[0,1];
dx_len := dx_max-dx_min;
dy_min := fzoom_box[1,0];
dy_max := fzoom_box[1,1];
dy_len := dy_max-dy_min;
rt_x := p_width/ dx_len;
rt_y := p_height/dy_len;
end
f_changed := 0;
end
function create(pms);
begin
inherited;
fdata_bounds_locked := array(0,0,0);
f_changed := 0;
fgrid := array();
for i:= 0 to 1 do
begin
gd := new tg_line_info();
gd.width := 0;
gd.Style := tgc_PS_DOT;
fgrid[i] := gd;
end
faxes_reverse := array(tgc_off,tgc_off,tgc_off);
fview := "2d";
fbox := tgc_off;
ffilled := tgc_off;
fx_location := tgc_bottom;
fy_location := tgc_left;
faxes_objects := array();
for i := 0 to 2 do
begin
axi := new tg_axis_main();
axi.tics_style := tgc_tics_v;//tgc_tics_r;
case i of
0: axi.tics_direction := tgc_bottom;
1:axi.tics_direction := tgc_left;
2:axi.visible := false;
end ;
faxes_objects[i] := axi;
axi.axes := self(true);
end
ftitle := new tg_label_axes();
ftitle.axes := self(true);
fx_label := new tg_label_axes();
fx_label.axes := self(true);
fy_label := new tg_label_axes();
fy_label.axes := self(true);
fy_label.font_angle := pi()/2;
fauto_ticks := array(tgc_on,tgc_on,tgc_on);
fmargins := array(0.125,0.125,0.125,0.125);
faxes_bounds := array( 0,0,1,1);
fdata_bounds := array((0,1),(0,1),(0,1));
fzoom_box := fdata_bounds;
//FA vector containing the handles of all graphics objects children of the
//axes These graphics objects are of type
//"Compound", "Rectangle", "Polyline", "Segs", "Arc", "Grayplot",.. (see Compound_properties,
//rectangle_properties, champ_properties, axis_properties, polyline_properties, segs_properties,
//grayplot_properties, surface_properties, fec_properties, text_properties, legend_properties)
end
published
property figure read fFigure write SetFigure; //窗口
property view read fview write set_view; //立体
property axises read get_axises;//axes_visible ;//= ["on","on","on"]
property axes_reverse read gs_axes_reverse write gs_axes_reverse;//axes_reverse ;//= ["off","off","off"]
property x_location read fx_location write set_x_location;//'bottom
property y_location read fy_location write set_y_location;//'left
property title read ftitle;
property x_label read fx_label;
property y_label read fy_label;
property z_label read fz_label;
property auto_ticks read gs_auto_ticks write gs_auto_ticks;
property box read fbox write set_box;
property filled read ffilled write set_filled;
property sub_ticks read gs_sub_ticks write gs_sub_ticks;
//上下左右空白
property margins read gs_margins write gs_margins;
property axes_bounds read gs_axes_bounds write gs_axes_bounds;
property data_bounds read gs_data_bounds write gs_data_bounds;
property zoom_box read gs_zoom_box write gs_zoom_box;
//在窗口中的区域
//网格线
property grid read get_grid;
//grid ;//= [-1,-1]
//grid_position ;//= "background"
//grid_thickness ;//= [1,1]
//grid_style ;//= [7,7]
//x_ticks.locations ;//= matrix 21x1
//y_ticks.locations ;//= matrix 11x1
//z_ticks.locations ;//= []
//x_ticks.labels ;//= matrix 21x1
//y_ticks.labels ;//= matrix 11x1
//z_ticks.labels ;//= []
//ticks_format ;//= ["","",""]
//ticks_st ;//= [1,1,1;0,0,0]
//sub_ticks ;//= [1,1]
font_style ;//= 6
font_size ;//= 1
font_color ;//= -1
fractional_font ;//= "off"
//isoview ;//= "off"
//cube_scaling ;//= "off"
//rotation_angles ;//= [0,270]
//log_flags ;//= "nnn"
//tight_limits ;//= ["off","off","off"]
//zoom_box ;//= []
//auto_margins ;//= "on"
//auto_clear ;//= "off"
//auto_scale ;//= "on"
//auto_stretch ;//= "on"
//hidden_axis_color ;//= 4
//hiddencolor ;//= 4
//line_mode ;//= "on"
//line_style ;//= 1
//thickness ;//= 1
//mark_mode ;//= "off"
//mark_style ;//= 0
//mark_size_unit ;//= "tabulated"
//mark_size ;//= 0
//mark_foreground ;//= -1
//mark_background ;//= -2
//foreground ;//= -1
//background ;//= -2
//arc_drawing_method ;//= "lines"
//clip_state ;//= "clipgrf"
//clip_box ;//= []
protected
function get_axes();override;
begin
return self(true);
end
private
fgrid;
faxes_objects;
fzoom_box;
fmargins;
faxes_bounds ;//= [0,0,1,1]
fdata_bounds;
fdata_bounds_locked;
ffilled;
fauto_ticks;
ftitle;
fx_label;
fy_label;
fz_label;
fx_location;
fy_location;
fview;
fbox;
faxes_reverse;
private
fwilldelfigure;
fwilladdfigure;
function paint_grid(cvs);//绘制表格
begin
xg := fgrid[0];
if xg.width>0 and ifnumber(xg.color) then
begin
set_lineinfo_to_canvas(cvs,xg);
y1 := p_top;
y2 := p_top+p_height;
for i,v in faxes_objects[0].executecommand("get_tics_value") do
begin
if v<fzoom_box[0,0] or v>fzoom_box[0,1] then continue;
if Coordinate_Mapping(v,0,0,_x,_y) then
begin
cvs.moveto(array(_x,y1));
cvs.lineto(array(_x,y2));
end
end
end
xg := fgrid[1];
if xg.width>0 and ifnumber(xg.color) then
begin
set_lineinfo_to_canvas(cvs,xg);
x1 := p_left;
x2 := p_left+p_width;
for i,v in faxes_objects[1].executecommand("get_tics_value") do
begin
if v<fzoom_box[1,0] or v>fzoom_box[1,1] then continue;
if Coordinate_Mapping(0,v,0,_x,_y) then
begin
cvs.moveto(array(x1,_y));
cvs.lineto(array(x2,_y));
end
end
end
end
function auto_set_axis();//自动计算坐标
begin
sz := array(p_width,p_height);
for i:=0 to 1 do
begin
axi :=faxes_objects[i];
axi.executecommand("set_bounds",fzoom_box[i]);
fsz := axi.fontinfo.size;
if fauto_ticks[i] = tgc_on then
begin
if i=0 then
begin
n := integer(sz[0]/(fsz*15));
end else
if i=1 then
begin
n := integer(sz[1]/(fsz*6));
end
xcd := array();
xcdls := array();
if n>0 then
begin
rt := new_bounds(fzoom_box[i,0],fzoom_box[i,1],a_,b_);
bs :=ceil((b_-a_)/(rt)/n);
axi.sub_tics := bs;
stp := bs*rt;
vi := a_;
ii := 0;
while vi<=b_ do
begin
xcd[ii++] := vi;
vi+=stp;
end
end
axi.xtics_coord := xcd;
end
end
end
function xy_in_paint_rect(x,y);//鼠标是否在坐标内
begin
if not ifnumber(x) then return false;
if not ifnumber(y) then return false;
if x<p_left or x>(p_left+p_width) then return false;
if y<p_top or y>(p_top+p_height) then return false;
return true;
end
function zoom_bound_op(a,b,dx,x,a1,b1);//缩放
begin
if x<a or x>b then return false;
if not(ifnumber(dx)) then return false ;
len := (b-a)/dx;
rt := (x-a)/(b-a);
a1 := x-len*rt;
b1 := a1+len;
return true;
end
function modify_label_postion(); //修正标签位置
begin
if fx_label and (fx_label.visible=tgc_on) and (fx_label.auto_position=tgc_on) then
begin
s := fx_label.text;
if s then
begin
x := p_left+(p_width-length(s)*10)/2;
ax := faxes_objects[0];
y := p_top+p_height+20;
if ax.visible=tgc_on and ax.tics_direction = tgc_bottom then
begin
y +=ax.fontinfo.size*2;
end
if fx_label.location=tgc_by_coordinates then
Coordinate_unMapping(x,y,_x,_y,_z);
else axes_unmapping(x,y,_x,_y,_z);
p := array(_x,_y);
fx_label.executecommand("auto_position_value",p);
end
end
if fy_label and (fy_label.visible=tgc_on) and (fy_label.auto_position=tgc_on) then
begin
s := fy_label.text;
fsz := fy_label.fontinfo.size;
if s then
begin
y := p_top+(p_height-length(s)*fsz)/2;
if (fy_location= tgc_left) then
begin
x := p_left+p_width+5+fsz*2;
end
else
begin
x := p_left-5;//-fy_label.fontinfo.size;
end
if fy_label.location=tgc_by_coordinates then
Coordinate_unMapping(x,y,_x,_y,_z);
else axes_unmapping(x,y,_x,_y,_z);
p := array(_x,_y);
fy_label.executecommand("auto_position_value",p);
end
end
if ftitle and (ftitle.visible=tgc_on) and (ftitle.auto_position=tgc_on) then
begin
s := ftitle.text;
if s then
begin
ax := faxes_objects[0];
y := p_top-20-(ftitle.fontinfo.size*2);
if (ax.visible=tgc_on) and (ax.tics_direction = tgc_top) then
begin
y -=(ax.fontinfo.size*2);
end
x := p_left+(p_width-length(s)*10)/2;
if ftitle.location=tgc_by_coordinates then
Coordinate_unMapping(x,y,_x,_y,_z);
else axes_unmapping(x,y,_x,_y,_z);
ftitle.executecommand("auto_position_value",array(_x,_y));
end
end
end
function modify_coordinate_postion();//修正坐标轴位置
begin
axy := faxes_objects[1];
case fy_location of
tgc_left:
begin
axy.ytics_coord := fzoom_box[0,(faxes_reverse[0] = tgc_on)];
end
tgc_right:
begin
axy.ytics_coord := fzoom_box[0,(faxes_reverse[0]<> tgc_on)];
end
tgc_middle:
begin
axy.ytics_coord := fzoom_box[0,0]+(fzoom_box[0,1]-fzoom_box[0,0])/2;
end
tgc_origin:
begin
if fzoom_box[0,0]<0 and fzoom_box[0,1]>0 then
axy.ytics_coord := 0;
else
begin
axy.ytics_coord := fzoom_box[0,(faxes_reverse[0] = tgc_on)];
end
end
end ;
axx := faxes_objects[0];
case fx_location of
tgc_bottom:
begin
axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]= tgc_on)];
end
tgc_top:
begin
axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]<> tgc_on)];
end
tgc_middle:
begin
axx.ytics_coord := fzoom_box[1,0]+(fzoom_box[1,1]-fzoom_box[1,0])/2;
end
tgc_origin:
begin
if fzoom_box[1,0]<0 and fzoom_box[1,1]>0 then
axx.ytics_coord := 0;
else
begin
axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]= tgc_on)];
end
end
end ;
end
function SetFigure(v); //添加窗口
begin
if v=fFigure then return ;
if fwilladdfigure and fwilladdfigure=v then
begin
fwilladdfigure := nil;
fFigure := v;
v.add_axes(self(true));
f_changed .|= c_g_paint_rect;
return ;
end
if fwilldelfigure and fwilldelfigure=tp then
begin
fwilldelfigure := nil;
fFigure := nil;
v.del_axes(self(true));
return ;
end
tp := fFigure;
if tp then //删除
begin
fwilldelfigure := tp;
tp.del_axes(self(true));
fwilldelfigure := nil;
end
if v is class(tg_figure) then //添加
begin
fwilladdfigure := v;
v.add_axes(self(true));
fwilladdfigure := nil;
end else
begin
fFigure := nil;
end
end
function set_filled(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fbox then
begin
ffilled := nv;
prop_changed("ffilled",nv);
end
end
function set_box(v);
begin
if (v in array(tgc_box_on,tgc_box_off,tgc_box_half,tgc_box_hidden_axes)) and v<>fbox then
begin
fbox := v;
prop_changed("box",v);
end
end
function set_x_location(v);
begin
if v<>fx_location and ( v in array(tgc_bottom,tgc_top,tgc_middle,tgc_origin)) then
begin
fx_location := v;
if v=tgc_bottom or v=tgc_top then faxes_objects[0].tics_direction := v;
prop_changed("x_location",v);
end
end
function set_y_location(v);
begin
if v<>fy_location and ( v in array(tgc_left,tgc_right,tgc_middle,tgc_origin)) then
begin
fy_location := v;
if v=tgc_left or v=tgc_right then faxes_objects[1].tics_direction := v;
prop_changed("y_location",v);
end
end
function get_grid(idx);
begin
if idx=0 or idx=1 then return fgrid[idx];
end
function set_view(v);
begin
return ;
end
function gs_auto_ticks(idx,v);//自动更新坐标标签
begin
tg_boolen_value(v,nv);
if nv=tgc_on or nv=tgc_off then
begin
if idx in array(0,1,2) then
begin
if fauto_ticks[idx]<>nv then
begin
fauto_ticks[idx] := nv;
if nv=tgc_on then faxes_objects[i].tics_style := tgc_tics_v;//faxes_objects[i].tics_style := tgc_tics_r;
//else faxes_objects[i].tics_style := tgc_tics_v;
prop_changed("auto_ticks",idx);
end
end
end else //get
begin
if idx in array(0,1,2) then return fauto_ticks[idx];
return fauto_ticks;
end
end
function get_axises(idx);
begin
if idx in array(0,1) then
begin
return faxes_objects[idx];
end
end
function gs_axes_bounds(idx,v);
begin
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2,3) then
begin
faxes_bounds[idx] := array(v[0],v[1]);
f_changed .|=c_g_paint_rect ;
prop_changed("axes_bounds",idx);
end
end else //get
begin
if idx in array(0,1,2,3) then return faxes_bounds[idx];
return faxes_bounds;
end
end
function gs_data_bounds(idx,v);
begin
if v=-1 then
begin
if idx in array(0,1,2) then
begin
fdata_bounds_locked[idx] := false;
end
end else
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2) then
begin
fdata_bounds[idx] := v;
fdata_bounds_locked[idx] := true;
prop_changed("data_bounds",idx);
end
end else //get
begin
if idx in array(0,1,2) then return fdata_bounds[idx];
return fdata_bounds;
end
end
function gs_zoom_box(idx,v);
begin
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2) then
begin
fzoom_box[idx] := v;
prop_changed("zoom_box",idx);
end
end else //get
begin
if idx in array(0,1,2) then return fzoom_box[idx];
return fzoom_box;
end
end
function gs_axes_reverse(idx,v); //反向
begin
if v=tgc_off or v=tgc_on then
begin
if idx in array(0,1,2) then
begin
faxes_reverse[idx] := v;
prop_changed("axes_reverse",idx);
end
end else //get
begin
if idx in array(0,1,2) then return faxes_reverse[idx];
return faxes_reverse;
end
end
function gs_margins(idx,v); //空白
begin
if ifnumber(v) then
begin
if idx in array(0,1,2,3) then
begin
fmargins[idx] := v;
f_changed .|= c_g_paint_rect;
prop_changed("margins",idx);
end
end else //get
begin
if idx in array(0,1,2,3) then return fmargins[idx];
return fmargins;
end
end
function gs_sub_ticks(idx,v); //小刻度线
begin
if ifnumber(v) and (v>=0) then
begin
if idx in array(0,1,2) then
begin
faxes_objects[idx].sub_tics := v;
end
end else //get
begin
if idx in array(0,1,2) then return faxes_objects[idx].sub_tics;
return array(faxes_objects[0].sub_tics,faxes_objects[1].sub_tics,faxes_objects[2].sub_tics);
end
end
end
type tg_canvas = class(TcustomCanvas)
uses utslvclgdi;
function create(h);
begin
inherited create();
FCvsHandle := h;
Handle := h;
faxesrgn := new TRGNRECT();
end
function axesclip();
begin
if faxesrgn then
begin
_wapi.SelectClipRgn(FCvsHandle,faxesrgn.Handle); //裁剪区域
end
end
function axesunclip();
begin
_wapi.SelectClipRgn(FCvsHandle,0);
end
function destroy();
begin
Handle := 0;
faxesrgn := nil;
end
property axesrec read FaxesRec write set_clip_rect;
private
FaxesRec;
FCvsHandle;
faxesrgn;
private
function set_clip_rect(rec);
begin
FaxesRec := rec;
faxesrgn.rect := rec;
end
end
type tg_axis_main = class(tg_axis) //主轴
public
function create(pms);
begin
inherited;
end
protected
function SetParent(V);override;
begin
end
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
if axs is class(tg_axes) then faxes := axs;
end
private
[weakref] faxes;
end
type tg_label_axes = class(tg_label) //坐标系标签
public
function create(pms);
begin
inherited;
clip_state := tgc_off;
auto_position := tgc_on;
end
protected
function SetParent(V);override;
begin
end
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
if axs is class(tg_axes) then faxes := axs;
end
private
[weakref] faxes;
end
type tg_axis = class(tg_base) //轴对象
function create(pms);
begin
inherited;
clip_state := tgc_off;
fticksize := 12;
fsubticksize := 6;
ftics_direction := tgc_bottom; //
fxtics_coord := array(0,1,2,3);
ftcmin := 0;
ftcmax := 3;
ftccount := 3;
fxtics_coord_v := array(0,1,2,3);
fytics_coord := 0;
ftics_labels := array("0","1","2","3");
ftics_segment := tgc_on;
ftics_style := tgc_tics_v;//"v";
fsub_tics := 2;
ftics_color := nil;
//"v". It's the default value, In this case, tics positions are given by the row factor xtics_coord for horizontal axis (ytics_coord for the vertical one).
//"r". In this case, tics positions are given by the vector [min,max,n] where n is the number of intervals.
//"i". In this case the vector given tics positions is of size 4, [k1,k2,a,n] then values are increasing between k1*10^a and k2*10^a, n is the number of intervals.
end
function executecommand(cmd,pm);override;
begin
case cmd of
"get_tics_value":return fxtics_coord_v;
"set_bounds": return set_zoom_bounds(pm);
end;
end
function paint(cvs);override;
begin
if visible<>tgc_on then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
subtks := array();
idx := 0;
if fsub_tics>1 then
begin
for i:= 0 to length(fxtics_coord_v)-2 do
begin
dx := (fxtics_coord_v[i+1]-fxtics_coord_v[i])/fsub_tics;
for j := 1 to (fsub_tics-1) do
begin
vi := fxtics_coord_v[i]+dx*j;
if fzoom_bounds and (vi<fzoom_bounds[0] or vi>fzoom_bounds[1]) then continue;
subtks[idx++] := vi;
end
end
end
case ftics_direction of
tgc_top:
begin
draw_axis(cvs,subtks,1);
end
tgc_bottom:
begin
draw_axis(cvs,subtks,1+2);
end
tgc_left:
begin
draw_axis(cvs,subtks,0);
end
tgc_right:
begin
draw_axis(cvs,subtks,0+2);
end
end
end
protected
function draw_tics(cvs,info);virtual;
begin
for i,v in info do
begin
cvs.drawtext(v[0],v[1]);
end
end
function check_parent(p);override;
begin
return (not(p)) or (p is class(tg_compound)) or (p is class(tg_axes));
end
published
/////////////////////////////////////
property tics_direction read ftics_direction write set_tics_direction;//= "top"
property xtics_coord read fxtics_coord write set_xtics_coord ;//= [2,3,4,5,6,7]
property ytics_coord read fytics_coord write set_ytics_coord ;//= 4
property tics_segment read ftics_segment write set_tics_segment; // true,false
property tics_color read ftics_color write set_tics_color; // -1
property tics_style read ftics_style write set_tics_style; // = "v"
property sub_tics read fsub_tics write set_sub_tics; // = 2
property tics_labels read ftics_labels write set_tics_labels; // = ["2","3","4","5","6","7"]
private
fzoom_bounds;
fticksize;
fsubticksize;
fxtics_coord_v;
ftcmin;
ftcmax;
ftccount;
///////////////////////////////
ftics_direction;
fxtics_coord;
fytics_coord;
fsub_tics;
ftics_color;
ftics_segment;
ftics_style;
ftics_labels;
//format_n ;//= ""
//fractional_font ;//= "off"
//clip_state ;//= "off"
//clip_box ;//= []
//user_data ;//= []
//tag ;//= ""
private
function draw_axis(cvs,subtks,flg);
begin
pw := lineinfo.width;
tklen := fticksize+(pw>0?pw:0);
tklensub := fsubticksize+(pw>0?pw:0);
vtic := flg .& 1 ;
vtic2 := (flg .&2)?1:-1;
set_lineinfo_to_canvas(cvs);
set_fontinfo_to_canvas(cvs);
///////////////////轴线////////////////////////////////
if ftics_segment=tgc_on then
begin
if fzoom_bounds then
begin
if vtic then
begin
Coordinate_Mapping(fzoom_bounds[0],fytics_coord,0,x,y);
cvs.moveto(array(x,y));
Coordinate_Mapping(fzoom_bounds[1],fytics_coord,0,x,y);
cvs.lineto(array(x,y));
end
else
begin
Coordinate_Mapping(fytics_coord,fzoom_bounds[0],0,x,y);
cvs.moveto(array(x,y));
Coordinate_Mapping(fytics_coord,fzoom_bounds[1],0,x,y);
cvs.lineto(array(x,y));
end
end else
begin
for i,v in fxtics_coord_v do
begin
if vtic then
Coordinate_Mapping(v,fytics_coord,0,x,y);
else Coordinate_Mapping(fytics_coord,v,0,x,y);
if i=0 then
cvs.moveto(array(x,y));
else
cvs.lineto(array(x,y));
end
end
end
/////////////////////////////////////////////////////
//////////////////刻度线以及刻度值///////////////////////////////////////
tcsinfo := array();
if ifnumber(ftics_color) then cvs.pen.color := ftics_color;
for i,v in fxtics_coord_v do
begin
if fzoom_bounds and (v<fzoom_bounds[0] or v>fzoom_bounds[1]) then continue;
if vtic then
Coordinate_Mapping(v,fytics_coord,0,x,y);
else Coordinate_Mapping(fytics_coord,v,0,x,y);
lbi := ftics_labels[i];
cvs.moveto(array(x,y));
sz := nil;
if lbi then
begin
sz := array((length(lbi))*fontinfo.size+4,fontinfo.size*2+4) ;//cvs.GetTextExtent(lbi);
end
if vtic then
begin
ny := y+(vtic2*tklen);
cvs.lineto(array(x,ny));
if sz then
begin
rec := array(x-sz[0]/2,0,x+sz[0]/2,0);
if ny>y then
begin
rec[1] := ny+5;
rec[3] := ny+sz[1]+5;
end else
begin
rec[1] := ny-sz[1]-5;
rec[3] := ny-5;
end
end
tcsinfo[length(tcsinfo)] := array(lbi,rec,"h");
//draw_tics(cvs,lbi,rec);
//cvs.drawtext(lbi,rec);
end
else
begin
nx := x+(vtic2*tklen);
cvs.lineto(array(nx,y));
if sz then
begin
rec := array(0,y-sz[1]/2,0,y+sz[1]/2);
if nx>x then
begin
rec[0] := nx+5;
rec[2] := nx+sz[0]+5;
end else
begin
rec[0] := nx-sz[0]-5;
rec[2] := nx-5;
end
//draw_tics(cvs,lbi,rec);
tcsinfo[length(tcsinfo)] := array(lbi,rec,"v");
//cvs.drawtext(lbi,rec);
end
end
//cvs.textout(lbi,array(x,y));
end
if tcsinfo then draw_tics(cvs,tcsinfo);
/////////////////////////////////////////////////////////////////////////
////////////////////子刻度线////////////////////////////////////////////////
for i,v in subtks do
begin
if vtic then
Coordinate_Mapping(v,fytics_coord,0,x,y);
else Coordinate_Mapping(fytics_coord,v,0,x,y);
cvs.moveto(array(x,y));
if vtic then
cvs.lineto(array(x,y+(vtic2*tklensub)));
else
cvs.lineto(array(x+(vtic2*tklensub),y));
end
end
function set_zoom_bounds(v);
begin
if ifarray(v) and v[0]<v[1] then
begin
fzoom_bounds := array(v[0],v[1]);
end else
begin
fzoom_bounds := nil;
end
end
function set_tics_direction(v);
begin
if v<>ftics_direction and ( v in array(tgc_top,tgc_left,tgc_right,tgc_bottom)) then
begin
ftics_direction := v;
prop_changed("tics_direction",v);
end
end
function tc_to_label(v);
begin
return format("%f",v);//tostn(v);
end
function set_xtics_coord(v);
begin
if v<> fxtics_coord and ifarray(v) then
begin
case ftics_style of
tgc_tics_v:
begin
lbs := array();
for i,vi in v do
begin
if not ifnumber(vi) then return ;
lbs[i] := tc_to_label(vi);
end
ftcmin := minvalue(v);
ftcmax := maxvalue(v);
if ftcmin=ftcmax then return ;
ftccount := length(v)-1;
fxtics_coord := v;
fxtics_coord_v := v;
ftics_labels := lbs;
end
tgc_tics_r:
begin
if not(v[0]<v[1] and v[2]>=1) then return ;
fxtics_coord := v;
ftcmin := v[0];
ftcmax :=v[1];
ftccount := v[2];
type_c_to_r();
end
end;
fxtics_coord := v;
prop_changed("xtics_coord",v);
end
end
function set_ytics_coord(v);
begin
if v<> fytics_coord then
begin
fytics_coord := v;
prop_changed("ytics_coord",v);
end
end
function set_tics_segment(v);
begin
nv := v?true:false;
if ftics_segment<>v then
begin
ftics_segment := v;
prop_changed("tics_segment",v);
end
end
function set_tics_color(v);
begin
if ftics_color<>v then
begin
ftics_color := v;
prop_changed("tics_color",v);
end
end
function set_tics_style(v);
begin
if v<>ftics_style and( v in array(tgc_tics_v,tgc_tics_r)) then
begin
ftics_style := v;
case v of
tgc_tics_v:
begin
fxtics_coord := array();
for i,v in fxtics_coord_v do
begin
fxtics_coord[i] := v;
end
end
tgc_tics_r:
begin
fxtics_coord := array();
fxtics_coord[0] := ftcmin;
fxtics_coord[1] := ftcmax;
fxtics_coord[2] := ftccount;
type_c_to_r();
end
end ;
prop_changed("tics_style",v);
end
end
function type_c_to_r();
begin
fxtics_coord_v := array();
ftics_labels := array();
vidx := 0;
for x := ftcmin to ftcmax step (ftcmax-ftcmin)/ftccount do
begin
fxtics_coord_v[vidx] := x;
ftics_labels[vidx] := tc_to_label(x);
vidx++;
end
if x>=ftcmax then
begin
fxtics_coord_v[vidx-1] := ftcmax ;
ftics_labels[vidx-1] := tc_to_label(ftcmax) ;
end else
begin
fxtics_coord_v[vidx] := ftcmax ;
ftics_labels[vidx] := tc_to_label(ftcmax) ;
end
end
function set_sub_tics(v);
begin
if v>=0 and v<>fsub_tics then
begin
fsub_tics := v;
prop_changed("sub_tics",v);
end
end
function set_tics_labels(v);
begin
if ifarray(v) and v<>ftics_labels then
begin
ftics_labels:=v;
prop_changed("tics_labels",v);
end
end
end
type tg_text = class(tg_base)
public
function create(pms);
begin
inherited;
clip_state := tgc_off;
ftext := array();
fdata := array();
ffont_angle := 0;
end
function paint(cvs);override;
begin
if (visible<>tgc_on) then return ;
if not fdata then return ;
if not Coordinate_Mapping(fdata[0],fdata[1],fdata[2],x,y) then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
get_text_size(w,h,hi);
set_lineinfo_to_canvas(cvs);
if ffont_angle<>0 then
begin
cvs.SaveDC();
cvs.trans(-ffont_angle,x,y);
x := 0;
y := 0;
end
if line_mode then
begin
rc := array(x,y,x+w,y+h);
cvs.draw_rect().rect(rc).draw();
end
set_fontinfo_to_canvas(cvs);
for i,v in ftext do
begin
cvs.textout(v,array(x,y+i*hi));
end
if ffont_angle<>0 then
cvs.RestoreDC();
end
published
property text read ftext write set_text;
property data read fdata write set_data;
property font_angle read ffont_angle write set_font_angle;
private
ftext;
fdata;
ffont_angle;
private
function get_text_size(w,h,hi);
begin
fw := fontinfo.size;
fh := fw*2;
hi:=fh+2;
w := 0;
h := 0;
for i,v in ftext do
begin
si := v;
w := max(w,length(si)*fw);
h+=fh;
end
h+=2;
end
function set_text(v);
begin
tx := array();
for i,vi in v do
begin
if ifstring(vi) then tx[length(tx)] := vi;
end
if ftext<>tx then
begin
ftext :=tx;
prop_changed("text",tx);
end
end
function set_data(d);
begin
if fdata<>d and ifarray(d) and ifnumber(d[0]) and ifnumber(d[1]) then
begin
fdata := d;
prop_changed("data",d);
end
end
function set_font_angle(arg);
begin
if arg<>ffont_angle then
begin
ffont_angle := arg;
prop_changed("font_angle",arg);
end
end
end
type tg_label =class(tg_base) //标签对象
function create(pms);
begin
inherited;
clip_state := tgc_off;
ftext := false;
flocation := tgc_by_coordinates;
fposition := array(0,0);
ffill_mode := false;
ffont_angle := 0;
fauto_rotation := false;
end
function paint(cvs);override;
begin
if tgc_on<>visible then return ;
if not ftext then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
set_fontinfo_to_canvas(cvs);
p := fposition;
if fauto_position=tgc_on then
begin
p := fauto_position_value;
end else
begin
p := fposition;
end
case flocation of
tgc_by_axes:
begin
if not axes_mapping(p[0],p[1],0,x_,y_) then return ;
end else //tgc_by_coordinates:
begin
if not Coordinate_Mapping(p[0],p[1],0,x_,y_) then return ;
end
end
if ffont_angle<>0 then
begin
cvs.SaveDC();
cvs.trans(-ffont_angle,x_,y_);
cvs.textout(ftext,array(0,0));
cvs.RestoreDC();
end else
cvs.textout(ftext,array(x_,y_));
end
function executecommand(cmd,p);override;
begin
case cmd of
"auto_position_value":
begin
fauto_position_value := p;
return ;
end
end;
return inherited;
end
protected
function check_parent(p);override;
begin
return (not p) or (p is class(tg_axis));
end
published
property text read ftext write set_text;//= ""
property position read fposition write set_positon;//[-27.697388,-1.7130177]
property location read flocation write Set_location;
property auto_position read fauto_position write set_auto_position;//"on"
//property auto_position_value read fauto_position_value write fauto_position_value;//"on"
property auto_rotation read fauto_rotation write set_auto_rotation;//"on"
property font_angle read ffont_angle write set_font_angle;//90
//font_foreground ;//= 6
//foreground ;//= 9
//background ;//= 23
//fill_mode ;//= "off"
//font_style ;//= 6
//font_size ;//= 4
//fractional_font ;//= "off"
//font_angle ;//= 90
private
flocation;
ftext;
fposition;
fauto_position_value;
ffont_angle;
fauto_position;
fauto_rotation;
private
function Set_location(v);
begin
if flocation<>v and (v in array(tgc_by_axes,tgc_by_coordinates)) then
begin
flocation := v;
end
end
function set_auto_position(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fauto_position then
begin
fauto_position := nv;
prop_changed("auto_postion",nil);
end
end
function set_font_angle(v);
begin
if v<>ffont_angle and ifnumber(v) then
begin
ffont_angle := v;
prop_changed("font_angle",v);
end
end
function set_text(v);
begin
if ifstring(v) and v<>ftext then
begin
ftext := v;
prop_changed("text",nil);
end
end
function set_positon(v);
begin
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) and v[0]<>fposition[0] and v[1]<>fposition[1] then
begin
fposition[0] :=v[0];
fposition[1] :=v[1];
fauto_position := tgc_off;
prop_changed("postion",v);
end
end
function set_auto_rotation(v);
begin
if not tg_boolen_value(v,nv) then return ;
if fauto_rotation<>nv then
begin
fauto_rotation := nv;
prop_changed("auto_rotation",nv);
end
end
end
type tg_compound = class(tg_graph) //组合对象
function create(pms);
begin
inherited;
end
protected
function check_parent(p);override;
begin
return (not(p)) or (p is class(tg_compound)) or (p is class(tg_axes));
end
end
type tg_tips = class(tg_base) //提示
function create(pms);
begin
inherited;
flocation := tgc_by_coordinates;
fdisplay_components := "xy";
fbox_mode := tgc_on;
mark_mode := tgc_on;
markinfo.Style := tgc_mks_square;
markinfo.size := 5;
fline_style := 0;
fforeground := -1;
fbackground := -2;
fmark_style := 11;
fdata_idx := -1;
frow_mode := false;
end
function executecommand(cmd,pm);override;
begin
case cmd of
"fresh":
begin
FData := nil;
ftext :="";
f_ps := nil;
end
end
end
function paint(cvs);override;
begin
if tgc_on<>visible then return ;
p := parent;
if not p then return ;
d := get_data();
if ifnil(d) then return ;
ss := get_text();
if not ss then return ;
if not(f_ps and ifnumber(f_ps[0]) and ifnumber(f_ps[1])) then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
ws := 0;
hs := array();
w := fontinfo.size;
h := w*2;
for i,v in ss do
begin
ws := max(ws,length(v)*w+w);
hs[i] := h+4;
end
Coordinate_Mapping(d[0],d[1],z,x_,y_);
sz := array(ws,sum(hs));
if mark_mode = tgc_on then
begin
mk := markinfo;
msz := max(ceil(mk.size/2),2);
paint_marks(mk,cvs,array((x_,y_)));
end
case flocation of
tgc_in_upper_left: lc := 0;
tgc_in_upper_right: lc := 1;
tgc_in_lower_right: lc := 2;
tgc_in_lower_left: lc := 3;
else
lc := (fdata_idx+1) mod 3;//randomfrom(array(0,1,2,3));
end ;
rec := get_rect_at_corner(x_,y_,sz[0],sz[1],msz,lc);
if fbox_mode=tgc_on then
begin
set_lineinfo_to_canvas(cvs);
cvs.draw_rect.rect(rec).draw();
end
b_x := rec[0];
b_y := rec[1];
set_fontinfo_to_canvas(cvs);
for i,v in ss do
begin
rci := array(b_x,b_y,b_x+ws,b_y+hs[i]);
cvs.drawtext(v,rci);
b_y+=hs[i];
end
end
published
//property interp_mode read finterp_mode write finterp_mode; //"on"
property location read flocation write set_location;
property box_mode read fbox_mode write set_box_mode; //"on"
property display_components read fdisplay_components write set_display_components; //"xy"
property data_idx read fdata_idx write set_data_idx;
property display_function read fdisplay_function write fdisplay_function;
property text read get_text write set_text;
property data read get_data;
private
[weakref]fdisplay_function;
flocation;
fbox_mode;
//finterp_mode;
fdisplay_components;
fdata_idx;
ftext;
fdata;
//auto_orientation ;//= "on"
//orientation ;//= 3
//label_mode ;//= "on"
//data ;//= [66.064054,-1.3511706,0]
//display_components ;//= "xy"
//display_function ;//= ""
//text ;//= ["X:66.064";"Y:-1.351"]
//detached_position ;//= []
protected
function check_parent(p);override;
begin
return ifnil(p) or (p is class(tg_graph));
end
private
f_ps;
function init_display(tip,ps,txts);
begin
d := get_data();
if ifarray(d) and ifnumber(d[0]) and ifnumber(d[1]) then
begin
px := d[0];
py := d[1];
ps := array(px,py);
txts := array();
for i := 1 to length(fdisplay_components) do
begin
vi := fdisplay_components[i];
case vi of
"x","X":
begin
txts[length(txts)] := vi+format(":%f",px);
end
"y","Y":
begin
txts[length(txts)] := vi+format(":%f",py);
end
end ;
end
end
end
function set_text(txt);
begin
if get_text()<>txt and ifarray(txt) then
begin
ftext := array();
for i,v in txt do
begin
if ifstring(v) then
begin
ftext[idx++] := v;
end
end
end
end
function get_text();
begin
if ftext then return ftext;
if iffuncptr(display_function) then
begin
call(display_function,self(true),ps,txt);
f_ps := ps;
end else
begin
init_display(self(true),ps,txt);
f_ps := ps;
end
ftext := txt;
return ftext;
end
function get_data();
begin
if fdata then return FData;
if not(fdata_idx>=0) then return nil;
p := parent;
if p then
begin
FData := p.get_graph_data_by_idx(fdata_idx);
return fdata;
end
return nil;
end
function set_data_idx(idx);
begin
if ifnumber(idx) and idx<>fdata_idx then
begin
fdata_idx := idx ;
executecommand("fresh",pm);
end
end
function set_location(v);
begin
if v<>flocation then
begin
flocation := v;
prop_changed("location",nv);
end
end
function set_display_components(v);
begin
if not( v and ifstring(v)) then return ;
if d_comp_ok(v) and fdisplay_components<>v then
begin
fdisplay_components := v;
executecommand("fresh",pm);
end
end
function set_box_mode(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fbox_mode then
begin
fbox_mode := nv;
prop_changed("box_mode",nv);
end
end
function d_comp_ok(dcp);
begin
t := array("x":1,"y":1,"z":1);
for i := 1 to length(dcp) do
begin
vi := dcp[i];
if t[vi]<>1 then return false;
t[vi] := 2;
end
return true;
end
end
type tg_legend = class(tg_base) //图例
function create(pms);
begin
inherited;
clip_state := tgc_off;
flocation := tgc_in_upper_right;
flinks := array();
FText := array();
fposition := nil;
end
function paint(cvs);override;
begin
if tgc_on<>visible then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
get_lenged_sizes(lw,lh,ws,hs,objs,ss);
arec := cvs.axesrec;
rc := arec;
dis := 30;
cvs.axesunclip();
set_lineinfo_to_canvas(cvs);
case flocation of
tgc_upper_caption:
begin
x := arec[0];
y := arec[1];
mx := ceil((arec[2]-arec[0]-lw)/2)-dis;
rc := get_rect_at_corner(x,y,lw,lh,dis,2,mx);
cvs.draw_rect().rect(rc).draw();
end
tgc_lower_caption:
begin
x := arec[0];
y := arec[3];
mx := ceil((arec[2]-arec[0]-lw)/2)-dis;
rc := get_rect_at_corner(x,y,lw,lh,dis,1,mx);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_upper_right:
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,dis,3);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_upper_left:
begin
x := arec[0];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,dis,2);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_lower_left:
begin
x := arec[0];
y := arec[3];
rc := get_rect_at_corner(x,y,lw,lh,dis,1);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_lower_right:
begin
x := arec[2];
y := arec[3];
rc := get_rect_at_corner(x,y,lw,lh,dis,0);
cvs.draw_rect().rect(rc).draw();
end
tgc_by_coordinates: //根据位置信息设置处理
begin
if ifnil(fposition) then
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,0,3);
Coordinate_unMapping(rc[0],rc[1],_x,_y,_z);
fposition := array(_x,_y);
end else
begin
Coordinate_Mapping(fposition[0],fposition[1],0,_x,_y);
rc:= array(_x,_y,_x+lw,_y+lh);
end
cvs.draw_rect().rect(rc).draw();
end
tgc_by_axes:
begin
if ifnil(fposition) then
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,0,3);
axes_unmapping(rc[0],rc[1],_x,_y,_z);
fposition := array(_x,_y);
end else
begin
axes_mapping(fposition[0],fposition[1],0,_x,_y);
rc:= array(_x,_y,_x+lw,_y+lh);
end
cvs.draw_rect().rect(rc).draw();
end
end;
b_x := rc[0];
b_y := rc[1];
set_fontinfo_to_canvas(cvs);
for i,v in objs do
begin
hi := hs[i];
if v then
begin
rci := array(b_x,b_y,b_x+ws[0],b_y+hi);
v.paint_legend(cvs,rci);
end
si := ss[i];
if si then
begin
rci := array(b_x+ws[0],b_y,b_x+ws[0]+ws[1],b_y+hi);
cvs.drawtext(si,rci);
end
b_y+=hi;
end
cvs.axesclip();
end
published
property location read flocation write set_location;
property postion read fposition write set_postion;
property links read flinks write set_links;
property text read FText write set_text;
protected
function check_parent(p);override;
begin
return ifnil(p) or (p is class(tg_axes));
end
private
[weakref] flinks;
flocation;
FText;
fposition;
//text ;//= "y1"
//font_style ;//= 6
//font_size ;//= 1
//font_color ;//= -1
//fractional_font ;//= "off"
//links ;//= "Polyline" [] 数组
//legend_location ;//= "in_upper_right"
//position ;//= [0.7379099,0.1325]
//line_width ;//= 0.1
//line_mode ;//= "on"
//thickness ;//= 1
//foreground ;//= -1
//fill_mode ;//= "on"
//background ;//= -2
//marks_count ;//= 3
//clip_state ;//= "off"
//clip_box ;//= []
private
function get_lenged_sizes(lw,lh,ws,hs,objs,ss);
begin
ws := array(0,0);
hs := array();
w := fontinfo.size;
h := w*2;
objs := array();
ss := array();
for i:= 0 to max(length(flinks),length(ftext))-1 do
begin
vi := flinks[i];
si := ftext[i];
if vi is class(tg_graph) then
begin
objs[i] := vi;
vi.get_legend_size(w1,h1);
ws[0] := max(ws[0],w1);
end else
begin
h1 := 0;
objs[i] := 0;
end
if ifstring(si) then
begin
ws[1] := max(w*length(si)+2,ws[1]);
ss[i] := si;
end else
begin
ss[i] := nil;
end
hs[i] := max(h+4,h1);
end
lw := ws[0]+ws[1];
lh := sum(hs);
end
function set_postion(v);
begin
if fposition<>v and ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
fposition := array(v[0],v[1]);
prop_changed("postion",v);
end
end
function set_text(s);
begin
idx := 0;
flg := false;
for i,v in s do
begin
if not ifstring(v) then continue;
if v<>ftext[idx] then
begin
ftext[idx] := v;
flg++;
end
idx++;
end
if flg then prop_changed("text",s);
end
function set_links(vs);
begin
if ifarray(vs) and vs<>flinks then
begin
flinks := vs;
prop_changed("links_changed",vs);
end
end
function set_location(v);
begin
vs := static array(tgc_in_upper_right,tgc_in_upper_left,tgc_in_lower_right,tgc_in_lower_left,
//tgc_out_upper_right,tgc_out_upper_left,tgc_out_lower_right,tgc_out_lower_left,
tgc_upper_caption,tgc_lower_caption,
tgc_by_coordinates,tgc_by_axes);
if v<>flocation and (v in vs) then
begin
flocation := v;
end
end
end
type tg_graph_base = class(tg_base) //兼容绘图和goup两个类型
function create(pm);
begin
inherited;
end
function get_data_bounds();virtual; //获取数据边界
begin
return get_node_data_bounds(self(true));
end
end
type tg_graph = class(tg_graph_base) //绘图对象,包括数据,提示等内容
function create(pms);
begin
inherited;
fgraph_data := array();
end
function get_data_tips(); //获得数据提示对象
begin
r := array();
for i:= 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
if vi is class(tg_tips) then
begin
r[ridx++] := vi;
end
end
return r;
end
function get_legend_size(w,h);virtual;
begin
h := fontinfo.size+4;
w := 100;
end
function paint_legend(cvs,rec);virtual; //绘制图例
begin
end
function get_graph_data_by_idx(idx); //获取数据点
begin
return fgraph_data[idx];
end
property graph_data read fgraph_data write set_graph_data;
protected
fgraph_data;//数据
protected
function prop_changed(n,v);override;
begin
case n of
"data":
begin
for i,v in get_data_tips() do
begin
v.executecommand("fresh",nil);
end
ax := axes;
if ax then
ax.executecommand("data_changed");
end else
begin
inherited;
end
end ;
end
function set_graph_data(v);virtual;
begin
if v<>fgraph_data then
begin
fgraph_data := v;
prop_changed("data",v);
end
end
end
type tg_Polyline = class(tg_graph) //线图对象
function create(pms);
begin
inherited;
clip_state := tgc_on;
fclosed := tgc_off;
line_mode := tgc_on;
mark_mode := tgc_off;
fpolyline_style := tgc_LS_interpolated;// interpolated,staircase,barplot,arrowed,filled,bar
fbar_width := 0;
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override;
begin
return fdata_bounds;
end
function paint(cvs);override;
begin
if tgc_on<> visible then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
xys := array();
set_lineinfo_to_canvas(cvs);
for i,v in fgraph_data do
begin
if not Coordinate_Mapping(v[0],v[1],z,x,y) then return ;
xys[i] := array(integer(x),integer(y));
end
Coordinate_Mapping(0,0,0,x,y);
paint_lines(cvs,fpolyline_style,xys,fclosed,array("line_mode":line_mode,"bar_width":fbar_width,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor,"x":x,"y":y));
mk := markinfo;
if mark_mode=tgc_on and mk.size>2 then
begin
paint_marks(mk,cvs,xys);
end
inherited;
end
function get_legend_size(w,h);virtual;
begin
mk := markinfo;
h := fontinfo.size+4;
w := 100;
if mark_mode=tgc_on then
begin
h := max(10,mk.size+4);
w := 5*h;
end
end
function paint_legend(cvs,rec);override; //绘制图例
begin
y0 := ceil(rec[1]+(rec[3]-rec[1])/2);
dis := ceil((rec[2]-rec[0])/5);
xys := array((rec[0]+dis,y0),(rec[0]+4*dis,y0));
set_lineinfo_to_canvas(cvs);
paint_lines(cvs,tgc_LS_interpolated,xys,0,array("line_mode":line_mode,"bar_width":fbar_width,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor));
mk := markinfo;
if mark_mode=tgc_on and mk.size>2 then
begin
xys := array((rec[0]+dis*2,y0),(rec[0]+3*dis,y0));
paint_marks(mk,cvs,xys);
end
end
property closed read fclosed write fclosed;//= "off"
property polyline_style read fpolyline_style write set_polyline_style;//= "0"
property bar_width read fbar_width write fbar_width;//= "0"
private
fdata_bounds;
fclosed;
fforeground;
fbackground;
fpolyline_style;
fbar_width;
//datatips;//: ["Datatip";"Datatip"]
//datatip_display_mode;//: "always"
//display_function ;//= ""
//display_function_data ;//= []
//fill_mode ;//= "off"
//thickness ;//= 4
//arrow_size_factor ;//= 1
//interp_color_vector ;//= []
//interp_color_mode ;//= "off"
//colors ;//= []
//mark_offset ;//= 0
//mark_stride ;//= 1
//x_shift ;//= []
//y_shift ;//= []
//z_shift ;//= []
//bar_width ;//= 0
//clip_state ;//= "clipgrf"
//clip_box ;//= []
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
fx := d[:,0];
fy := d[:,1];
fdata_bounds[0,0] := minvalue(fx);
fdata_bounds[1,0] := minvalue(fy);
fdata_bounds[0,1] := maxvalue(fx);
fdata_bounds[1,1] := maxvalue(fy);
inherited;
end
end
private
function set_polyline_style(v);
begin
if v<>fpolyline_style then
begin
fpolyline_style := v;
end
end
end
type tg_line_info = class(tg_const)
function create();
begin
fcolor := 0;
FWidth := 1;
FStyle := tgc_PS_SOLID;
fbkcolor := nil;
end
property Style read FStyle write FStyle;
property width read FWidth write fwidth;
property size read FWidth write fwidth;
property color read fcolor write fcolor;
property bkcolor read fbkcolor write fbkcolor;
private
fwidth;
fcolor;
FStyle;
fbkcolor;
end
type tg_font_info = class(tg_const)
function create();
begin
fstyle := nil;
fsize := 7;
fforeground := 0;
fbackground := nil;
end
property style read fstyle write fstyle;
property size read fsize write fsize;
property color read fforeground write fforeground;
property bkcolor read fbackground write fbackground;
private
fstyle;
fsize;
fsize_unit;
fforeground;
fbackground;
end
type tg_mark_info = class(tg_const)
function create();
begin
fstyle := tgc_mks_dot;
fsize := 0;
fsize_unit := tgc_mk_point;
fforeground := 0;
fbackground := 0xffffff;
end
property style read fstyle write fstyle;
property size read fsize write fsize;
property size_unit read fsize_unit write fsize_unit;
property color read fforeground write fforeground;
property bkcolor read fbackground write fbackground;
private
fstyle;
fsize;
fsize_unit;
fforeground;
fbackground;
end
type tg_base = class(TNode,tg_const) //基类,提供层次关系结构
public
function create(pms);
begin
class(TNode).create();
fclip_state := tgc_on;
fvisibe := tgc_on;
fline_mode := tgc_off;
fmark_mode := tgc_off;
flineinfo := new tg_line_info();
fmarkinfo := new tg_mark_info();
ffontinfo := new tg_font_info();
end
function axes_mapping(x,y,z,_x,_y);virtual;
begin
p := get_axes();
if p then return p.axes_mapping(x,y,z,_x,_y);
return false;
end
function axes_unmapping(x,y,z,_x,_y);virtual;
begin
p := get_axes();
if p then return p.axes_unmapping(x,y,z,_x,_y);
return false;
end
function Coordinate_Mapping(x,y,z,_x,_y);virtual;
begin
p := get_axes();
if p then return p.Coordinate_Mapping(x,y,z,_x,_y);
return false;
end
function Coordinate_unMapping(x,y,x_,y_,z_);virtual;
begin
p := get_axes;
if p then return p.Coordinate_unMapping(x,y,x_,y_,z_);
return false;
end
function executecommand(cmd,pm);virtual;
begin
end
function paint(cvs);virtual; //绘制
begin
if tgc_on<> visible then return ;
for i := 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
vi.paint(cvs);
end
end
function set_lineinfo_to_canvas(cvs,info);
begin
if info is class(tg_line_info) then li := info;
else
li := lineinfo;
cl := li.color;
cvs.pen.style := li.style;
if ifnumber(cl) then
begin
cvs.pen.color := cl;
end else
begin
cvs.pen.Style := tgc_BS_NULL;
end
cvs.pen.width := li.width;
bcl := li.bkcolor;
if ifnumber(bcl) then
begin
cvs.brush.color := li.bkcolor;
cvs.brush.Style := tgc_BS_SOLID;
end
else
begin
cvs.brush.Style := tgc_BS_NULL;
end
end
function set_fontinfo_to_canvas(cvs,info);
begin
if info is class(tg_font_info) then fi := info;
else
fi := fontinfo;
cvs.font.color := fi.color;
cvs.font.bkcolor := fi.bkcolor;
cvs.font.width := fi.size;
cvs.font.height := fi.size*2;
end
published
property line_mode read fline_mode write set_line_mode;
property mark_mode read fmark_mode write set_mark_mode;
property clip_state read fclip_state write set_clip_state;
property axes read get_axes write set_axes;
property visible read fvisibe write setvisible;
property lineinfo read flineinfo;
property markinfo read fmarkinfo;
property fontinfo read ffontinfo;
public
user_data;
tag;
protected
function get_axes();virtual;
begin
p := parent;
if p then return p.axes;
end
function set_axes(axs);virtual;
begin
end
function check_parent(p);virtual; //父节点检查
begin
return true;
end
function prop_changed(n,v);virtual; //改变通知
begin
axs := get_axes();
if axs then fg := axs.figure;
if fg then
begin
fg.executecommand("figure_need_fresh",p);
end
end
function SetParent(V);virtual;
begin
if not check_parent(v) then return ;
if v then ct := v.NodeCount;
r := inherited;
if v then ct2 := v.NodeCount;
if ct2>ct then
begin
ax := axes;
if ax then ax.executecommand("node_add_in",self(true));
end
return r;
end
private
fclip_state;
fline_mode;
fmark_mode;
fvisibe;
flineinfo;
fmarkinfo;
ffontinfo;
function set_clip_state(v);
begin
if tg_boolen_value(v,nv) and (nv<>fclip_state) then
begin
fclip_state := nv;
prop_changed("clip_state",nv);
end
end
function set_line_mode(v);
begin
if tg_boolen_value(v,nv) and (nv<>fline_mode) then
begin
fline_mode := nv;
prop_changed("line_mode",nv);
end
end
function set_mark_mode(v);
begin
if tg_boolen_value(v,nv) and nv<>fmark_mode then
begin
fmark_mode := nv;
prop_changed("mark_mode",nv);
end
end
function setvisible(v);//设置可见
begin
if tg_boolen_value(v,nv) and (nv<>fvisibe) then
begin
fvisibe := nv;
prop_changed("visible",fvisibe);
end
end
end
type tg_const = class()
////////////基础///////////////////
static const tgc_off = "off";
static const tgc_on = "on";
static const tgc_box_off = "off";
static const tgc_box_on = "on";
static const tgc_box_half = "half";
/////////////坐标轴///////////////////
static const tgc_top = "top";
static const tgc_bottom = "bottom";
static const tgc_left = "left";
static const tgc_right = "right";
static const tgc_middle = "middle";
static const tgc_origin = "origin";
static const tgc_box_hidden_axes = "hidden_axes";
static const tgc_tics_v = "v";
static const tgc_tics_r = "r";
static const tgc_tics_i = "i";
//////标记类型//////////////////////
static const tgc_mks_dot = "dot"; //原点
static const tgc_mks_plus = "plus"; //加号
static const tgc_mks_star = "star"; //圈叉
static const tgc_mks_diamond = "diamond"; //正方形
static const tgc_mks_diamond_plus = "diamond_plus"; //正方形
static const tgc_mks_square = "square"; //正方形
static const tgc_mks_circle = "circle";//圆圈
static const tgc_mks_pentagram = "pentagram";//五角
static const tgc_mks_asterisk = "asterisk";//米字
static const tgc_mks_cross = "cross";//叉
static const tgc_mks_triangle_up = "triangle_up";
static const tgc_mks_triangle_down = "triangle_down";
static const tgc_mks_triangle_left = "triangle_left";
static const tgc_mks_triangle_right = "triangle_right";
static const tgc_mk_tabulated = "tabulated";
static const tgc_mk_point = "point";
/////////////////数据提示类型////////////////////////////////////
static const tgc_DT_always = "always";
static const tgc_DT_mouseclick = "mouseclick";
static const tgc_DT_mouseover = "mouseover";
////////////画笔画刷类型/////////////////////////////////
static const tgc_PS_SOLID=0x0;
static const tgc_PS_DASH=0x1;
static const tgc_PS_DOT=0x2;
static const tgc_PS_DASHDOT=0x3;
static const tgc_PS_DASHDOTDOT=0x4;
static const tgc_PS_NULL=0x5 ;
static const tgc_BS_NULL=1;
static const tgc_BS_SOLID=0;
///////////////////线型///////////////////////////////
static const tgc_LS_interpolated="interpolated";
static const tgc_LS_staircase="staircase";
static const tgc_LS_arrowed="arrowed";
static const tgc_LS_barplot="barplot";
static const tgc_LS_filled="filled";
static const tgc_LS_bar="bar";
/////////////////相对位置////////////////////////////
static const tgc_in_upper_right = "in_upper_right";
static const tgc_in_upper_left = "in_upper_left";
static const tgc_in_lower_right = "in_lower_right";
static const tgc_in_lower_left = "in_lower_left";
static const tgc_upper_caption = "upper_caption";
static const tgc_lower_caption = "lower_caption";
static const tgc_by_coordinates = "by_coordinates";
static const tgc_by_axes = "by_axes";
//static const tgc_out_upper_right = "out_upper_right";
//static const tgc_out_upper_left = "out_upper_left";
//static const tgc_out_lower_right = "out_lower_right";
//static const tgc_out_lower_left = "out_lower_left";
//////////////
end
implementation
function mg_bds(bds,d); //合并数据上下界
begin
d[0,0] := min(bds[0,0],d[0,0]);
d[0,1] := max(bds[0,1],d[0,1]);
d[1,0] := min(bds[1,0],d[1,0]);
d[1,1] := max(bds[1,1],d[1,1]);
d[2,0] := min(bds[2,0],d[2,0]);
d[2,1] := max(bds[2,1],d[2,1]);
end
function p_trans(x,y,ag,_x,_y);//旋转
begin
_x := x*cos(ag)+y*sin(ag);
_y := -x*sin(ag)+y*cos(ag);
end
function paint_lines(cvs,pls,xys,cls,ifo);//划线
begin
o := static new tg_const();
case pls of
o.tgc_LS_staircase:
begin
if ifo["line_mode"]<>o.tgc_on then return ;
last := array();
for i,v in xys do
begin
if i=0 then
begin
last := v;
cvs.moveto(v);
end else
begin
cvs.lineto(array(v[0],last[1]));
cvs.lineto(v);
last := v;
end
end
end
o.tgc_LS_barplot:
begin
for i,v in xys do
begin
cvs.moveto(array(v[0],v[1]));
cvs.lineto(array(v[0],ifo["y"]));
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
end
o.tgc_LS_bar:
begin
b_w := integer(ifo["bar_width"]/2);
cvs.brush.color := ifo["bkcolor"];
for i,v in xys do
begin
if b_w>=1 then
begin
v1 := array(v[0]-b_w,v[1]);
v2 := array(v[0]+b_w,v[1]);
v3 := array(v[0]+b_w,ifo["y"]);
v4 := array(v[0]-b_w,ifo["y"]);
cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw();
end else
begin
cvs.moveto(array(v[0],v[1]));
cvs.lineto(array(v[0],ifo["y"]));
end
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
end
o.tgc_LS_arrowed:
begin
if ifo["line_mode"]<>o.tgc_on then return ;
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
vlast := xys[0];
for i,v in xys do
begin
if i<1 then continue;
x := v[0];
y := v[1];
dx := x-vlast[0];
dy := y-vlast[1];
arg := arctan(dy/dx)+pi();
sz := 15;
p_trans(sz,0,-(arg-pi()/6),x1,y1);
cvs.moveto(v);
cvs.lineto(array(v[0]+x1,v[1]+y1));
p_trans(sz,0,-(arg+pi()/6),x1,y1);
cvs.moveto(v);
cvs.lineto(array(v[0]+x1,v[1]+y1));
vlast := v;
end
end
o.tgc_LS_filled:
begin
cvs.brush.color := ifo["color"];
for i,v in xys do
begin
if i=0 then continue;
v1 := v;
v2 := array(v[0],ifo["y"]);
v4 := xys[i-1];
v3 := array(v4[0],ifo["y"]);
cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw();
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,ifo);
end
else
begin
if ifo["line_mode"]<>o.tgc_on then return ;
cvs.draw_polyline().points(xys union ((cls=o.tgc_on and length(xys)>2)?array(xys[0]):array())).draw();
end
end
end
function paint_marks(mk,dc,xys); //绘制点
begin
o := static new tg_const();
tp := mk.Style;
sz := mk.size;
a := integer(sz/2);
b := max(a,(sz-a));
a := b;
dc.pen.Style := 0;
dc.pen.color := mk.color;
dc.brush.style := 0;
dc.brush.color := mk.bkcolor;
case tp of
o.tgc_mks_pentagram:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
vv := array();
for ii := 0 to 11 do
begin
if (ii mod 2)=1 then
begin
p_trans(0,-a/2,(ii*36)/180*pi(),_x,_y);
end else
p_trans(0,-a,(ii*36)/180*pi(),_x,_y);
vv[ii] := array(v[0]+_x,v[1]+_y);
end
sp.points(vv).draw();
end
end
o.tgc_mks_triangle_up:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0],v[1]-a);
p_trans(0,-a,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(0,-a,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_down:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0],v[1]+a);
p_trans(0,a,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(0,a,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_left:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0]-a,v[1]);
p_trans(-a,0,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(-a,0,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_right:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0]+a,v[1]);
p_trans(a,0,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(a,0,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_diamond_plus:
begin
mk.Style := o.tgc_mks_diamond ;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_diamond_plus;
end
o.tgc_mks_diamond:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y);
v2 := array(x+b,y);
v3 := array(x,y-a);
v4 := array(x,y+b);
sp.points(array(v1,v3,v2,v4)).draw();
end
end
o.tgc_mks_dot,o.tgc_mks_circle,o.tgc_mks_square:
begin
if tp=o.tgc_mks_dot then
dc.brush.color := mk.color;
if tp=o.tgc_mks_square then pse := dc.draw_rect();
else
pse := dc.draw_ellipse();
for i,v in xys do
begin
rec := array(v[0]-a,v[1]-a,v[0]+b,v[1]+b);
pse.rect(rec).draw();
end
end
o.tgc_mks_plus:
begin
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y);
v2 := array(x+b,y);
v3 := array(x,y-a);
v4 := array(x,y+b);
dc.moveto(v1);
dc.lineto(v2);
dc.moveto(v3);
dc.lineto(v4);
end
end
o.tgc_mks_star:
begin
mk.Style := o.tgc_mks_circle;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_star;
end
o.tgc_mks_cross:
begin
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y-a);
v2 := array(x+b,y+b);
v3 := array(x+b,y-a);
v4 := array(x-a,y+b);
dc.moveto(v1);
dc.lineto(v2);
dc.moveto(v3);
dc.lineto(v4);
end
end
o.tgc_mks_asterisk:
begin
mk.Style := o.tgc_mks_cross;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_asterisk;
end
end ;
end
function tg_boolen_value(v,nv); //规则化boolean
begin
if v=true or v="on" then
begin
nv := "on";
return true;
end else
if v=false or v="off" then
begin
nv := "off";
return true;
end
end
////////////////边界取整////////////////////////////
function new_bound_factor(a,n);
begin
if a>1 and a<=10 then
begin
return int(a)*10^n;
end else
if a>10 then
begin
n++;
return new_bound_factor(a/10,n);
end else
if a<=1 then
begin
n--;
return new_bound_factor(a*10,n);
end
end
function new_bounds(a,b,a_,b_,par);
begin
a_ := a;
b_ := b;
if not(par>=1) then par:=20;//20;
r := new_bound_factor((b-a)/par,n);
if r<>0 then
begin
a_:=floor(a/r)*r;
b_:= ceil(b/r)*r;
end
return r;
end
function get_node_data_bounds(nd); //获取节点的范围
begin
d := zeros(3,2);
for i := 0 to nd.NodeCount-1 do
begin
vi := nd.GetNodeByIndex(i);
if vi is class(tg_graph_base) then
begin
bds := vi.get_data_bounds();
mg_bds(bds,d);
end
end
return d;
end
function get_rect_at_corner(x,y,w,h,itv,flg,mvx,mvy); //计算围绕点的区域位置
begin
//0左上 1右上 2 右下 3 左下
r := zeros(4);
case flg of
0:
begin
r[0] :=x-w-itv;
r[1] :=y-h-itv;
r[2] :=x-itv;
r[3] :=y-itv;
end
1:
begin
r[0] :=x+itv;
r[1] :=y-h-itv;
r[2] :=x+w+itv;
r[3] :=y-itv;
end
2:
begin
r[0] :=x+itv;
r[1] :=y+itv;
r[2] :=x+w+itv;
r[3] :=y+h+itv;
end
3:
begin
r[0] :=x-w-itv;
r[1] :=y+itv;
r[2] :=x-itv;
r[3] :=y+h+itv;
end
4: //中
begin
w2 := ceil(w/2);
h2 := ceil(h/2);
r[0] :=x-w2;
r[1] :=y-h2;
r[2] :=x+w2;
r[3] :=y+h2;
end
end;
if mvx>0 or mvx<0 then
begin
r[0]+=mvx;
r[2]+=mvx;
end
if mvy>0 or mvy<0 then
begin
r[1]+=mvy;
r[3]+=mvy;
end
return r;
end
function rec_to_points(rec);
begin
return array(rec[array(0,1)],rec[array(2,1)],rec[array(2,3)],rec[array(0,3)],rec[array(0,1)]);
end
////////////////////////////////////////
initialization
finalization
end.