Handling OnClick events in D3 with Websocket Integration

My goal is to implement a Websocket in JavaScript that transmits a variable obtained when clicking on a node in a D3 chart. While I have made progress using static data, I'm struggling with initiating the code upon node click to retrieve the "user information". At this point, what I need help with most is extracting the variable from the OnClick event on the D3 node and passing it as a parameter via Websocket for data retrieval to display.

Websocket:

var jsonObject = "";
var username = "test_123";

function init() {
  testWebSocket();
}

function testWebSocket() {
  websocket = new WebSocket(wsUri);
  websocket.onopen = function(evt) {
    onOpen(evt)
  };
  websocket.onclose = function(evt) {
    onClose(evt)
  };
  websocket.onmessage = function(evt) {
    onMessage(evt)
    testObject();
  };
  websocket.onerror = function(evt) {
    onError(evt)
  };
}

function onOpen(evt) {
  console.log("CONNECTED");
  doSend('{"request":"getTweetRelationshipGraphForUser", "screen_name" : }');
}

function onClose(evt) {
  console.log("DISCONNECTED");
}

function onMessage(evt) {
  console.log("Message: " + evt.data);
  jsonObject = evt.data;
  console.log("json object: "+jsonObject);
  return jsonObject;
  //  websocket.close();
}

function onError(evt) {
  console.log("Error:" + evt.data);
}

function doSend(message) {
  console.log("SENT: " + message);
  websocket.send(message);
}

function testObject(){
  document.getElementById("test").innerHTML = jsonObject;
  console.log(jsonObject);
}

window.addEventListener("load", init, false);

D3 Javascript

function start() {
  var w = 1200,
    h = 600,
    radius = 10,
    node,
    link,
    root;

  var count = 0;

  var force = d3.layout.force()
    .on("tick", tick)
    .charge(function (d) {
      return -500;
    })
    .linkDistance(function (d) {
      return d.target._children ? 100 : 50;
    })
    .size([w, h - 160]);

  var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h);

  svg.append("rect")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "#000");

  root = JSON.parse(jsonObject);
  console.log("root" + root);
  root.fixed = true;
  root.x = w / 2;
  root.y = h / 2 - 80;
  update();

  function update() {
    var nodes = root.nodes,
      links = root.links;

    // Restart the force layout.
    force
      .nodes(nodes)
      .links(links)
      .start();

    // Update the links…
    link = svg.selectAll(".link")
      .data(links);

    // Enter any new links.
    link.enter().insert("svg:line", ".node")
      .attr("class", "link")
      .attr("x1", function (d) {
        return d.source.x;
      })
      .attr("y1", function (d) {
        return d.source.y;
      })
      .attr("x2", function (d) {
        return d.target.x;
      })
      .attr("y2", function (d) {
        return d.target.y;
      });

    // Exit any old links.
    link.exit().remove();

    // Update the nodes…
    node = svg.selectAll("circle.node")
      .data(nodes, function (d) {
        return d.name;
      })
      .style("fill", color);

    node.transition()
      .attr("r", radius);

    // Enter any new nodes.
    node.enter().append("svg:circle")
      .attr("xlink:href", function (d) {
        return d.image;
      })
      .attr("class", "node")
      .attr("cx", function (d) {
        return d.x;
      })
      .attr("cy", function (d) {
        return d.y;
      })
      .attr("r", radius)
      .attr("r", function (d) {
        return d.size * 2;
      })
      .style("fill", color)
      .on("click", click)
      .call(force.drag);
    node.append("title")
      .text(function (d) {
        return d.name;
      });

    // Exit any old nodes.
    node.exit().remove();

    title = svg.selectAll("text.title")
      .data(nodes);

    // Enter any new titles.
    title.enter()
      .append("text")
      .attr("class", "title");
    //.text(function(d) { return d.name; });

    // Exit any old titles.
    title.exit().remove();
  }

  function tick() {
    link.attr("x1", function (d) {
      return d.source.x;
    })
      .attr("y1", function (d) {
        return d.source.y;
      })
      .attr("x2", function (d) {
        return d.target.x;
      })
      .attr("y2", function (d) {
        return d.target.y;
      });

    node.attr("cx", function (d) {
      return d.x;
    })
      .attr("cy", function (d) {
        return d.y;
      });

    title.attr("transform", function (d) {
      return "translate(" + d.x + "," + d.y + ")";
    });
  }

  // Color leaf nodes orange, and packages white or blue.
  function color(d) {
    if (d._children) {
      return "#95a5a6";
    } else {
      switch (d.group) {
        case 'r': //adverb
          return "#e74c3c";
          break;
        case 'n': //noun
          return "#3498db";
          break;
        case 'v': //verb
          return "#2ecc71";
          break;
        case 's': //adjective
          return "#e78229";
          break;
        default:
          return "rgb(0, 238, 238)";
      }
    }
  }

  // Toggle children on click.
  function click(d) {
    document.getElementById("image").src = d.image;
    document.getElementById("username").innerHTML = "Username:" + d.name;
    document.getElementById("id").innerHTML = "ID:" + d.id;
    document.getElementById("friends").innerHTML = d.friend;
    document.getElementById("nodeTitle").innerHTML = "";
    document.getElementById("size").innerHTML = d.size;
    //document.getElementById("id").innerHTML = "Friend Count:" + d.name;
    //if (d._children)
    //grabImage();
    //document.getElementById("image").innerHTML = (d.image);

    /*if (d.children) { 
     d._children = d.children;
     d.children = null;
     } else {
     d.children = d._children;
     d._children = null;
     }
     update();*/
  }

  function mouseover() {
    d3.select(this).select("circle").transition()
      .duration(750)
      .attr("r", 16);
  }


  function mouseout() {
    d3.select(this).select("circle").transition()
      .duration(750)
      .attr("r", 8);
  }

  // Returns a list of all nodes under the root.
  function flatten(root) {
    var nodes = [], i = 0;

    function recurse(node) {
      if (node.children) node.size = node.children.reduce(function (p, v) {
        return p + recurse(v);
      }, 0);
      if (!node.id) node.id = ++i;
      nodes.push(node);
      return node.size;
    }

    root.size = recurse(root);
    return nodes;
  }
}

do {
  var intervalID = window.setTimeout(start, 1000)
} while (jsonObject != "") {

}

Answer №1

After reviewing your needs, I have made some adjustments to the code provided. Currently, my focus is on implementing websockets for retrieving financial data and using d3.js for visualization. To achieve this, you need to establish an initialization point for the websocket connection and a rendering initiation point for the d3 code. These should be in a closed loop so that when a user clicks on a node, information is sent to the websocket, and upon receiving data from the websocket, the chart will be updated.

`    var jsonObject = "";
        var username = "test_123";

        function init() {
          testWebSocket();
        }

        function testWebSocket() {
          websocket = new WebSocket(wsUri);
          websocket.onopen = function(evt) {
            onOpen(evt)
          };
          websocket.onclose = function(evt) {
            onClose(evt)
          };
          websocket.onmessage = function(evt) {
            onMessage(evt)
            testObject();
          };
          websocket.onerror = function(evt) {
            onError(evt)
          };
        }

        function onOpen(evt) {
          console.log("CONNECTED");
          doSend('{"request":"getTweetRelationshipGraphForUser", "screen_name" : }');
        }

        function onClose(evt) {
          console.log("DISCONNECTED");
        }

        function onMessage(evt) {
          console.log("Message: " + evt.data);
          jsonObject = evt.data;

    //initiate the d3 rendering with new JSON
    start(jsonObject);


          console.log("json object: "+jsonObject);
          return jsonObject;
           }

        function onError(evt) {
          console.log("Error:" + evt.data);
        }

        function doSend(message) {

          websocket.send(message);
        }

      function initiateForInput(userName){
       //updating userinfo to JSON and send the wrapper to doSend
      var userInfoJson='{"request":"getTweetRelationshipGraphForUser", "screen_name" :'+userName+' }';
       doSend(userInfoJson);
    }


        function testObject(){
          document.getElementById("test").innerHTML = jsonObject;
          console.log(jsonObject);
        }

        window.addEventListener("load", init, false);

d3 file:-

    function start(newJsonObject) {
  var w = 1200,
    h = 600,
    radius = 10,
    node,
    link,
    root;

  var count = 0;

  var force = d3.layout.force()
    .on("tick", tick)
    .charge(function (d) {
      return -500;
    })
    .linkDistance(function (d) {
      return d.target._children ? 100 : 50;
    })
    .size([w, h - 160]);

  var svg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h);

  svg.append("rect")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "#000");

  root = JSON.parse(newJsonObject);
  console.log("root" + root);
  root.fixed = true;
  root.x = w / 2;
  root.y = h / 2 - 80;
  update();

  function update() {
    var nodes = root.nodes,
      links = root.links;

    // Restart the force layout.
    force
      .nodes(nodes)
      .links(links)
      .start();

    // Update the links…
    link = svg.selectAll(".link")
      .data(links);

    // Enter any new links.
    link.enter().insert("svg:line", ".node")
      .attr("class", "link")
      .attr("x1", function (d) {
        return d.source.x;
      })
      .attr("y1", function (d) {
        return d.source.y;
      })
      .attr("x2", function (d) {
        return d.target.x;
      })
      .attr("y2", function (d) {
        return d.target.y;
      });

    // Exit any old links.
    link.exit().remove();

    // Update the nodes...
    node = svg.selectAll("circle.node")
      .data(nodes, function (d) {
        return d.name;
      })
      .style("fill", color);

    node.transition()
      .attr("r", radius);

    // Enter any new nodes.
    node.enter().append("svg:circle")
      .attr("xlink:href", function (d) {
        return d.image;
      })
      .attr("class", "node")
      .attr("cx", function (d) {
        return d.x;
      })
      .attr("cy", function (d) {
        return d.y;
      })
      .attr("r", radius)
      .attr("r", function (d) {
        return d.size * 2;
      })
      .style("fill", color)
      .on("click", click)
      .call(force.drag);
    node.append("title")
      .text(function (d) {
        return d.name;
      });

    // Exit any old nodes.
    node.exit().remove();

    title = svg.selectAll("text.title")
      .data(nodes);

    // Enter any new titles.
    title.enter()
      .append("text")
      .attr("class", "title");
    //.text(function(d) { return d.name; });

    // Exit any old titles.
    title.exit().remove();
  }

  function tick() {
    link.attr("x1", function (d) {
      return d.source.x;
    })
      .attr("y1", function (d) {
        return d.source.y;
      })
      .attr("x2", function (d) {
        return d.target.x;
      })
      .attr("y2", function (d) {
        return d.target.y;
      });

    node.attr("cx", function (d) {
      return d.x;
    })
      .attr("cy", function (d) {
        return d.y;
      });

    title.attr("transform", function (d) {
      return "translate(" + d.x + "," + d.y + ")";
    });
  }

  // Color leaf nodes orange, and packages white or blue.
  function color(d) {
    if (d._children) {
      return "#95a5a6";
    } else {
      switch (d.group) {
        case 'r': //adverb
          return "#e74c3c";
          break;
        case 'n': //noun
          return "#3498db";
          break;
        case 'v': //verb
          return "#2ecc71";
          break;
        case 's': //adjective
          return "#e78229";
          break;
        default:
          return "rgb(0, 238, 238)";
      }
    }
  }

  // Toggle children on click.
  function click(d) {
    document.getElementById("image").src = d.image;
    document.getElementById("username").innerHTML = "Username:" + d.name;
    document.getElementById("id").innerHTML = "ID:" + d.id;
    document.getElementById("friends").innerHTML = d.friend;
    document.getElementById("nodeTitle").innerHTML = "";
    document.getElementById("size").innerHTML = d.size;



    //command to websockets

    initiateForInput(d.name);






    //document.getElementById("id").innerHTML = "Friend Count:" + d.name;
    //if (d._children)
    //grabImage();
    //document.getElementById("image").innerHTML = (d.image);

    /*if (d.children) { 
     d._children = d.children;
     d.children = null;
     } else {
     d.children = d._children;
     d._children = null;
     }
     update();*/
  }

  function mouseover() {
    d3.select(this).select("circle").transition()
      .duration(750)
      .attr("r", 16);
  }


  function mouseout() {
    d3.select(this).select("circle").transition()
      .duration(750)
      .attr("r", 8);
  }

  // Returns a list of all nodes under the root.
  function flatten(root) {
    var nodes = [], i = 0;

    function recurse(node) {
      if (node.children) node.size = node.children.reduce(function (p, v) {
        return p + recurse(v);
      }, 0);
      if (!node.id) node.id = ++i;
      nodes.push(node);
      return node.size;
    }

    root.size = recurse(root);
    return nodes;
  }
}

do {
  var intervalID = window.setTimeout(start, 1000)
} while (jsonObject != "") {

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending information to a single component among several

I'm developing a custom DownloadButton component in VueJS that features an animation when clicked and stops animating once the download is complete. The DownloadButton will be utilized within a table where it's replicated multiple times. I intend ...

Certain cases will see success with iPhone jquery/ajax functionality, while others may encounter

I am facing an issue with multiple pages in my project that utilize AJAX to submit a form to django. While the buttons work perfectly on various platforms and browsers like Chrome, Firefox, and desktop Safari, they seem to malfunction specifically on mobil ...

lint-staged executes various commands based on the specific folder

Within my project folder, I have organized the structure with two subfolders: frontend and backend to contain their respective codebases. Here is how the root folder is set up: - backend - package.json - other backend code files - frontend - p ...

Here is a way to return a 400 response in `express.js` when the JSON request body is invalid

How can I make my application send a response with status code 400 instead of throwing an error if the request body contains invalid JSON? import express from 'express' app.use(express.urlencoded({ extended: false })) app.use(express.json()) ...

Reactstrap: Is it necessary to enclose adjacent JSX elements within a wrapping tag?

While working on my React course project, I encountered an issue with my faux shopping website. The error message that keeps popping up is: Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...& ...

Update the default arrow icon in the expand/collapse navigation bar

I need help changing the downward arrow in the code below to a fontawesome icon. I'm unsure about how to: 1. Remove the default arrow on the right of the parent node. 2. Use "+/-" symbols to represent the collapse state. It seems that the onclick c ...

Ways to access information from doc.data()

<template> <div> {{ id }} {{ title }} </div> </template> <script> import { useRoute } from 'vue-router' import 'firebase/firebase-firestore' import { db } from '@/fdb' export default ...

Vue2: when passing a function as a prop, a warning will be triggered indicating that the prop has

As a newcomer to Vue, I've been enjoying working with Single File Components. Before diving into my main project idea, I decided to experiment with some small components to get a better grasp of the concept. One such experiment involved creating a co ...

Utilizing RxJS finalize in Angular to control the frequency of user clicks

Can someone provide guidance on using rxjs finalized in angular to prevent users from clicking the save button multiple times and sending multiple requests? When a button click triggers a call in our form, some users still tend to double-click, leading to ...

Choose the option from the jQuery dropdown list based on the displayed text instead of the value

In continuation of my previous question on jQuery getting values from multiple selects together, I am working with a select list like this: <select name="access" class="change" id="staff_off" runat="server"> <option value="8192">Off< ...

nodejs promises and their implementation in loops

Currently delving into the realm of promises in nodejs, here's an example code snippet for you to peruse: The result when running the below code is as follows: test - 1 test - 2 test - 3 test - 4 var Q = require('q'); var promise = Q.when( ...

What are some ways I can efficiently load large background images on my website, either through lazy loading or pre

Just dipping my toes into the world of javascript. I'm currently tackling the challenge of lazy loading some large background images on my website. My goal is to have a "loading" gif displayed while the image is being loaded, similar to how it works ...

What is the best way to extract values based on a key

export class Installment { constructor( public isResurring: boolean, public isInstallment: boolean, public price: string, public sku: string ) { } this.keys = Object.keys(this.paymentPlans); for(let key of this. ...

What is the best way for me to collect messages submitted through a form on my website?

After completing my website using HTML, CSS, and JavaScript, I added a form with inputs for name, email, and message at the bottom of the page. Now, I am trying to figure out how to receive the information submitted by visitors in my email. ...

Arranging grid elements in Material-UI

Currently, I am in the process of transforming a JavaFx window into a web application using React.js & Material Ui. The goal is to replicate the appearance and functionality of the original JavaFx application as closely as possible. The layout of the wind ...

Encountering a Selection Issue with IE8

I am encountering an issue with my script that involves a form with two select elements for region and state, allowing users to filter states based on the selected region. Everything works smoothly except for one problem - when testing in IE8, I receive th ...

Ways to modify font color in JavaScript "type"

Recently, I came across a fascinating technique where by simply refreshing the page, the text changes sentences. I managed to implement the code successfully, however, I am having trouble changing the color, size, and alignment of the text. <script type ...

Is it possible to exclude certain static files from being served in express.static?

const express = require('express'); const app = express(); app.use('/app', express.static(path.resolve(__dirname, './app'), { maxage: '600s' })) app.listen(9292, function(err){ if (err) console.log(err); ...

What is a more effective method for linking values with variables in an object?

Can you suggest a more efficient way to write this in JavaScript? let foo; if(bar) { foo = bar.value; } I am attempting to prevent a react error from occurring when `bar` is null if I were to use const foo = bar.value. ...

Nested ui-view is not appearing as expected

I have a query about Angular UI-Router and its ui-views functionality. I am facing an issue where only the ui-view with the name "languages" is displaying, despite declaring three ui-views inside another one. Any assistance in resolving this would be highl ...