tslediter/funcext/tvclib/utvclgraphics.tsf

1790 lines
52 KiB
Plaintext

unit utvclgraphics;
interface
uses utslvclauxiliary;
//tsl绘图库
//20240126
{
//////////////////绘图范例//////////////////////////
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 tcustomfigure(self);
fg.Caption := "hello1";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg;
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.data := d;
line.parent := axs;
end
fg;
end
}
type tcustomfigure = class(tcustomcontrol,tg_const) //绘图窗口
function create(AOwner);
begin
inherited;
faxeses := new tnumindexarray();
end
function paint();override; //绘制
begin
for i,v in faxeses.data do
begin
v.axes_paint_rect_changd();
v.paint(canvas);
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 Recycling();override;
begin
for i,v in faxeses.data do
begin
v.figure := nil;
end
inherited;
end
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
fwilladdaxs;
fwilldelaxs;
faxeses;
end
type tg_axis_main = class(tg_axis) //主轴
public
function create(pms);
begin
inherited;
end
protected
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
faxes := axs;
end
private
[weakref] faxes;
end
type tg_label_axes = class(tg_label) //坐标系标签
public
function create(pms);
begin
inherited;
auto_position := tgc_on;
end
protected
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
faxes := axs;
end
private
[weakref] faxes;
end
type tg_axis = class(tg_base) //轴对象
function create(pms);
begin
inherited;
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_t_s_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);virtual;
begin
case cmd of
"get_tics_value":return fxtics_coord_v;
end;
end
function paint(cvs);override;
begin
if not visible then return ;
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
subtks[idx++] := fxtics_coord_v[i]+dx*j;
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 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
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
tklen := fticksize;
tklensub := fsubticksize;
vtic := flg .& 1 ;
vtic2 := (flg .&2)?1:-1;
cvs.pen.width := lineinfo.width;
cvs.pen.color := lineinfo.color;
cvs.pen.style := lineinfo.style;
cvs.font.color := fontinfo.color;
cvs.font.bkcolor := fontinfo.bkcolor;
cvs.font.width := fontinfo.size;
cvs.font.height := fontinfo.size*2;
if ftics_segment=tgc_on then
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
if ifnumber(ftics_color) then cvs.pen.color := ftics_color;
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);
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
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
cvs.drawtext(lbi,rec);
end
end
//cvs.textout(lbi,array(x,y));
end
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_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("%.2f",v);//tostn(v);
end
function set_xtics_coord(v);
begin
if v<> fxtics_coord and ifarray(v) then
begin
case ftics_style of
tgc_t_s_v:
begin
lbs := array();
for i,vi in v do
begin
if not ifnumber(vi) then return ;
lbs[i] := tc_to_label(v);
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_t_s_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
nv := v?true:false;
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_t_s_v,tgc_t_s_r)) then
begin
ftics_style := v;
case v of
tgc_t_s_v:
begin
fxtics_coord := array();
for i,v in fxtics_coord_v do
begin
fxtics_coord[i] := v;
end
end
tgc_t_s_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_label =class(tg_base) //标签对象
function create(pms);
begin
inherited;
ftext := false;
fposition := array(0,0);
fauto_position_value := array(0,0);
ffill_mode := false;
ffont_angle := 0;
fauto_position := tgc_off;
fauto_rotation := false;
end
function paint(cvs);override;
begin
if not visible then return ;
if not ftext then return ;
cvs.font.width := fontinfo.size;
cvs.font.height := fontinfo.size*2;
cvs.font.color := fontinfo.color;
if fauto_position=tgc_on then
begin
p := fauto_position_value;
end else
begin
p := fposition;
end
if Coordinate_Mapping(p[0],p[1],0,x_,y_) then
begin
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
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 auto_position read fauto_position write set_auto_position;//"on"
property auto_postion_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
ftext;
fposition;
fauto_position_value;
ffont_angle;
fauto_position;
fauto_rotation;
private
function set_auto_position(v);
begin
if not(tgc_off=v or tgc_on=v) then return ;
if v<>fauto_position then
begin
fauto_position := v;
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 fauto_rotation<>v and (v in array(tgc_on,tgc_off)) then
begin
fauto_rotation := v;
prop_changed("auto_rotation",v);
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_axes = class(tg_graph) //坐标系
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;
///////////////////////////////////////////
public
function Coordinate_unMapping(x,y,_x,_y,_z);override; //画布到坐标
begin
if not(fFigure and fFigure.HandleAllocated()) then return 0;
if faxes_reverse[0]=tgc_on then //x轴
begin
_x := fdata_bounds[0,0]-(x-p_left-p_width)/rt_x;
end else
begin
_x := (x-p_left)/rt_x+fdata_bounds[0,0];
end
if faxes_reverse[1]=tgc_on then //y轴
begin
_y := (y-p_top)/rt_y +fdata_bounds[1,0];
end else
begin
_y := fdata_bounds[1,0]-(y-p_top-p_height)/rt_y;
end
return true;
end
function Coordinate_Mapping(x,y,z,_x,_y);override; //坐标到画布
begin
if not(fFigure and fFigure.HandleAllocated()) then return 0;
if faxes_reverse[0]=tgc_on then //x轴
begin
_x := p_left+p_width-(x-fdata_bounds[0,0])*rt_x;
end else
begin
_x := (x-fdata_bounds[0,0])*rt_x+p_left;
end
if faxes_reverse[1]=tgc_on then //y轴
begin
_y := (y-fdata_bounds[1,0])*rt_y+p_top;
end else
begin
_y := p_top+p_height-(y-fdata_bounds[1,0])*rt_y;
end
return true;
end
function paint(cvs);override;
begin
if not visible then return ;
modify_coordinate_postion();
inherited;
paint_grid(cvs);
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
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_paint_rect_changd(); //绘制区域改变
begin
fr := fFigure.clientrect;
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];
merge_graph_data_bounds();
axes_data_bounds_changed();
end
function axes_data_bounds_changed(); //数据区域
begin
dx_min := fdata_bounds[0,0];
dx_max := fdata_bounds[0,1];
dx_len := dx_max-dx_min;
dy_min := fdata_bounds[1,0];
dy_max := fdata_bounds[1,1];
dy_len := dy_max-dy_min;
rt_x := p_width/ dx_len;
rt_y := p_height/dy_len;
end
function merge_graph_data_bounds();//数据区域
begin
d := get_data_bounds();
fdata_bounds := d;
faxes_objects[0].xtics_coord := array(d[0,0],d[0,1],10);
faxes_objects[1].xtics_coord := array(d[1,0],d[1,1],10);
end
function create(pms);
begin
inherited;
fgrid := array();
for i:= 0 to 1 do
begin
gd := new tg_line_info();
gd.width := 0;
gd.Style := tgc_PS_DASH;
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_t_s_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("on","on","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 := array();
//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 fzoom_box write fzoom_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;
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
cvs.pen.width :=xg.width;
cvs.pen.color := xg.color;
cvs.pen.Style := xg.Style;
y1 := p_top;
y2 := p_top+p_height;
for i,v in faxes_objects[0].executecommand("get_tics_value") do
begin
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
cvs.pen.width :=xg.width;
cvs.pen.color := xg.color;
cvs.pen.Style := xg.Style;
x1 := p_left;
x2 := p_left+p_width;
for i,v in faxes_objects[1].executecommand("get_tics_value") do
begin
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 get_tics(tk);
begin
r := array();
rd := tk.xtics_coord;
case tk.tics_style of
tgc_t_s_v:
begin
end
else //tgc_t_s_r:
begin
end
end
end
function modify_label_postion(); //修正标签位置
begin
if fx_label and fx_label.visible and fx_label.text then
begin
s := fx_label.text;
if s then
begin
x := p_left+(p_width-length(s)*10)/2;
Coordinate_unMapping(x,p_top+p_height+40,_x,_y,_z);
p := array(_x,_y);
fx_label.auto_postion_value := p;
end
end
if fy_label and fy_label.visible and fy_label.text then
begin
s := fy_label.text;
if s then
begin
y := p_top+(p_height-length(s)*10)/2;
if (fy_location= tgc_left) then x := p_left+p_width+40;
else
x := p_left-40;
Coordinate_unMapping(x,y,_x,_y,_z);
p := array(_x,_y);
fy_label.auto_postion_value := p;
end
end
if ftitle and ftitle.visible then
begin
s := ftitle.text;
if s then
begin
x := p_left+(p_width-length(s)*10)/2;
Coordinate_unMapping(x,p_top-40,_x,_y,_z);
p := array(_x,_y);
ftitle.auto_postion_value := p;
end
end
end
function modify_coordinate_postion();
begin
case fy_location of
tgc_left:
begin
faxes_objects[1].ytics_coord := fdata_bounds[0,(faxes_reverse[0] = tgc_on)];
end
tgc_right:
begin
faxes_objects[1].ytics_coord := fdata_bounds[0,(faxes_reverse[0]<> tgc_on)];
end
tgc_middle:
begin
faxes_objects[1].ytics_coord := fdata_bounds[0,0]+(fdata_bounds[0,1]-fdata_bounds[0,0])/2;
end
tgc_origin:
begin
faxes_objects[1].ytics_coord := 0;
end
end ;
case fx_location of
tgc_bottom:
begin
faxes_objects[0].ytics_coord := fdata_bounds[1,(faxes_reverse[1]= tgc_on)];
end
tgc_top:
begin
faxes_objects[0].ytics_coord := fdata_bounds[1,(faxes_reverse[1]<> tgc_on)];
end
tgc_middle:
begin
faxes_objects[0].ytics_coord := fdata_bounds[1,0]+(fdata_bounds[1,1]-fdata_bounds[1,0])/2;
end
tgc_origin:
begin
faxes_objects[0].ytics_coord := 0;
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));
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(tcustomfigure) then //添加
begin
fwilladdfigure := v;
v.add_axes(self(true));
fwilladdfigure := nil;
end else
begin
fFigure := nil;
end
end
function set_filled(v);
begin
if (v in array(tgc_on,tgc_off)) and v<>fbox then
begin
ffilled := v;
prop_changed("ffilled",v);
end
end
function set_box(v);
begin
if (v in array(tgc_box_on,tgc_box_on,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("x_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
if v=tgc_on or v=tgc_off then
begin
if idx in array(0,1,2) then
begin
if fauto_ticks[idx]<>v then
begin
fauto_ticks[idx] := 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]);
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 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;
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_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;
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;
//prop_changed("axes_visible",idx);
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_tips = class(tg_base)
function create(pms);
begin
inherited;
finterp_mode := tgc_off;
fbox_mode := tgc_on;
fline_style := 0;
fforeground := -1;
fbackground := -2;
fmark_mode := tgc_on;
fmark_style := 11;
end
property interp_mode read finterp_mode write finterp_mode; //"on"
property box_mode read fbox_mode write fbox_mode; //"on"
private
fbox_mode;
finterp_mode;
//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"]
//font_foreground ;//= -1
//font_style ;//= 6
//font_size ;//= 1
//detached_position ;//= []
//mark_size_unit ;//= "point"
//mark_size ;//= 8
//mark_foreground ;//= -3
//mark_background ;//= -2
end
type tg_legend = class(tg_base)
function create(pms);
begin
inherited;
end
//parent Axes
//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 ;//= []
end
type tg_graph = class(tg_base)
function create(pms);
begin
inherited;
end
function get_data_bounds();virtual;
begin
d := zeros(3,2);
for i := 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
if vi is class(tg_graph) then
begin
bds := vi.get_data_bounds();
mg_bds(bds,d);
end
end
return d;
end
end
type tg_Polyline = class(tg_graph)
function create(pms);
begin
inherited;
fclosed := tgc_off;
//fmark_style :=tgc_mks_dot ;//= 9
//fmark_size_unit := "point";//= "point","tabulated"
//fmark_size :=0;//= 0
//fmark_foreground := 16;//= 16
//fmark_background := 15;//= 15
//fforeground := 33 ;//= 33
//fbackground := 26 ;//= 26
fline_mode := tgc_on;
fmark_mode := tgc_on;
fpolyline_style := tgc_LS_interpolated;// interpolated,staircase,barplot,arrowed,filled,bar
fbar_width := 0;
fdata_bounds := array((0,10),(0,10),(0,10));
end
function get_data_bounds();override;
begin
return fdata_bounds;
end
function paint(cvs);override;
begin
if not visible then return ;
xys := array();
if fline_mode=tgc_on then
begin
cvs.pen.Style := lineinfo.Style;
cvs.pen.color := lineinfo.color;
cvs.pen.width := lineinfo.width;
for i,v in fdata do
begin
if not Coordinate_Mapping(v[0],v[1],z,x,y) then return ;
xys[i] := array(integer(x),integer(y));
end
case fpolyline_style of
tgc_LS_staircase:
begin
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
else
begin
cvs.draw_polyline().points(xys).draw();
end
end;
mk := markinfo;
if mark_mode=tgc_on and mk.size>2 then
begin
paint_marks(mk,cvs,xys);
end
end
end
property closed read fclosed write fclosed;//= "off"
//property mark_style read fmark_style write fmark_style;//= "dot"
//property mark_size_unit read fmark_size_unit write fmark_size_unit;//= "point"
//property mark_size read fmark_size write fmark_size;//= "0"
//property mark_foreground read fmark_foreground write fmark_foreground;//= "0"
//property foreground read fforeground write fforeground;//= "0"
//property mark_background read fmark_background write fmark_background;//= "0"
//property background read fbackground write fbackground;//= "0"
property line_mode read fline_mode write fline_mode;//= "0"
property mark_mode read fmark_mode write fmark_mode;//= "0"
property polyline_style read fpolyline_style write fpolyline_style;//= "0"
property bar_width read fbar_width write fbar_width;//= "0"
property data read fdata write set_data;
private
fdata_bounds;
fclosed;
fmark_size_unit;
fmark_style;
fmark_size;
fmark_foreground;
fmark_background;
fforeground;
fbackground;
fline_mode;
fmark_mode;
fpolyline_style;
fbar_width;
fdata;//数据
//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 ;//= []
private
fx;
fy;
function set_data(d); //设置数据
begin
if d<>FData then
begin
FData := d;
fx := fdata[:,0];
fy := fdata[:,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);
prop_changed("data",v);
end
end
end
type tg_line_info = class(tg_const)
function create();
begin
fcolor := 0;
FWidth := 1;
FStyle := tgc_PS_SOLID;
end
property width read FWidth write fwidth;
property color read fcolor write fcolor;
property Style read FStyle write FStyle;
private
fwidth;
fcolor;
FStyle;
end
type tg_font_info = class(tg_const)
function create();
begin
fstyle := tgc_mks_dot;
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();
fvisibe := true;
flineinfo := new tg_line_info();
fmarkinfo := new tg_mark_info();
ffontinfo := new tg_font_info();
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 not visible then return ;
for i := 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
vi.paint(cvs);
end
end
published
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;
protected
function get_axes();virtual;
begin
p := parent;
if p then return p.axes;
end
function set_axes(axs);virtual;
begin
end
public
user_data;
tag;
protected
function check_parent(p);virtual; //父节点检查
begin
return true;
end
function prop_changed(n,v);virtual; //改变通知
begin
end
function SetParent(V);virtual;
begin
if not check_parent(p) then return ;
return inherited;
end
private
fvisibe;
flineinfo;
fmarkinfo;
ffontinfo;
function setvisible(v);//设置可见
begin
nv := v?true:false;
if nv<>fvisibe then
begin
fvisibe := nv;
prop_changed("visible",fvisibe);
end
end
end
type tg_const = class()
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_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_box_hidden_axes = "hidden_axes";
static const tgc_t_s_v = "v";
static const tgc_t_s_r = "r";
static const tgc_t_s_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_dm_always = "always";
static const tgc_dm_mouseclick = "mouseclick";
static const tgc_dm_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_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" ;
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_marks(mk,dc,xys);
begin
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.color := mk.bkcolor;
case tp of
"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
"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
"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
"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
"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
"diamond_plus":
begin
mk.Style := "diamond";
paint_marks(mk,dc,xys);
mk.Style := "plus";
paint_marks(mk,dc,xys);
mk.Style := "diamond_plus";
end
"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
"dot","circle","squre":
begin
if tp="dot" then
dc.brush.color := mk.color;
if tp="squre" 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
"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
"star":
begin
mk.Style := "circle";
paint_marks(mk,dc,xys);
mk.Style := "plus";
paint_marks(mk,dc,xys);
mk.Style := "star";
end
"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
"asterisk":
begin
mk.Style := "cross";
paint_marks(mk,dc,xys);
mk.Style := "plus";
paint_marks(mk,dc,xys);
mk.Style := "asterisk";
end
end ;
end
initialization
finalization
end.