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]=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(); r := array(p_left-1,p_top-1,p_left+p_width+1,p_top+p_height+1); o := new TCanvsRgnClipAutoSave(cvs,r); inherited; o := nil; 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 if fclosed and length(xys)>2 then cvs.draw_polyline().points( xys union xys[0:0]).draw(); else 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.