2

I wrote the code for making an interactive graph which have some major problems.

The idea is that first, I want to display three clickable SVGs. After clicking on one of them, the two unclicked SVGs have to hide, the clicked one stays on the screen, and the new one appears. From that point, the user can add each time one SVG to the chart by clicking on the most recently added SVG (the previous ones become not clickable).

I have created JS class to contain nodes that will have data linked to them and each element from the class will have d3.js SVG element.

I have some problems with my code. There is a problem with removing clicked SVG object from array with JS node-classes (I can remove notclicked SVGs from the screen, but how to remove them from JS array?). For some reason, in the second part of the interaction, two SVGs appear, not one, and after more clicking the amount of SVGs on the screen is way too big. I think I have major problems with flagging what can be clicked and how many things appear on the screen. Also my graph appears outside the DOM element.

It would be great to get some help with this code:


const nodes = []; // array to contain created and visible node obj

let clicked = 'false'; // flag clicked SVG

const graphSpace = d3.select('#graph');
const width = window.innerWidth;
const height = window.innerHeight;
const svg = graphSpace.append('svg')
    .attr('width', width)
    .attr('height', height);

function init() {
    let initialNode;
    //create 3 objects in array and render svg elements in html
    for(let i = 0; i < 3; i++) {
        initialNode = new NodeObject(nodeData[i].name, nodeData[i].description, nodeData[i].symbol, nodeData[i].nodeArray, Math.random() * width, Math.random() * height);
        nodes.push(initialNode);
        createInitialNode();
    }
}

function createInitialNode() {
    // render SVG elements
    let rand = Math.floor(Math.random() * 5) + 1;

    svg.selectAll('.node')
        .data(nodes) // asocjacja kolekcji elementów z danymi
        .enter()
        .append('image')
        .attr('class', 'node')
        .attr('x', d => d.x)
        .attr('y', d => d.y)
        .attr('width', 220)
        .attr('height', 220)
        .attr('xlink:href', 'svg/s' + rand + '.svg')
}

function firstClick() {
    let notClickedNodes = [];
    // after first click leave clicked SVG, hide 2 not-clicked SVGs and create new SVG
    svg.selectAll('.node').on('click', (event, d) => {
        if(clicked === 'false') {
            d3.select(event.currentTarget).attr('class', 'clicked') // change class of the clicked element to 'clicked'
            d3.selectAll('.node') // select remaining SVGs
                .attr('class', 'notClickedInitial'); // add class to not clicked SVGs
            d3.selectAll('.notClickedInitial').remove();
            // remove those nodes from the nodes array - how?
            clicked = 'true';
        }
        addNode(d);
    });

}

init();
firstClick();

function addNode(d) { //
    nodes.push({x: Math.random() * width, y: Math.random() * height});

    let rand = Math.floor(Math.random() * 5) + 1;

    const node = svg.selectAll('.clicked')
        .data(nodes)
        .enter()
        .append('image')
        .attr('class', 'notClicked')
        .attr('x', d => d.x)
        .attr('y', d => d.y)
        .attr('width', 220)
        .attr('height', 220)
        .attr('xlink:href', 'svg/s' + rand + '.svg')

    let count = 0;

    svg.selectAll('.notClicked').on('click', (event, d) => {
        if(count === 0) {
            d3.select(event.currentTarget).attr('class', 'clicked')
            addNode(d);
            console.log(nodes);
            count += 1;
        }
    });
}

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.