• 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-016.js ./demo/canvas-017.js ./demo/canvas-018.js ./demo/canvas-019.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-057.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/canvas-065.js ./demo/canvas-066.js ./demo/canvas-067.js ./demo/canvas-068.js ./demo/canvas-069.js ./demo/canvas-070.js ./demo/canvas-071.js ./demo/canvas-072.js ./demo/canvas-073.js ./demo/canvas-201.js ./demo/canvas-202.js ./demo/canvas-203.js ./demo/canvas-204.js ./demo/canvas-205.js ./demo/canvas-206.js ./demo/canvas-207.js ./demo/canvas-208.js ./demo/canvas-209.js ./demo/canvas-210.js ./demo/canvas-211.js ./demo/canvas-212.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/dom-019.js ./demo/dom-020.js ./demo/dom-021.js ./demo/filters-001.js ./demo/filters-002.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-029.js ./demo/filters-030.js ./demo/filters-031.js ./demo/filters-032.js ./demo/filters-033.js ./demo/filters-034.js ./demo/filters-035.js ./demo/filters-036.js ./demo/filters-037.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/js/mediapipe/tasks-vision/vision-bundle.js ./demo/js/mediapipe/tasks-vision/wasm/vision_wasm_internal.js ./demo/js/mediapipe/tasks-vision/wasm/vision_wasm_nosimd_internal.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/modules/canvas-minimap.js ./demo/modules/canvas-scene-editor.js ./demo/modules/demo-m006-c1.js ./demo/modules/demo-m006-c2.js ./demo/modules/demo-m006-c3.js ./demo/modules/demo-m006-c4.js ./demo/modules/demo-m006-utils.js ./demo/modules/dom-entity-editor.js ./demo/modules/entity-copy-paste.js ./demo/modules/entity-manipulation-gui.js ./demo/modules/entity-navigation.js ./demo/modules/entity-ring-builder.js ./demo/modules/london-crime-lines.js ./demo/modules/london-crime-stacked-bars.js ./demo/modules/lottie-loader.js ./demo/modules/simple-chart-frame.js ./demo/modules/simple-graph-lines.js ./demo/modules/simple-graph-stacked-bars.js ./demo/modules/wikipedia-views-spiral-chart.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/particles-017.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/snippets/animated-highlight-gradient-text-snippet.js ./demo/snippets/animated-hover-gradient-snippet.js ./demo/snippets/animated-word-gradient-snippet.js ./demo/snippets/before-after-slider-infographic.js ./demo/snippets/bubbles-text-snippet.js ./demo/snippets/green-box-snippet.js ./demo/snippets/jazzy-button-snippet.js ./demo/snippets/page-performance-snippet-test.js ./demo/snippets/page-performance-snippet.js ./demo/snippets/pan-image-snippet.js ./demo/snippets/placeholder-effect-snippet.js ./demo/snippets/ripple-effect-snippet.js ./demo/snippets/risograph-text-gradient-snippet.js ./demo/snippets/spotlight-text-snippet-test.js ./demo/snippets/spotlight-text-snippet.js ./demo/snippets/swirling-stripes-text-snippet.js ./demo/snippets/word-highlighter-snippet.js ./demo/snippets/worley-text-gradient-snippet.js ./demo/temp-001.js ./demo/temp-shape-scale-investigation.js ./demo/tensorflow-001.js ./demo/tensorflow-002.js ./demo/utilities.js
  • §

    Demo Modules 005

    Accessible GUI-based simple canvas editor

    Related files:

    • Accessible GUI-based simple canvas editor - main demo

    Usage

    This module creates graphical underlays so that users can see entitys they’ve highlighted (via keyboard navigation) or selected (via mouse or keyboard). It creates the selectedEntitys and keyboardEntitys Group objects, to which the appropriate fillters are applied. It also handles navigation between entitys using the keyboard arrows, alongside moving highlighted entitys via the keyboard. The module adds the following zones to the supplied Canvas wrapper:

    • An entity drag zone, to drag entitys around the scene editor Cell (processingOrder: 100)
    • A keyboard zone - to handle arrow and SHIFT + arrow (entity navigation), and Enter and Backspace (for entity selection) keystrokes

    Inputs to the initializeEntityNavigation function

    • canvas - SC canvas wrapper object (required)
    • cell - the scene Cell wrapper object, from the canvas-minimap module (required)
    • dashboard - an object containing DOM form functions, from the dom-entity-editor module (required)

    Output from the initializeEntityNavigation function - is an object containing the following attributes:

    • selectedEntitys - the selected entitys group, used by other modules
    • addControllerAttributes - an object containing attributes that need to be added to entitys which will be controlled by the scene editor
    • removeControllerAttributes - an object containing attributes that need to be set on entitys to remove them from scene editor control
    • checkForEntityNavigationHoverActions - a function to add to an animation object, which invokes the Canvas wrapper’s checkHover functionality
    • updateControllerDisplay - an object containing functions to update the canvas element’s cursor appearance during hover and drag actions
    • killEntityNavigation - kill function, to remove everything associated with the scene navigation functionality
  • §

    Filter weight arrays

    const weights1 = [0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 15, 0, 1, 1, 19, 1, 1, 1, 22, 1, 1, 1, 25, 1, 1, 1, 29, 1, 1, 1, 32, 1, 0, 0, 36, 0, 0, 0, 39, 0, 0, 0, 43, 0, 0, 0, 47, 0, 0, 0, 50, 0, 0, 0, 54, 0, 1, 1, 58, 1, 1, 1, 61, 1, 1, 1, 65, 1, 1, 1, 68, 1, 1, 1, 72, 1, 1, 1, 75, 1, 0, 0, 78, 0, 0, 0, 82, 0, 0, 0, 85, 0, 0, 0, 88, 0, 0, 0, 91, 0, 1, 1, 94, 1, 1, 1, 97, 1, 1, 1, 100, 1, 1, 1, 103, 1, 0, 0, 105, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0, 113, 0, 0, 0, 115, 0, 0, 0, 117, 0, 1, 1, 119, 1, 1, 1, 121, 1, 1, 1, 123, 1, 1, 1, 125, 1, 1, 1, 127, 1, 0, 0, 129, 0, 0, 0, 130, 0, 0, 0, 132, 0, 0, 0, 133, 0, 0, 0, 134, 0, 0, 0, 136, 0, 1, 1, 137, 1, 1, 1, 138, 1, 1, 1, 139, 1, 1, 1, 140, 1, 1, 1, 141, 1, 1, 1, 142, 1, 0, 0, 143, 0, 0, 0, 144, 0, 0, 0, 145, 0, 0, 0, 145, 0, 0, 0, 146, 0, 1, 1, 147, 1, 1, 1, 147, 1, 1, 1, 148, 1, 1, 1, 148, 1, 0, 0, 149, 0, 0, 0, 149, 0, 0, 0, 149, 0, 0, 0, 150, 0, 0, 0, 150, 0, 0, 0, 150, 0, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 151, 1, 0, 0, 151, 0, 0, 0, 151, 0, 0, 0, 151, 0, 0, 0, 151, 0, 0, 0, 151, 0, 0, 0, 151, 0, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 151, 1, 1, 1, 150, 1, 1, 1, 150, 1, 0, 0, 150, 0, 0, 0, 150, 0, 0, 0, 149, 0, 0, 0, 149, 0, 0, 0, 149, 0, 1, 1, 148, 1, 1, 1, 148, 1, 1, 1, 148, 1, 1, 1, 147, 1, 0, 0, 147, 0, 0, 0, 146, 0, 0, 0, 146, 0, 0, 0, 146, 0, 0, 0, 145, 0, 0, 0, 145, 0, 1, 1, 144, 1, 1, 1, 144, 1, 1, 1, 143, 1, 1, 1, 143, 1, 1, 1, 142, 1, 0, 0, 141, 0, 0, 0, 141, 0, 0, 0, 140, 0, 0, 0, 140, 0, 0, 0, 139, 0, 0, 0, 138, 0, 1, 1, 138, 1, 1, 1, 137, 1, 1, 1, 137, 1, 1, 1, 136, 1, 1, 1, 135, 1, 1, 1, 134, 1, 0, 0, 134, 0, 0, 0, 133, 0, 0, 0, 132, 0, 0, 0, 132, 0, 0, 0, 131, 0, 1, 1, 130, 1, 1, 1, 129, 1, 1, 1, 129, 1, 1, 1, 128, 1, 0, 0, 127, 0, 0, 0, 126, 0, 0, 0, 125, 0, 0, 0, 125, 0, 0, 0, 124, 0, 0, 0, 123, 0, 1, 1, 122, 1, 1, 1, 121, 1, 1, 1, 120, 1, 1, 1, 119, 1, 1, 1, 119, 1, 0, 0, 118, 0, 0, 0, 117, 0, 0, 0, 116, 0, 0, 0, 114, 0, 0, 0, 113, 0, 0, 0, 112, 0, 1, 1, 111, 1, 1, 1, 110, 1, 1, 1, 109, 1, 1, 1, 108, 1, 1, 1, 107, 1, 1, 1, 106, 1, 0, 0, 105, 0, 0, 0, 104, 0, 0, 0, 103, 0, 0, 0, 102, 0, 0, 0, 101, 0, 1, 1, 100, 1, 1, 1, 99, 1, 1, 1, 98, 1, 1, 1, 97, 1, 0, 0, 96, 0, 0, 0, 95, 0, 0, 0, 94, 0, 0, 0, 93, 0, 0, 0, 92, 0, 0, 0, 91, 0, 1, 1, 90, 1, 1, 1, 89, 1, 1, 1, 88, 1, 1, 1, 87, 1, 1, 1, 86, 1, 0, 0, 85, 0, 0, 0, 84, 0, 0, 0, 83, 0, 0, 0, 82, 0, 0, 0, 81, 0, 0, 0, 80, 0, 1, 1, 79, 1, 1, 1, 78, 1, 1, 1, 77, 1, 1, 1, 76, 1, 1, 1, 75, 1, 1, 1, 74, 1, 0, 0, 73, 0, 0, 0, 72, 0, 0, 0, 71, 0, 0, 0, 70, 0, 0, 0, 69, 0, 1, 1, 68, 1, 1, 1, 67, 1, 1, 1, 66, 1, 1, 1, 65, 1, 0, 0, 64, 0, 0, 0, 63, 0, 0, 0, 62, 0, 0, 0, 61, 0, 0, 0, 60, 0, 0, 0, 59, 0, 1, 1, 58, 1, 1, 1, 57, 1, 1, 1, 56, 1, 1, 1, 55, 1, 1, 1, 54, 1, 0, 0, 53, 0, 0, 0, 52, 0, 0, 0, 51, 0, 0, 0, 50, 0, 0, 0, 49, 0, 0, 0, 48, 0, 1, 1, 47, 1, 1, 1, 46, 1, 1, 1, 45, 1, 1, 1, 44, 1, 1, 1, 43, 1, 1, 1, 42, 1, 0, 0, 41, 0, 0, 0, 40, 0, 0, 0, 39, 0, 0, 0, 38, 0, 0, 0, 37, 0, 1, 1, 36, 1, 1, 1, 35, 1, 1, 1, 34, 1, 1, 1, 33, 1, 0, 0, 32, 0, 0, 0, 31, 0, 0, 0, 30, 0, 0, 0, 29, 0, 0, 0, 28, 0, 0, 0, 27, 0, 1, 1, 26, 1, 1, 1, 25, 1, 1, 1, 24, 1, 1, 1, 23, 1, 1, 1, 22, 1, 0, 0, 21, 0, 0, 0, 20, 0, 0, 0, 19, 0, 0, 0, 18, 0, 0, 0, 17, 0, 0, 0, 16, 0, 1, 1, 15, 1, 1, 1, 14, 1, 1, 1, 13, 1, 1, 1, 12, 1, 1, 1, 11, 1, 1, 1, 10, 1, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 5, 0, 1, 1, 4, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 0];
    
    const weights2 = [0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 22, 0, 0, 0, 30, 0, 0, 0, 38, 0, 1, 1, 46, 1, 1, 1, 53, 1, 1, 1, 60, 1, 1, 1, 67, 1, 1, 1, 74, 1, 0, 0, 80, 0, 0, 0, 86, 0, 0, 0, 92, 0, 0, 0, 97, 0, 0, 0, 103, 0, 0, 0, 108, 0, 1, 1, 113, 1, 1, 1, 117, 1, 1, 1, 122, 1, 1, 1, 126, 1, 1, 1, 130, 1, 1, 1, 134, 1, 0, 0, 137, 0, 0, 0, 140, 0, 0, 0, 144, 0, 0, 0, 147, 0, 0, 0, 150, 0, 1, 1, 152, 1, 1, 1, 155, 1, 1, 1, 157, 1, 1, 1, 160, 1, 0, 0, 162, 0, 0, 0, 164, 0, 0, 0, 166, 0, 0, 0, 167, 0, 0, 0, 169, 0, 0, 0, 171, 0, 1, 1, 172, 1, 1, 1, 173, 1, 1, 1, 174, 1, 1, 1, 176, 1, 1, 1, 177, 1, 0, 0, 178, 0, 0, 0, 178, 0, 0, 0, 179, 0, 0, 0, 180, 0, 0, 0, 181, 0, 0, 0, 181, 0, 1, 1, 182, 1, 1, 1, 182, 1, 1, 1, 182, 1, 1, 1, 183, 1, 1, 1, 183, 1, 1, 1, 183, 1, 0, 0, 183, 0, 0, 0, 183, 0, 0, 0, 183, 0, 0, 0, 183, 0, 0, 0, 183, 0, 1, 1, 183, 1, 1, 1, 183, 1, 1, 1, 183, 1, 1, 1, 183, 1, 0, 0, 182, 0, 0, 0, 182, 0, 0, 0, 182, 0, 0, 0, 181, 0, 0, 0, 181, 0, 0, 0, 180, 0, 1, 1, 180, 1, 1, 1, 180, 1, 1, 1, 179, 1, 1, 1, 178, 1, 1, 1, 178, 1, 0, 0, 177, 0, 0, 0, 177, 0, 0, 0, 176, 0, 0, 0, 175, 0, 0, 0, 175, 0, 0, 0, 174, 0, 1, 1, 173, 1, 1, 1, 173, 1, 1, 1, 172, 1, 1, 1, 171, 1, 1, 1, 170, 1, 1, 1, 169, 1, 0, 0, 169, 0, 0, 0, 168, 0, 0, 0, 167, 0, 0, 0, 166, 0, 0, 0, 165, 0, 1, 1, 164, 1, 1, 1, 164, 1, 1, 1, 163, 1, 1, 1, 162, 1, 0, 0, 161, 0, 0, 0, 160, 0, 0, 0, 159, 0, 0, 0, 157, 0, 0, 0, 156, 0, 0, 0, 155, 0, 1, 1, 154, 1, 1, 1, 153, 1, 1, 1, 152, 1, 1, 1, 151, 1, 1, 1, 150, 1, 0, 0, 149, 0, 0, 0, 148, 0, 0, 0, 147, 0, 0, 0, 146, 0, 0, 0, 145, 0, 0, 0, 144, 0, 1, 1, 143, 1, 1, 1, 142, 1, 1, 1, 141, 1, 1, 1, 140, 1, 1, 1, 139, 1, 1, 1, 138, 1, 0, 0, 137, 0, 0, 0, 136, 0, 0, 0, 135, 0, 0, 0, 134, 0, 0, 0, 133, 0, 1, 1, 132, 1, 1, 1, 131, 1, 1, 1, 130, 1, 1, 1, 129, 1, 0, 0, 128, 0, 0, 0, 127, 0, 0, 0, 126, 0, 0, 0, 125, 0, 0, 0, 124, 0, 0, 0, 123, 0, 1, 1, 122, 1, 1, 1, 121, 1, 1, 1, 120, 1, 1, 1, 119, 1, 1, 1, 118, 1, 0, 0, 117, 0, 0, 0, 116, 0, 0, 0, 115, 0, 0, 0, 114, 0, 0, 0, 113, 0, 0, 0, 112, 0, 1, 1, 111, 1, 1, 1, 110, 1, 1, 1, 109, 1, 1, 1, 108, 1, 1, 1, 107, 1, 1, 1, 106, 1, 0, 0, 105, 0, 0, 0, 104, 0, 0, 0, 103, 0, 0, 0, 102, 0, 0, 0, 101, 0, 1, 1, 100, 1, 1, 1, 99, 1, 1, 1, 98, 1, 1, 1, 97, 1, 0, 0, 96, 0, 0, 0, 95, 0, 0, 0, 94, 0, 0, 0, 93, 0, 0, 0, 92, 0, 0, 0, 91, 0, 1, 1, 90, 1, 1, 1, 89, 1, 1, 1, 88, 1, 1, 1, 87, 1, 1, 1, 86, 1, 0, 0, 85, 0, 0, 0, 84, 0, 0, 0, 83, 0, 0, 0, 82, 0, 0, 0, 81, 0, 0, 0, 80, 0, 1, 1, 79, 1, 1, 1, 78, 1, 1, 1, 77, 1, 1, 1, 76, 1, 1, 1, 75, 1, 1, 1, 74, 1, 0, 0, 73, 0, 0, 0, 72, 0, 0, 0, 71, 0, 0, 0, 70, 0, 0, 0, 69, 0, 1, 1, 68, 1, 1, 1, 67, 1, 1, 1, 66, 1, 1, 1, 65, 1, 0, 0, 64, 0, 0, 0, 63, 0, 0, 0, 62, 0, 0, 0, 61, 0, 0, 0, 60, 0, 0, 0, 59, 0, 1, 1, 58, 1, 1, 1, 57, 1, 1, 1, 56, 1, 1, 1, 55, 1, 1, 1, 54, 1, 0, 0, 53, 0, 0, 0, 52, 0, 0, 0, 51, 0, 0, 0, 50, 0, 0, 0, 49, 0, 0, 0, 48, 0, 1, 1, 47, 1, 1, 1, 46, 1, 1, 1, 45, 1, 1, 1, 44, 1, 1, 1, 43, 1, 1, 1, 42, 1, 0, 0, 41, 0, 0, 0, 40, 0, 0, 0, 39, 0, 0, 0, 38, 0, 0, 0, 37, 0, 1, 1, 36, 1, 1, 1, 35, 1, 1, 1, 34, 1, 1, 1, 33, 1, 0, 0, 32, 0, 0, 0, 31, 0, 0, 0, 30, 0, 0, 0, 29, 0, 0, 0, 28, 0, 0, 0, 27, 0, 1, 1, 26, 1, 1, 1, 25, 1, 1, 1, 24, 1, 1, 1, 23, 1, 1, 1, 22, 1, 0, 0, 21, 0, 0, 0, 20, 0, 0, 0, 19, 0, 0, 0, 18, 0, 0, 0, 17, 0, 0, 0, 16, 0, 1, 1, 15, 1, 1, 1, 14, 1, 1, 1, 13, 1, 1, 1, 12, 1, 1, 1, 11, 1, 1, 1, 10, 1, 0, 0, 9, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 5, 0, 1, 1, 4, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 0];
  • §

    Initialization function (exported)

    const initializeEntityNavigation = (items = {}, scrawl) => {
  • §

    Check we have required arguments/values

        const { canvas, cell, dashboard } = items;
    
        if (scrawl == null) throw new Error('SC entity navigation module error: missing Scrawl-canvas object argument');
    
        let argsCheck = '';
    
        if (canvas == null) argsCheck += ' - Canvas wrapper';
        if (cell == null) argsCheck += ' - Cell wrapper';
        if (dashboard == null) argsCheck += ' - DOM entity editor dashboard functionality';
    
        if (argsCheck.length) throw new Error(`SC entity navigation module error: missing arguments${argsCheck}`);
  • §

    Make an object to hold functions we’ll use for UI

        const setCursorTo = {
    
            auto: () => {
                canvas.set({
                    css: {
                        cursor: 'auto',
                    },
                });
            },
            pointer: () => {
                canvas.set({
                    css: {
                        cursor: 'pointer',
                    },
                });
            },
            grabbing: () => {
                canvas.set({
                    css: {
                        cursor: 'grabbing',
                    },
                });
            },
        };
  • §

    Sometimes the supplied cell may not be shown directly in the canvas - for example, the canvas-minimap.js module does not directly show its mainCell; in these cases we need to make sure entitys in the Cell get included in the event cascade

        cell.set({
            includeInCascadeEventActions: true,
            checkForEntityHover: true,
            onEntityHover: setCursorTo.pointer,
            onEntityNoHover: setCursorTo.auto,
        });
  • §

    Entity selection for editing

    Editing options are dependant on:

    • if more than 1 entitys selected, then a restricted set of editing options get presented and will affect all entitys (in a delta-like manner)
    • if only one entity is selected, then editing options should relate to that entity’s type

    We use a filter to help indicate which entitys are currently selected

        scrawl.makeFilter({
            name: 'selected-entitys-border',
            actions: [
                {
                    action: 'invert-channels',
                    lineIn: 'source-alpha',
                    includeGreen: false,
                    includeBlue: false,
                },
                {
                    action: 'gaussian-blur',
                    radius: 2,
                },
                {
                    action: 'vary-channels-by-weights',
                    useMixedChannel: false,
                    weights: weights2,
                },
            ],
        });
  • §

    Group compile ordering

    • keyboardEntitys group two beneath the canvas base group
    • selectedEntitys group above keyboardEntitys group
    • the canvas base group needs to be raised by two to accommodate these additional groups
        const canvasGroup = cell.get('group');
        let canvasOrder = 2;
    
        if (canvasGroup) {
    
            canvasOrder = canvasGroup.get('order') + 2;
    
            canvasGroup.set({
                order: canvasOrder,
            });
        }
    
        const selectedEntitys = scrawl.makeGroup({
            name: `${cell.name}-selected-entitys`,
            host: cell.name,
            order: canvasOrder - 1,
            filters: ['selected-entitys-border'],
            memoizeFilterOutput: true,
        });
  • §

    Function to add/remove an entity to/from the selectedEntitys Group

        const selectEntity = (entity) => {
    
            const arts = selectedEntitys.artefacts;
    
            if (arts.includes(entity.name)) selectedEntitys.removeArtefacts(entity);
            else selectedEntitys.addArtefacts(entity);
  • §

    Selected entitys have a red border around them, to make them easier to identify

    • We need to reset the group filter memoization to make them display
    • Recalculating the borders is too expensive to do this on every Display cycle
            selectedEntitys.set({
                noFilters: false,
            });
    
            dashboard.refresh(selectedEntitys, updateControllersDisplayOnEnd);
        };
    
        const clearSelectedEntitys = () => {
    
            selectedEntitys.clearArtefacts();
    
            selectedEntitys.set({
                noFilters: false,
            });
    
            dashboard.refresh(selectedEntitys, updateControllersDisplayOnEnd);
        };
  • §

    A set of attributes that can be applied to entitys to include them from the entity controllers system

        const addControllerAttributes = {
    
            onUp: function (e) {
    
                if (e.shiftKey) selectEntity(this);
            },
        };
  • §

    A set of attributes that can be applied to entitys to remove them from the entity controllers system

        const removeControllerAttributes = {
            onUp: () => {},
        };
    
        const cascade = (e) => canvas.cascadeEventAction('up', e);
        scrawl.addListener('up', cascade, canvas.domElement);
  • §

    Accessibility - Keyboard navigation

        canvas.set({
            role: 'application',
            includeInTabNavigation: true,
        });
  • §

    Setup a group which will display the current keyboard-navigated entity

        scrawl.makeFilter({
            name: 'keyboard-entitys-border',
            actions: [
                {
                    action: 'gaussian-blur',
                    lineIn: 'source-alpha',
                    radius: 3,
                },
                {
                    action: 'vary-channels-by-weights',
                    useMixedChannel: false,
                    weights: weights1,
                },
            ],
        });
    
        const keyboardEntitys = scrawl.makeGroup({
            name: `${cell.name}-keyboard-entitys`,
            host: cell.name,
            order: canvasOrder - 2,
            filters: ['keyboard-entitys-border'],
            memoizeFilterOutput: true,
        });
  • §

    Setup some state to keep track of navigable entitys, and where we currently are in that list

        const entityNames = [];
        let currentKeyboardEntity;
    
        const updateEntityNames = () => {
    
            entityNames.length = 0;
            entityNames.push(...canvasGroup.artefacts);
        };
    
        const getNextEntity = (forward = true) => {
    
            updateEntityNames();
    
            const len = entityNames.length;
    
            if (!len) return null;
    
            if (len === 1 || !currentKeyboardEntity) return canvasGroup.getArtefact(entityNames[0]);
    
            let entityIndex = entityNames.indexOf(currentKeyboardEntity.name);
    
            if (entityIndex < 0) return null;
    
            if (forward) entityIndex++;
            else entityIndex--;
    
            if (entityIndex < 0) entityIndex = len - 1;
            else if (entityIndex >= len) entityIndex = 0;
    
            return canvasGroup.getArtefact(entityNames[entityIndex]) || null;
        };
    
        const keyboardNavigateEntitys = (forward = true) => {
    
            currentKeyboardEntity = getNextEntity(forward);
    
            keyboardEntitys.clearArtefacts();
    
            if (currentKeyboardEntity) keyboardEntitys.addArtefacts(currentKeyboardEntity);
    
            keyboardEntitys.set({
                noFilters: false,
            });
        };
  • §

    Add/remove a highlighted entity to/from the selection

        const keyboardSelectEntity = () => {
    
            if (currentKeyboardEntity) selectEntity(currentKeyboardEntity);
        };
  • §

    Move the highlighted entity

        const keyboardPositionEntity = (direction = '', delta = 1) => {
  • §

    Check we have an entity to move, and in which direction to move it

            if (direction && currentKeyboardEntity) {
  • §

    Perform the move

                switch (direction) {
    
                    case 'left' :
                        currentKeyboardEntity.setDelta({
                            startX: -delta,
                        });
                        break;
    
                    case 'right' :
                        currentKeyboardEntity.setDelta({
                            startX: delta,
                        });
                        break;
    
                    case 'up' :
                        currentKeyboardEntity.setDelta({
                            startY: -delta,
                        });
                        break;
    
                    case 'down' :
                        currentKeyboardEntity.setDelta({
                            startY: delta,
                        });
                        break;
                }
  • §

    Trigger the Group filters to update their output

                keyboardEntitys.set({
                    noFilters: false,
                });
    
                if (selectedEntitys.artefacts.includes(currentKeyboardEntity.name)) {
    
                    selectedEntitys.set({
                        noFilters: false,
                    });
                }
            }
        };
  • §

    Keyboard event listener functions

        const keyboard = scrawl.makeKeyboardZone({
    
            zone: canvas,
    
            shiftOnly: {
                Backspace: () => clearSelectedEntitys(),
                Enter: () => keyboardSelectEntity(),
                ArrowLeft: () => keyboardPositionEntity('left'),
                ArrowUp: () => keyboardPositionEntity('up'),
                ArrowRight: () => keyboardPositionEntity('right'),
                ArrowDown: () => keyboardPositionEntity('down'),
            },
    
            none: {
                Backspace: () => clearSelectedEntitys(),
                Enter: () => keyboardSelectEntity(),
                ArrowLeft: () => keyboardNavigateEntitys(true),
                ArrowRight: () => keyboardNavigateEntitys(false),
            },
        });
  • §

    Drag-and-drop entitys

        const updateControllersDisplayOnStart = () => {
    
            keyboardEntitys.set({
                noFilters: true,
            });
            selectedEntitys.set({
                noFilters: true,
            });
            setCursorTo.grabbing();
        };
    
        const updateControllersDisplayOnEnd = () => {
    
            keyboardEntitys.set({
                noFilters: false,
            });
            selectedEntitys.set({
                noFilters: false,
            });
            setCursorTo.pointer();
        };
  • §

    Keep the DOM entity editor’s form synchronised with selected entity movement

        const enqueueDashboardUpdates = () => {
    
            if (selectedEntitys.artefacts.length === 1) {
    
                const name = selectedEntitys.artefacts[0];
    
                const artefact = selectedEntitys.getArtefact(name);
    
                const [startX, startY] = artefact.get('start');
    
                dashboard.queue.push({
                    startX: Math.round(startX),
                    startY: Math.round(startY),
                });
            }
        };
  • §

    Drag entitys around the scene

        const entityNavigationDrag = scrawl.makeDragZone({
            zone: canvas,
            coordinateSource: cell,
            collisionGroup: cell.name,
            endOn: ['up', 'leave'],
            preventTouchDefaultWhenDragging: true,
            updateOnStart: updateControllersDisplayOnStart,
            updateOnEnd: () => {
                updateControllersDisplayOnEnd();
                enqueueDashboardUpdates();
            },
            processingOrder: 100,
        });
  • §

    Show the DOM entity editor’s initial message

        dashboard.refresh(selectedEntitys, updateControllersDisplayOnEnd);
  • §

    Cleanup and return

        const killEntityNavigation = () => {
            selectedEntitys.kill(true);
            keyboardEntitys.kill(true);
            cascade();
            entityNavigationDrag();
            keyboard.kill();
        };
  • §

    Return object

        return {
            selectedEntitys,
            addControllerAttributes,
            removeControllerAttributes,
            checkForEntityNavigationHoverActions: () => canvas.checkHover(),
            updateControllerDisplay: {
                onStart: updateControllersDisplayOnStart,
                onEnd: updateControllersDisplayOnEnd,
                setCursorTo,
            },
            killEntityNavigation,
        };
    };
  • §

    Export

    export {
        initializeEntityNavigation,
    };