Conditions

Applications needs to be able to define the conditions under wich figures are able to be modified. These conditions are bussiness logic that is App dependent and can not be abstracted directly in Canvas. The Figure Conditions API fill this need providing a way for App to express rules that Canvas will use internally. At the same time, these conditions can be used by Apps to define their own logic. A condition query DSL is provided that makes it easy to define if a list of figures complies with a set of conditions.

App level conditions

Cx.Figure.condition defines or extends a condition:

Cx.Figure.condition(name,function(figure){ return boolean });
// Rasters will not be scalable for this App
Cx.Figure.condition('scalable',function(figure){
return ! ( figure instanceof Cx.Raster );
});

Once a condition is defined, it can be used to check if a list of figures fullfills the rule.

if( canvas.are(figures,'scalable') ){
// Good to go, allow this action...

Several conditions can be combined in single query

if( canvas.are(figures,'rotatable','scalable') ){
// Ok, transform the figures...

Because the figures will usually be the canvas.selectedFigures() list, you can just pass the target figures directly to the query:

if( canvas.are('selectedFigures','groupable') ){
// Green light, enable the group action buttons

All valid targets are accepted: 'figures', 'contextFigures', 'allFigures'.

Canvas driven by the App

Canvas uses conditions query checks internally in the Select Tool, the 3D Tool interaction, the HUD tools and actions and generally in every place that requires a decision that is better defined by the App.

The following conditions are checked: 'selectable', 'movable', 'scalable', 'rotatable', skewable', 'groupable', 'nodeEditable', 'zorderable'. For example, in 3D mode texture islands transformations are restricted and they are only movable and rotatable.

If the application extends any of these conditions, Canvas will correctly follow their rules.

// App defined decoration will not be selectable
Cx.Figure.condition('selectable',function(figure){
return figure.xType() != 'App.Decoration';
});

Helper conditions

Canvas pre-defines the following conditions: 'text', 'shape', 'raster', 'group', 'proxyGroup'.
Fine grained: 'simpleText', 'multiPartText', 'typesetText', 'fullColorRaster', 'monochromeRaster'.
For 3D mode: 'textureIsland'

These conditions can be used to simplify the condition definitions.

// Only text can be moved in this App
Cx.Figure.condition('movable','text');

The ! char can be used to negate a condition.

// Proxy Groups are not groupable in this App
Cx.Figure.condition('groupable','!proxyGroup');

Async Conditions

Async conditions can be specified post fixing the name with the $ char

// Defines what figures are small for this App
Cx.Figure.condition('small$',function(figure){
return figure.bounds$() .then(function(bounds){
return bounds.width() < 100 && bounds.height() < 100;
});
};

To check async conditions, the async version of the query is used

Cx.if$( canvas.are$( figures, '!small$' ), function(){
// Figures are big enough for this action to proceed...

Array Conditions

There are conditions that defines rules over the list of figures as a whole.

Cx.Figure.arrayCondition(name,function(figures){ return boolean });
// A list of figures is Groupable if there are at least two figures
Cx.Figure.arrayCondition('groupable',function(figures){
return figures.length >= 2;
});

Array conditions are combined with figure conditions when querying.

Cx.Figure.condition('groupable','!raster');
Cx.assert( canvas.are([ raster, text ],'groupable') == false );
// It passes the array condition, but fails because there is a raster

Canvas defines array conditions for 'groupable' and 'zorderable'.
It also defines helper conditions to check the number of figures: '1', '1+', '2', '2+'.

Cx.Figure.arrayCondition('groupable','2+');

Canvas Instance Conditions

It is advisable to use as much as possible App level figure conditions to define the rules of the application. If specific logic is needed for a given Canvas instance, the canvas version of the condition and arrayCondition functions can be used. This may be used to implement an interactive preview where figures can only be moved.

// None of the figures will be scalable in this Canvas
canvas.condition('scalable',function(figure){ return false; });
// Disallow z ordering if there is more than one figure in the list
canvas.arrayCondition('zorderable','1');

Canvas queries

Query to check if a list of figures fullfills a set of requirements

canvas.are(figures,conditions...);
canvas.are$(figures,conditions...);

Query to check if a single figure fullfills a set of requirements

canvas.is(figure,condition...);
canvas.is$(figure,conditions...);

Query to filter the figures that fullfills a set of requirements

canvas.only(figures,conditions...);
canvas.only$(figures,conditions...);

Save and Restore conditions

If the App can spawn several modes, each with its own bussines rules, common global conditions can be defined and then each mode can save at start up the current state of the conditions and restore them when the mode is changed (in the same way that HTML5 Canvas context.save() and canvas.restore() works).

Cx.Figure.saveConditions();
Cx.Figure.restoreConditions();

The same can be done with Canvas conditions, although normally it will be more convenient to instanciate a new Canvas for each mode.

canvas.saveConditions();
canvas.restoreConditions();