focus.js

/**
 * @file Activate/disable focus on a node and focus controls.
 * @author Guillaume Brioudes
 * @copyright MIT License ANR HyperOtlet
 */

/**
 * Display some nodes, hide all others
 * Turn on the 'focusMode'
 * @param {string} nodeIdsList - List of ids from nodes to keep displayed
 */

 function nodeFocus(nodeIdsList) {
    view.focusMode = false; // for reset display

    let idsToHide = [];

    graph.nodes = graph.nodes.map(function(item) {
        if (nodeIdsList.includes(item.id)) {
            // if item comes from the nodeIdsList
            item.isolated = true;
        } else {
            item.isolated = false;
            idsToHide.push(item.id);
        }
        return item;
    });

    // display nodeIds if their are not filtered
    const filteredNodes = getNodesHideByFilter();
    let idsToDisplay = nodeIdsList
        .filter(id => !filteredNodes.includes(id));

    hideNodes(idsToHide);
    view.focusMode = true;
    displayNodes(idsToDisplay);
}

/** @namespace */

const focus = {
    checkbox: document.getElementById('focus-check'),
    range: document.getElementById('focus-range'),
    isActive: false,
    focusedNodeId: undefined,
    focusedNode: undefined,
    levels: [],

    /**
     * Get focus levels from the active record and lauche first one
     * @param {string | number} focusedNodeId - Id of the current activated record
     */
    init : function(focusedNodeId = view.openedRecordId) {
        if (focusedNodeId === undefined) { this.hide(); return; }

        this.focusedNodeId = Number(focusedNodeId);

        // get infos about the focused node
        this.focusedNode = document.querySelector('[data-node="' + this.focusedNodeId + '"]');
        this.focusedNode.classList.add('focus');
        highlightNodes([focusedNodeId]);
        // get focus levels and limit it
        this.levels = graph.nodes.find(i => i.id === this.focusedNodeId).focus;
        this.range.setAttribute('max', this.levels.length)
        // launch use
        this.display();
        this.range.focus(); // to control range with keyboard arrows
        this.set(1);
    },

    /**
     * Reset and display and active focus inputs
     */
    display: function() {
        this.checkbox.checked = true;
        this.range.classList.add('active');
        this.range.value = 1;
    },

    /**
     * Reset and hide focus inputs
     */
    hide : function() {
        this.checkbox.checked = false;
        this.range.classList.remove('active');
        this.range.value = 1;
    },

    /**
     * Lauch a focus level
     * @param {number} level - Level number
     */
    set: function(level) {
        this.isActive = true;

        // cut the levels array to keep the targeted level and others before
        level = this.levels.slice(0, level);
        level.push([this.focusedNodeId]); // add the node id as a level
        level = level.flat(); // merge all levels as one focus

        nodeFocus(level);
    },

    /**
     * Unset focus parameters and focus
     * @param {number} level - Level number
     */
    disable : function() {
        if (this.isActive === false) { return; }

        // throw infos about the focus
        this.isActive = false;
        this.focusedNode.classList.remove('focus');
        this.focusedNode = undefined;
        this.focusedNodeId = undefined;
        this.levels = [];

        this.hide();
        resetFocus();
    }
}

focus.checkbox.addEventListener('change', () => {
    if (focus.checkbox.checked == true) {
        focus.init();
    } else {
        focus.disable();
    }
});

focus.range.addEventListener('change', () => {
    if (focus.range.value <= 1) {
        focus.range.value = 1; }

    focus.set(focus.range.value);
});

/**
 * Display nodes hidden by nodeFocus(),
 * if their are not filtered
 */

 function resetFocus() {
    view.focus = undefined;

    const filteredNodes = getNodesHideByFilter();

    const idsToDisplay = graph.nodes
        .filter(item => item.isolated === false && !filteredNodes.includes(item.id))
        .map(item => item.id);

    graph.nodes = graph.nodes.map(function(item) {
        item.isolated = false;
        return item;
    });

    view.focusMode = false;
    displayNodes(idsToDisplay);
}