• 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 a large Cell wrapper which we can use to host the entitys to be used in the scene, alongside a draggable, keyboard accessible minimap for navigating around the Cell. The module will also add the following zones to the supplied Canvas wrapper:

    • A frame drag zone, to drag the frame around the map - the main navigation functionality (processingOrder: 20)
    • A map drag zone, to drag the map around the Canvas wrapper’s base Cell (processingOrder: 21)
    • A keyboard zone - the frame and map can be moved using ALT + arrows keystrokes, and can be hidden/revealed using the ALT + backspace keystroke

    Inputs to the initializeMinimap function

    • canvas - SC canvas wrapper object (required)
    • mainDimensions - a Number, or an array of [width, height] Numbers, setting the size of the scene Cell which will be returned to the calling code (default: 1600)
    • mapDimensions - a Number, or an array of [width, height] Numbers, setting the size of minimap that appears on the scene Cell (default: 200)

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

    • checkForMinimapChanges - a function that can be invoked by an animation object, to adjust responsively to changes in the host DOM canvas element’s dimensions (responsive canvas)
    • mainCell - the scene Cell wrapper object
    • killCanvasMinimap - kill function, to remove everything associated with the scene Cell and minimap from the SC library
  • §

    Initialization function (exported)

    const initializeMinimap = (args = {}, scrawl) => {
  • §

    Check we have required arguments/values

        if (scrawl == null) throw new Error('SC entity navigation module error: missing Scrawl-canvas object argument');
    
    /* eslint-disable-next-line */
        let { mainDimensions, mapDimensions, supportedKey, canvas } = args;
    
        let argsCheck = '';
    
        if (canvas == null) argsCheck += ' Canvas wrapper;';
    
        if (argsCheck.length) throw new Error(`SC canvas minimap module error: missing arguments -${argsCheck}`);
  • §

    Magic numbers

        let mainDimensionX = 1600,
            mainDimensionY = 1600,
            mapDimensionX = 200,
            mapDimensionY = 200;
    
        if (mainDimensions) {
    
            if (Array.isArray(mainDimensions)){
    
                mainDimensionX = mainDimensions[0] || 1600;
                mainDimensionY = mainDimensions[1] || 1600;
            }
            else if (mainDimensions.toFixed) {
    
                mainDimensionX = mainDimensions || 1600;
                mainDimensionY = mainDimensions || 1600;
            }
        }
    
        if (mapDimensions) {
    
            if (Array.isArray(mapDimensions)){
    
                mapDimensionX = mapDimensions[0] || 200;
                mapDimensionY = mapDimensions[1] || 200;
            }
            else if (mapDimensions.toFixed) {
    
                mapDimensionX = mapDimensions || 200;
                mapDimensionY = mapDimensions || 200;
            }
        }
    
        const mainMapRatioX = mainDimensionX / mapDimensionX,
            mainMapRatioY = mainDimensionY / mapDimensionY;
    
        let [displayWidth, displayHeight] = canvas.get("dimensions");
    
        let frameWidth = (displayWidth / mainDimensionX) * mapDimensionX;
        let frameHeight = (displayHeight / mainDimensionY) * mapDimensionY;
    
        canvas.set({
            includeInTabNavigation: true,
        });
  • §

    Build out the main Cell (default: 1600px x 1600px)

    • we don’t actually display this Cell
        const mainCell = canvas.buildCell({
    
            name: "main-cell",
            dimensions: [mainDimensionX, mainDimensionY],
            shown: false,
        });
  • §

    Rely on the main code to populate the main Cell with entitys, and the functionality required to interact with them. We only care here about displaying the main map in the canvas element

  • §

    Display the main Cell in the base Cell

        const mainCellPicture = scrawl.makePicture({
    
            name: "main-cell-picture",
            group: canvas.base.name,
            asset: "main-cell",
            dimensions: [displayWidth, displayHeight],
            copyDimensions: [displayWidth, displayHeight]
        });
  • §

    Build out the smaller map Cell (default: 200px x 200px)

    • this will initially display in the top right corner
    • it will be draggable too
        const pivotGroup = scrawl.makeGroup({
    
            name: "map-cell-pivot-group",
            host: canvas.base.name
        });
    
        const mapPivot = scrawl.makeBlock({
    
            name: "map-cell-pivot",
            group: "map-cell-pivot-group",
            start: [displayWidth - mapDimensionX, 0],
            dimensions: [mapDimensionX, mapDimensionY],
            method: "none"
        });
  • §

    Functionality so we can drag-drop the map Cell around the base Cell

        const mapDragZone = scrawl.makeDragZone({
            zone: canvas,
            collisionGroup: "map-cell-pivot-group",
            coordinateSource: canvas.base,
            endOn: ["up", "leave"],
            preventTouchDefaultWhenDragging: true,
            processingOrder: 21,
        });
    
        const mapCell = canvas.buildCell({
    
            name: "map-cell",
            dimensions: [mapDimensionX, mapDimensionY],
  • §

    We pivot the map Cell to the draggable Block entity

    • wherever the Block goes, the map Cell will follow
            pivot: "map-cell-pivot",
            lockTo: "pivot",
            backgroundColor: "white",
  • §

    The map Cell needs to compile after the large Cell

            compileOrder: 1
        });
  • §

    Now we can copy the large Cell into the map Cell

        scrawl.makePicture({
    
            name: "map-cell-picture",
            group: "map-cell",
            asset: "main-cell",
            dimensions: ["100%", "100%"],
            copyDimensions: ["100%", "100%"],
            lineWidth: 4,
            method: "fillThenDraw",
        });
  • §

    Add the draggable map frame

        const myFrameGroup = scrawl.makeGroup({
    
            name: "map-cell-frame-group",
            host: mapCell.name
        });
    
        const frame = scrawl.makeBlock({
    
            name: "map-cell-frame",
            group: "map-cell-frame-group",
            dimensions: [frameWidth, frameHeight],
            strokeStyle: "red",
            lineWidth: 2,
            method: "draw"
        });
  • §

    Functionality so we can drag-drop the frame around the map Cell

        const checkPermittedFramePosition = (x, y) => {
    
            if (x < 0 || y < 0) return false;
            if (x + frameWidth > mapDimensionX) return false;
            if (y + frameHeight > mapDimensionY) return false;
    
            return true;
        };
    
        const updateFrames = (x, y) => {
    
            const newX = x * mainMapRatioX,
            newY = y * mainMapRatioY;
  • §

    Adjust the position of the Picture wrt to the frame in the map

            mainCellPicture.set({
                copyStartX: newX,
                copyStartY: newY
            });
  • §

    Adjust the position of the large Cell wrt the base Cell

            mainCell.set({
                startX: -newX,
                startY: -newY
            });
        };
    
        const exitDrag = () => {
    
            let [x, y] = frame.get('position');
    
            if (x < 0) x = 0;
            if (y < 0) y = 0;
            if (x + frameWidth > mapDimensionX) x = mapDimensionX - frameWidth;
            if (y + frameHeight > mapDimensionY) y = mapDimensionY - frameHeight;
    
            frame.set({
                start: [x, y],
            });
    
            updateFrames(x, y);
        };
    
        const checkMinimapFrameDrag = () => {
    
            const [x, y] = frame.get('position');
    
            if (checkPermittedFramePosition(x, y)) updateFrames(x, y);
            else frameDragZone('exit');
        };
    
        const frameDragZone = scrawl.makeDragZone({
    
            zone: canvas,
            collisionGroup: "map-cell-frame-group",
            coordinateSource: mapCell,
            endOn: ["up", "leave"],
            updateWhileMoving: checkMinimapFrameDrag,
            updateOnPrematureExit: exitDrag,
            preventTouchDefaultWhenDragging: true,
            exposeCurrentArtefact: true,
            processingOrder: 20,
        });
    
    
        const checkForMinimapChanges = () => {
    
            const [w, h] = canvas.get("dimensions");
    
            if (w !== displayWidth || h !== displayHeight) {
    
                displayWidth = w;
                displayHeight = h;
    
                frameWidth = (displayWidth / mainDimensionX) * mapDimensionX;
                frameHeight = (displayHeight / mainDimensionY) * mapDimensionY;
    
                mainCellPicture.set({
                    dimensions: [displayWidth, displayHeight],
                    copyDimensions: [displayWidth, displayHeight]
                });
    
                frame.set({
                    dimensions: [frameWidth, frameHeight]
                });
    
                mapPivot.set({
                    start: [displayWidth - mapDimensionX, 0]
                });
            }
    
            mainCell.updateHere();
            mapCell.updateHere();
        };
  • §

    Keyboard navigation

        const moveFrame = (direction) => {
    
            let [x, y] = frame.get('position');
    
            switch (direction) {
    
                case 'left' :
                    x -= 1;
                    break;
                case 'up' :
                    y -= 1;
                    break;
                case 'right' :
                    x += 1;
                    break;
                case 'down' :
                    y += 1;
                    break;
            }
    
            if(checkPermittedFramePosition(x, y)) {
    
                const newX = x * mainMapRatioX,
                    newY = y * mainMapRatioY;
    
                frame.set({
                    startX: x,
                    startY: y,
                });
  • §

    Adjust the position of the Picture wrt to the frame in the map

                mainCellPicture.set({
                    copyStartX: newX,
                    copyStartY: newY
                });
  • §

    Adjust the position of the large Cell wrt the base Cell

                mainCell.set({
                    startX: -newX,
                    startY: -newY
                });
            }
        };
    
        const moveMinimap = (direction) => {
    
            let [x, y] = mapPivot.get('position');
    
            switch (direction) {
    
                case 'left' :
                    x -= 2;
                    break;
                case 'up' :
                    y -= 2;
                    break;
                case 'right' :
                    x += 2;
                    break;
                case 'down' :
                    y += 2;
                    break;
            }
    
            mapPivot.set({
                startX: x,
                startY: y,
            });
        };
  • §

    Show/hide minimap

        let minimapIsShowing = true;
        const displayMinimap = () => {
    
            minimapIsShowing = !minimapIsShowing;
    
            mapPivot.set({
                visibility: minimapIsShowing,
            });
    
            mapCell.set({
                shown: minimapIsShowing,
            });
        };
  • §

    Keyboard event listener functions

        const keyboard = scrawl.makeKeyboardZone({
    
            zone: canvas,
    
            shiftAlt: {
                Backspace: () => displayMinimap(),
                ArrowLeft: () => moveMinimap('left'),
                ArrowUp: () => moveMinimap('up'),
                ArrowRight: () => moveMinimap('right'),
                ArrowDown: () => moveMinimap('down'),
            },
    
            altOnly: {
                Backspace: () => displayMinimap(),
                ArrowLeft: () => moveFrame('left'),
                ArrowUp: () => moveFrame('up'),
                ArrowRight: () => moveFrame('right'),
                ArrowDown: () => moveFrame('down'),
            },
        });
  • §

    Cleanup and return

        const killCanvasMinimap = () => {
            pivotGroup.kill(true);
            myFrameGroup.kill(true);
            mainCell.get('group').kill(true);
            mapCell.get('group').kill(true);
            keyboard.kill();
            frameDragZone();
            mapDragZone();
        };
  • §

    Return object

        return {
            mainCell,
            checkForMinimapChanges,
            killCanvasMinimap,
        };
    };
  • §

    Export

    export {
        initializeMinimap,
    };