- Jump To … +
  ./source/core/animation-loop.js ./source/core/display-cycle.js ./source/core/document-root-elements.js ./source/core/document.js ./source/core/events.js ./source/core/init.js ./source/core/library.js ./source/core/random-seed.js ./source/core/shared-vars.js ./source/core/snippets.js ./source/core/system-flags.js ./source/core/user-interaction.js ./source/core/utilities.js ./source/factory/action.js ./source/factory/anchor.js ./source/factory/animation.js ./source/factory/array-pool.js ./source/factory/bezier.js ./source/factory/block.js ./source/factory/canvas.js ./source/factory/cell-fragment.js ./source/factory/cell.js ./source/factory/cog.js ./source/factory/color.js ./source/factory/conic-gradient.js ./source/factory/coordinate.js ./source/factory/crescent.js ./source/factory/drag-zone.js ./source/factory/element.js ./source/factory/emitter.js ./source/factory/filter-engine-bluenoise-data.js ./source/factory/filter-engine.js ./source/factory/filter.js ./source/factory/font-attributes.js ./source/factory/gradient.js ./source/factory/grid.js ./source/factory/group.js ./source/factory/image-asset.js ./source/factory/keyboard-zone.js ./source/factory/line-spiral.js ./source/factory/line.js ./source/factory/loom.js ./source/factory/mesh.js ./source/factory/net.js ./source/factory/noise-asset.js ./source/factory/observe-update.js ./source/factory/oval.js ./source/factory/palette.js ./source/factory/particle-force.js ./source/factory/particle-history.js ./source/factory/particle-spring.js ./source/factory/particle-world.js ./source/factory/particle.js ./source/factory/pattern.js ./source/factory/phrase.js ./source/factory/picture.js ./source/factory/polygon.js ./source/factory/polyline.js ./source/factory/quadratic.js ./source/factory/quaternion.js ./source/factory/radial-gradient.js ./source/factory/raw-asset.js ./source/factory/reaction-diffusion-asset.js ./source/factory/rectangle.js ./source/factory/render-animation.js ./source/factory/shape.js ./source/factory/spiral.js ./source/factory/sprite-asset.js ./source/factory/stack.js ./source/factory/star.js ./source/factory/state.js ./source/factory/tetragon.js ./source/factory/ticker.js ./source/factory/tracer.js ./source/factory/tween.js ./source/factory/unstacked-element.js ./source/factory/vector.js ./source/factory/video-asset.js ./source/factory/wheel.js ./source/mixin/anchor.js ./source/mixin/asset-advanced-functionality.js ./source/mixin/asset-consumer.js ./source/mixin/asset.js ./source/mixin/base.js ./source/mixin/cascade.js ./source/mixin/cell-key-functions.js ./source/mixin/delta.js ./source/mixin/display-shape.js ./source/mixin/dom.js ./source/mixin/entity.js ./source/mixin/filter.js ./source/mixin/mimic.js ./source/mixin/path.js ./source/mixin/pattern.js ./source/mixin/pivot.js ./source/mixin/position.js ./source/mixin/shape-basic.js ./source/mixin/shape-curve.js ./source/mixin/shape-path-calculation.js ./source/mixin/styles.js ./source/mixin/tween.js

- §

  # Display shape mixin

  This mixin defines additional attributes and functions for Stack and Canvas artefacts, in particular adding hooks for functions that will be automatically invoked when the artefact’s dimensions update.

- §

  #### Demos:

  - Canvas-034 - Determine the displayed shape of the visible canvas; react to changes in the displayed shape
  - DOM-016 - Determine the displayed shape of the visible stack; react to changes in the displayed shape
- §

  #### Imports

      import { isa_fn, isa_number, mergeOver, pushUnique, λnull, Ωempty } from '../core/utilities.js';

      import { _entries, BANNER, LANDSCAPE, LARGER, LARGEST, PORTRAIT, RECTANGLE, REGULAR, SKYSCRAPER, SMALLER, SMALLEST, ZERO_STR } from '../core/shared-vars.js';

- §

  #### Export function

      export default function (P = Ωempty) {

- §

  #### Shared attributes

          const defaultAttributes = {

- §

  Scrawl-canvas recognises five shapes, separated by four breakpoints:

  - `banner`
  - `landscape`
  - `rectangle`
  - `portrait`
  - `skyscraper`

  The values assigned to the breakpoints are Float numbers for the displayed Canvas element’s width/height ratio - the value `3` represents the case where the width value is three times more than the height value, while `0.35` represents a width (roughly) 3 times less than the height.

  We can set a Canvas artefact’s breakpoints in one go using the dedicated `setDisplayShapeBreakpoints()` function, as below. Alternatively we can use the regular `set()` function, supplying the attributes `breakToBanner`, `breakToLandscape`, `breakToPortrait` and `breakToSkyscraper` as required. The values given here are the default values for Canvas artefacts.

              breakToBanner: 3,
              breakToLandscape: 1.5,
              breakToPortrait: 0.65,
              breakToSkyscraper: 0.35,

              actionBannerShape: null,
              actionLandscapeShape: null,
              actionRectangleShape: null,
              actionPortraitShape: null,
              actionSkyscraperShape: null,

- §

  Scrawl-canvas also recognises five areas, again separated by four breakpoints:

  - `smallest`
  - `smaller`
  - `regular`
  - `larger`
  - `largest`

  The values assigned to the breakpoints are Float numbers for the displayed Canvas element’s pixel area (`width * height`).

  - Useful for dynamic Cells - for example Canvas base Cells, where the canvas `baseMatchesCanvasDimensions` flag has been set to `true`; in these situations we can use the area breakpoints to adjust entity dimensions and scales, and text font sizes, to better match the changed environment.
  - The other option - to set the base Cell’s dimensions to known, static values and set the canvas’s `fit` attribute - suffers from image degredation when the canvas and its base cell’s dimensions are excessively different.

              breakToSmallest: 20000,
              breakToSmaller: 80000,
              breakToLarger: 180000,
              breakToLargest: 320000,

              actionSmallestArea: null,
              actionSmallerArea: null,
              actionRegularArea: null,
              actionLargerArea: null,
              actionLargestArea: null,
          };
          P.defs = mergeOver(P.defs, defaultAttributes);
          mergeOver(P, defaultAttributes);

- §

  #### Packet management

          P.packetFunctions = pushUnique(P.packetFunctions, ['actionBannerShape', 'actionLandscapeShape', 'actionRectangleShape', 'actionPortraitShape', 'actionSkyscraperShape', 'actionSmallestArea', 'actionSmallerArea', 'actionRegularArea', 'actionLargerArea', 'actionLargestArea']);

- §

  #### Clone management

  No additional clone functionality defined here

- §

  #### Kill management

  No additional kill functionality defined here

- §

  #### Get, Set, deltaSet

          const G = P.getters,
              S = P.setters;

- §

  Get displayShape - returns the current display shape for the Canvas or Stack artefact. Returns a string whose value can be one of `banner`, `landscape`, `rectangle`, `portrait`, or `skyscraper`.

          G.displayShape = function () {

              return this.currentDisplayShape;
          };

- §

  Get displayShapeBreakpoints - returns an object with the current Number values for each of the breakpoint attributes.

          G.displayShapeBreakpoints = function () {

              return {
                  breakToBanner: this.breakToBanner,
                  breakToLandscape: this.breakToLandscape,
                  breakToPortrait: this.breakToPortrait,
                  breakToSkyscraper: this.breakToSkyscraper,
                  breakToSmallest: this.breakToSmallest,
                  breakToSmaller: this.breakToSmaller,
                  breakToLarger: this.breakToLarger,
                  breakToLargest: this.breakToLargest,
              };
          };

- §

  Set displayShapeBreakpoints - breakpoints can be set individually, or alternatively they can be supplied in an object keyed to this attribute

          S.displayShapeBreakpoints = function (items = Ωempty) {

              for (const [key, val] of _entries(items)) {

                  if (isa_number(val)) {

                      switch (key) {

                          case 'breakToBanner' :
                              this.breakToBanner = val;
                              break;

                          case 'breakToLandscape' :
                              this.breakToLandscape = val;
                              break;

                          case 'breakToPortrait' :
                              this.breakToPortrait = val;
                              break;

                          case 'breakToSkyscraper' :
                              this.breakToSkyscraper = val;
                              break;

                          case 'breakToSmallest' :
                              this.breakToSmallest = val;
                              break;

                          case 'breakToSmaller' :
                              this.breakToSmaller = val;
                              break;

                          case 'breakToLarger' :
                              this.breakToLarger = val;
                              break;

                          case 'breakToLargest' :
                              this.breakToLargest = val;
                              break;
                      }
                  }
              }
              this.dirtyDisplayShape = true;
              this.dirtyDisplayArea = true;
          };

- §

  `setDisplayShapeBreakpoints` - an alternative mechanism to set breakpoints beyond the normal `set` function

          P.setDisplayShapeBreakpoints = S.displayShapeBreakpoints;

- §

  Set breakToBanner - the breakpoint between `landscape` and `banner` display shapes; value will generally be a number greater than `1`

          S.breakToBanner = function (item) {

              if (isa_number(item)) this.breakToBanner = item;
              this.dirtyDisplayShape = true;
          };

- §

  Set breakToLandscape - the breakpoint between `landscape` and `rectangle` display shapes; value will generally be a number greater than `1`

          S.breakToLandscape = function (item) {

              if (isa_number(item)) this.breakToLandscape = item;
              this.dirtyDisplayShape = true;
          };

- §

  Set breakToPortrait - the breakpoint between `portrait` and `rectangle` display shapes; value will generally be a number greater than `0` and less than `1`

          S.breakToPortrait = function (item) {

              if (isa_number(item)) this.breakToPortrait = item;
              this.dirtyDisplayShape = true;
          };

- §

  Set breakToSkyscraper - the breakpoint between `portrait` and `skyscraper` display shapes; value will generally be a number greater than `0` and less than `1`

          S.breakToSkyscraper = function (item) {

              if (isa_number(item)) this.breakToSkyscraper = item;
              this.dirtyDisplayShape = true;
          };

- §

  Set breakToSmallest - the breakpoint between `smaller` and `smallest` display shapes

          S.breakToSmallest = function (item) {

              if (isa_number(item)) this.breakToSmallest = item;
              this.dirtyDisplayArea = true;
          };

- §

  Set breakToSmaller - the breakpoint between `regular` and `smaller` display shapes

          S.breakToSmaller = function (item) {

              if (isa_number(item)) this.breakToSmaller = item;
              this.dirtyDisplayArea = true;
          };

- §

  Set breakToLarger - the breakpoint between `regular` and `larger` display shapes

          S.breakToLarger = function (item) {

              if (isa_number(item)) this.breakToLarger = item;
              this.dirtyDisplayArea = true;
          };

- §

  Set breakToLargest - the breakpoint between `larger` and `largest` display shapes

          S.breakToLargest = function (item) {

              if (isa_number(item)) this.breakToLargest = item;
              this.dirtyDisplayArea = true;
          };

- §

  Each display shape has an associated hook function (by default a function that does nothing) which Scrawl-canvas will run each time it detects that the Canvas display shape has changed to that shape. We can replace these null-functions with our own; this allows us to configure the scene/animation to accommodate different display shapes, thus making the code reusable in a range of different web page environments.

  We can set/update these functions at any time using the normal `set()` function. We can also set/update the functions using dedicated `setAction???Shape()` functions:

- §

  Set actionBannerShape - must be a Function

          S.actionBannerShape = function (item) {

              if (isa_fn(item)) this.actionBannerShape = item;
              this.dirtyDisplayShape = true;
          };

- §

  `setActionBannerShape` - an alternative mechanism to set the actionBannerShape function, beyond the normal `set` functionality

          P.setActionBannerShape = S.actionBannerShape;

- §

  Set actionLandscapeShape - must be a Function

          S.actionLandscapeShape = function (item) {

              if (isa_fn(item)) this.actionLandscapeShape = item;
              this.dirtyDisplayShape = true;
          };

- §

  `setActionLandscapeShape` - an alternative mechanism to set the actionLandscapeShape function, beyond the normal `set` functionality

          P.setActionLandscapeShape = S.actionLandscapeShape;

- §

  Set actionRectangleShape - must be a Function

          S.actionRectangleShape = function (item) {

              if (isa_fn(item)) this.actionRectangleShape = item;
              this.dirtyDisplayShape = true;
          };

- §

  `setActionRectangleShape` - an alternative mechanism to set the actionRectangleShape function, beyond the normal `set` functionality

          P.setActionRectangleShape = S.actionRectangleShape;

- §

  Set actionPortraitShape - must be a Function

          S.actionPortraitShape = function (item) {

              if (isa_fn(item)) this.actionPortraitShape = item;
              this.dirtyDisplayShape = true;
          };

- §

  `setActionPortraitShape` - an alternative mechanism to set the actionPortraitShape function, beyond the normal `set` functionality

          P.setActionPortraitShape = S.actionPortraitShape;

- §

  Set actionSkyscraperShape - must be a Function

          S.actionSkyscraperShape = function (item) {

              if (isa_fn(item)) this.actionSkyscraperShape = item;
              this.dirtyDisplayShape = true;
          };

- §

  `setActionSkyscraperShape` - an alternative mechanism to set the actionSkyscraperShape function, beyond the normal `set` functionality

          P.setActionSkyscraperShape = S.actionSkyscraperShape;

- §

  Set actionSmallestArea - must be a Function

          S.actionSmallestArea = function (item) {

              if (isa_fn(item)) this.actionSmallestArea = item;
              this.dirtyDisplayArea = true;
          };

- §

  `setActionSmallestArea` - an alternative mechanism to set the actionSmallestArea function, beyond the normal `set` functionality

          P.setActionSmallestArea = S.actionSmallestArea;

- §

  Set actionSmallerArea - must be a Function

          S.actionSmallerArea = function (item) {

              if (isa_fn(item)) this.actionSmallerArea = item;
              this.dirtyDisplayArea = true;
          };

- §

  `setActionSmallerArea` - an alternative mechanism to set the actionSmallerArea function, beyond the normal `set` functionality

          P.setActionSmallerArea = S.actionSmallerArea;

- §

  Set actionRegularArea - must be a Function

          S.actionRegularArea = function (item) {

              if (isa_fn(item)) this.actionRegularArea = item;
              this.dirtyDisplayArea = true;
          };

- §

  `setActionRegularArea` - an alternative mechanism to set the actionRegularArea function, beyond the normal `set` functionality

          P.setActionRegularArea = S.actionRegularArea;

- §

  Set actionLargerArea - must be a Function

          S.actionLargerArea = function (item) {

              if (isa_fn(item)) this.actionLargerArea = item;
              this.dirtyDisplayArea = true;
          };

- §

  `setActionLargerArea` - an alternative mechanism to set the actionLargerArea function, beyond the normal `set` functionality

          P.setActionLargerArea = S.actionLargerArea;

- §

  Set actionLargestArea - must be a Function

          S.actionLargestArea = function (item) {

              if (isa_fn(item)) this.actionLargestArea = item;
              this.dirtyDisplayArea = true;
          };

- §

  `setActionLargestArea` - an alternative mechanism to set the actionLargestArea function, beyond the normal `set` functionality

          P.setActionLargestArea = S.actionLargestArea;

- §

  #### Prototype functions

- §

  `initializeDisplayShapeActions` - internal function; called by the Canvas and Stack artefact constructors

          P.initializeDisplayShapeActions = function () {

              this.actionBannerShape = λnull;
              this.actionLandscapeShape = λnull;
              this.actionRectangleShape = λnull;
              this.actionPortraitShape = λnull;
              this.actionSkyscraperShape = λnull;

              this.currentDisplayShape = ZERO_STR;
              this.dirtyDisplayShape = true;

              this.actionSmallestArea = λnull;
              this.actionSmallerArea = λnull;
              this.actionRegularArea = λnull;
              this.actionLargerArea = λnull;
              this.actionLargestArea = λnull;

              this.currentDisplayArea = ZERO_STR;
              this.dirtyDisplayArea = true;
          };

- §

  `cleanDisplayShape` - internal function; replaces the function defined in the dom.js mixin, invoked when required as part of the DOM artefact `prestamp` functionality

          P.cleanDisplayShape = function () {

              this.dirtyDisplayShape = false;

              const [width, height] = this.currentDimensions;

              if (width > 0 && height > 0) {

                  const ratio = width / height,
                      current = this.currentDisplayShape,
                      banner = this.breakToBanner,
                      landscape = this.breakToLandscape,
                      portrait = this.breakToPortrait,
                      skyscraper = this.breakToSkyscraper;

                  if (ratio > banner) {

                      if (current != BANNER) {

                          this.currentDisplayShape = BANNER;
                          this.actionBannerShape();
                          return true;
                      }
                      return false;
                  }
                  else if (ratio > landscape) {

                      if (current != LANDSCAPE) {

                          this.currentDisplayShape = LANDSCAPE;
                          this.actionLandscapeShape();
                          return true;
                      }
                      return false;
                  }
                  else if (ratio < skyscraper) {

                      if (current != SKYSCRAPER) {

                          this.currentDisplayShape = SKYSCRAPER;
                          this.actionSkyscraperShape();
                          return true;
                      }
                      return false;
                  }
                  else if (ratio < portrait) {

                      if (current != PORTRAIT) {

                          this.currentDisplayShape = PORTRAIT;
                          this.actionPortraitShape();
                          return true;
                      }
                      return false;
                  }
                  else {

                      if (current != RECTANGLE) {

                          this.currentDisplayShape = RECTANGLE;
                          this.actionRectangleShape();
                          return true;
                      }
                      return false;
                  }
              }
              else {

                  this.dirtyDisplayShape = true;
                  return false;
              }
          };

- §

  `cleanDisplayArea` - internal function; replaces the function defined in the dom.js mixin, invoked when required as part of the DOM artefact `prestamp` functionality

  - Note that `cleanDisplayArea` fires before `cleanDisplayShape`!

          P.cleanDisplayArea = function () {

              this.dirtyDisplayArea = false;

              const [width, height] = this.currentDimensions;

              if (width > 0 && height > 0) {

                  const area = width * height,
                      current = this.currentDisplayArea,
                      largest = this.breakToLargest,
                      larger = this.breakToLarger,
                      smaller = this.breakToSmaller,
                      smallest = this.breakToSmallest;

                  if (area > largest) {

                      if (current != LARGEST) {

                          this.currentDisplayArea = LARGEST;
                          this.actionLargestArea();
                          return true;
                      }
                      return false;
                  }
                  else if (area > larger) {

                      if (current != LARGER) {

                          this.currentDisplayArea = LARGER;
                          this.actionLargerArea();
                          return true;
                      }
                      return false;
                  }
                  else if (area < smallest) {

                      if (current != SMALLEST) {

                          this.currentDisplayArea = SMALLEST;
                          this.actionSmallestArea();
                          return true;
                      }
                      return false;
                  }
                  else if (area < smaller) {

                      if (current != SMALLER) {

                          this.currentDisplayArea = SMALLER;
                          this.actionSmallerArea();
                          return true;
                      }
                      return false;
                  }
                  else {

                      if (current != REGULAR) {

                          this.currentDisplayArea = REGULAR;
                          this.actionRegularArea();
                          return true;
                      }
                      return false;
                  }
              }
              else {

                  this.dirtyDisplayArea = true;
                  return false;
              }
          };

- §

  `updateDisplayShape` - use this function to force the Canvas or Stack artefact to re-evaluate its current display shape, and invoke the action hook function associated with that shape.

          P.updateDisplayShape = function () {

              this.currentDisplayShape = ZERO_STR;
              this.dirtyDisplayShape = true;
          };

- §

  `updateDisplayArea` - use this function to force the Canvas or Stack artefact to re-evaluate its current display area, and invoke the action hook function associated with that area.

          P.updateDisplayArea = function () {

              this.currentDisplayArea = ZERO_STR;
              this.dirtyDisplayArea = true;
          };

- §

  `updateDisplay` - perform update for both display shape and area.

          P.updateDisplay = function () {

              this.updateDisplayShape();
              this.updateDisplayArea();
          };
      }