- 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

- §

  # Observe and update

  Okay, so I got very bored of writing boilerplate to react to various form elements user interactions across the demos. So I wrote some functions to setup (and take down) batches of DOM event listeners to make my life easier. These are:

  - scrawl.addNativeListener()
  - scrawl.removeNativeListener()

  Then there was the use case for reacting to various mouse (and touch) events, so I bundled all those up into a set of complementary functions:

  - scrawl.addListener()
  - scrawl.removeListener()

  Even so, there was still a lot of boilerplate code to write, in particular to listening for user interaction with form elements (which can be anywhere on the web page). So I further factorised that code into an observeAndUpdate function which uses the listener functions internally.

  I have no idea how useful the observeAndUpdate function will be to anyone else. All I know is that it works for me and my demos, and that makes me happy.

  Note: observeAndUpdate() returns a function that will (in theory) remove all the bundled event listeners from their DOM elements when it is invoked. Not yet tested.

- §

  `Exported function` (to modules and the scrawl object). Capture changes in a form and apply them to a target Scrawl-canvas artefact, asset, style, group, etc object

  observeAndUpdate - example

      scrawl.observeAndUpdate({

          // The input event which will trigger the O&U
          event: ['input', 'change'],

          // CSS selector used to gather the DOM elements this O&U will be attached to
          origin: '.controlItem',

          // The SC artefact, or Group object, to be updated by user interaction changes
          target: piccy,

          // Performs an `addNativeListener` when true; `addListener` when false
          useNativeListener: true,

          // Invokes the event listener's `preventDefault` function
          preventDefault: true,

          // The SC artefact attributes to be updated by various DOM inputs. See below
          updates: {

              copy_start_xPercent: ['copyStartX', '%'],
              copy_start_xAbsolute: ['copyStartX', 'round'],

              copy_start_yPercent: ['copyStartY', '%'],
              copy_start_yAbsolute: ['copyStartY', 'round'],

              copy_dims_widthPercent: ['copyWidth', '%'],
              copy_dims_widthAbsolute: ['copyWidth', 'round'],

              copy_dims_heightPercent: ['copyHeight', '%'],
              copy_dims_heightAbsolute: ['copyHeight', 'round'],
          },

          // A callback function to be performed after any attributes updates
          callback: () => myLoom.update(),

          // Similarly, we can invoke a function to run before performing the updates
          setup: () => myLoom.update(),
      });

      import * as library from "../core/library.js";

      import { isa_fn, xt, xta, λnull, Ωempty } from "../core/utilities.js";

      import { addListener, addNativeListener, removeListener, removeNativeListener } from "../core/events.js";

      import { _ceil, _floor, _round, FALSE, T_GROUP, TRUE } from '../core/shared-vars.js';

- §

  observeAndUpdate - exported function

      export const observeAndUpdate = function (items = Ωempty) {

          if (!xta(items.event, items.origin, items.updates)) return false;

          const target = (items.target.substring && items.targetLibrarySection) ?
              library[items.targetLibrarySection][items.target] :
              items.target;

          if (!target) return false;

          const event = items.event,
              origin = items.origin;

          const listener = (items.useNativeListener) ? addNativeListener : addListener,
              killListener = (items.useNativeListener) ? removeNativeListener : removeListener;

          let stop = λnull;

          if (items.preventDefault) {

              stop = (e) => {

                  e.preventDefault();
                  e.returnValue = false;
              };
          }

          const setup = (isa_fn(items.setup)) ? items.setup : λnull;

          const callback = (isa_fn(items.callback)) ? items.callback : λnull;

          const func = function (e) {

              stop(e);

              const id = (e && e.target) ? e.target.id : false;

              if (id) {

                  const updates = items.updates,
                      actionArray = updates[id];

                  if (actionArray) {

                      setup();

                      const actionAttribute = actionArray[0],
                          action = actionArray[1],
                          targetVal = e.target.value;

                      let actionFlag = true,
                          val;

                      switch (action) {

- §

  Supplied value converted to float Number

                          case 'float' :
                              val = parseFloat(targetVal);
                              break;

- §

  Supplied value converted to integer Number

                          case 'int' :
                              val = parseInt(targetVal, 10);
                              break;

- §

  Supplied value rounded up or down to nearest integer Number

                          case 'round' :
                              val = _round(targetVal);
                              break;

- §

  Supplied value rounded down to nearest integer Number

                          case 'roundDown' :
                              val = _floor(targetVal);
                              break;

- §

  Supplied value rounded up to nearest integer Number

                          case 'roundUp' :
                              val = _ceil(targetVal);
                              break;

- §

  Supplied value not modified in any way

                          case 'raw' :
                              val = targetVal;
                              break;

- §

  Supplied value converted to String

                          case 'string' :
                              val = `${targetVal}`;
                              break;

- §

  Supplied value converted to Boolean

                          case 'boolean' :
                              if (xt(targetVal)) {

                                  if (targetVal.substring) {

                                      if (TRUE == targetVal.toLowerCase()) val = true;
                                      else if (FALSE == targetVal.toLowerCase()) val = false;
                                      else val = (parseFloat(targetVal)) ? true : false;
                                  }
                                  else val = (targetVal) ? true : false;
                              }
                              else val = false;
                              break;

- §

  Supplied value converted to float number, then action value (eg: ‘%’) added to result to output a String

                          default :
                              if (action.substring) val = `${parseFloat(targetVal)}${action}`;
                              else actionFlag = false;
                      }

- §

  Update - we can apply updates to a Group of artefacts, or to a single artefact

                      if (actionFlag) {

                          if (target.type == T_GROUP) {

                              target.setArtefacts({
                                  [actionAttribute]: val
                              });
                          }
                          else {

                              target.set({
                                  [actionAttribute]: val
                              });
                          }

- §

  Invoke any supplied callback function

                          callback();
                      }
                  }
              }
          };

          const kill = function () {

              killListener(event, func, origin);
          };

          listener(event, func, origin);

          return kill;
      };

      export const makeUpdater = (items = Ωempty) => observeAndUpdate(items);