Is there a way to limit the brushing height - say 50% of y axis (only from Y axis 0 - 250, brushing should work) ? Example fiddle
JS Code:
var hitslineChart = dc.barChart("#chart-line-hitsperday");
var data = [
{date: "12/27/2012", http_404: 2, http_200: 190, http_302: 100},
{date: "12/28/2012", http_404: 2, http_200: 10, http_302: 100},
{date: "12/29/2012", http_404: 1, http_200: 300, http_302: 200},
{date: "12/30/2012", http_404: 2, http_200: 90, http_302: 0},
{date: "12/31/2012", http_404: 2, http_200: 90, http_302: 0},
{date: "01/01/2013", http_404: 2, http_200: 90, http_302: 0},
{date: "01/02/2013", http_404: 1, http_200: 10, http_302: 1},
{date: "01/03/2013", http_404: 2, http_200: 90, http_302: 0},
{date: "01/04/2013", http_404: 2, http_200: 90, http_302: 0},
{date: "01/05/2013", http_404: 2, http_200: 90, http_302: 0},
{date: "01/06/2013", http_404: 2, http_200: 200, http_302: 1},
{date: "01/07/2013", http_404: 1, http_200: 200, http_302: 100}
];
var ndx = crossfilter(data);
var parseDate = d3.time.format("%m/%d/%Y").parse;
data.forEach(function(d) {
d.date = Date.parse(d.date);
d.total= d.http_404+d.http_200+d.http_302;
});
var dateDim = ndx.dimension(function(d) {return d.date;});
var hits = dateDim.group().reduceSum(function(d) {return d.total;});
var minDate = dateDim.bottom(1)[0].date;
var maxDate = dateDim.top(1)[0].date;
hitslineChart.width(500)
.height(200)
.dimension(dateDim)
.group(hits)
.x(d3.time.scale().domain([minDate,maxDate]));
dc.renderAll();
Thanks,
Arun
Although your example uses dc.js 1.7.0, I'm going to answer for dc.js 2.0, since it's a lot newer and a few APIs have changed.
The technique is to override the functions from the coordinateGridMixin which size the brush. This gets a little hairy, but it's possible.
It turns out we'll have to override three undocumented functions which render the brush, renderBrush, setBrushY, and (unfortunately) resizeHandlePath.
The reason this gets hairy is that we really want to override brushHeight, but that one is a private function.
We'll define our own like this:
function height_over_2() {
return (hitslineChart._xAxisY() - hitslineChart.margins().top)/2;
}
For renderBrush, we need to shift the brush down by height_over_2(). We'll pass through the call first, then modify the transform:
dc.override(hitslineChart, 'renderBrush', function(g) {
hitslineChart._renderBrush(g);
var gBrush = hitslineChart.select('g.brush')
.attr('transform', 'translate(' + hitslineChart.margins().left + ',' + (hitslineChart.margins().top + height_over_2()) + ')')
});
setBrushY we'll replace entirely (we could just assign to it, but we'll use dc.override for consistency):
dc.override(hitslineChart, 'setBrushY', function(gBrush) {
gBrush.selectAll('rect')
.attr('height', height_over_2());
gBrush.selectAll('.resize path')
.attr('d', hitslineChart.resizeHandlePath);
});
Finally, resizeHandlePath also uses the height, and here we (ugh) have to copy a big chunk of code out of dc.js, which was itself copied from the crossfilter demo:
dc.override(hitslineChart, 'resizeHandlePath', function (d) {
var e = +(d === 'e'), x = e ? 1 : -1, y = height_over_2() / 3;
return 'M' + (0.5 * x) + ',' + y +
'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) +
'V' + (2 * y - 6) +
'A6,6 0 0 ' + e + ' ' + (0.5 * x) + ',' + (2 * y) +
'Z' +
'M' + (2.5 * x) + ',' + (y + 8) +
'V' + (2 * y - 8) +
'M' + (4.5 * x) + ',' + (y + 8) +
'V' + (2 * y - 8);
});
Fork of your fiddle: http://jsfiddle.net/gordonwoodhull/anz9gfy0/13/
Related
I'm using three.js to generate a 3D model and export it as GLB or GLTF using THREE.GLTFExporter. Goal is to make it viewable on our site using google AR.
https://kaboomlaser.com/pages/ar-test (link to files)
The model looks perfectly fine when I view it in https://sandbox.babylonjs.com/ or other GLTF/glb viewers.
See here: https://gltf-viewer.donmccurdy.com/#model=https://cdn.shopify.com/s/files/1/0290/5459/9273/files/test.glb
but when I open it in Googles AR scene previewer https://vr.google.com/scene-viewer-preview , it ends up empty.
Other models I tried did show up in scene previewer, but with the meshes all spiky and weird.
Below the code I used to reproduce the issue with a simple model. (This outputs the models in the link above).
What am I missing?
var x = 0, y = 0;
var heartShape = new THREE.Shape();
heartShape.moveTo(x + 5, y + 5);
heartShape.bezierCurveTo(x + 5, y + 5, x + 4, y, x, y);
heartShape.bezierCurveTo(x - 6, y, x - 6, y + 7, x - 6, y + 7);
heartShape.bezierCurveTo(x - 6, y + 11, x - 3, y + 15.4, x + 5, y + 19);
heartShape.bezierCurveTo(x + 12, y + 15.4, x + 16, y + 11, x + 16, y + 7);
heartShape.bezierCurveTo(x + 16, y + 7, x + 16, y, x + 10, y);
heartShape.bezierCurveTo(x + 7, y, x + 5, y + 5, x + 5, y + 5);
var geometry = new THREE.ExtrudeBufferGeometry(heartShape, {
depth: 4, bevelEnabled: false,
bevelThickness: 0.4,
bevelSize: 0.4,
steps: 2,
BevelSegments: 2,
curveSegments: 10
});
var material = new THREE.MeshLambertMaterial({ color: 0xa00A0A });
var mesh = new THREE.Mesh(geometry, material);
var scene = new THREE.Scene();
scene.add(mesh);
const options = {
binary: true,
forceIndices: true
};
var exporter = new GLTFExporter();
exporter.parse(scene, function (data) {
if (options.binary) {
savetoFile(data, 'test.glb', 'model/gltf-binary');
}
else {
savetoFile(JSON.stringify(data), 'test.gltf', 'text/plain');
}
},
options);
I had the same issue with some of the models I got from Poly.
Try to Import the model in Blender and Export again. I tried with your model and it works fine
I want to visualize state changes over time, and I'm not sure how to do it using d3 transitions. Simple chained transitions are pretty straightforward. But in this case, for each transition I need access to the object's data and I also need a way to keep track of the count of the transition I'm currently on (so I know which state change to use).
It's easy to do a simple brute force version:
http://bl.ocks.org/aschneiderman/4f7a8824c96f33aa7ad48c729b739409
var members = [
{ id: 1, state: [1, 3, 1, 2, 3] },
{ id: 2, state: [1, 2, 2, 1, 1] },
{ id: 7, state: [2, 3, 1, 2, 3] },
{ id: 112, state: [2, 2, 2, 1, 3] },
{ id: 127, state: [3, 3, 1, 2, 1] },
[...]
{ id: 296, state: [2, 1, 1, 2, 1] }
];
var Distance = 200;
d3.select("svg").selectAll("rect")
.data(members)
.enter().append("rect")
.attr("x",0)
.attr("y",function(d,i) { return 80 + ( 500 - ((d.state[0] % 3) * 250) ) + i*25} )
.attr("width",10)
.attr("height",10)
.style("fill", "Crimson")
.transition()
.ease(d3.easeLinear)
.duration(600)
.delay(0)
.attr("x", 60 + (1 * Distance))
.attr("y", function(d,i) { return 80 + ( 500 - ((d.state[1] % 3) * 250) ) + i*25} )
.transition()
.ease(d3.easeLinear)
.duration(600)
.delay(0)
.attr("x", 60 + (2 * Distance))
.attr("y", function(d,i) { return 80 + ( 500 - ((d.state[2] % 3) * 250) ) + i*25} )
.transition()
.ease(d3.easeLinear)
.duration(600)
.delay(0)
.attr("x", 60 + (3 * Distance))
.attr("y", function(d,i) { return 80 + ( 500 - ((d.state[3] % 3) * 250) ) + i*25} ) ;
How do I modify the code so I can run n transitions on each rectangle, where n = the number of state changes? Any pointers or d3 examples would be greatly appreciated.
I'm making a game. I want 2 separate lines to rotate clockwise and when the player touches the screen the rotation should change to counterclockwise. Right now, when it changes to counterclockwise, the UIBezierPath flips the node. I don't want the node to be flipped, just rotate the other way.
func clockwise() {
let dx = leftside.position.x - self.frame.width / 2
let dy = leftside.position.y - self.frame.height / 2
let rad = atan2(dy, dx)
let path = UIBezierPath(arcCenter: CGPoint(x: self.frame.width / 2, y: self.frame.height / 2), radius: 85, startAngle: rad, endAngle: rad + CGFloat(M_PI * 4), clockwise: true)
let follow = SKAction.followPath(path.CGPath, asOffset: false, orientToPath: true, speed: 250)
leftside.runAction(SKAction.repeatActionForever(follow).reversedAction())
let dx1 = rightside.position.x - self.frame.width / 2
let dy1 = rightside.position.y - self.frame.height / 2
let rad1 = atan2(dy1, dx1)
let path1 = UIBezierPath(arcCenter: CGPoint(x: self.frame.width / 2, y: self.frame.height / 2), radius: 85, startAngle: rad1, endAngle: rad1 + CGFloat(M_PI * 4), clockwise: true)
let follow1 = SKAction.followPath(path1.CGPath, asOffset: false, orientToPath: true, speed: 250)
rightside.runAction(SKAction.repeatActionForever(follow1).reversedAction())
}
func counterclockwise() {
let dx = leftside.position.x - self.frame.width / 2
let dy = leftside.position.y - self.frame.height / 2
let rad = atan2(dy, dx)
let path = UIBezierPath(arcCenter: CGPoint(x: self.frame.width / 2, y: self.frame.height / 2), radius: 85, startAngle: rad, endAngle: rad + CGFloat(M_PI * 4), clockwise: true)
let follow = SKAction.followPath(path.CGPath, asOffset: false, orientToPath: true, speed: 250)
leftside.runAction(SKAction.repeatActionForever(follow))
let dx1 = rightside.position.x - self.frame.width / 2
let dy1 = rightside.position.y - self.frame.height / 2
let rad1 = atan2(dy1, dx1)
let path1 = UIBezierPath(arcCenter: CGPoint(x: self.frame.width / 2, y: self.frame.height / 2), radius: 85, startAngle: rad1, endAngle: rad1 + CGFloat(M_PI * 4), clockwise: true)
let follow1 = SKAction.followPath(path1.CGPath, asOffset: false, orientToPath: true, speed: 250)
rightside.runAction(SKAction.repeatActionForever(follow1))
}
Is there any way to define shape in 3d like
var x = 0, y = 0, z=0 ;
var heartShape = new THREE.Shape();
heartShape.moveTo( x + 25, y + 25,z );
heartShape.bezierCurveTo( x + 25, y + 25, z,x + 20, y,z, x, y,z );
heartShape.bezierCurveTo( x - 30, y,z, x - 30, y + 35, ,z,x - 30,y + 35,z-30 );
....
you can go through this example for various shape creation....
http://threejs.org/examples/#webgl_geometry_shapes
Up until now, I've been using loops to add line elements to a D3 visualization, but this doesn't seem in the spirit of the API.
Let's say I have got some data,
var data = {time: 1, value: 2, value2: 5, value3: 3,value4: 2},
{time: 2, value: 4, value2: 9, value3: 2,value4: 4},
{time: 3, value: 8, value2:12, value3: 2,value4:15}]);
I'd like four lines, with time as the X for all 4.
I can do something like this:
var l = d3.svg.line()
.x(function(d){return xScale(d[keys[0]]);})
.y(function(d,i){
return yScale(d[keys[1]]);})
.interpolate("basis");
var l2 = d3.svg.line()
.x(function(d){return xScale(d[keys[0]]);})
.y(function(d,i){
return yScale(d[keys[2]]);})
.interpolate("basis");
var l3 = d3.svg.line()
.x(function(d){return xScale(d[keys[0]]);})
.y(function(d,i){
return yScale(d[keys[3]]);})
.interpolate("basis");
var l4 = d3.svg.line()
.x(function(d){return xScale(d[keys[0]]);})
.y(function(d,i){
return yScale(d[keys[4]]);})
.interpolate("basis");
And then add these one by one (or by a loop).
var line1 = group.selectAll("path.path1")
.attr("d",l(data));
var line2 = group.selectAll("path.path2")
.attr("d",l2(data));
var line3 = group.selectAll("path.path3")
.attr("d",l3(data));
var line4 = group.selectAll("path.path4")
.attr("d",l4(data));
Is there a better more general way of adding these paths?
Yes. First I would restructure your data for easier iteration, like this:
var series = [
[{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 8}],
[{time: 1, value: 5}, {time: 2, value: 9}, {time: 3, value: 12}],
[{time: 1, value: 3}, {time: 2, value: 2}, {time: 3, value: 2}],
[{time: 1, value: 2}, {time: 2, value: 4}, {time: 3, value: 15}]
];
Now you need just a single generic line:
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.value); });
And, you can then add all of the path elements in one go:
group.selectAll(".line")
.data(series)
.enter().append("path")
.attr("class", "line")
.attr("d", line);
If you want to make the data structure format smaller, you could also extract the times into a separate array, and then use a 2D array for the values. That would look like this:
var times = [1, 2, 3];
var values = [
[2, 4, 8],
[5, 9, 12],
[3, 2, 2],
[2, 4, 15]
];
Since the matrix doesn't include the time value, you need to look it up from the x-accessor of the line generator. On the other hand, the y-accessor is simplified since you can pass the matrix value directly to the y-scale:
var line = d3.svg.line()
.interpolate("basis")
.x(function(d, i) { return x(times[i]); })
.y(y);
Creating the elements stays the same:
group.selectAll(".line")
.data(values)
.enter().append("path")
.attr("class", "line")
.attr("d", line);