Click here to Skip to main content
Click here to Skip to main content
Go to top

Canvas implementation for C#

, 21 Mar 2004
Rate this:
Please Sign up or sign in to vote.
Design and implementation of canvas in C#

Introduction

In many different applications, graphical input is needed. Along with creating new graphical objects such as lines, rectangles and polygons, objects editing and viewing in different scale are required. In some cases, graphics events such as shape creation, selection and moving should be bound to some application logic.

Canvas or graphical editor is a component that provides an application with such functionality.

Background

Canvas control or widget is a component containing different types of graphical objects responsible for its viewing and editing.

Most of the GUI toolkits have their own canvas components. For example, there are canvases in Qt toolkit, Borland C++ Builder and Tcl/Tk. Somehow, it’s missing in .NET.

For canvas implementation and functionality, I use my experience with Qt and Tcl/Tk toolkits. In both toolkits, canvas provides rich functionality to create and manipulate graphical objects.

In both toolkits, scaling and translating of canvas affects geometry of graphical objects stored inside. It’s inconvenient when you're storing “real world“ measurements in your canvas, so each time you edit it in the canvas, you should keep track on changes of the “real world” coordinate system.

To avoid this inconvenience, this implementation is logically divided to geometrical model and view. When you're editing objects inside the canvas, geometrical model (presented in “real world” coordinates) is changing and the view (client coordinates) stays the same, and when you rescale and scroll the canvas, the geometrical model stays unchanged.

Canvas geometrical model could have several views showing different parts of the model. All views are updated automatically when the model changes, it means that if you moving or editing shape in one of the views you will see changes in others.

Using canvas

Canvas is implemented in Canvas.cs file in CanvasControl namespace.

Example how to use it is in CanvasDemo.cs file.

To create a new Canvas and connect to its events:

// create new canvas
canvas1 = new CanvasControl.Canvas();
// connect listeners to canvas events
canvas1.CoordChangeEvent += new
  CanvasControl.Canvas.CoordChangeEventHandler(OnCoordChainged);
canvas1.ItemNewEvent += new
  CanvasControl.Canvas.ItemEventHandler(OnNewCanvasItem);
canvas1.ItemEnterEvent += new
  CanvasControl.Canvas.ItemEventHandler(OnEnterCanvasItem);

where:

CoordChangeEvent event is generated when cursor moves inside the Canvas. A second parameter of the event handler CoordChangeEventHandler contains coordinates of the cursor and R,G,B values of the background image.

public void OnCoordChainged(object sender, 
CanvasControl.CoordEventArgs e)
{
    textBox1.Text = e.X.ToString() + "," + e.Y.ToString();
}

ItemNewEvent and ItemEnterEvent – events are generated when cursor enters and leaves graphical object. The second parameter contains ID (index) of the object. Graphical object could be accessed by its ID.

public void OnEnterCanvasItem(object sender, 
CanvasControl.ItemEventArgs e)
{
    textBox3.Text = e.indx.ToString();
}

In order to create additional view of existing Canvas (its geometrical model) we should create second Canvas, say canvas2 and attach it to previous one:

canvas2 = new CanvasControl.Canvas();
canvas2.setGeomModel(canvas1.getGeomModel());

Canvas itself does not contain other graphical controls, it’s controlled by its API. But there is an option to connect Scrollbar controls to update scrollbars controls during canvas navigation.

canvas1.connectScrolls(hScrollBar1,vScrollBar1);

To create, move or select graphical objects, we need to change Canvas state as follows:

// create graphical objects
canvas1.CreateRectangle();

canvas1.CreateLine();

canvas1.CreatePolygon();

// move objects
canvas1.StartMoving();
// select objects
canvas1.StartSelection();

Graphical object could be accessed by its ID and geometrical and other properties could be retrieved or updated. In the function bellow, ID-s of selected items are retrieved and updated with user defined color.

private void btnColor_Click(object sender, System.EventArgs 
e)
{
        ColorDialog colorDialog = new ColorDialog();
        if(colorDialog.ShowDialog() != DialogResult.OK)
                 return;

        Color color = colorDialog.Color;
        int [] selected = canvas1.GetSelected();
        foreach(int i in selected)
        {
                 CanvasControl.CanvasItem item = canvas1.GetItem(i);
                 item.Icolor = color;
                 item.select(false);
        }

        canvas1.Invalidate();
        canvas1.Update();
}

You can create your own geometrical object, to do it, you should implement CanvasItem interface (see Canvas.cs file) and use Canvas.AddShape method to put it into the canvas.

Design issues

Several design patterns are used in the design of the canvas.

Template pattern is used in CanvasItem class to implement some shapes common functionality in the base class.

Observer pattern is used to notify subscribers about canvas changes, it's implemented using C# events.

Facade pattern is used to hide internal canvas objects from the user.

In the class diagram above classes creating canvas contol are presented

  • Canvas - encapsulates view of the canvas control (Model/View pattern). Canvas is syncronized with geometrical model CanvasGeomModelvia C# events. Every time the model had changed the model generates ItemChangedEvent or ModelChangedEvent forcing canvas update the view. Each time the view Canvas needs to display the model, it calls draw method of CanvasGeomModel specifying graphical context (or painter object) Graphics and a Matrix transformaion between "client" coordinate system of view and "real world" coordinate system of the model. Eventually from CanvasGeomModel draw request is delegated to concreat shapes, which implement CanvasItem draw interface to draw itself on the view.
  • CanvasGeomModel - encapsulates geometrical model of the canvas control. It is responsable for storing, editing and displaying of different shapes, derived from CanvasItem class. Geometrical objects are represented in the model in "real world" coordinates independently from "client" coordinates of different views.
  • CanvasItem - encapsulates common behavior of geometrical objects or shapes stored in geometrical model CanvasGeomModel. It represents interface using by Canvas to manipulate and display differents types of shapes. In order to create new shape one should implement methods defined in CanvasItem interface.
      public class LineCanvasItem : CanvasItem
      {
        public float x1;
        public float y1;
        public float x2;
        public float y2;
        private bool is_selected = false;
    
        // construct from 2 points coordinates
        public LineCanvasItem(float x_1,float y_1,float x_2,float y_2)
        {
          x1 = x_1;
          y1 = y_1;
          x2 = x_2;
          y2 = y_2;
        }
        // returns true if item is selected
        public override bool isSelected()
        {
          return is_selected;
        }
        // select item
        public override void select(bool m)
        {
          is_selected = m;
        }
        // returns true if the item is within the distanse
        public override bool isCloseToPoint(PointF pnt,float dist)
        {
          double curr_dist = Geom.segmentToPointSqrDist(
            new PointF(x1,y1),new PointF(x2,y2),pnt);
    
          return Math.Sqrt(curr_dist) < dist;
        }
        // return bounding box of the item
        public override RectangleF boundingBox()
        {
          return new RectangleF(x1,y1,x2-x1,y2-y1);
        }
        // start point X coordinate of the shape
        public override float X()
        {
          return x1;
        }
        // start point Y coordinate of the shape
        public override float Y()
        {
          return y1;
        }
        // move shape to specified location
        public override void move(PointF p)
        {
          float dx = p.X-x1;
          float dy = p.Y-y1;
    
          x1 += dx;
          y1 += dy;
    
          x2 += dx;
          y2 += dy;
        }
        // move shape by specified shift
        public override void moveBy(float xs,float ys)
        {
          x1+=xs;
          y1+=ys;
    
          x2+=xs;
          y2+=ys;
        }
        // draw shape on the view
        public override void draw(Graphics graph,
            System.Drawing.Drawing2D.Matrix trans)
        {
          // transform points to "client" view coordinate system
          PointF [] points = {new PointF(x1,y1), new PointF(x2,y2)};
          trans.TransformPoints(points);
    
          // draw line in "client" coordinate system
          if(is_selected)
            graph.DrawLine(new Pen(Color.Cyan),
              (int)points[0].X,(int)points[0].Y,
              (int)points[1].X,(int)points[1].Y);
          else
            graph.DrawLine(new Pen(Icolor),(int)points[0].X,
              (int)points[0].Y,
              (int)points[1].X,(int)points[1].Y);
        }
      }
            
    Then Canvas.AddShape method should be used to add new shape to the canvas:
     canvas1.AddShape(new LineCanvasItem(10,10,100,100));        
  • Geom - Geometrical procedures used in Canvas.

History

  • 28/02/2004 Initial version.
  • 17/03/2004 Geometrical model separated from canvas view + design explanations.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Eduard Baranovsky
Web Developer
Canada Canada
Baranovsky Eduard has been a software developer for more then 10 years. He has an experence in image processing, computer graphics and distributed systems design.

Comments and Discussions

 
QuestionSave canvas with drawing PinmemberSukirtiShetty1-Mar-14 0:53 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 21:39 
Generaldraw line between 2 points GDAL PinmemberThabet Tech17-Jun-09 4:13 
QuestionDocumentation Pinmembergilles berbey25-Oct-07 12:02 
GeneralNeeds zoom to region PinmemberThomas West6-Apr-05 10:50 
GeneralScrollbars and scrolling PinmemberThomas West5-Apr-05 14:48 
GeneralRe: Scrollbars and scrolling Pinmemberjamesyla16-Sep-09 18:56 
GeneralException throw in designer PinmemberKarim Shehadeh9-Nov-04 15:31 
GeneralRe: Exception throw in designer PinmemberEduard Baranovsky10-Nov-04 7:27 
GeneralRe: Exception throw in designer PinmemberKarim Shehadeh10-Nov-04 7:40 
QuestionRe: Exception throw in designer PinmemberarielProgramador4-May-06 9:39 
Hi Eduard, nice app! I would like to know if you have the new version of Canvas with support for circles ?
 
Regards and thanks!
Ariel
AnswerRe: Exception throw in designer PinmemberEduard Baranovsky10-May-06 7:57 
GeneralMoveTo on Map PinmemberThomas West5-Oct-04 14:09 
GeneralIs there any way we can save Canvas information to a database PinmemberThomas Ushus18-Sep-04 1:09 
GeneralRe: Is there any way we can save Canvas information to a database PinmemberEduard Baranovsky24-Sep-04 2:59 
GeneralText selectable &amp; Arc implementation Pinmemberpxp13-Aug-04 14:08 
GeneralRe: Text selectable &amp; Arc implementation PinmemberEduard Baranovsky18-Aug-04 3:01 
GeneralRe: Text selectable &amp; Arc implementation Pinmemberpxp18-Aug-04 3:14 
GeneralRe: Text selectable &amp; Arc implementation PinmemberEduard Baranovsky19-Aug-04 3:57 
GeneralRe: Text selectable &amp; Arc implementation Pinmemberpxp19-Aug-04 12:42 
QuestionText on this Canvas? PinmemberClinton Pierce23-Apr-04 8:20 
AnswerRe: Text on this Canvas? PinmemberEduard Baranovsky26-Apr-04 6:05 
QuestionCan you use this for a tennis court? PinmemberNicoVB30-Mar-04 5:36 
AnswerRe: Can you use this for a tennis court? PinmemberEduard Baranovsky31-Mar-04 9:42 
QuestionAdding a bitmap item to the canvas? PinmemberElwood15117-Mar-04 9:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 22 Mar 2004
Article Copyright 2004 by Eduard Baranovsky
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid