Creating and Editing Templates in Customer's Canvas

In the previous sections, we paid much attention to what Customer's Canvas is, its role in web-to-print solutions, and where it is embedded (refer to Integration with E-commerce). This topic elaborates on another aspect - how to create and edit product templates in Customer's Canvas. This functionality is crucial because the purpose of Customer's Canvas is the customization of print products. Consequently, understanding how to work with templates is very important for a successful implementation of Customer's Canvas.

The Photoshop Templates section describes in detail how to use Adobe Photoshop to prepare templates. The InDesign Templates section covers creating templates in Adobe InDesign. They may give the impression that this is the only way to create templates for Customer's Canvas - in Adobe software. Actually, this is not true: Customer's Canvas can be used as a template editor in itself.

Providing Product Templates

Working directly with Photoshop or InDesign templates is convenient when using Adobe software is the only way to work with the initial templates. Once these templates have been customized by users in the Design Editor, you must handle these templates in the internal format of Customer's Canvas. In this case, you need to organize separate storage for these templates and Adobe templates. Also, you must recognize situations when you need an internal file or when you need an Adobe file and initialize Customer's Canvas differently depending on the file type.

On the other hand, if you only use templates in the internal format as a design you load into the editor, you don't need to worry about whether you are opening the initial template, a work created by your user, or a template modified by your employee. It always works in the same way and can load the designs with the already-specified product properties (like bleed zones), rendering settings, and the editor's configuration.

In your admin panel, you can implement a template management section and add product templates in the following ways:

For example, you can integrate Customer's Canvas into an e-commerce system. In the administrative panel of such a system, you can associate products with templates, enable their customization, and specify price-lists for the custom features. The workflow of providing templates to your users may look as follows:

  1. A designer selects a product for which they want to create a template.
  2. They open the Design Editor. The site initiates an empty product according to the selected product size.
  3. They create the template in the editor.
  4. The Design Editor saves the template into a server file system. The e-commerce system saves a template's thumbnail in its database and publishes it on the site.

To understand how to work with Customer's Canvas templates, let's learn about the internal file format (so-called state files).

State Files

A state file is the result of saving all objects loaded in the editor, i.e. its state. A state contains all information on the product, including images, user changes, fonts, colors, etc. These states also contain rendering settings and the Design Editor's configuration.

Customer's Canvas does not automatically clean up the state files. They are kept forever, until you delete these files manually or through the Web API. The only exception is when you enable the Demonstration mode. In this case, state files of anonymous users will be automatically removed when the session expires.

Creating State Files

State files are created every time you call Editor.saveProduct to save a product or Editor.finishProductDesign to render a print file and generate URLs that link to hi-res and proof images. By default, state files have unique names that look like aaaaaaaa-bbbb-cccc-xxxx-yyyyyyyyyyyy.st. Also, you can specify user-friendly names when using these methods.

For example, you can save a product as follows:

JavaScript
// Save your product to the t-shirt.st state file.
// Note, if a file with the same name already exists, it will be overwritten.
editor.finishProductDesign({stateId: "t-shirt"})
    .then(function (result) {
        // Verify a state ID and a user ID.
        stateId = result.stateId;
        userId = result.userId;
        // Get links to hi-res outputs.
        hiResOutputUrls = result.hiResOutputUrls;
        console.log("User " + usedID + " successfully saved the product " + stateId);
        console.log(hiResOutputUrls);
    })

You can find a complete code sample on the Introducing the IFrame API page.

By default, product states are saved in the ..\userdata\<someUserId>\states\ folder for every user. The ..\userdata\ folder contains states and images for all your users. The someUserId value is determined when you load the Design Editor.

JavaScript
let iframe = document.getElementById("editorFrame");
// For example, define an empty page as a product.
let productDefinition = { surfaces: [{ width: 800, height: 600 }] };
// Set the ID of the user who will create state files.
let config = { userId: 'someUserId' };
// Load the Design Editor.
CustomersCanvas.IframeApi.loadEditor(
    iframe, 
    productDefinition,
    config
);

You can change the default location for user images and states through the UserDataFolder parameter in AppSettings.config. You can move state files between folders of different users, rename them, or back them up.

Note

By default, the image data is embedded into the .st file as a Base64 string. It makes the state file self-contained - you can easily copy it to a backup drive, restore, or even move it to another Customer's Canvas instance. However, such files can become pretty large. To avoid this, you can enable a space-saving mode by setting the StateFileStorageEnabled to true in AppSettings.config. In this case, all images will be stored in the ..\userdata\StateFileCache\ folder and state files will have links to the files in this folder. As a trade-off, you will have to copy this cache folder during the backup procedures or migration to another Customer's Canvas instance.

Loading State Files

If you open the state folder, you will see a lot of state files. How do you pick the right one? To load a state, you should know its name (i.e. the state ID). You can get the state name when a Promise object returned by the Editor.saveProduct or Editor.finishProductDesign is resolved. The state ID, along with other information about the state, is passed to the successful resolution callback.

JavaScript
// Save a product.
editor.saveProduct()
    .then(function (result) {
        // Get a state identifier and a user identifier.
        stateId = result.stateId;
        userId = result.userId;
        console.log("State was saved successfully. Its id is " + stateId);
        ...
    })
    .catch(function (error) {
        ...
    });
...
// Now, you can load the previously saved product.
CustomersCanvas.IframeApi.loadEditor(iframe, stateId, { userId: userId });

Find more examples in Introducing the IFrame API.

Now, let's see how you can get a list of state files through the Web API.

Web API for Manipulating State Files

You can use our REST API to manipulate state files. For example, you can get a list of a user's state files by using the following request.

JavaScript
// Define the ID of the user who created state files.
const userId = "default";
// Pass the user ID to the StateFiles controller.
const url = `https://localhost:44300/api/users/${userId}/states`;
fetch(url).then(response => {
    return response.json();
}).then(json => {
    // Output state file names to the console.
    json.forEach(st => {
        console.log(st.stateId);
    });
});

Webhooks for Loading and Saving State Files

Customer's Canvas also allows you to implement custom HTTP callbacks triggered by saving and loading the state files in the editor. In this case, you can organize external storage for state files. To enable such webhooks, you need to define ExternalStatePushUrl and ExternalStatePullUrl in AppSettings.config.

Master User

When your employees create templates, their state files are saved under their user folder and they are not available to other users. How do you make their work available to all users of your site?

To provide a template for all of your users, the specified state file must be located in the master user folder. The master user is a special user whose resources, such as images or state files, are accessible to every user in your system. When a user sets a state file to load, Customer's Canvas first looks for the state in the state folder of this user, and if it cannot be found there, the master user folder is checked. Usually, the master user's folder is ..\userdata\masteruser\states\. Here, masteruser is the value of the MasterUserId parameter specified in AppSettings.config.

A state file can appear in the master's folder in one of two ways. Firstly, you can allow a designer to work under an arbitrary user ID in your system, and when the work is done, just move a state file to the master user folder manually. Another way is to set the MasterUserId as the value of the userId configuration parameter when loading the editor. In the latter case, when the designer saves a product, its state file is placed right into the master user folder. You can rename state files in the folder to make their names more human-readable.

Product Initialization Samples

Importing a PSD/IDML Template

Let us assume you have a file named stamp.psd. You should put it into the ..\assets\designs\ folder, which contains all PSD and IDML templates, and use the following JavaScript.

JavaScript
// An iframe where CustomersCanvas editor should be loaded.
let iframe = document.getElementById("editorFrame");
// Specify the PSD name here (without the extension).
let productTemplate = { surfaces: ['stamp'] };
// Specify the user ID (in our case, masteruser, to make our template public automatically).
let config = { userId: 'masteruser' };
// Load the Design Editor.
CustomersCanvas.IframeApi.loadEditor(
    iframe,
    productTemplate,
    config
);

Loading a Rasterized Image as a Background

If you have an image, you can load it into the editor as a background. The image can be a .png, .jpg, or .jpeg file. For example, to load SummerPhoto.jpg, put it into the ..\assets\designs\ folder and use the following JavaScript.

JavaScript
// Specify the image name here (without an extension).
let backgroundImage  = { surfaces: ['SummerPhoto'] };
// Specify the user ID (in our case, masteruser, to make our template public automatically).
let config = { userId: 'masteruser' };
// Load the Design Editor.
CustomersCanvas.IframeApi.loadEditor(
    iframe,
    backgroundImage,
    config
);

Opening a Blank Product

Now, let us create a template for an 800x600 product from scratch.

JavaScript
// Specify the empty product size, in points.
let emptyProductDefinition  = { surfaces: [{width: 800, height: 600}] };
// Specify the user ID (in our case, masteruser, to make our template public automatically).
let config = { userId: 'masteruser' };
// Load the Design Editor.
CustomersCanvas.IframeApi.loadEditor(
    iframe,
    emptyProductDefinition,
    config
);

Loading a Template from a State File

To load a state file, you need to specify an identifier of the user who created this state. The Design Editor looks for the state in the state folder of this user.

JavaScript
let iframe = document.getElementById("editorFrame");
// Specify a state file name to load a product.
let stateId = "ee9293bc-c887-433d-a5bd-454888f07a8a";
// Pass an identifier of the user who created this state, in the editor config.
let config = { userId: 'JohnWood' };
// Load the Design Editor.
CustomersCanvas.IframeApi.loadEditor(
    iframe,
    stateId,
    config
);

When a state file represents a multipage product, you can create a new product by using certain pages from this state file.

JavaScript
let productDefinition = {
    // Create a product based on a page from a state file.
    surfaces: [{
        // Specify a state file name.
        stateId: "ee9293bc-c887-433d-a5bd-454888f07a8a",
        // Select the second surface.
        surface: 1
    }]
};
let config = { userId: 'JohnWood' };
CustomersCanvas.IframeApi.loadEditor(
    iframe,
    productDefinition,
    config
);

See Also

Manual

IFrame API Reference