playgrdstar
creative coding space
2 min readSep 16, 2018

--

D3 in the Shadows

After a while, we use D3 in a fairly predictable way. Set up the SVG canvas. Select and append elements. Get the data entered. Position and size the elements based on the data entered. Bind elements to new data. Exit and remove elements if the data no longer exists.

We get drawn into thinking that we can only use D3 in such a way. But what if we want to use D3’s ability to translate data (from the data domain to the dimensions of the screen); or we want to use the inbuilt capabilities of the transition function.

Why would you want to do that? You might ask.

Well, it allows us to use the many capabilities of D3, but use another library like three.js to draw to the screen.

So what i will do in this post is to show a way in which you could use D3 in the usual way, but instead output the text to the screen.

First, we create an array of data.

var data = [];
var numElements = 50;

for (var i=0; i<numElements; i+=10){
for (var j=0; j<numElements; j+=10){
data.push({x:i,y:j});
}
}

Next we create a function to bind data to DOM elements. But notice that these are not actual DOM elements (e.g. rect or div) that are drawn to the screen. They are like shadow DOM elements, lurking in the background, but with actual data bound to them.

function indata(data){

var dataJoin = svg.selectAll('.shadow')
.data(data);

var dataEnter = dataJoin.enter()
.append('custom')
.attr('class', 'shadow')
.attr('x',0)
.attr('y',0)
.attr('radius', 0);

dataJoin.merge(dataEnter)
.transition()
.duration(1000)
.attr('x',function(d){
return d.x;
})
.attr('y', function(d){
return d.y;
})
.attr('radius', function(d){
return 500/numElements;
});

var dataExit = dataJoin.exit()
.transition()
.duration(1000)
.attr('x', 0)
.attr('y', 0)
.attr('radius',0)
.remove();
};

Next we ‘draw’ the data bound to these shadow DOM elements to the screen by finding the DOM nodes they are bound to.

function outdata() {
var shadowElements = svg.selectAll('custom.shadow');

shadowElements.each(function(d){
var node = d3.select(this);
// console.log(node.attr('x'));
// console.log(node.attr('y'));
// console.log(node.attr('radius'));

d3.select('#text-output')
.html(function(){
return 'Width/Number of Elements=' + node.attr('radius');
})
});
};

We can check on the output by either logging them to the console, or actually printing the values to a div.

Next to be able to see the transition in action, we have to run the outdata function (which is what ‘draws’ stuff) repeatedly over a period of time.

indata(data);

var dataTimer = d3.timer(function(elapsed){
outdata();
if (elapsed>1000) {dataTimer.stop();}
});

I’ve also inserted a text input field which will take a new number of elements specified, run the indata and outdata functions.

d3.select('#text-input').on('keydown', function(){
if (d3.event.keyCode === 13){
data = [];
numElements = +this.value;
for (var i=0; i<numElements; i+=10){
for (var j=0; j<numElements; j+=10){
data.push({x:i,y:j});
}
}
// console.log(data.length);
indata(data);
var dataTimer = d3.timer(function(elapsed){
outdata();
if (elapsed>1000) {dataTimer.stop();}
});
}
})

The full code for this is available here.

--

--

playgrdstar
creative coding space

ming // gary ang // illustration, coding, writing // portfolio >> playgrd.com | writings >> quaintitative.com