You are viewing Jcrop 2.x documentation — click here for legacy v0.9.x

Managing Selections

Jcrop 2.x now allows manipulate multiple concurrent selections, if your interface requires this capability (it's off by default). Effective use of these features presents a few challenges, described and addressed in some minor detail here.

Selection Mode

Jcrop can now operate in single or multiple selection mode. The multi configuration option specifies this behavior. In addition, new selections created by dragging on the stage (outside of any existing selections) can be disabled altogether.

Three effective modes are possible (in order of precedence)

Selection ModeOption SettingNew Selection Behavior
No New SelectionsallowSelect: falseNothing happens
Single Selectionmulti: false (default)Any existing selection(s) will be removed
Multiple Selectionsmulti: trueNew selection becomes current, existing selections move to back

Note on multiple selections: If the multiMax option is set with an integer value, Jcrop will prevent new selections beyond that number. If the option is set to zero (the default), there is no limit.

Accessing Selections

Type of selectionAPI property/keyDescription
Current Selectionjcrop_api.ui.selection
jcrop_api.ui.multi[0]
The currently active selection
Multiple Selectionsjcrop_api.ui.multi[n]Any available selection where n is index number

setOptions() Behavior on multiple selections

When the equivalent of the a setOptions() call occurs, a cropconfig event is triggered on the container. The StageManager object watches for this event and passes the configuration changes to each available selection according to the table below.

Behavior of setOptions() call on multiple selections, based on option settings

Current SelectionInactive SelectionResult of setOptions()
linkCurrent: truelinked: trueBoth selections are updated
linkCurrent: falselinked: trueOnly linked selection is updated
linkCurrent: truelinked: falseOnly current selection is updated
linkCurrent: falselinked: false
Neither selection is updated
Notes
  • Any time a configuration update occurs, the main Jcrop instance configuration is updated.
  • New selections will receive the current applicable Jcrop configuration, regardless of the value of either option.

Calling setOptions() method per Selection

When the StageManager performs the cascading behavior decribed above it iterates over the available selections and calls Selection.setOptions() on each selection that should receive the updated set of options.

It's also possible to call this method directly on a Selection
jcrop_api.ui.selection.setOptions({ aspectRatio: 1.2 });
jcrop_api.ui.multi[1].setOptions({ canDrag: false });

In this case, the options are passed directly to the Selection object regardless of linked or linkCurrent option settings. Of course, if called directly on the Selection, only the options on the Selection are updated. It does not disturb the options of the core Jcrop instance, nor any other Selection.

Creating New Selections

A basic API method exists to create a new Selection on the Jcrop instance.
var sel = jcrop_api.newSelection();
  • Accepts a Selection object as a parameter
  • Constructs with selectionConstructor option value if none given
  • Selection.init() is called
  • Selection becomes current active selection

The new selection can now be controlled by the API or the end user just like any other selection (according to its option settings, at least).

New selections created this way are not set to any initial position. Since the newSelection() method returns the Selection object that is created, we can chain an update() method call at the same time.

var sel = jcrop_api.newSelection().update(
  $.Jcrop.wrapFromXywh([ x, y, w, h ])
);

Extending Selection Behavior

It is now relatively simple to change the behavior of Selection objects, and by extension, the behavior of Jcrop itself. This section will briefly cover creating a new Selection object and replacing the built-in constructor with our new one.

First, create an empty constructor function
var CoordsSel = function(){ };

Since the Selection object is already incredibly complex, you probably want to start with the default behavior. And since Javascript uses prototypical inheritance—a subject way too complicated to explain here—let's just say this is how we extend the Selection object:

CoordsSel.prototype = new $.Jcrop.component.Selection;

Of course there are many ways to do a similar thing with Javascript.

The main point to remember is that any constructor you set as a selectionComponent, or pass in as a new selection, must be generally compatible with the built-in Selection object. Think of the built-in objects as something of an "interface" (a concept formally lacking in Javascript). With great power comes great responsibility.

Now we can go about customizing the prototype further:

$.extend(CoordsSel.prototype,$.Jcrop.component.Selection.prototype,{
  attach: function(){
    // Prepend an element to Selection.element (selection container)
    this.coords = $('<div> x </div>').addClass('jcrop-coords');
    this.element.prepend(this.coords);
  },
  update: function(b,ord){

    // Call original update() method first, with arguments
    $.Jcrop.component.Selection.prototype.update.call(this,b,ord);

    // Update coordinates
    this.coords.html(b.w+' &times '+b.h);

    return this;
  }
});

If you are following along, we've created essentially an extended Selection object, and replaced two of its methods. Since we wanted to preserve the original update() behavior, we called it from the original prototype.

Now we need to tell Jcrop to use our CoordsSel object instead of the default Selection component. There are several ways to do this, depending on which selections we want to use it.

Replace global selectionComponent default

$.Jcrop.defaults.selectionComponent = CoordsSel;

If called prior to creating a Jcrop instance, the new object becomes the default for all selections on that instance.

Set as default selectionComponent per Jcrop instance

$('#target').Jcrop({
  selectionComponent: CoordsSel
});

Here, we are only changing the selectionComponent contructor value on a specific instance.

Create with newSelection() in a Jcrop instance

jcrop_api.newSelection(new CoordSel);

Note: When passing a selection to newSelection() you must pass a constructed object. Don't forget the keyword new!

A more direct approach

If you want to modify the behavior of the Selection element across the entire page, and do not need to preserve it for any reason, you can modify its prototype directly.

$.Jcrop.component.Selection.prototype.attach = function(){
  console.log('Selection attached!');
};

Modifying prototype objects will also affect any current objects using that prototype. For this reason, it is recommended that direct prototype modifications be made prior to creating Jcrop instances.