Retrieve Data Bindings d3 - javascript

I'm attempting to create a d3 plugin ala this stackoverflow question:
How to make a d3 plugin?
But within his shown example
(function() {
d3.selection.prototype.editable = d3.selection.enter.prototype.editable = function() {
return this.attr('data-editable', true);
};
})();
I don't see how he can actually retrieve the data associated with the selection. Is this something that can even be retrieved with this extension of d3.selection? I mucked through the d3 source a little bit but found myself far more confused than before.
Can someone who has written a d3 extension/plugin guide me in the right direction?

In javascript, the object that this refers to is (usually, and in your example code above) determined by the object which calls the function where this appears.
Hence the line return this.attr('data-editable', true); will return the exact same d3 selection object that calls editable.
So you will get back the normal old d3 selection object, just as you would in the ordinary d3 method chaining pattern. Once you have that, getting the data is just a matter of looking up the API for the d3 selection object.
If you are interested specifically in how to get the data back, take a look at the data method. From the link above, when that method is called with no arguments:
If values is not specified, then this method returns the array of data
for the first group in the selection. The length of the returned array
will match the length of the first group, and the index of each datum
in the returned array will match the corresponding index in the
selection. If some of the elements in the selection are null, or if
they have no associated data, then the corresponding element in the
array will be undefined.

Related

JavaScript Array-Push?

I'm using charts.js, where I want to add one datarow per minute. Hence to avoid a complete redraw, Im using some ajax and just pushing a new element to the chart.
Pushing VALUES works fine, however, pushing to the label-array shows very strange behaviour. I'v now tried everything from a simple push upto iteratively cloning the whole array, copy all values, replacing the whole array... The result is still the same.
The added element seems to be always end up with index 0, therefore ending up left in the chart, rather than on the right side.
Upon initial pageload, the data that is existing is loaded as a json-array, which works as expected, for example:
var labels = ["16:00", "16:01", "16:02"]
Now, using some ajax, I retrieve a new Dataset for 16:03. Pushing that label to the array like this:
...
labels.push("16:03");
console.log(labels);
...
and inspecting it in the browser afterwards leads to the following strange view:
The stringified representation looks as expected:
(4) ["16:00", "16:01", "16:02", "16:03"]
But when expanding the view in chrome, the result is:
0: "16:03"
1: "16:00"
2: "16:01"
3: "16:02"
So, iterating the array by using index-values obviously leads to a different result than using .toString(). I have no idea what is happening here. I'm mainly confused, why the stringified version looks different than the actual drill down on indexes?
Running a vanilla-example of these steps leads to the desired result. So it has to do something with the "context" of that array. But I have no idea where to start digging ;)
Here's a screenshot
edit:
Following the example over here, it should work like that...
https://www.chartjs.org/docs/latest/developers/updates.html
Comment of #CBroe made me figure it out:
Uppon initial loading, I did not outline the labels explicit, because there i'm having whole objects like {x:"16:00", temp="20", rain="0"} i'm feeding the datarows of chart.js with.
Now, when altering the label-array, chart-js seems to apply the following logic:
Labels-Array is a dedicated Array that EXISTS but is empty if not explicit defined.
In the Getter of that array, Any Labels derived from data-objects are appended to the array.
hence, pushing to the actual array starts with index "0" if it's inititially empty. But looking at the result of the getter then delivers the static array + any required label derived from the data objects given.
Now outlining the labels-array explicit as well, this resolves the issue.

is it possible to get handles of all chars in a stage?

I wish to get handles of all the charts in a stage in order to modify background settings.
I noticed there is a stage.forEachChild(function(element) { … }) method that allows you to fire up a function for each stage element.
For example:
stage.forEachChild(function(element) {
alert(element.id());
});
The problem is that "element" type is anychart.graphics.vector.Element; instead I need a anychart.core.Chart object in order to call the background() method. Is there a way to do that?
Unfortunately, is a GraphicsJS entity and it returns its graphic vector elements as children. It doesn't control charts. You can store all chart in an object or array and iterate them, or apply a unique ID to every chart and get access to them at any moment by anychart.getChartById('CHART_ID');. For details, check the sample by the link in a comment below.

How to deal with missing data in d3.js

I've successfully created several plots with d3 by parsing XML files such as this one.
Now I'm wondering how to deal with incomplete datasets. In my particular example, some sub-elements are missing in some elements. In that case I want d3 to discard the element and not display anything. At the moment, I am applying a filter to the dataset before feeding it into d3's data() function.
Is there a smarter of way of doing this on the fly? Ideally I'd just like to return null when setting an attribute and the required sub-element turns out not to exist.
Full disclaimer: I'm just starting to learn d3.js.
This can be obtained by setting the display property on the data joined DOM elements:
elemSelection.style("display", function (d) {
return is_data_NA(d) ? "none" : null;
});
Here is a short mock example: http://jsfiddle.net/rU4XL/
Note that by default, the function which accept value as a function such as .attr, .style, etc., will remove the attribute or content from the selection if the value function returns null. Hence, in this case, the display attribute would be removed from the elements in the elemSelection which have valid data.

KnockoutJS: Update/Insert data to a viewModel using mapping

I've been trying to figure this out for quite some time now. I couldn't find anything that addresses this problem, but please correct me if I'm wrong.
The problem:
I have data from a JSON API comming in, with an nested array/object structure. I use mapping to initially fill the model with my data. To update this, I want to extend the model if new data arrives, or update the existing data.
As far as I found out, the mapping option key, should do this trick for me, but I might have misunderstood the functionality of the mapping options.
I've boiled down the problem to be represented by this example:
var userMapping = {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
}
};
// JSON call replaced with values
var viewModel = {
users: ko.mapping.fromJS([], userMapping)
};
// Should insert new - new ID?
ko.mapping.fromJS([{"id":1,"name":"Foo"}, {"id":2,"name":"Bar"}], userMapping, viewModel.users);
// Should only update ID#1 - same ID?
ko.mapping.fromJS([{"id":1,"name":"Bat"}], userMapping, viewModel.users);
// Should insert new - New ID?
ko.mapping.fromJS([{"id":3,"name":"New"}, {"id":4,"name":"New"}], userMapping, viewModel.users);
ko.applyBindings(viewModel);​
Fiddle: http://jsfiddle.net/mikaelbr/gDjA7/
As you can see, the first line inserts the data. All good. But when I try to update, it replaces the content. The same for the third mapping; it replaces the content, instead of extening it.
Am I using it wrong? Should I try to extend the content "manually" before using mapping?
Edit Solution:
I solved this case by having a second helper array storing all current models. On new data i extended this array, and updated the view model to contain the accumulated items.
On update (In my case a WebSocket message), I looped through the models, changed the contents of the item in question, and used method valueHasMutated() to give notice of changed value to the Knockout lib.
From looking at your example code the mapping plugin is behaving exactly as I would expect it to. When you call fromJS on a collection you are effectively telling the mapping plugin this is the new contents of that collection. For example:
On the second line, How could it know whether you were updating or whether you had simply removed id:2?
I can't find any mention of a suitable method that treats the data as simply an update, although you could add one. Mapped arrays come with some helpful methods such as mappedIndexOf to help you find particular items. If you receive an update data set simply loop through it, find the item and update it with a mapping.fromJS call to that particular item. This can easily be generalized into reusable method.
You can use ko.mapping.updateFromJS() to update existing values. However, it does not add new values so that would be a problem in your instance. Take a look at the link below for more details.
Using updateFromJS is replacing values when it should be adding them
Yes, you should first collect all data into a list or array and then apply the mapping to that list. Otherwise you are going to overwrite the values in your viewModel.

How can I call an element from an array created by "document.getElementBytag()"?

I am trying to make a page work for my website using the mootools framework. I have looked everywhere I can think of for answers as to why this isn't working, but have come up empty.
I want to populate several arrays with different data types from the html, and then, by calling elements from each array by index number, dynamically link and control those elements within functions. I was testing the simple snippet of code below in mootools jsfiddle utility. Trying to call an element from array "region" directly returns "undefined" and trying to return the index number of an element returns the null value of "-1".
I cannot get useful data out of this array. I can think of three possible reasons why, but cannot figure out how to identify what is really happening here:
1. Perhaps this array is not being populated with any data at all.
2. Perhaps it is being populated, but I am misunderstanding what sort of data is gotten by "document.getElementBytag()" and therefore, the data cannot be displayed with the "document.writeln()" statement. (Or am I forced to slavishly create all my arrays?)
3. Perhaps the problem is that an array created in this way is not indexed. (Or is there something I could do to index this array?)
html:
<div>Florida Virginia</div>
<div>California Nevada</div>
<div>Ohio Indiana</div>
<div>New York Massachussetts</div>
<div>Oregon Washington</div>
js:
var region = $$('div');
document.writeln(region[2]);
document.writeln(region.indexOf('Ohio Indiana'));
Thanks for helping a js newbie figure out what is going on in the guts of this array.
$$ will return a list of DOM elements. If you are only interested in the text of those DOM nodes, then extract that bit out first. As #Dimitar pointed out in the comments, calling get on an object of Elements will return an array possibly by iterating over each element in the collection and getting the property in question.
var region = $$('div').get('text');
console.log(region[2]); // Ohio Indiana
console.log(region.indexOf('Ohio Indiana')); // 2
Also use, console.log instead of document.writeln or document.write, reason being that calling this function will clear the entire document and replace it with whatever string was passed in.
See an example.

Categories