Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding objects per each JSON data record

How do I add new elements (by this I mean planets) to the below stellar system in the code snippet, based on JSON data such as this:

        [{
           "rowid": 1,
           "Radius size": 3 ,
           "Distance": 110 pixels,
        },
         {
           "rowid": 2,
           "Size": 2.5,
           "Distance": 120 pixels,
        }]

Each row ID is its own planet with its own size and position. The distance is of course based on the distance of the planet from the sun element, which is center of the page. The distance per planet needs to be in a different angle, otherwise they'd all line up perfectly (unrealistic). Any ideas on how this can be achieved?

var ball = {};

function makeBall(spec) {
  // Create the element
  var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
  // Set its various attributes
  ["id", "cx", "cy", "r", "class"].forEach(function(attrName) {
    if (spec.element[attrName]) {
      circle.setAttribute(attrName, spec.element[attrName]);
    }
  });
  // Add it to the sun
  document.getElementById("Sun2").appendChild(circle);
  // Remember its animation settings in `ball`
  ball[spec.element.id] = spec.animation;
}

function addObject() {
  // Create a spec to use with makeBall from the fields
  var spec = {
    element: {
      id: document.getElementById("new-id").value,
      class: document.getElementById("new-class").value,
      r: parseFloat(document.getElementById("new-r").value)
    },
    animation: {
      speed: 2,
      spin: 30,
      side: 40
    }
  };
  // Some minimal validation
  if (!spec.element.id || !spec.element.r || !spec.animation.speed || !spec.animation.spin || isNaN(spec.animation.side)) {
    alert("Need all values to add a ball");
  } else if (ball[spec.element.id]) {
    alert("There is already a ball '" + spec.element.id + "'");
  } else {
    // Do it!
    makeBall(spec);
  }
}

function rotation(coorX, coorY, object) {
  object.side += (1.0 / object.speed);
  var ang = object.side * 2.0 * Math.PI / 180.0;
  var r = object.spin;

  return {
    x: Math.cos(ang) * r - Math.sin(ang) * r + coorX,
    y: Math.sin(ang) * r + Math.cos(ang) * r + coorY
  };
}

function rotationball(circle) {
  var x, y, x_black, y_black, e, newpos, black;

  // We always rotate around black
  black = document.getElementById("black");
  
  // Get this circle and update its position
  e = document.getElementById(circle);
  x_black = parseFloat(black.getAttribute("cx"));
  y_black = parseFloat(black.getAttribute("cy"));
  newpos = rotation(x_black, y_black, ball[circle]);

  e.setAttribute("cx", newpos.x);
  e.setAttribute("cy", newpos.y);
}

function animate() {
  Object.keys(ball).forEach(function(id) {
    rotationball(id);
  });
}

var animateInterval = setInterval(animate, 1000 / 60);
.st0 {
  fill: yellow;
}

.st1 {
  fill: orange;
}
<div>Add ball:
  <label>
    ID: <input type="text" id="new-id" value="newball">
  </label>
  <label>
    R: <input type="text" id="new-r" value="10">
  </label>
  <label>
    Speed: <input type="text" id="new-speed" value="1.2">
  </label>
  <label>
    Spin: <input type="text" id="new-spin" value="80">
  </label>
  <label>
    Side: <input type="text" id="new-side" value="0.0">
  </label>
  <label>
    Class: <input type="text" id="new-class" value="st1">
  </label>
  <button type="button" onclick="addObject()">
    Make Ball
  </button>
</div>

<div class="spinning">
  <svg xmlns="http://www.w3.org/2000/svg" id="solly" viewBox="0 0 1000 600">
    <g id="Sun2">
      <circle id="black" class="st0" cx="500" cy="300.8" r="10" />
    </g>
  </svg>
</div>
The above is code (not entirely mine), that adds new balls (planets) if it has its own ID. I just want to switch this up with the JSON dataset.

EDIT: Below are original examples of two records. As you can see it offers a lot more but redundant properties. All I really require from each record are the size (Planet Radius [Jupiter radii] and distance (Distance [pc]). Distance would need to be converted to pixels, size is trickier.

     [{
       "rowid": 1,
       "Host name": "TrES-3",
       "Number of Planets in System": 1,
       "Planet Mass or M*sin(i)[Jupiter mass]": 1.91,
       "Planet Radius [Jupiter radii]": 1.336,
       "Planet Density [g": {
          "cm**3]": 0.994
       },
       "Distance [pc]": 228,
       "Effective Temperature [K]": 5650,
       "Date of Last Update": "5/14/2014"
    },
     {
       "rowid": 2,
       "Host name": "UZ For",
       "Number of Planets in System": 2,
       "Planet Mass or M*sin(i)[Jupiter mass]": 6.3,
       "Planet Radius [Jupiter radii]": null,
       "Planet Density [g": {
          "cm**3]": null
       },
       "Distance [pc]": null,
       "Effective Temperature [K]": null,
       "Date of Last Update": "5/14/2014"
    }]
like image 674
JohnMichael Avatar asked Aug 31 '16 07:08

JohnMichael


1 Answers

It's actually pretty simple:

If you read through the HTML, you will notice that clicking the "Make Ball" button will call addObject(). So you go and check for that function in the JS code. addObject() simply parses the values from the input fields into an object called spec, then calls makeBall(spec).

What you need to do is to provide the exact same data object spec for the makeBall function, for each of your JSON data.

function addObjectsFromJson(json){
    // using try catch block because JSON.parse will throw an error if the json is malformed
    try{
        var array = JSON.parse(json);
        for(var i = 0; i < array.length; i++){
            var planet = array[i];
            // create a spec to use with makeBall from the json
            var spec = {
                element: {
                    id: planet.rowid,
                    // you don't provide a style class in your json yet, using yellow as default
                    class: 'st0',
                    // your json must have a standard property for radius,
                    // currently you have "Radius size" (is wrong since
                    // properties cannot have spaces) and "Size"
                    r: planet["Planet Radius [Jupiter radii]"]
                },
                animation: {
                    speed: 2,
                    spin: 30,
                    side: planet["Distance [pc]"]
                }
            };
            makeBall(spec);
        }
    }catch(e){
        console.log('error: ' + e);
    }
}

I don't see a property for adding a distance in the makeBall() function though.

Handle JSON via ajax with jQuery:

// assuming your local server runs on port 8080
$.getJSON('localhost:8080/path/to/your/file', function (json) {
    // since we use getJSON, it is already parsed and a javascript object
    // additional parsing inside the addObjectsFromJson function is not necassary
    // and would throw an error
    addObjectsFromJson(json);
});

function addObjectsFromJson(json) {
    for (var i = 0; i < json.length; i++) {
        var planet = json[i];
        // create a spec to use with makeBall from the json
        var spec = {
            element: {
                id: planet.rowid,
                // you don't provide a style class in your json yet, using yellow as default
                class: 'st0',
                // your json must have a standard property for radius,
                // currently you have "Radius size" (is wrong since properties cannot have spaces) and "Size"
                    r: planet["Planet Radius [Jupiter radii]"]
                },
                animation: {
                    speed: 2,
                    spin: 30,
                    side: planet["Distance [pc]"]
        };
        makeBall(spec);
    }
}
like image 166
Danmoreng Avatar answered Oct 07 '22 12:10

Danmoreng