Layers and Objects

Note

You can refer to the web-to-print solution based on AJAX Vector Objects, Customer's Canvas. You can consider it as a ready-to-use editor that you may want to embed into your website or as an example demonstrating how AJAX Vector Objects can be used for your needs.

As we discussed in the previous topics, Canvas is a graphic document which serves to create interactive designs. All designs are comprised of two types of entities: layers and objects. Objects are visible graphics primitives, whereas layers are invisible containers for objects. This topic describes layers and objects in more detail and discusses how to manipulate them. It contains for the following paragraphs:

Introduction to Layers and objects

This paragraph discusses the basic aspects of layers and objects, and contains the following items:

First, let us have a look at all the different kinds of graphics objects supported in AJAX Vector Objects:

To learn about specific features related to each of these object types, read the Working with Specific Objects article.

The following image illustrates an example of the objects/layers hierarchy on Canvas:

Hierarchy of objects location on Canvas

As the example shows, a layer can contain any amount of objects, whereas an object is associated with only one layer. Following this logic, you cannot add an object directly to Canvas, this requires a layer to be added to Canvas first, and then the object is supposed to be put on the layer. Canvas introduces the concept of "current object" - in other words, the object that gets the focus and processes all user input. Canvas can have only one current object being manipulated by the user at a time. The layer containing the current object is defined as the current layer. We will discuss how to manipulate the current layer/object below in more detail.

Creating an object on Canvas is very easy. As an example, let us draw a rectangle. To perform this we need to generate a layer first and add it to Canvas, then create an instance of RectangleVObject and add it to an object collection of the layer:

ASP.NET
var layer = new Layer();
layer.VObjects.Add(new RectangleVObject(75, 45, 90, 60){
    BorderWidth = 0,
    FillColor = System.Drawing.Color.Blue
});
CanvasViewer1.Canvas.Layers.Add(layer);
JavaScript
var canvasViewer = $find("<%= CanvasViewer1.ClientID %>");
var layer = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Layer();
var rectangle = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(75, 45, 90, 60);
rectangle.set_borderWidth(0);
rectangle.set_fillColor("#0000FF");
layer.get_vObjects().add(rectangle);
canvasViewer.get_canvas().get_layers().add(layer);
canvasViewer.get_canvas().redraw(true);
Note

If you make changes to Canvas via JavaScript, the viewport does not update automatically. Thus, do not forget to redraw Canvas in your code using the Canvas.redraw() method.

After launching both these snippets you will see the same results:

Adding a rectangle to Canvas

As we already know, Canvas requires setting the workspace size, which defines an area where objects are located (if you are not familiar with the workspace concept, read this paragraph). As the workspace has a coordinate system in points, all object coordinates and sizes are also specified in points. Let us consider where the rectangle from our example is located on the workspace:

Adding a rectangle to Canvas

All layers on Canvas are organized as an array where indexes define Z-order: the less the index value is, the higher the layer is located. In practice, this means that objects located on a layer with a higher index overlap objects on a layer with a lower index. Also, objects associated with the same layer have their own Z-order. Changing layer/object indexes you can manage the order of displaying design elements on Canvas.

Current Object and Current Layer

As we mentioned before, Canvas supports the concept of current layer/object. We also know that users can manipulate the current object, which gets all the user input. This way, the current object is the currently selected object on Canvas having special control grips for interactive transformations. You can see how our rectangle object looks if we make it current:

Current object on Canvas

As objects cannot live without layers, the current object defines the current layer - the layer which the current object belongs to. There are two ways to set or get the current layer - via CurrentLayerIndex or CurrentLayer properties. Let us look at an example which uses these methods to change the current layer:

C#
CanvasViewer1.Canvas.CurrentLayerIndex = 2;
var currentLayer = CanvasViewer1.Canvas.CurrentLayer;
currentLayer.Name = "New Current Layer";
JavaScript
var canvas = $find("<%= CanvasViewer1.ClientID %>").get_canvas();
canvas.set_currentLayerIndex(2);
var currentLayer = Canvas.get_currentLayer();
currentLayer.set_name("New Current Layer");

Now, let us do the same for the current object. We will set the first layer in the layer collection as the current layer and then make the first object in its object collection as the current object. After that, we will change the object name:

C#
CanvasViewer1.Canvas.CurrentLayerIndex = 0;
CanvasViewer1.Canvas.CurrentVObjectIndex = 0;
var currentObject = CanvasViewer1.Canvas.CurrentVObject;
currentObject.Name = "New Current Object";
JavaScript
var canvas = $find("<%= CanvasViewer1.ClientID %>").get_canvas();
canvas.set_currentLayerIndex(0);
canvas.set_currentVObjectIndex(0);
var currentObject = Canvas.get_currentVObject();
currentObject.set_name("New Current Object");
Note

After the user clicks on an object, it becomes current and it also automatically sets the corresponding current layer. However, if you operate objects programmatically using an API, you need to specify the current layer before setting the current object.

Using History

Almost every graphic editor allows users to undo and redo their actions. In AJAX Vector Objects, you can also enable these features in your application.

AJAX Vector Objects provides the History class that tracks all modifications applied to the Canvas content. To allow History to keep the track of all the changes you need to set the History.Enable property to true:

C#
CanvasViewer1.Canvas.History.Enable = true;
JavaScript
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_history().set_enable(true);

Now, if you need to undo or redo the last action, just call the Undo() or Redo() method:

C#
protected void Undo_Click(object sender, EventArgs e)
{
    CanvasViewer1.Canvas.History.Undo();
}

protected void Redo_Click(object sender, EventArgs e)
{
    CanvasViewer1.Canvas.History.Redo();
}
JavaScript
function undo_onclick() {
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_history().undo()
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().redraw(true);
}
function redo_onclick() {
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_history().redo()
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().redraw(true);
}

If you need to limit the number of actions in the undo history, you can use the MaxUndoStepCount property which sets the maximum amount of undo steps. The history preserves 10 actions by default. Also, you can clear the history in three different ways:

  • Deleting the undo history via the ClearUndo() method.
  • Deleting the redo history via the ClearRedo() method.
  • Deleting the entire history via the Clear() method.

Working with Layers

This paragraph explains how to work with layers and contains the following items:

All layers are stored in LayerCollection which is accessed via Layers. There are two ways to find a layer - by Name or Index in the collection. The following snippet illustrates how to retrieve layers by Index:

C#
CanvasViewer1.Canvas.Layers.Add(new Layer());
var layer = CanvasViewer1.Canvas.Layers[0];
JavaScript
var canvas = $find("<%= CanvasViewer1.ClientID %>").get_canvas();

canvas.get_layers().add(new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Layer());
var layer = Canvas.get_layers().get_item(0);

Using the Index property is very convenient when Canvas contains a small number of layers. However, if you create a complex design with many layers, keeping track of all the indexes becomes difficult. In this case, you can use the Name property. On the server side you can use either the GetByName(String) method returning a layer by name, or GetLayersByName(String) retrieving an array of layers that contain specific string names. Let us see how to perform the previous task, only this time using the Name property:

C#
layer.Name = "Name";
var layerByName = CanvasViewer1.Canvas.Layers.GetByName("Name");

Use the getLayersByName() property on the client side to retrieve a list of layers with a specific string in the name:

JavaScript
layer.set_name("Name");
var layerByName = Canvas.get_layers().getLayersByName("Name")[0];

Locking Layers

When you create a graphic template for further user customizations, you may need to forbid a user from changing objects on the template. With AJAX Vector Objects you can lock the objects via the Locked property:

C#
CanvasViewer1.Canvas.CurrentLayer.Locked = true;
JavaScript
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_currentLayer().set_locked(true);

Moreover, you can restrict an area on the template where a user can manipulate objects. To perform this you need to set a rectangle region on the layer using the Region property:

C#
CanvasViewer1.Canvas.CurrentLayer.Region = new System.Drawing.RectangleF(0, 0, 100, 100);
JavaScript
var canvasViewer = $find("<%= CanvasViewer1.ClientID %>");
canvasViewer.get_canvas().get_currentLayer().set_region(
    new System.Drawing.RectangleF(0, 0, 100, 100));

During the design process, you may need to hide some layers, which can be done using the Visible property:

C#
CanvasViewer1.Canvas.CurrentLayer.Visible = false;
JavaScript
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_currentLayer().set_visible(false);

Common Operations

Now, let us consider some more examples of common operations.

  • Getting the number of existing layers:

    C#
    int i = CanvasViewer1.Canvas.Layers.Count();
    
    JavaScript
    var i = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_count();
    
  • Adding a layer to the end of the Canvas.Layers collection, that is, the layer that will be the highest one on Canvas:

    C#
    CanvasViewer1.Canvas.Layers.Add(new Layer());
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().add(
        new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Layer());
    
  • Inserting a layer to the specified position in the Canvas.Layers collection:

    C#
    var layer = new Layer();
    CanvasViewer1.Canvas.Layers.Insert(2, layer);
    
    JavaScript
    var layer = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Layer();
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().insert(2, layer);
    
  • Deleting a layer from the Canvas.Layers collection by a specified index:

    C#
    CanvasViewer1.Canvas.Layers.RemoveAt(2);
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().removeAt(2);
    
  • Changing Z-order. As the Z-order equals the index in the Canvas.Layers collection, all you need is to move the layer in the collection:

    C#
    CanvasViewer1.Canvas.Layers.Move(2, 0);
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().move(2, 0);
    

Working with Objects

This paragraph explains how to work with objects and contains the following items:

Objects are graphic elements on Canvas associated with a particular layer and stored in the Layer.VObjects collection. Objects have the same properties as layers, namely:

  • Visible hides or shows an object on Canvas.
  • Locked forbids a user from transforming the object.
  • Index allows you to access an object by index in the Layer.VObjects collection.
  • Name associates an object with a specific name and helps to retrieve the object by that name from the Layer.VObjects collection.

AJAX Vector Objects provides the ability to assign additional data to an object via the Tag property. Tag accepts a Dictionary that contains a collection of key-value pairs of any type:

C#
CanvasViewer1.Canvas.CurrentLayer.VObjects.Add(new RectangleVObject(10, 10, 10, 10){
    FillColor = System.Drawing.Color.Red,
    Name = "Rectangle Name",
    Tag = new Dictionary<string, string>(){
        {"Name", "Rectangle Name"},
        {"Color", "Red"}}
});
JavaScript
var rectangle = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(10, 10, 10, 10);
rectangle.set_fillColor("#FF0000");
rectangle.set_name("Rectangle Name");
rectangle.set_tag({ "Name": "Rectangle Name", "Color": "Red" });
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_currentLayer().get_vObjects().add(rectangle);

Object Transformation

All transformations made to the object are stored in the Transform property. They are always applied to the original object state. This means that if you transform an object programmatically, you need to keep in mind that if, for example, you rotate the object by 45 degrees, and then you need to rotate it by 45 degrees more, you should set the angle in the Transform instance to 90 degrees.

Transform includes the most popular object operations: resizing, rotating, and translating.

For resizing, there is the Transform.Scale(Double, Double) method which accepts width and height multipliers as arguments. If these multipliers are equal, the object is resized proportionally. The following snippets demonstrate how to upscale a rectangle to twice the original size:

C#
var resize = new Transform();
resize.Scale(2.0, 2.0);
CanvasViewer1.Canvas.CurrentVObject.Transform = resize;

The client API provides the Transform.ScaleX and Transform.ScaleY properties that represent the width and height multipliers, respectively. Let us look at how to scale an object disproportionately on the client side:

JavaScript
var resize = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Transform();
resize.set_scaleX(3.0);
resize.set_scaleY(2.0);
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_currentVObject().set_transform(resize);

The Transform.Translate(Double, Double) method allows you to move an object if you use the server API. It accepts two parameters specifying a distance to translate the object along the workspace:

C#
var translate = new Transform();
translate.Translate(CanvasViewer1.WorkspaceWidth / 4, CanvasViewer1.WorkspaceHeight / 4);
CanvasViewer1.Canvas.CurrentVObject.Transform = translate;

On the client side, you can translate an object specifying the Transform.TranslateX and Transform.TranslateY properties:

JavaScript
var canvasViewer = $find("<%= CanvasViewer1.ClientID %>");
var translate = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Transform();
translate.set_translateX(CanvasViewer.get_workspaceWidth() / 4);
translate.set_translateY(CanvasViewer.get_workspaceHeight() / 4);
canvasViewer.get_canvas().get_currentVObject().set_transform(translate);

To rotate an object, use the Transform.Angle property, which defines an angle in degrees and applies the transform to the object:

C#
var rotate = new Transform(){Angle = 45.0};
CanvasViewer1.Canvas.CurrentVObject.Transform = rotate;
JavaScript
var rotate = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.Transform();
rotate.set_angle(45.0);
canvasViewer.get_canvas().get_currentVObject().set_transform(rotate);

Object Permissions

AJAX Vector Objects provides the ability to define what a user can do with a particular object. If you need to forbid a user from performing specific actions to the object, use the Permission class that exposes the following members:

Member Name Description
AllowArbitraryResize Determines whether users can resize an object arbitrarily.
AllowDelete Determines whether the object can be deleted using Del key.
AllowMoveHorizontal Determines whether the object can be moved horizontally.
AllowMoveVertical Determines whether the object can be moved vertically.
AllowFreeMove Only returns a value indicating whether the object can be moved both horizontally and vertically. This property turns to false if at least one of AllowMoveHorizontal/AllowMoveVertical is false.
AllowProportionalResize Determines whether users can resize the object proportionally.
AllowRotate Determines whether users can rotate the object.
NoPrint If true, AJAX Vector Objects will skip the object while rendering print-ready output.
NoShow Determines whether the object is displayed on Canvas.

Let us look at an example of working with permissions. The following snippets demonstrate how to forbid a user from rotating and resizing an object:

C#
var rectangle = new RectangleVObject(75, 45, 90, 60);
rectangle.Permissions.AllowRotate = false;
rectangle.Permissions.AllowProportionalResize = false;
rectangle.Permissions.AllowArbitraryResize = false;
CanvasViewer1.Canvas.CurrentLayer.VObjects.Add(rectangle);
JavaScript
var rectangle = new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(75, 45, 90, 60);
rectangle.get_permissions().set_allowRotate(false);
rectangle.get_permissions().set_allowProportionalResize(false);
rectangle.get_permissions().set_allowArbitraryResize(false);
$find("<%= CanvasViewer1.ClientID %>").get_canvas().get_currentLayer().get_vObjects().add(Rectangle);

Common Operations

  • Getting the number of existing objects in a layer:

    C#
    int i = CanvasViewer1.Canvas.Layers[0].VObjects.Count();
    
    JavaScript
    var i = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().get_count();
    
  • Adding an object to the end of the Layer.VObjects collection, meaning the object will be the highest one in the layer:

    C#
    CanvasViewer1.Canvas.Layers[0].VObjects.Add(new RectangleVObject(0, 0, 100, 100));
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().add(
        new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(0, 0, 100, 100));
    
  • Inserting an object to the specified position in the Layer.VObjects collection:

    C#
    CanvasViewer1.Canvas.Layers[0].VObjects.Insert(1, new RectangleVObject(0, 0, 50, 50));
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().insert(1,
        new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(0, 0, 50, 50));
    
  • Getting an object by its index:

    C#
    CanvasViewer1.Canvas.Layers[0].VObjects.Add(new RectangleVObject(0, 0, 50, 50));
    var getObject = CanvasViewer1.Canvas.Layers[0].VObjects[0];
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().add(
        new Aurigma.GraphicsMill.AjaxControls.VectorObjects.RectangleVObject(0, 0, 50, 50));
    var getObject = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().get_item(0);
    
  • Getting an object by its name:

    C#
    rectangle.Name = "Rectangle";
    var getObjectByName = CanvasViewer1.Canvas.Layers.GetVObjectsByName("Rectangle");
    
    JavaScript
    rectangle.set_name("Rectangle");
    var getObjectByName = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().getVObjectsByName("Rectangle")[0];
    
  • Deleting an object from the Layer.VObjects collection by a specified index:

    C#
    CanvasViewer1.Canvas.Layers[0].VObjects.RemoveAt(2);
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().removeAt(2);
    
  • Changing the object's Z-order. As the Z-order is an index of the object, all you need to do is just move the object in the Layer.VObjects collection:

    C#
    CanvasViewer1.Canvas.Layers[0].VObjects.Move(2, 0);
    
    JavaScript
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().move(2, 0);
    
  • Cloning an object:

    C#
    var cloneObject = CanvasViewer1.Canvas.Layers[0].VObjects[0].Clone();
    
    JavaScript
    var cloneObject = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().get_item(0).clone();
    
  • Transferring an object from its current layer to another one:

    C#
    var objectTransferring = CanvasViewer1.Canvas.Layers[1].VObjects[0];
    CanvasViewer1.Canvas.Layers[1].VObjects.RemoveAt(0);
    CanvasViewer1.Canvas.Layers[0].VObjects.Add(objectTransferring);
    
    JavaScript
    var objectTransferring = $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(1).get_vObjects().get_item(0);
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(1).get_vObjects().removeAt(0);
    $find("<%= CanvasViewer1.ClientID %>").get_canvas().get_layers().get_item(0).get_vObjects().add(objectTransferring);
    

See Also

Reference

Manual

Other