- Jump To … +
  ./demo/canvas-001.js ./demo/canvas-002.js ./demo/canvas-003.js ./demo/canvas-004.js ./demo/canvas-005.js ./demo/canvas-006.js ./demo/canvas-007.js ./demo/canvas-008.js ./demo/canvas-009.js ./demo/canvas-010.js ./demo/canvas-011.js ./demo/canvas-012.js ./demo/canvas-013.js ./demo/canvas-014.js ./demo/canvas-015.js ./demo/canvas-015a.js ./demo/canvas-016.js ./demo/canvas-017.js ./demo/canvas-018.js ./demo/canvas-019.js ./demo/canvas-019a.js ./demo/canvas-020.js ./demo/canvas-021.js ./demo/canvas-022.js ./demo/canvas-023.js ./demo/canvas-024.js ./demo/canvas-025.js ./demo/canvas-026.js ./demo/canvas-027.js ./demo/canvas-028.js ./demo/canvas-029.js ./demo/canvas-030.js ./demo/canvas-031.js ./demo/canvas-032.js ./demo/canvas-033.js ./demo/canvas-034.js ./demo/canvas-035.js ./demo/canvas-036.js ./demo/canvas-037.js ./demo/canvas-038.js ./demo/canvas-039.js ./demo/canvas-040.js ./demo/canvas-041.js ./demo/canvas-042.js ./demo/canvas-043.js ./demo/canvas-044.js ./demo/canvas-045.js ./demo/canvas-046.js ./demo/canvas-047.js ./demo/canvas-048.js ./demo/canvas-049.js ./demo/canvas-050.js ./demo/canvas-051.js ./demo/canvas-052.js ./demo/canvas-053.js ./demo/canvas-054.js ./demo/canvas-055.js ./demo/canvas-056.js ./demo/canvas-058.js ./demo/canvas-059.js ./demo/canvas-060.js ./demo/canvas-061.js ./demo/canvas-062.js ./demo/canvas-063.js ./demo/canvas-064.js ./demo/core-001.js ./demo/delaunator-001.js ./demo/delaunator-002.js ./demo/dom-001.js ./demo/dom-002.js ./demo/dom-003.js ./demo/dom-004.js ./demo/dom-005.js ./demo/dom-006.js ./demo/dom-007.js ./demo/dom-008.js ./demo/dom-009.js ./demo/dom-010.js ./demo/dom-011.js ./demo/dom-012.js ./demo/dom-013.js ./demo/dom-015.js ./demo/dom-016.js ./demo/dom-017.js ./demo/dom-018.js ./demo/filters-001.js ./demo/filters-002.js ./demo/filters-002a.js ./demo/filters-003.js ./demo/filters-004.js ./demo/filters-005.js ./demo/filters-006.js ./demo/filters-007.js ./demo/filters-008.js ./demo/filters-009.js ./demo/filters-010.js ./demo/filters-011.js ./demo/filters-012.js ./demo/filters-013.js ./demo/filters-014.js ./demo/filters-015.js ./demo/filters-016.js ./demo/filters-017.js ./demo/filters-018.js ./demo/filters-019.js ./demo/filters-020.js ./demo/filters-021.js ./demo/filters-022.js ./demo/filters-023.js ./demo/filters-024.js ./demo/filters-025.js ./demo/filters-026.js ./demo/filters-027.js ./demo/filters-028.js ./demo/filters-101.js ./demo/filters-102.js ./demo/filters-103.js ./demo/filters-104.js ./demo/filters-105.js ./demo/filters-501.js ./demo/filters-502.js ./demo/filters-503.js ./demo/filters-504.js ./demo/filters-505.js ./demo/mediapipe-001.js ./demo/mediapipe-002.js ./demo/mediapipe-003.js ./demo/modules-001.js ./demo/modules-002.js ./demo/modules-003.js ./demo/modules-004.js ./demo/modules-005.js ./demo/modules-006.js ./demo/packets-001.js ./demo/packets-002.js ./demo/particles-001.js ./demo/particles-002.js ./demo/particles-003.js ./demo/particles-004.js ./demo/particles-005.js ./demo/particles-006.js ./demo/particles-007.js ./demo/particles-008.js ./demo/particles-009.js ./demo/particles-010.js ./demo/particles-011.js ./demo/particles-012.js ./demo/particles-013.js ./demo/particles-014.js ./demo/particles-015.js ./demo/particles-016.js ./demo/rapier-001.js ./demo/snippets-001.js ./demo/snippets-002.js ./demo/snippets-003.js ./demo/snippets-004.js ./demo/snippets-005.js ./demo/snippets-006.js ./demo/tensorflow-001.js ./demo/tensorflow-002.js ./demo/utilities.js

- §

  # Demo DOM 017

  Testing getCanvas(), getStack() functionality

- §

  Run code

      import * as scrawl from '../source/scrawl.js';

      import { reportSpeed, reportFullLibrary } from './utilities.js';

- §

  #### Scene setup

      const canvasParent = document.querySelector('#canvas-parent');
      const canvasSwitchButton = document.querySelector('#canvas-switch');
      const canvasReplaceButton = document.querySelector('#canvas-replace');
      const canvasRemoveButton = document.querySelector('#canvas-remove');

      const stackParent = document.querySelector('#stack-parent');
      const stackSwitchButton = document.querySelector('#stack-switch');
      const stackReplaceButton = document.querySelector('#stack-replace');
      const stackRemoveButton = document.querySelector('#stack-remove');

- §

  KeyboardZones and DragZones don’t integrate with their canvas/stack parents - they’re useful add-ons rather than an integrated part of the system. So we need to have an elegant way to handle them.

      const dragZones = {};

- §

  #### User interaction (CANVAS test)

  ## Switch canvas

- §

  Load a new canvas with a different namespace into the parent element. Emulates a react component render when the component details have changed. For example:

  - Start with the square canvas - onboard and capture details about that canvas and associated artefacts/objects in the libarary
  - Switch to the round canvas - capture details about that canvas and associated artefacts/objects in the libarary. Details about the square canvas will not be removed from the library without specific instruction even though the related DOM canvas no longer exists
  - Switch back to the square canvas - it is at this point that SC should recognise the details it holds about the previous canvas are no longer relevant, purge everything related to that old canvas from the library, and then repopulate with new data
  - Existing functionality for Canvas.kill() is to delete the associated DOM data structures for that canvas from the page - though the canvas itself was removed some time prior and SC did nothing about it. Make sure that any errors emerging from that activity are properly captured and handled
- §

  ## Replace canvas

- §

  Load a new canvas with the same namespace into the parent element. Emulates a react component render when the component details have NOT changed - the component is rendered again because something else in the page has triggered a more general render. For example:

  - Start with the square canvas - onboard and capture details about that canvas and associated artefacts/objects in the libarary
  - Replace that canvas with another square canvas. SC needs to identify that while details about the canvas still exist, that canvas has gone and the new canvas needs to be processed and data about it - and all related artefacts/objects - stored in the library
- §

  ## Remove canvas

- §

  Purge everything relating to the current canvas’s namespace from the SC library

      const insertCanvas = (element, parent) => {
          console.log('inserting a canvas into the DOM parent');

          parent.innerHTML = element;
      };

      const buildSquareCanvas = (namespace) => {
          console.log('build a new square canvas element', namespace);

          const name = n => `${namespace}-${n}`;

- §

  build canvas

          const c = `
          <canvas
            id=${namespace}
            width="400"
            height="400"
            data-base-background-color="aliceblue"
          ></canvas>
          `;

- §

  insert and capture

          insertCanvas(c, canvasParent);

          const canvas = captureCanvasIntoLibrary(namespace);

- §

  create required artefacts/objects

          if (canvas != null) {

              scrawl.makeGradient({
                  name: name('gradient'),
                  end: ['100%', '100%'],
                  colors: [
                      [0, 'red'],
                      [999, 'blue'],
                  ],
                  colorSpace: 'OKLAB',
              });

              scrawl.makeFilter({
                  name: name('filter'),
                  method: 'randomNoise',
                  width: 20,
                  height: 20,
                  level: 1,
              });

              scrawl.makeBlock({
                  name: name('block'),
                  start: ['center', 'center'],
                  handle: ['center', 'center'],
                  dimensions: ['50%', '50%'],
                  fillStyle: name('gradient'),
                  lockFillStyleToEntity: true,
                  lineWidth: 2,
                  method: 'fillThenDraw',
                  delta: {
                      roll: 0.2,
                  },
                  filters: [name('filter')],
                  anchor: {
                      name: name('wikipedia-link'),
                      href: 'https://en.wikipedia.org/wiki/Square',
                      description: 'Link to the Wikipedia article on squares (opens in new tab)',
                      focusAction: true,
                      blurAction: true,
                  },

- §

  @ts-expect-error

                  onEnter: function () { this.set({ lineWidth: 6 }) },

- §

  @ts-expect-error

                  onLeave: function () { this.set({ lineWidth: 2 }) },

- §

  @ts-expect-error

                  onUp: function () { this.clickAnchor() },
              });

              scrawl.addListener('move', () => canvas.cascadeEventAction('move'), canvas.domElement);

              scrawl.addNativeListener('click', () => {
                  if (canvas.here.active) canvas.cascadeEventAction('up');
              }, canvas.domElement);

              scrawl.makeRender({
                  name: name('animation'),
                  target: canvas,
                  observer: true,
              });

              scrawl.makeTween({
                  name: name('tween'),
                  cycles: 0,
                  duration: 5000,
                  targets: name('block'),
                  definitions: [{
                      attribute: 'scale',
                      start: 0.8,
                      end: 1.2,
                      engine: 'easeOutIn',
                  }],
                  reverseOnCycleEnd: true,
                  observer: name('animation'),
              }).run();
          }
      };

      const buildCircleCanvas = (namespace) => {
          console.log('build a new circle canvas element', namespace);

          const name = n => `${namespace}-${n}`;

- §

  build canvas

          const c = `
          <canvas
            id=${namespace}
            width="400"
            height="400"
            data-base-background-color="aliceblue"
          ></canvas>
          `;

- §

  insert and capture

          insertCanvas(c, canvasParent);

          const canvas = captureCanvasIntoLibrary(namespace);

- §

  create required artefacts/objects

          if (canvas != null) {

              scrawl.makeGradient({
                  name: name('gradient'),
                  end: ['100%', '100%'],
                  colors: [
                      [0, 'green'],
                      [999, 'orange'],
                  ],
                  colorSpace: 'OKLAB',
              });

              scrawl.makeFilter({
                  name: name('filter'),
                  method: 'randomNoise',
                  width: 20,
                  height: 20,
                  level: 1,
              });

              scrawl.makeWheel({
                  name: name('wheel'),
                  start: ['center', 'center'],
                  handle: ['center', 'center'],
                  startAngle: 30,
                  endAngle: -30,
                  radius: '25%',
                  fillStyle: name('gradient'),
                  lockFillStyleToEntity: true,
                  lineWidth: 2,
                  method: 'fillThenDraw',
                  delta: {
                      roll: 0.2,
                  },
                  filters: [name('filter')],
                  anchor: {
                      name: name('wikipedia-link'),
                      href: 'https://en.wikipedia.org/wiki/Circle',
                      description: 'Link to the Wikipedia article on circles (opens in new tab)',
                      focusAction: true,
                      blurAction: true,
                  },

- §

  @ts-expect-error

                  onEnter: function () { this.set({ lineWidth: 6 }) },

- §

  @ts-expect-error

                  onLeave: function () { this.set({ lineWidth: 2 }) },

- §

  @ts-expect-error

                  onUp: function () { this.clickAnchor() },
              });

              scrawl.addListener('move', () => canvas.cascadeEventAction('move'), canvas.domElement);

              scrawl.addNativeListener('click', () => {
                  if (canvas.here.active) canvas.cascadeEventAction('up');
              }, canvas.domElement);

              scrawl.makeRender({
                  name: name('animation'),
                  target: canvas,
                  observer: true,
              });

              scrawl.makeTween({
                  name: name('tween'),
                  cycles: 0,
                  duration: 5000,
                  targets: name('wheel'),
                  definitions: [{
                      attribute: 'scale',
                      start: 0.8,
                      end: 1.2,
                      engine: 'easeOutIn',
                  }],
                  reverseOnCycleEnd: true,
                  observer: name('animation'),
              }).run();
          }
      };

      const captureCanvasIntoLibrary = (namespace) => {
          console.log('capture the new canvas into the library:', namespace);

          return scrawl.getCanvas(namespace);
      };

      const swapCanvases = () => {
          console.log('swap the canvases!');

          if (currentCanvas === squareCanvasNamespace) {

              currentCanvas = circleCanvasNamespace;
              buildCircleCanvas(currentCanvas);
          }
          else {

              currentCanvas = squareCanvasNamespace;
              buildSquareCanvas(currentCanvas);
          }
      };

      const reloadCanvas = () => {
          console.log('reload the current canvas:', currentCanvas);

          if (currentCanvas === squareCanvasNamespace) buildSquareCanvas(currentCanvas);
          else if (currentCanvas === circleCanvasNamespace) buildCircleCanvas(currentCanvas);
          else console.log('nothing to reload');
      };

      const removeCanvas = () => {
          console.log('remove the current canvas:', currentCanvas);

          scrawl.library.purge(currentCanvas);
          currentCanvas = noCanvas;
      };

- §

  Initial display

      const squareCanvasNamespace = 'my-square-canvas';
      const circleCanvasNamespace = 'my-circle-canvas';
      const noCanvas = '';

      let currentCanvas = squareCanvasNamespace;

      buildSquareCanvas(squareCanvasNamespace);

      scrawl.addNativeListener('click', swapCanvases, canvasSwitchButton);
      scrawl.addNativeListener('click', reloadCanvas, canvasReplaceButton);
      scrawl.addNativeListener('click', removeCanvas, canvasRemoveButton);

- §

  #### User interaction (STACK test)

  ## Switch stack

- §

  Load a new stack with a different namespace into the parent element. Emulates a react component render when the component details have changed. For example:

  - Start with the stack1 - onboard and capture details about that stack and associated artefacts/objects in the libarary
  - Switch to the stack2 - capture details about that stack and associated artefacts/objects in the libarary. Details about the stack1 will not be removed from the library without specific instruction even though the related DOM stack no longer exists
  - Switch back to the stack1 - it is at this point that SC should recognise the details it holds about the previous stack are no longer relevant, purge everything related to that old stack from the library, and then repopulate with new data
  - Existing functionality for Stack.kill() is to delete the associated DOM data structures for that stack from the page - though the stack itself was removed some time prior and SC did nothing about it. Make sure that any errors emerging from that activity are properly captured and handled
- §

  ## Replace stack

- §

  Load a new stack with the same namespace into the parent element. Emulates a react component render when the component details have NOT changed - the component is rendered again because something else in the page has triggered a more general render. For example:

  - Start with the stack1 - onboard and capture details about that stack and associated artefacts/objects in the libarary
  - Replace that stack with another stack1. SC needs to identify that while details about the stack still exist, that stack has gone and the new stack needs to be processed and data about it - and all related artefacts/objects - stored in the library
- §

  ## Remove stack

- §

  Purge everything relating to the current stack’s namespace from the SC library

      const insertStack = (element, parent) => {
          console.log('inserting a stack into the DOM parent');

          parent.innerHTML = element;
      };

      const buildStack1 = (namespace) => {
          console.log('build a new stack1 element', namespace);

          const name = n => `${namespace}-${n}`;

- §

  build stack

          const s = `
      <div id="${namespace}" data-scrawl-stack>

          <div id="${name('simple-svg')}">
              <svg
                  width="200px"
                  height="150px"
                  xmlns="http://www.w3.org/2000/svg"
                  viewbox="0 0 400 300">

                  <rect width="100%" height="100%" fill="red" />
                  <circle cx="100%" cy="100%" r="150" fill="blue" stroke="black" />
                  <polygon points="120,0 240,225 0,225" fill="green"/>
                  <text x="50" y="100" font-family="Verdana" font-size="55" fill="white" stroke="black" stroke-width="2">Hello!</text>
              </svg>
          </div>
          <div id="${name('dom-element')}">
              <p>Drag and drop the elements around the stack.</p>
              <ul>
                  <li>Tomatoes</li>
                  <li>Cauliflower</li>
                  <li>Broccoli</li>
              </ul>
          </div>
      </div>
          `;

- §

  insert and capture

          insertStack(s, stackParent);

          const stack = captureStackIntoLibrary(namespace);

- §

  create required artefacts/objects

          if (stack != null) {

              stack.set({
                  dimensions: [400, 400],
                  perspectiveZ: 1200,
                  css: {
                      margin: '1em auto',
                      backgroundColor: 'lightgray',
                      borderRadius: '10px',
                  },
              });

- §

  Kill any old dragzone

              if (dragZones[namespace]) dragZones[namespace]();

              dragZones[namespace] = scrawl.makeDragZone({
                  zone: stack,
                  endOn: ['up', 'leave'],
                  preventTouchDefaultWhenDragging: true,
              });

              const svg = scrawl.library.artefact[name('simple-svg')];
              if (svg) {
                  svg.set({
                      start: ['10%', '10%'],
                      width: 200,
                      roll: -10,
                      yaw: 40,
                      css: {
                          border: '1px dashed black',
                          boxSizing: 'border-box',
                      },
                  });
              }

              const domEl = scrawl.library.artefact[name('dom-element')];
              if (domEl) {
                  domEl.set({
                      start: ['70%', '70%'],
                      handle: ['50%', '50%'],
                      dimensions: [200, 200],
                      roll: 10,
                      yaw: -35,
                      css: {
                          border: '1px dashed green',
                          padding: '0.5em',
                          borderRadius: '10px',
                          display: 'grid',
                          justifyContents: 'center',
                          alignItems: 'center',
                          backgroundColor: 'beige'
                      },
                  });
              }

              scrawl.makeRender({
                  name: name('animation'),
                  target: stack,
                  observer: true,
              });
          }
      };

      const buildStack2 = (namespace) => {
          console.log('build a new stack1 element', namespace);

          const name = n => `${namespace}-${n}`;

- §

  build stack

          const s = `
      <div id="${namespace}" data-scrawl-stack>
          <canvas
            id=${name('canvas')}
            width="400"
            height="400"
            data-base-background-color="honeydew"
          ></canvas>
      </div>
          `;

- §

  insert and capture

          insertStack(s, stackParent);

- §

  Note: stacks don’t capture any canvases they may contain

          const stack = captureStackIntoLibrary(namespace);
          const canvas = captureCanvasIntoLibrary(name('canvas'));

- §

  create required artefacts/objects

          if (stack != null && canvas != null) {

              stack.set({
                  dimensions: [400, 400],
                  perspectiveZ: 1200,
                  css: {
                      margin: '1em auto',
                      backgroundColor: 'darkslategray',
                      borderRadius: '10px',
                  },
              });

              canvas.set({
                  start: ['center', 'center'],
                  handle: ['center', 'center'],
                  trackHere: 'local',
                  delta: {
                      pitch: 0.25,
                      yaw: 0.1,
                      roll: 0.08,
                  },
              });

              scrawl.makeBlock({
                  name: name('canvas-border'),
                  start: ['2.5%', '2.5%'],
                  dimensions: ['95%', '95%'],
                  lineWidth: 8,
                  strokeStyle: 'orange',
                  method: 'draw',
                  order: 1,
              });

              scrawl.makeWheel({
                  name: name('canvas-blob'),
                  start: ['center', 'center'],
                  handle: ['center', 'center'],
                  lockTo: 'mouse',
                  radius: '15%',
                  fillStyle: 'blue',
                  lineWidth: 8,
                  strokeStyle: 'red',
                  method: 'fillThenDraw',
              });

              scrawl.makeRender({
                  name: name('animation'),
                  target: [stack, canvas],
                  observer: true,
                  afterCreated: () => stack.set({ width: 400 }),
              });
          }
      };

      const captureStackIntoLibrary = (namespace) => {
          console.log('capture the new stack into the library:', namespace);

          return scrawl.getStack(namespace);
      };

      const swapStacks = () => {
          console.log('swap the stacks!');

          if (currentStack === stack1Namespace) {

              currentStack = stack2Namespace;
              buildStack2(currentStack);
          }
          else {

              currentStack = stack1Namespace;
              buildStack1(currentStack);
          }
      };

      const reloadStack = () => {
          console.log('reload the current stack:', currentStack);

          if (currentStack === stack1Namespace) buildStack1(currentStack);
          else if (currentStack === stack2Namespace) buildStack2(currentStack);
          else console.log('nothing to reload');
      };

      const removeStack = () => {
          console.log('remove the current stack:', currentStack);

          scrawl.library.purge(currentStack);
          currentStack = noStack;
      };

- §

  Initial display

      const stack1Namespace = 'my-first-stack';
      const stack2Namespace = 'my-second-stack';
      const noStack = '';

      let currentStack = stack1Namespace;

      buildStack1(stack1Namespace);

      scrawl.addNativeListener('click', swapStacks, stackSwitchButton);
      scrawl.addNativeListener('click', reloadStack, stackReplaceButton);
      scrawl.addNativeListener('click', removeStack, stackRemoveButton);

- §

  #### Scene animation

  Function to display frames-per-second data, and other information relevant to the demo

      const report = reportSpeed('#reportmessage', () => reportFullLibrary(scrawl));

- §

  Create the Display cycle animation

      scrawl.makeRender({

          name: "report-animation",
          noTarget: true,
          afterShow: report,
      });

- §

  #### Development and testing

      console.log(scrawl.library);