2

I want to update a shape's label, x position, and y position values that are displayed in a <div> when the shape is clicked. https://jsfiddle.net/NovasTaylor/q8cLhw9b/

The user edits the form fields to change values as desired, then clicks commit to write the changes (if any) back to the JSON array.

I built the form within the rectangle's "click" event which also triggers opacity to show the form in the <div> at the top of the page:

.on("click", function(d){
  d3.select("#rectInfo").style("opacity", 1);

  var infoForm = d3.select("#rectInfo").append("form")
   .attr("id", "foo")
   .attr("action", "javascript:submitForm();")
   .attr("method", "post")
   .attr("class", "formEle");

The display works as desired. However, I do not know how to push the values from the form back to the JSON array. The submitForm() function merely clears the div convent.

function submitForm(){
  d3.selectAll(".formEle").remove();
  d3.select("#rectInfo").style("opacity", 0);
}

How do I get the values from the form back into the JSON array?

2
  • Why are you using a form? Are you going to send this data to somewhere else? It seems to me that you just want to change the loaded data... if that's correct, you should not use a form. Commented Dec 1, 2017 at 3:10
  • You are correct. I just want to update the data and it does not need to be a form. The data stays within the page. In my previous post (stackoverflow.com/questions/47481625/…) you stated my question was too broad so I further developed my example to create the <div> and show the values in editable fields the only way I know how: using a form (I'm an old guy - think PERL CGI!) . I am very open to other methods that display all 3 parameters at once in the div for edit, then push back into the array and have the div content disappear from view. Commented Dec 1, 2017 at 12:55

1 Answer 1

3
+50

According to your comment, you are not sending this information to anywhere. Therefore, you don't need a form.

So, just append regular text inputs to that div...

var div = d3.select("#rectInfo")

var labelText = div.append("p")
    .text("Label: ");

var labelInput = labelText.append("input")
    .attr("size", "15")
    .attr("type", "text")
    .attr("value", d.label);

var xPosText = div.append("p")
    .text("X pos: ");

var xPosInput = xPosText.append("input")
    .attr("size", "15")
    .attr("type", "text")
    .attr("value", d.x);

var yPosText = div.append("p")
    .text("Y pos: ");

var yPosInput = yPosText.append("input")
    .attr("size", "15")
    .attr("type", "text")
    .attr("value", d.y);

... and create a button that, on "click", gets the values of the inputs and changes the x, y and label properties:

var button = div.append("button")
    .text("Submit/Hide")
    .on("click", function() {
        d3.select(self).attr("x", function(d) {
            return d.x = +xPosInput.node().value
        }).attr("y", function(d) {
            return d.y = +yPosInput.node().value
        });
        d3.select("#text" + i).text(function(d) {
                return "Label: " + (d.label = labelInput.node().value);
            })
            .attr("x", function(d) {
                return d.x = +xPosInput.node().value + 10
            }).attr("y", function(d) {
                return d.y = +yPosInput.node().value + 10
            });
    })

Pay attention to this pattern:

return d.x = +xPosInput.node().value

It does two things:

  1. It returns a value (in this case, +xPosInput.node().value);
  2. It assigns that value to d.x, therefore changing our datum.

Also, the input returns a string, even if the user types a number... that's why there is a unary plus operator before xPosInput.node().value in the example above.

As a final note, I'm not a fan of removing/re-appending elements (I'm talking about the div). You could simply updated them. However, as I told you in my other answer, this is a different issue and here at S.O. we try to keep just one issue per question (so, I'm not dealing with it in this answer).

Here is your code with those changes:

var rectInfoActive = false;
var rectData = [{
  "label": "one",
  "x": 100,
  "y": 50,
  "height": 100,
  "width": 120,
  "color": "green"
}, {
  "label": "two",
  "x": 250,
  "y": 50,
  "height": 100,
  "width": 120,
  "color": "purple"
}, {
  "label": "three",
  "x": 400,
  "y": 50,
  "height": 100,
  "width": 120,
  "color": "red"
}];

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

var rects = svg.selectAll("rect")
  .data(rectData)
  .enter()
  .append("g");

rects.append("rect")
  .attr("x", function(d) {
    return d.x;
  })
  .attr("y", function(d) {
    return d.y;
  })
  .attr("height", function(d) {
    return d.height;
  })
  .attr("width", function(d) {
    return d.width;
  })
  .style("fill", function(d) {
    return d.color;
  })
  .on('mouseover', function(d) {
    var rectSelection = d3.select(this)
      .style({
        opacity: '0.5'
      })
  })
  .on('mouseout', function(d) {
    var rectSelection = d3.select(this)
      .style({
        opacity: '1'
      })
  })
  .on("click", function(d, i) {

    var self = this;

    if (rectInfoActive == true) {
      // clicked a node while previous info block displayed
      d3.selectAll("input").remove();
      d3.selectAll(".formEle").remove();
      d3.select("#rectInfo").selectAll("*").remove();
      d3.select("#rectInfo").style("opacity", 0);
    }

    d3.select("#rectInfo").style("opacity", 1);

    // Form displayed in /div becomes visible onclick of a rect.
    // submit button clears the form. No data update yet.
    var div = d3.select("#rectInfo")

    var labelText = div.append("p")
      .text("Label: ");

    var labelInput = labelText.append("input")
      .attr("size", "15")
      .attr("type", "text")
      .attr("value", d.label);

    var xPosText = div.append("p")
      .text("X pos: ");

    var xPosInput = xPosText.append("input")
      .attr("size", "15")
      .attr("type", "text")
      .attr("value", d.x);

    var yPosText = div.append("p")
      .text("Y pos: ");

    var yPosInput = yPosText.append("input")
      .attr("size", "15")
      .attr("type", "text")
      .attr("value", d.y);

    var button = div.append("button")
      .text("Submit/Hide")
      .on("click", function() {
        d3.select(self).attr("x", function(d) {
          return d.x = +xPosInput.node().value
        }).attr("y", function(d) {
          return d.y = +yPosInput.node().value
        });
        d3.select("#text" + i).text(function(d) {
            return "Label: " + (d.label = labelInput.node().value);
          })
          .attr("x", function(d) {
            return d.x = +xPosInput.node().value + 10
          }).attr("y", function(d) {
            return d.y = +yPosInput.node().value + 10
          });

        d3.select("#rectInfo").selectAll("*").remove();
        d3.select("#rectInfo").style("opacity", 0);
      })

    rectInfoActive = true;



  });
// END OF FORM

// Rectangle Label
rects.append("text")
  .attr("id", function(d, i) {
    return "text" + i
  })
  .style("fill", "black")
  .attr("dy", ".35em")
  .attr("x", function(d) {
    return d.x + 10;
  })
  .attr("y", function(d) {
    return d.y + 10;
  })
  .text(function(d) {
    return "Label: " + d.label
  });



// Misc functions -------------------------------------------------------------
// clearTheForm ----
// Clear the form and input values. This will later become the Update function
//  that will update changed values back into the JSON array.
#rectInfo {
  background-color: white;
  position: relative;
  padding: 10px;
  width: 230px;
  height: 100px;
  border: 2px;
  outline: grey solid thin;
}

#rectInfo p {
  margin: 4px;
}

.formLabel {
  font-family: courier;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Click on a shape to see its label, x, y pos.
  Submit button clears the div (not working here in fiddle)
  but should be changed to instead call a fnt that updates the data with values changed in the form.
-->

<div id="rectInfo" style="opacity:0">
  <!-- Rect info will appear here -->
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.