- 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

- §

  # Pattern factory

  Scrawl-canvas Pattern objects implement the Canvas API’s createPattern method. The resulting CanvasPattern object can be used by any Scrawl-canvas entity as its `fillStyle` or `strokeStyle`.

  - Most pattern-related functionality has been coded up in the styles mixin, and is documented there.
  - Functionality associated with assets, which Patterns use as their source, has been coded up in the assetConsumer mixin.
  - Patterns fully participate in the Scrawl-canvas packet system, thus can be saved, restored, cloned, killed, etc.
  - Patterns cannot be animated as such, but a Cell wrapper that is used as the Pattern’s source can be animated in any of the normal ways.
  - Scrawl-canvas does not support the Canvas API `CanvasPattern.setTransform()` method - it appears to be based on the SVGMatrix interface, which was deprecated in the SVG2 standard.
- §

  #### Demos:

  - Canvas-009 - Pattern styles; Entity web link anchors; Dynamic accessibility
  - Canvas-035 - Pattern style functionality
- §

  #### Imports

      import { constructors, entity } from '../core/library.js';

      import { doCreate, mergeOver, pushUnique, isa_obj, Ωempty } from '../core/utilities.js';

      import { gettableVideoAssetAtributes, settableVideoAssetAtributes } from './video-asset.js';

      import { gettableImageAssetAtributes, settableImageAssetAtributes } from './image-asset.js';

      import baseMix from '../mixin/base.js';
      import patternMix from '../mixin/pattern.js';
      import assetConsumerMix from '../mixin/asset-consumer.js';

      import { $IMAGE, $VIDEO, _isArray, _keys, _values, NAME, STYLES, T_PATTERN, UNDEF } from '../core/shared-vars.js';

- §

  #### Pattern constructor

      const Pattern = function (items = Ωempty) {

          this.makeName(items.name);
          this.register();
          this.set(this.defs);
          this.set(items);

          return this;
      };

- §

  #### Pattern prototype

      const P = Pattern.prototype = doCreate();
      P.type = T_PATTERN;
      P.lib = STYLES;
      P.isArtefact = false;
      P.isAsset = false;

- §

  #### Mixins

      baseMix(P);
      patternMix(P);
      assetConsumerMix(P);

- §

  #### Pattern attributes

  - Attributes defined in the base mixin: name.
  - Attributes defined in the pattern mixin: repeat, patternMatrix, matrixA, matrixB, matrixC, matrixD, matrixE, matrixF.
  - Attributes defined in the assetConsumer mixin: asset, spriteTrack, imageSource, spriteSource, videoSource, source.

      const defaultAttributes = {};
      P.defs = mergeOver(P.defs, defaultAttributes);

- §

  #### Packet management

      P.packetObjects = pushUnique(P.packetObjects, ['asset']);

      P.finalizePacketOut = function (copy, items) {

          if (_isArray(items.patternMatrix)) copy.patternMatrix = items.patternMatrix;
          else {

              const m = this.patternMatrix;
              if (m) copy.patternMatrix = [m.a, m.b, m.c, m.d, m.e, m.f];
          }

          return copy;
      };

- §

  #### Clone management

  No additional clone functionality required

- §

  #### Kill management

      P.kill = function () {

          const { name, asset, removeAssetOnKill } = this;
          let state, defs, fill, stroke;

          if (isa_obj(asset)) asset.unsubscribe(this);

- §

  Remove style from all entity state objects

          _values(entity).forEach(ent => {

              state = ent.state;
              defs = state.defs;

              if (state) {

                  fill = state.fillStyle;
                  stroke = state.strokeStyle;

                  if (isa_obj(fill) && fill.name == name) state.fillStyle = defs.fillStyle;
                  if (isa_obj(stroke) && stroke.name == name) state.strokeStyle = defs.strokeStyle;
              }
          });

- §

  Cascade kill invocation to the asset object, if required

          if (removeAssetOnKill) {

              if (removeAssetOnKill.substring) asset.kill(true);
              else asset.kill();
          }

- §

  Remove style from the Scrawl-canvas library

          this.deregister();

          return this;
      };

- §

  #### Get, Set, deltaSet

  Pattern `get` and `set` (but not `deltaSet`) functions need to take into account their current source, whose attributes can be retrieved/amended directly on the Picture object

- §

  `get`

      P.get = function (item) {

          const source = this.source;

          if ((item.indexOf($VIDEO) == 0 || item.indexOf($IMAGE) == 0) && source) {

              if (gettableVideoAssetAtributes.includes(item)) return source[item.substring(6)];
              else if (gettableImageAssetAtributes.includes(item)) return source[item.substring(6)];
          }

          else {

              const getter = this.getters[item];

              if (getter) return getter.call(this);

              else {

                  const def = this.defs[item];

                  if (typeof def != UNDEF) {

                      const val = this[item];
                      return (typeof val != UNDEF) ? val : def;
                  }
                  return undefined;
              }
          }
      };

- §

  `set`

      P.set = function (items = Ωempty) {

          const keys = _keys(items),
              keysLen = keys.length;

          if (keysLen) {

              const setters = this.setters,
                  source = this.source,
                  defs = this.defs;

              let fn, i, key, value;

              for (i = 0; i < keysLen; i++) {

                  key = keys[i];
                  value = items[key];

                  if ((key.indexOf($VIDEO) == 0 || key.indexOf($IMAGE) == 0) && source) {

                      if (settableVideoAssetAtributes.includes(key)) source[key.substring(6)] = value
                      else if (settableImageAssetAtributes.includes(key)) source[key.substring(6)] = value
                  }

                  else if (key && key != NAME && value != null) {

                      fn = setters[key];

                      if (fn) fn.call(this, value);
                      else if (typeof defs[key] != UNDEF) this[key] = value;
                  }
              }
              this.dirtyFilterIdentifier = true;
          }
          return this;
      };

- §

  #### Prototype functions

- §

  `getData` function called by Cell objects when calculating required updates to its CanvasRenderingContext2D engine, specifically for an entity’s fillStyle, strokeStyle and shadowColor attributes.

  - This is the point when we clean Scrawl-canvas assets which have told their subscribers that asset data/attributes have updated

      P.getData = function (entity, cell) {

          if (this.dirtyAsset) this.cleanAsset();
          this.asset.checkSource(this.sourceNaturalWidth, this.sourceNaturalHeight);

          return this.buildStyle(cell);
      };

- §

  #### Factory

      scrawl.importDomImage('.mypatterns');

      scrawl.makePattern({

          name: 'brick-pattern',
          asset: 'brick',

      }).clone({

          name: 'marble-pattern',
          imageSource: 'img/marble.png',
      });

      scrawl.makeBlock({

          name: 'marble-block',

          width: '40%',
          height: '40%',

          startX: '25%',
          startY: '25%',

          handleX: 'center',
          handleY: 'center',

          lineWidth: 20,
          lineJoin: 'round',

          method: 'fillThenDraw',

          fillStyle: 'marble-pattern',
          strokeStyle: 'brick-pattern',
      });

      export const makePattern = function (items) {

          if (!items) return false;
          return new Pattern(items);
      };

      constructors.Pattern = Pattern;