I am trying to integrate Vue.js and D3.js. What I notice is sometimes the CSS classes don't really work on the svg elements. I am giving the snippet of the vue component below.
<template>
<div>
<h1>Hello world</h1>
<svg width="300" height="100" ref="barchart"></svg>
</div>
</template>
<script>
import * as d3 from "d3";
export default {
name: "LineChart",
mounted() {
d3.select("h1").attr("class","red-text")
var data = [10,20,15,30,60];
var barHeight = 20;
var bar = d3
.select(this.$refs.barchart)
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("class","rect")
.attr("width", function(d) {
return d;
})
.attr("height", barHeight - 1)
.attr("transform", function(d, i) {
return "translate(0," + i * barHeight + ")";
});
}
};
</script>
<style scoped>
.rect{
fill: blue;
}
.red-text{
color:red;
}
</style>
Its output is obtained as :-
scoped css output
But as sson as I remove the scoped attribute, the code works fine. New output :-
global css output
Thanks in advance!
Scoped styles work by vue assigning a unique attribute to dom elements, and then adjusting the style rules by adding an extra criteria for elements to have that attribute. Example in vue guide. However, since elements dynamically created with d3 aren't managed by vue (since they aren't part of the template), it doesn't work out of the box. One way to solve this, is to to use deep selector (e.g. svg >>> .rect { ... }), which doesn't attach the additional unique attribute criteria for the child elements.
If you just want to color the bars you don't need explicit css. You can just set:
.style("fill", function(d) { return 'blue'; })
on your bar.
Related
My objective is to change the opacity of a specific path.
This is where I am adding a path for each slice in the chart:
h = f.selectAll("path").data(o);
h.enter().append("path")
.attr("id", function (t, n) { return "path-" + n})
.attr("d", x).attr("fill-rule", "evenodd").style("fill", n).on("click", l)
.on("mouseover", function(t,n) {mouseover("path-" + n)});
inside of the mouseover function here is what I have tried:
function mouseover(d){
// d is the id of the path that was hovered over
// d looks like 'path-20'
d3.selectAll("path").style("opacity", 0.3); // changes opacity for entire sunburst chart
d3.selectAll(d).style("opacity", 0.3); // does nothing
d3.selectAll("path-20").style("opacity", 0.3); // does nothing
d3.select(d).style("opacity", 0.3); // does nothing
d3.select("path-20").style("opacity", 0.3); // does nothing
}
Firstly, if you want to select by a class, use .<class-name> instead. If you want to select by an ID, use #<id>. These are universal selectors from CSS, jQuery, vanilla JavaScript, and also D3.
Much easier, though, is that for the function on("mouseover", function() { ... }), on the place of the dots, this now points to the HTMLElement you want to select.
That makes the following function perfect for what you want:
const data = d3.range(5);
d3.select('svg')
.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('width', 20)
.attr('height', 20)
.attr('x', function(d, i) {
return 30 * i;
})
.attr('y', 40)
.on('mouseover', function() {
d3.select(this).attr('opacity', 0.2);
})
.on('mouseleave', function() {
d3.select(this).attr('opacity', null);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
I am very new to charting with D3 and NDV3.
I am putting the charts inside tabs. (Using Foundation 6.4)
The first chart is fine but the chart on the next clicked tab has a width issue. If I re-size the window it expands to the proper size.
Here is the code based on their example. Both charts are the same code - just with different IDs.
Thanks for any insight on using charts inside jquery tabs.
the code:
<div id="chart1"></div>
<script>
var chart;
var data;
var legendPosition = "top";
nv.addGraph(function () {
chart = nv.models.lineChart()
.options({
duration: 300,
useInteractiveGuideline: true
})
;
chart.xAxis
.axisLabel("Time (s)")
.tickFormat(d3.format(',.1f'))
.staggerLabels(true)
;
chart.yAxis
.axisLabel('Voltage (v)')
.tickFormat(function (d) {
return d3.format(',.2f')(d);
})
;
data = sinAndCos();
d3.select('#chart1').append('svg')
.datum(data)
.attr('height', 400)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function sinAndCos() { ... }
</script>
First tab is fine - second one is very narrow.
this is the link for the Foundation Tabs.
https://foundation.zurb.com/sites/docs/tabs.html
Thank you very much. Cheers.
Looking at the source code of nvd3 the width and height are determined by the style attribute of the svg.
Add the svg to the div yourself and give it a style attribute. Maybe it also works with a CSS style width and height, for responsive websites. Just like an image you specify the size.
<div id="chart1">
<svg id="svg-chart1" style="width:800;height:400;"></svg>
</div>
<script>
....
d3.select('#svg-chart1')
.datum(data)
.call(chart);
....
</script>
Or with a different selector
<div id="chart1">
<svg style="width:800;height:400;"></svg>
</div>
<script>
....
d3.select('#chart1 svg')
.datum(data)
.call(chart);
....
</script>
I used the line chart example from the NVD3 site and got errors on these lines
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.transitionDuration(350) //how fast do you want the lines to transition?
so I commented them out. But looking at your example you set these with the options() method. Using options() I get the interactive guideline and no errors.
Today I am learning about D3.js
I started by studying this content:
https://bost.ocks.org/mike/circles/
Most of it seems easy to understand and follow.
But I have a problem getting exit() to work.
I do understand the idea that I can use exit() to force elements in my DOM to synch with values in a JS array.
So I wrote some code to demonstrate this idea and my code fails.
I want to know how I can rewrite my JS so that exit() will force elements in my DOM to synch with values in a JS array.
<html>
<body>
Ref:
<a href='https://bost.ocks.org/mike/circles/' target='x'>
https://bost.ocks.org/mike/circles/
</a>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
// I should create 3 circles
var svg1 = d3.select('body')
.append('svg')
.attr('id','svg1')
.attr('width',800).selectAll("circle")
.data([0, 1, 2])
.enter()
.append("circle")
.attr("cy", 60)
.attr("cx", function(d, i) { return i * 100 + 30 })
.attr("r", function(d) { return 5+5*d })
// So far so good. I see 3 circles
// Now I should remove some.
var mycircles_a = svg1.selectAll("circle")
.data([99, 88])
// I should ask D3 to make the data-array sync with the circle-elements:
mycircles_a.exit().remove()
// Above call fails for some reason; I still see 3 circles!
// I should see 2 circles because mycircles_a is bound to an array with only 2 values.
'bye'
</script>
</body>
</html>
In your example svg1 is, itself, an "enter" selection.
Your code works just fine if you break the chain, making svg1 just a selection that creates the SVG:
var svg1 = d3.select('body')
.append('svg')
.attr('id','svg1')
.attr('width',800);
svg1.selectAll("circle")
.data([0, 1, 2])
.enter()
.append("circle")
.attr("cy", 60)
.attr("cx", function(d, i) { return i * 100 + 30 })
.attr("r", function(d) { return 5+5*d })
var mycircles_a = svg1.selectAll("circle")
.data([99, 88])
mycircles_a.exit().remove()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
You're not saving a reference to svg1 correctly.
https://jsfiddle.net/y008c61L/
var svg1 = d3.select('body')
.append('svg')
.attr('id','svg1')
.attr('width',800);
svg1.selectAll("circle")
//...
I am trying to access particular variable from a csv file as shown below:
Month,Year,leaves
Jan,2011, 20
Feb, 2011, 30
Mar,2011, 40
What I am trying to achieve is to create a bar chart with height being the leaves value. Below is the code that I used to access leaves field from the csv file imported. I am doing something wrong here, as I am new to D3.js I am pretty confused about accessing an object or referencing an object (syntax in general). I don't care about year, month, I am just trying to create a simple bar chart with leaves. Any help or pointer towards valuable resources would be much appreciated.
Thanks
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="d3.min.js"></script>
<h4> D3 Bar Chart </h4>
</head>
<style>
.bar{
display:inline-block;
width: 20px;
height: 80px;
margin-right: 2px;
background-color: teal;
}
</style>
<body>
<script>
d3.csv("sl_month_year.csv", function(error, data)
{ if(error) {
console.log(error);}
else {console.log(data);
var bar = d3.selectAll("body")
.select("div")
.data(data.length)
.enter()
.append("div")
.attr("class","bar")
.style("height", function(d) { for (i=0; i <= d.length; i++) { return d.[i].leaves + "px" ;});
});
I see a few things that seem wrong to me in your code.
First, you try to access a property using d.[i].leaves in your loop; I think what you try to do is d[i].leaves.
Second, you do not actually need to loop on the elements in your collection, as d3 will handle that for you.
I would go for a different way of using selections, using a simple select for the body and a selectAll for the div's, and bind to the data directly instead of data.length.
Code below should be fine (untested though):
d3.csv("sl_month_year.csv", function(error, data){
if(error) {
console.log(error);}
else {
console.log(data);
var bar = d3.select("body")
.selectAll("div")
.data(data)
.enter()
.append("div")
.attr("class","bar")
.style("height", function(d) {
return d.leaves + "px" ;
});
});
Browser: Dartium Version 34.0.1847.0 (258268)
I want to embed D3 inside Polymer.dart elements and I'm just beginning to sort out how Dart and JS interoperate. I started by creating a vanilla HTML page using HTML5/CSS3/JS from D3's introductory tutorial on how to make a bar chart to be sure my D3 implementation worked in Dartium.
I then moved the D3 code into a custom polymer element (shown below) and its companion dart source file (not shown). How do I instruct D3 to perform its selection inside the shadow DOM?
<!-- D3 code copied from: http://bost.ocks.org/mike/bar/ -->
<polymer-element name="dart-js">
<template>
<!-- D3 style -->
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<content>
<!-- D3 container -->
<div class="chart">inside dart-js shadow-root</div>
<!-- D3 JS -->
<script type="application/javascript">
console.log("inside content");
var data = [4, 8, 15, 16, 23, 42];
console.log("data: " + data); // data: 4,8,15,16,23,42
console.log("select: <" + d3.select(".chart") + ">"); // select: <>
// How do I instruct d3 to search inside the shadow DOM?
d3.select(".chart")
.selectAll("div")
.data(data)
.enter().append("div")
.style("width", function (d) { return d * 10 + "px"; })
.text(function (d) { return d; })
</script>
</content>
</template>
<script type="application/dart;component=1" src="dart_js.dart"></script>
</polymer-element>
d3 can't find elements inside a shadowDOM but you look up the element in Dart and pass it to d3's select method.
something like this (not tested)
import 'dart:js' as js;
js.context['d3'].callMethod('select', [shadowRoot.querySelector('.chart')]);
more info about Dart-JS-interop:
https://www.dartlang.org/articles/js-dart-interop/
I wrapped the D3 JS fragment that prints the bar chart in a function and invoked it from Dart as follows:
dart-js.html
var x = function(elt) {
console.log('x');
d3.select(elt)
.selectAll("div")
.data(data)
.enter().append("div")
.style("width", function (d) { return d * 10 + "px"; })
.text(function (d) { return d; });
};
dart_js.dart
import 'package:polymer/polymer.dart';
import 'dart:js' as js;
#CustomTag('dart-js')
class DartJs extends PolymerElement {
/* Life cycle events */
// required -- constructor must call superclass
DartJs.created() : super.created() {
print("dart-js started");
}
#override void enteredView() {
super.enteredView();
print('dart_js entered');
js.context.callMethod('x', [shadowRoot.querySelector('.chart')]);
}
}