Understanding Filters

Scope of this Document

  • Describes advanced functionality not required to operate basic Jcrop features
  • Descriptions of filter design or behavior apply to built-in filters only
    (Yours can work however you want.)

Introducing Filters

Filters receive the actual selection being drawn and calculate the selection that would result based on the rules implemented by the filter. Jcrop comes loaded with a set of default features that implement its core functionality. These filters can be modified, altered, or replaced, to radically alter Jcrop's behavior. Let's take a look at how they are created and used.

Dragging Operation

As you drag a new selection, Jcrop tracks the actual area you are dragging from the point you pressed down the mouse button, to wherever you are currently dragging. If you resize a selection, Jcrop figures the opposite corner as the initial point and tracks the position of the handle you are dragging.

This works fantastically for dragging and manipulating free-form selections. But what about features like aspect ratio locking, or minimum and maximum selection limits? These features must determine selection coordinates that would be drawn within the true selection boundary actually being dragged.

The Filter Chain

Filters are called in a chain. The first filter receives the raw selection coordinates from the dragging operation. It performs any modifications and returns a resulting set of coordinates. That output is fed into the next filter, and so on. The selection values at the end of the chain will be used to draw the updated selection on the instance.

Filter Priority

Because filters are called in a chain, it is critical they be called in the correct order. Each filter must have a property Filter.priority that stores an integer value. The value is used to sort the filter chain any time a filter is added or removed. This way, you can add or remove filters at any time, and not worry about disrupting the order of the chain. Priority values are ordered lowest to highest.

Filter Lifecycle

Understanding the filter lifecycle is useful when:
  • Creating new filters
  • Attempting to modify existing filters
  • Debugging filter and selection behavior

Filter Constructors

Filters begin their life as a simple object constructor. The constructor function can be empty with no arguments. When the Filter is constructed and registered with the instance, Jcrop will call the necessary methods to attach it in the following steps.

Built-in Jcrop Filters are located at $.Jcrop.filter and have short names called tags. At the time of this writing, tags are not well utilized to manage filters beyond being used as a common short name, this will be expanded upon in the future.

Built-in Filters applied by default

5$.Jcrop.filter.constrainConstrains Selection to container
12$.Jcrop.filter.extentEnforces container edge margin
15$.Jcrop.filter.ratioAspect ratio locking
22$.Jcrop.filter.backoffFixes boundary errors from extent and ratio
90$.Jcrop.filter.roundRounds pixel values
95$.Jcrop.filter.shaderImplements selection shading

Jcrop Instantiation

Upon startup, Jcrop examines the applyFilters option value. This value is an array of filter key names for each filter in the above table. The instance iterates over that list of key names, constructing objects from $.Jcrop.filter. For a value in applyFilters of ratio, Jcrop will construct new $.Jcrop.filter.ratio (which is actually the RatioFilter object).

Customize initial filters when starting an instance
  applyFilters: [ 'constrain', 'shader' ]

If you started Jcrop like this, options like aspectRatio, minSize, and edge would be completely ineffective. If you really want to see some strange behavior, try removing the ConstrainFilter, or mixing up the filter priority values.

Tip: If you need to refer to an instance's filter later, use jcrop_api.filter.keyname

Selection Inheritance

When any new selection is created, applyFilters is inspected, and each named filter is added to Selection.filter. While it is good to know that each Selection has its own independent chain of filters, most use cases would attach the same filters to every Selection. The reason being, the default filters are designed to be instance-wide. In more plain terms, Selections typically only have a reference to the constructed filter inherited from the Jcrop instance itself. This is not a requirement, so a unique filter object could be applied to an individual Selection if desired.

Selection-specific settings

Filters can access the instance as well as the current Selection, so they can implement configuration-specific behavior for any specific selection. An example of this would be multiple active selections each with their own aspectRatio value. The same RatioFilter object is used to filter the coordinates, but it does so based on the aspectRatio setting of that particular selection.

Examine the source code for the built-in filters! They contain many useful patterns for effective filter design, and reading the source may help clarify some of these concepts.

Filter Design

All filters shipped with Jcrop are designed with common features

  • The constructor does not require any arguments
  • Designed to run instance-wide (not necessarily on all selections)
  • Selections may contain option settings that affect filter behavior
  • Contains a property Filter.priority for ordering
  • Contains a method Filter.filter() for processing data

Constructing Filters

Jcrop constructs all filters listed in the applyFilters configuration option and attaches them to the instance at Jcrop.filter automatically on startup. Any necessary configuration is also performed at this time.

Managing Filters on an Instance

For performance, filters are designed to be instance-wide. To simplify filter management,

Instance-wide Filters

When Jcrop starts, it looks at the applyFilters option for a list of filters.

Adding a Filter

Needs documentation

Removing a Filter

Let's say for example, you are using an aspectRatio setting and you want the highest precision output possible. Since RoundFilter is running after the RatioFilter, the values are currently being rounded.

Managing Filters on a Selection

Each Selection has its own list of filters. Since most filters (all built-in filters) are designed to run instance-wide, this is simply