I am trying to make buuble plot according to geo location.All my datas come from local .csv file. First i plotted only with one datasets and it worked fine.Now i have inserted two more datasets and everything is messed up. The code doesnt plot naything at all. I think it could be because i am not using any staements and writing the same code below the previous one.If you could give me some suggestions ,it would be quite helpful.
csv data :link
function createBubbleChart(error, countries, continentNames) {
var airports = countries.map(function(country) { return +country.airports; }), population = countries.map(function(country) { return +country.population; }),median_age = countries.map(function(country) { return +country.median_age; });
var meanairports = d3.mean(airports),meanpopulation = d3.mean(population),meanmedian_age = d3.mean(median_age),
airportsExtent = d3.extent(airports),populationExtent = d3.extent(population),median_ageExtent = d3.extent(median_age),
airportsScaleX,populationScaleX,median_ageScaleX,
airportsScaleY,populationScaleY,median_ageScaleY;
/* var airports = countries.map(function(country){ return +country.airports; });
var meanairports = d3.mean(airports),
airportsExtent = d3.extent(airports),
airportsScaleX,
airportsScaleY;*/
var continents = d3.set(countries.map(function(country) { return country.ContinentCode; }));
var continentColorScale = d3.scaleOrdinal(d3.schemeCategory10)
.domain(continents.values());
var width = 1200,
height = 800;
var svg,
circles,
circleSize = { min: 10, max: 80 };
var circleRadiusScale = d3.scaleSqrt()
.domain(airportsExtent)
.domain(populationExtent)
.domain(median_ageExtent)
.range([circleSize.min, circleSize.max]);
var forces,
forceSimulation;
createSVG();
toggleContinentKey(!flagFill());
createCirclesairports();
createCirclespopulation();
createCirclesmedian_age();
createForces();
createForceSimulation();
addFlagDefinitions();
addFillListenerairports();
addFillListenerpopulation();
addFillListenermedian_age();
addGroupingListeners();
function createSVG() {
svg = d3.select("#bubble-chart")
.append("svg")
.attr("width", width)
.attr("height", height);
}
function toggleContinentKey(showContinentKey) {
var keyElementWidth = 150,
keyElementHeight = 30;
var onScreenYOffset = keyElementHeight*1.5,
offScreenYOffset = 100;
if (d3.select(".continent-key").empty()) {
createContinentKey();
}
var continentKey = d3.select(".continent-key");
if (showContinentKey) {
translateContinentKey("translate(0," + (height - onScreenYOffset) + ")");
} else {
translateContinentKey("translate(0," + (height + offScreenYOffset) + ")");
}
function createContinentKey() {
var keyWidth = keyElementWidth * continents.values().length;
var continentKeyScale = d3.scaleBand()
.domain(continents.values())
.range([(width - keyWidth) / 2, (width + keyWidth) / 2]);
svg.append("g")
.attr("class", "continent-key")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.selectAll("g")
.data(continents.values())
.enter()
.append("g")
.attr("class", "continent-key-element");
d3.selectAll("g.continent-key-element")
.append("rect")
.attr("width", keyElementWidth)
.attr("height", keyElementHeight)
.attr("x", function(d) { return continentKeyScale(d); })
.attr("fill", function(d) { return continentColorScale(d); });
d3.selectAll("g.continent-key-element")
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) { return continentKeyScale(d) + keyElementWidth/2; })
.text(function(d) { return continentNames[d]; });
// The text BBox has non-zero values only after rendering
d3.selectAll("g.continent-key-element text")
.attr("y", function(d) {
var textHeight = this.getBBox().height;
// The BBox.height property includes some extra height we need to remove
var unneededTextHeight = 4;
return ((keyElementHeight + textHeight) / 2) - unneededTextHeight;
});
}
function translateContinentKey(translation) {
continentKey
.transition()
.duration(500)
.attr("transform", translation);
}
}
function flagFill() {
return isChecked("#flags");
}
function isChecked(elementID) {
return d3.select(elementID).property("checked");
}
/* function createCircles(){
createCirclesairport();
}*/
/* function createCircles() {
var formatairports = d3.format(","),formatpopulation = d3.format(","),formatmedian_age = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.airports),(d.population),(d.median_age); })
.on("mouseover", function(d) {
updateCountryInfo(d);
})
.on("mouseout", function(d) {
updateCountryInfo();
});
updateCircles();
function updateCountryInfo(country) {
var info = "";
if (country) {
info = [country.CountryName, formatairports(country.airports),formatpopulation(country.population),formatmedian_age(country.median_age)].join(": ");
}
d3.select("#country-info").html(info);
}
}*/
/* function updateCirclesairport(){
updateCircles();
}*/
function createCirclesairports() {
var formatairports = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.airports); })
.on("mouseover", function(d) {
updateCountryInfoairports(d);
})
.on("mouseout", function(d) {
updateCountryInfoairports();
});
updateCirclesairports();
function updateCountryInfoairports(country) {
var info = "";
if (country) {
info = [country.CountryName, formatairports(country.airports)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclesairports() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
function createCirclespopulation() {
var formatpopulation = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.population); })
.on("mouseover", function(d) {
updateCountryInfopopulation(d);
})
.on("mouseout", function(d) {
updateCountryInfopopulation();
});
updateCirclespopulation();
function updateCountryInfopopulation(populationcountry) {
var info = "";
if (country) {
info = [country.CountryName, formatpopulation(country.population)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclespopulation() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
function createCirclesmedian_age() {
var formatmedian_age = d3.format(",");
circles = svg.selectAll("circle")
.data(countries)
.enter()
.append("circle")
.attr("r", function(d) { return circleRadiusScale(d.median_age); })
.on("mouseover", function(d) {
updateCountryInfomedian_age(d);
})
.on("mouseout", function(d) {
updateCountryInfomedian_age();
});
updateCirclesmedian_age();
function updateCountryInfomedian_age(country) {
var info = "";
if (country) {
info = [country.CountryName, formatmedian_age(country.median_age)].join(": ");
}
d3.select("#country-info").html(info);
}
}
function updateCirclesmedian_age() {
circles
.attr("fill", function(d) {
return flagFill() ? "url(#" + d.CountryCode + ")" : continentColorScale(d.ContinentCode);
});
}
/*function createForces(){
createForcesairport();
}
*/
function createForces() {
var forceStrength = 0.05;
forces = {
combine: createCombineForces(),
countryCenters: createCountryCenterForces(),
continent: createContinentForces(),
airports: createairportsForces(),
population: createpopulationForces(),
median_age: createmedian_ageForces(),
};
function createCombineForces() {
return {
x: d3.forceX(width / 2).strength(forceStrength),
y: d3.forceY(height / 2).strength(forceStrength)
};
}
function createCountryCenterForces() {
var projectionStretchY = 0.25,
projectionMargin = circleSize.max,
projection = d3.geoEquirectangular()
.scale((width / 2 - projectionMargin) / Math.PI)
.translate([width / 2, height * (1 - projectionStretchY) / 2]);
return {
x: d3.forceX(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[0];
}).strength(forceStrength),
y: d3.forceY(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[1] * (1 + projectionStretchY);
}).strength(forceStrength)
};
}
function createContinentForces() {
return {
x: d3.forceX(continentForceX).strength(forceStrength),
y: d3.forceY(continentForceY).strength(forceStrength)
};
function continentForceX(d) {
if (d.ContinentCode === "EU") {
return left(width);
} else if (d.ContinentCode === "AF") {
return left(width);
} else if (d.ContinentCode === "AS") {
return right(width);
} else if (d.ContinentCode === "NA" || d.ContinentCode === "SA") {
return right(width);
}
return center(width);
}
function continentForceY(d) {
if (d.ContinentCode === "EU") {
return top(height);
} else if (d.ContinentCode === "AF") {
return bottom(height);
} else if (d.ContinentCode === "AS") {
return top(height);
} else if (d.ContinentCode === "NA" || d.ContinentCode === "SA") {
return bottom(height);
}
return center(height);
}
function left(dimension) { return dimension / 4; }
function center(dimension) { return dimension / 2; }
function right(dimension) { return dimension / 4 * 3; }
function top(dimension) { return dimension / 4; }
function bottom(dimension) { return dimension / 4 * 3; }
}
function createairportsForces() {
var projectionStretchY = 0.25,
projectionMargin = circleSize.max,
projection = d3.geoEquirectangular()
.scale((width / 2 - projectionMargin) / Math.PI)
.translate([width / 2, height * (1 - projectionStretchY) / 2]);
var scaledairportsMargin = circleSize.max;
airportsScaleX = d3.scaleBand()
/*.domain(continentNamesDomain)*/
.range([scaledairportsMargin, width - scaledairportsMargin*2]);
airportsScaleY = d3.scaleLog()
.domain(airportsExtent)
.range([height - scaledairportsMargin, scaledairportsMargin*2]);
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var centerCirclesInScaleBandOffset = airportsScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[0];
}).strength(forceStrength),
y: d3.forceY(function(d) {
return projection([d.CenterLongitude, d.CenterLatitude])[1] * (1 + projectionStretchY);
}).strength(forceStrength),
x: d3.forceX(function(d) {
return airportsScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return airportsScaleY(d.airports);
}).strength(forceStrength),
};
/*
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledairportsMargin = circleSize.max;
airportsScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledairportsMargin, width - scaledairportsMargin*2]);
airportsScaleY = d3.scaleLog()
.domain(airportsExtent)
.range([height - scaledairportsMargin, scaledairportsMargin*2]);
var centerCirclesInScaleBandOffset = airportsScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return airportsScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return airportsScaleY(d.airports);
}).strength(forceStrength)
};*/
}
function createpopulationForces() {
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledpopulationMargin = circleSize.max;
populationScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledpopulationMargin, width - scaledpopulationMargin*2]);
populationScaleY = d3.scaleLog()
.domain(populationExtent)
.range([height - scaledpopulationMargin, scaledpopulationMargin*2]);
var centerCirclesInScaleBandOffset = populationScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return populationScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return populationScaleY(d.population);
}).strength(forceStrength)
};
}
function createmedian_ageForces() {
var continentNamesDomain = continents.values().map(function(continentCode) {
return continentNames[continentCode];
});
var scaledmedian_ageMargin = circleSize.max;
median_ageScaleX = d3.scaleBand()
.domain(continentNamesDomain)
.range([scaledmedian_ageMargin, width - scaledmedian_ageMargin*2]);
median_ageScaleY = d3.scaleLog()
.domain(median_ageExtent)
.range([height - scaledmedian_ageMargin, scaledmedian_ageMargin*2]);
var centerCirclesInScaleBandOffset = median_ageScaleX.bandwidth() / 2;
return {
x: d3.forceX(function(d) {
return median_ageScaleX(continentNames[d.ContinentCode]) + centerCirclesInScaleBandOffset;
}).strength(forceStrength),
y: d3.forceY(function(d) {
return median_ageScaleY(d.median_age);
}).strength(forceStrength)
};
}
}
function createForceSimulation() {
forceSimulation = d3.forceSimulation()
.force("x", forces.combine.x)
.force("y", forces.combine.y)
.force("collide", d3.forceCollide(forceCollideairports))
.force("collide", d3.forceCollide(forceCollidepopulation))
.force("collide", d3.forceCollide(forceCollidemedian_age));
forceSimulation.nodes(countries)
.on("tick", function() {
circles
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
}
function forceCollideairports(d) {
return countryCenterGrouping() || airportsGrouping() ? 0 : circleRadiusScale(d.airports) + 1 ;
}
function forceCollidepopulation(d) {
return countryCenterGrouping() || populationGrouping() ? 0 : circleRadiusScale(d.population) + 1 ;
}
function forceCollidemedian_age(d) {
return countryCenterGrouping() || median_ageGrouping() ? 0 : circleRadiusScale(d.median_age) + 1 ;
}
function countryCenterGrouping() {
return isChecked("#country-centers");
}
function airportsGrouping() {
return isChecked("#airports");
}
function populationGrouping() {
return isChecked("#population");
}
function median_ageGrouping() {
return isChecked("#median_age");
}
function addFlagDefinitions() {
var defs = svg.append("defs");
defs.selectAll(".flag")
.data(countries)
.enter()
.append("pattern")
.attr("id", function(d) { return d.CountryCode; })
.attr("class", "flag")
.attr("width", "100%")
.attr("height", "100%")
.attr("patternContentUnits", "objectBoundingBox")
.append("image")
.attr("width", 1)
.attr("height", 1)
// xMidYMid: center the image in the circle
// slice: scale the image to fill the circle
.attr("preserveAspectRatio", "xMidYMid slice")
.attr("xlink:href", function(d) {
return "flags/" + d.CountryCode + ".svg";
});
}
/* function addFillListener(){
addFillListenerairport();
}
*/
function addFillListenerairports() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !airportsGrouping());
updateCirclesairports();
});
}
function addFillListenerpopulation() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !populationGrouping() );
updateCirclespopulation();
});
}
function addFillListenermedian_age() {
d3.selectAll('input[name="fill"]')
.on("change", function() {
toggleContinentKey(!flagFill() && !median_ageGrouping());
updateCirclesmedian_age();
});
}
function addGroupingListeners() {
addListener("#combine", forces.combine);
addListener("#country-centers", forces.countryCenters);
addListener("#continents", forces.continent);
addListener("#airports", forces.airports);
addListener("#population", forces.population);
addListener("#median_age", forces.median_age);
function addListener(selector, forces) {
d3.select(selector).on("click", function() {
updateForces(forces);
toggleContinentKey(!flagFill() && !airportsGrouping() && !populationGrouping() && !median_ageGrouping());
toggleairportsAxes(airportsGrouping()),
togglepopulationAxes(populationGrouping()),
togglemedian_ageAxes(median_ageGrouping());
});
}
function updateForces(forces) {
forceSimulation
.force("x", forces.x)
.force("y", forces.y)
.force("collide", d3.forceCollide(forceCollideairports))
.force("collide", d3.forceCollide(forceCollidepopulation))
.force("collide", d3.forceCollide(forceCollidemedian_age))
.alphaTarget(0.5)
.restart();
}
function toggleairportsAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(airportsScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(airportsScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
function togglepopulationAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(populationScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(populationScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
function togglemedian_ageAxes(showAxes) {
var onScreenXOffset = 40,
offScreenXOffset = -40;
var onScreenYOffset = 40,
offScreenYOffset = 100;
if (d3.select(".x-axis").empty()) {
createAxes();
}
var xAxis = d3.select(".x-axis"),
yAxis = d3.select(".y-axis");
if (showAxes) {
translateAxis(xAxis, "translate(0," + (height - onScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + onScreenXOffset + ",0)");
} else {
translateAxis(xAxis, "translate(0," + (height + offScreenYOffset) + ")");
translateAxis(yAxis, "translate(" + offScreenXOffset + ",0)");
}
function createAxes() {
var numberOfTicks = 10,
tickFormat = ".0s";
var xAxis = d3.axisBottom(median_ageScaleX)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + offScreenYOffset) + ")")
.call(xAxis)
.selectAll(".tick text")
.attr("font-size", "16px");
var yAxis = d3.axisLeft(median_ageScaleY)
.ticks(numberOfTicks, tickFormat);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + offScreenXOffset + ",0)")
.call(yAxis);
}
function translateAxis(axis, translation) {
axis
.transition()
.duration(500)
.attr("transform", translation);
}
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="style.css" rel="stylesheet">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
<script src="scriptpopulation.js"></script>
<title>D3 Country Bubble Chart</title>
</head>
<body>
<div id="controls">
<span>
<label><input id="country-centers" type="radio" name="grouping" value="country-centers-">Country Centers</label>
<label><input id="population" type="radio" name="grouping" value="population">population</label>
<label><input id="airports" type="radio" name="grouping" value="airports">Airportss</label>
<label><input id="median_age" type="radio" name="grouping" value="median_age">smedian_age</label>
</span>
<span>
<label><input id="colors" type="radio" name="fill" value="colors" checked>Colors</label>
<label><input id="flags" type="radio" name="fill" value="flags">Flags</label>
</span>
</div>
<div id="country-info"></div>
<div id="bubble-chart"></div>
<script>
d3.queue()
.defer(d3.csv, "countries.csv")
.defer(d3.json, "continent-names.json")
.await(createBubbleChart);
</script>
</body>
</html>
strong text
Related
I'm relatively new to D3 and trying to add labels to a grouped bar chart.. So for the following picture which is an example, I would like to align label properly under grouped bar chart.
Code
Currently I am using the following code to create grouped bar chart
renderChart(data) {
d3.select("#group-bar-chart").select("svg").remove();
const width = document.querySelector("#group-bar-chart").clientWidth * 0.9,
height = 500,
margin = { top: 50, left: 40, bottom: 60, right: 40 },
chartWidth = width - (margin.left + margin.right),
chartHeight = height - (margin.top + margin.bottom),
colors = ["#22a348", "#e63c20", "#367af0"];
const svg = d3.select("#group-bar-chart").append("svg");
const chartLayer = svg.append("g").classed("chartLayer", true)
const xScale = d3.scaleBand();
const xScale1 = d3.scaleBand().padding(0.05);
const xInScale = d3.scaleBand();
const yScale = d3.scaleLinear()
const color = d3.scaleOrdinal().range(colors);
const keys = Object.keys(data[0]).filter(k => k !== 'objId' && k !== 'label');
main(data);
function main(data) {
const nested = d3.nest()
.rollup(function (d) {
const { 'label': omit, ...res } = d[0];
return res;
})
.key(function (d) { return d.label })
.entries(data)
nested.forEach(function (d) {
d.val = keys.map(function (key) {
return { key: key, value: d.value[key] }
})
})
setSize(nested)
drawChart(nested)
}
function setSize(nested) {
svg.attr("width", width).attr("height", height)
chartLayer
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr("transform", "translate(" + [margin.left, margin.top] + ")")
xScale.domain(nested.map(function (d) { return d.key }))
.range([0, chartWidth]).paddingInner(0.3)
xInScale.domain(keys).range([0, xScale.bandwidth()])
const yMax = d3.max(nested.map(function (d) {
const values = keys.map(function (key) {
return d.value[key]
})
return d3.max(values)
}))
yScale.domain([0, yMax]).range([chartHeight, 0])
}
function drawChart(nested) {
xScale1.domain(nested.map(d => { return d.key; })).rangeRound([0, chartWidth]);
const t = d3.transition()
.duration(1000)
.ease(d3.easeLinear)
const barGroup = chartLayer.selectAll(".bar-group")
.data(nested)
const newBarGroup = barGroup.enter()
.append("g")
.attr("class", "bar-group");
barGroup.merge(newBarGroup)
.attr("transform", function (d) { return "translate(" + [xScale(d.key), 0] + ")"; });
const bar = newBarGroup.selectAll(".bar")
.data(function (d) { return d.val })
const newBar = bar.enter().append("rect").attr("class", "bar")
bar.merge(newBar)
.attr("width", xInScale.bandwidth())
.attr("height", 0)
.attr("fill", function (d) { return color(d.key); })
.attr("transform", function (d) { return "translate(" + [xInScale(d.key), chartHeight] + ")" })
bar.merge(newBar).transition(t)
.attr("height", function (d) { return chartHeight - yScale(d.value); })
.attr("transform", function (d) { return "translate(" + [xInScale(d.key), yScale(d.value)] + ")" })
chartLayer.append("g")
.attr("class", "axis")
.style('transform', 'translate(0px, 420px)')
.style('text-anchor', 'middle')
.call(d3.axisTop(xScale1));
}
function wrap(text, width) {
text.each(function () {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
}
What I am looking for is look like image bellow.
Edit: I have edited the question, earlier values were not reflecting on the x axis now that got resolved .Now as the slider moves the data doesn't change in the graph and i can see changing x values.
I'm trying to implement a jquery slider in d3 following this link. The example is generating data of some random numbers while my data is in the below format:
{storeid: 5722646637445120, peoplesum: 87, date: "2018-06-03"}
{storeid: 5722646637445120, peoplesum: 90, date: "2018-06-04"}
{storeid: 5722646637445120, peoplesum: 114, date: "2018-06-05"}
I'm able to trigger events when i move my slider but the values are not reflecting on the graph now. So that mean my view is not updating the SVG correctly which is my assumption. I could be wrong here as well.
My x axis should have the date range and y should be peoplesum and it could be a single or a multiline graph.
Updated Code:
private initSvg() {
d3.select("svg").remove();
this.svg = d3.select("#d3Id")
.append("svg")
.attr("width", this.width + this.margin.left + this.margin.right)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("transform",
"translate(" + this.margin.left + "," + this.margin.top + ")")
.attr("stroke-width", 2);
}
private initAxis() {
// Parse the date / time
var parseDate = timeParse("%b %Y");
this.formatTime = timeParse("%e %B");
// Set the ranges
this.x = d3Scale.scaleTime().range([0, this.width]);
this.y = d3Scale.scaleLinear().range([this.height, 0]);
}
private drawAxis() {
var X = this.x;
var Y = this.y;
this.xAxis = d3.axisBottom(this.x)
.ticks(5);
// var xAxis = d3.axisBottom(this.x).tickSize(-this.height).ticks(3);
// // Add the x-axis.
// this.svg.append("svg:g")
// .attr("class", "x axis")
// .attr("transform", "translate(0," + this.height + ")")
// .call(xAxis);
this.yAxis = d3.axisLeft(this.y)
.ticks(5);
// Define the line
this.priceline = d3Shape.line()
.x(function (d) { return X(new Date(d['date'])); })
.y(function (d) { return Y(d['peoplesum']); });
}
private drawLine() {
if ( this.data[0]['d3_parameter_maker'] === true)
{
this.x.domain([0, d3.max(this.data, function (d) { return d['date']; })]);
}
else if ( this.data[0]['d3_parameter_maker'] === undefined)
{
//console.log("aksdad")
var mindate = new Date(this.dashboard_date['startTime']),
maxdate = new Date(this.dashboard_date['endTime']);
this.x.domain([mindate,maxdate]);
}
console.log(new Date(this.dashboard_date['startTime']));
// Scale the range of the data
var svgVar = this.svg;
var pricelineVar = this.priceline;
var margin = this.margin;
var height = this.height;
let thisObj = this;
this.mouseOver = [];
let X = this.x;
let Y = this.y;
if ( this.mouseFlag < 0) {
for ( let i = 0; i < this.peopleInSumArr.length; i++) {
this.mouseOver[i] = true;
}
} else {
for (let i = 0; i < this.peopleInSumArr.length; i++) {
if (i !== this.mouseFlag) {
this.mouseOver[i] = false;
}
}
this.mouseOver[this.mouseFlag] = true;
}
this.y.domain([0, d3.max(this.data, function (d) { return d['peoplesum']; })]);
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function (d) { return d['storeid']; })
.entries(this.data);
// set the colour scale
var color = d3.scaleOrdinal(d3.schemeCategory10);
var legendSpace = this.width / dataNest.length; // spacing for the legend
var div1 = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
dataNest.forEach(function (data, i) {
thisObj.svg.append("path")
.attr("class", "line")
.style("fill", "none")
.attr("d", thisObj.priceline(data.values))
.attr('opacity', thisObj.mouseOver !== undefined && thisObj.mouseOver[i] === true ? 1 : 0.2)
.style('cursor', 'pointer')
.style("stroke", function () { // Add the colours dynamically
return data['color'] = color(data.key);
})
.attr("stroke-width", 3)
.on('click', function () { // on mouse in show line, circles and text
thisObj.mouseFlag = i;
thisObj.initSvg();
thisObj.initAxis();
thisObj.drawAxis();
thisObj.drawLine();
});
// Add the scatterplot
thisObj.svg.selectAll("dot")
.data(data.values)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function (d) { return thisObj.x(new Date(d.date)); })
.attr("cy", function (d) { return thisObj.y(d.peoplesum); })
.style('cursor', 'pointer')
.on("mouseover", function (d) {
div1.transition()
.duration(200)
.style("opacity", .9);
// tslint:disable-next-line:no-unused-expression
div1.html("<b>Date: </b>" + d.date + "<br/>" + "<b>Sum: </b>" + d.peoplesum.toFixed(2))
.style('position', 'absolute')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style('text-align', 'center')
.style('width', '100px')
.style('height', '30px')
.style('padding', '2px')
.style('font', '12px sans-serif')
.style('background-color', 'lightsteelblue')
.style('border', '0px')
.style('border-radius', '8px')
.style('cursor', 'pointer')
.style('pointer-events', 'none');
})
.on("mouseout", function (d) {
div1.transition()
.duration(500)
.style("opacity", 0);
});
// Add the X Axis
// Add the Y Axis
thisObj.svg.append("text")
.attr("x", (legendSpace / 2) + i * legendSpace) // space legend
.attr("y", height + (margin.bottom / 2) + 5)
.attr("class", "legend") // style the legend
.style('cursor', 'pointer')
.style("fill", function () { // Add the colours dynamically
return data['color'] = color(data.key);
})
.text(data.key)
.attr("stroke-width", 3)
.on('click', function () { // on mouse in show line, circles and text
thisObj.mouseFlag = i;
thisObj.initSvg();
thisObj.initAxis();
thisObj.drawAxis();
thisObj.drawLine();
});
});
// Add the X Axis
let xAxisSelection= this.svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + this.height + ")")
xAxisSelection.call(d3.axisBottom(this.x));
// Add the Y Axis
let yAxisLeft =this.svg.append("g")
.attr("class", "y axis")
yAxisLeft.call(d3.axisLeft(this.y));
var clip = this.svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", this.width)
.attr("height", this.height);
// Add the line by appending an svg:path element with the data line we created above
// do this AFTER the axes above so that the line is above the tick-lines
var path = this.svg.append("svg")
.attr("class","path")
.attr("clip-path", "url(#clip)")
.attr( thisObj.priceline(this.data));
function zoom(begin, end) {
thisObj.x.domain([begin, end - 1]);
var t = thisObj.svg.transition().duration(0);
var size = moment(moment(end).toDate()).diff(moment(begin).toDate(), 'days');
console.log("size",size);
var step = size / 10;
var ticks = [];
const startDate = new Date(moment(begin).toDate());
for (var i = 0; i <= 10; i++) {
var xAxisDate = new Date(moment(begin).toDate())
// Add a day
xAxisDate.setDate(startDate.getDate() + i)
ticks.push(xAxisDate);
}
xAxisSelection.call(d3.axisBottom(thisObj.x.domain(d3.extent(ticks))));
}
//console.log("this.data)",this.data)
$(function() {
$( "#slider-range" ).slider({
range: true,
min: new Date(mindate).getTime() / 1000,
max: new Date(maxdate).getTime() / 1000,
step: 86400,
values: [ new Date(mindate).getTime() / 1000, new Date(maxdate).getTime() / 1000 ],
slide: function( event, ui ) {
//console.log("ui.values[0]",ui.values)
var begin = d3.min([(new Date(ui.values[ 0 ] *1000).toDateString() ), thisObj.data.length]);
var end = new Date(ui.values[ 1 ] *1000).toDateString(); // 0]);
//console.log("begin:", moment(begin).toDate(), "end:", moment(end).format('yyyy-mm-dd'), thisObj.data);
console.log(begin);
console.log(end);
zoom(begin, end);
}
});
});
}
}
Please find below the screenshot of the graph
Adding the clip path functionality because data was going beyond y axis.
private initSvg() {
d3.select("svg").remove();
this.svg = d3.select("#d3Id")
.append("svg")
.attr("width", this.width + this.margin.left + this.margin.right)
.attr("height", this.height + this.margin.top + this.margin.bottom)
.append("g")
.attr("transform",
"translate(" + this.margin.left + "," + this.margin.top + ")")
.attr("stroke-width", 2);
}
private initAxis() {
// Parse the date / time
// var parseDate = timeParse("%b %Y");
// this.formatTime = timeParse("%e %B");
// Set the ranges
this.x = d3Scale.scaleTime().range([0, this.width]);
this.y = d3Scale.scaleLinear().range([this.height, 0]);
}
private drawAxis() {
var X = this.x;
var Y = this.y;
this.xAxis = d3.axisBottom(this.x)
.ticks(5);
// var xAxis = d3.axisBottom(this.x).tickSize(-this.height).ticks(3);
// // Add the x-axis.
// this.svg.append("svg:g")
// .attr("class", "x axis")
// .attr("transform", "translate(0," + this.height + ")")
// .call(xAxis);
this.yAxis = d3.axisLeft(this.y)
.ticks(5);
// Define the line
this.priceline = d3Shape.line()
.x(function(d) {
return X(new Date(d['date']));
})
.y(function(d) {
return Y(d['peoplesum']);
});
}
private drawLine() {
if (this.data[0]['d3_parameter_maker'] === true) {
this.x.domain([1, d3.max(this.data, function(d) {
return parseInt(d['date']);
})]);
} else if (this.data[0]['d3_parameter_maker'] === undefined) {
var mindate = new Date(this.dashboard_date['startTime']),
maxdate = new Date(this.dashboard_date['endTime']);
this.x.domain([mindate, maxdate]);
}
console.log(new Date(this.dashboard_date['startTime']));
// Scale the range of the data
var svgVar = this.svg;
var pricelineVar = this.priceline;
var margin = this.margin;
var height = this.height;
let thisObj = this;
this.mouseOver = [];
let X = this.x;
let Y = this.y;
if (this.mouseFlag < 0) {
for (let i = 0; i < this.peopleInSumArr.length; i++) {
this.mouseOver[i] = true;
}
} else {
for (let i = 0; i < this.peopleInSumArr.length; i++) {
if (i !== this.mouseFlag) {
this.mouseOver[i] = false;
}
}
this.mouseOver[this.mouseFlag] = true;
}
this.y.domain([0, d3.max(this.data, function(d) {
return d['peoplesum'];
})]);
var clip = thisObj.svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", this.width)
.attr("height", this.height);
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {
return d['storeid'];
})
.entries(this.data);
// set the colour scale
var color = d3.scaleOrdinal(d3.schemeCategory10);
var legendSpace = this.width / dataNest.length; // spacing for the legend
var div1 = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
dataNest.forEach(function(data, i) {
thisObj.svg.append("path")
.attr("class", "line")
.style("fill", "none")
.datum(data)
.attr("d", function(d) {
return thisObj.priceline(d.values);
})
.attr('opacity', thisObj.mouseOver !== undefined && thisObj.mouseOver[i] === true ? 1 : 0.2)
.style('cursor', 'pointer')
.style("stroke", function() { // Add the colours dynamically
return data['color'] = color(data.key);
})
.attr("stroke-width", 3)
.attr("clip-path", "url(#clip)")
.on('click', function() { // on mouse in show line, circles and text
thisObj.mouseFlag = i;
thisObj.initSvg();
thisObj.initAxis();
thisObj.drawAxis();
thisObj.drawLine();
});
// Add the scatterplot
thisObj.svg.selectAll("dot")
.data(data.values)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) {
return thisObj.x(new Date(d.date));
})
.attr("cy", function(d) {
return thisObj.y(d.peoplesum);
})
.style('cursor', 'pointer')
.on("mouseover", function(d) {
div1.transition()
.duration(200)
.style("opacity", .9);
// tslint:disable-next-line:no-unused-expression
div1.html("<b>Date: </b>" + d.date + "<br/>" + "<b>Sum: </b>" + d.peoplesum.toFixed(2))
.style('position', 'absolute')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style('text-align', 'center')
.style('width', '100px')
.style('height', '30px')
.style('padding', '2px')
.style('font', '12px sans-serif')
.style('background-color', 'lightsteelblue')
.style('border', '0px')
.style('border-radius', '8px')
.style('cursor', 'pointer')
.style('pointer-events', 'none');
})
.on("mouseout", function(d) {
div1.transition()
.duration(500)
.style("opacity", 0);
});
// Add the X Axis
// Add the Y Axis
thisObj.svg.append("text")
.attr("x", (legendSpace / 2) + i * legendSpace) // space legend
.attr("y", height + (margin.bottom / 2) + 5)
.attr("class", "legend") // style the legend
.style('cursor', 'pointer')
.style("fill", function() { // Add the colours dynamically
return data['color'] = color(data.key);
})
.text(data.key)
.attr("stroke-width", 3)
.on('click', function() { // on mouse in show line, circles and text
thisObj.mouseFlag = i;
thisObj.initSvg();
thisObj.initAxis();
thisObj.drawAxis();
thisObj.drawLine();
});
});
// Add the X Axis
let xAxisSelection = this.svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + this.height + ")")
xAxisSelection.call(d3.axisBottom(this.x));
// Add the Y Axis
this.svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(this.y));
if (this.data[0]['d3_parameter_maker'] === undefined)
{
this.daily_Data_slider(mindate,xAxisSelection,maxdate)
}
else
{
this.hourly_Data_slider(xAxisSelection)
}
}
private daily_Data_slider(mindate,xAxisSelection,maxdate){
var svgVar = this.svg;
var pricelineVar = this.priceline;
var margin = this.margin;
var height = this.height;
let thisObj = this;
function zoom(begin, end) {
thisObj.x.domain([new Date(begin), new Date(end)]);
var t = thisObj.svg.transition().duration(0);
var size = moment(moment(end).toDate()).diff(moment(begin).toDate(), 'days');
console.log("size", size);
var step = size / 10;
var ticks = [];
const startDate = new Date(moment(begin).toDate());
for (var i = 0; i <= 10; i++) {
var xAxisDate = new Date(moment(begin).toDate())
// Add a day
xAxisDate.setDate(startDate.getDate() + i)
ticks.push(xAxisDate);
}
xAxisSelection.call(d3.axisBottom(thisObj.x.domain(d3.extent(ticks))));
// Redraw the line:
d3.selectAll("circle")
.attr("cx", function(d) {
return thisObj.x(new Date(d.date));
})
.attr("cy", function(d) {
return thisObj.y(d.peoplesum);
})
d3.selectAll(".line").attr("d", function(d) {
return thisObj.priceline(d.values);
})
}
//console.log("this.data)",this.data)
$(function() {
$("#slider-range").slider({
range: true,
min: new Date(mindate).getTime() / 1000,
max: new Date(maxdate).getTime() / 1000,
step: 86400,
values: [new Date(mindate).getTime() / 1000, new Date(maxdate).getTime() / 1000],
slide: function(event, ui) {
//console.log("ui.values[0]",ui.values)
var begin = d3.min([(new Date(ui.values[0] * 1000).toDateString()), thisObj.data.length]);
var end = new Date(ui.values[1] * 1000).toDateString(); // 0]);
//console.log("begin:", moment(begin).toDate(), "end:", moment(end).format('yyyy-mm-dd'), thisObj.data);
console.log("begin", begin);
console.log("end", end);
if (new Date(moment(moment(moment(begin).toDate()).add(10, 'days')).format("YYYY-MM-DD")) <= new Date(end)) {
zoom(begin, end);
}
}
});
});
}
I am trying to tween the heights of the various arcs in this chart
jsfiddle
http://jsfiddle.net/0ht35rpb/193/
I've seen this example but not sure how to start implementing it.
d3 how to tween inner radius for pie chart
I've seen this sample on various tweening maths. http://andyshora.com/tweening-shapes-paths-d3-js.html
var $this = $("#chart");
var data = [{
"label": "Overall Stress",
"value": 89
},{
"label": "Emotional Stress",
"value": 1
},{
"label": "Behavioural difficulties",
"value": 29
},{
"label": "hyperactivity and concetration",
"value": 89
},{
"label": "Getting along with others",
"value": 19
},{
"label": "Keen and helpful behaviour",
"value": 45
}];
var w = 350;
var h = 350;
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f", "#c12fff"];
return colores_g[n % colores_g.length];
}
var arcGenerator = {
radius: 70,
oldData: "",
init: function(el, data, w, h){
var stardata = [
{
"segments": data
}
];
this.el = el;
var clone = $.extend(true, {}, stardata);
this.oldData = this.setData(clone, false);
this.setup(el, this.setData(stardata, true), w, h);
},
update: function(data){
var clone = $.extend(true, {}, data);
this.animate(this.setData(data, true));
this.oldData = this.setData(clone, false);
},
animate: function(data){
var that = this;
var chart = d3.select(this.el);
that.generateArcs(chart, data);
},
setData: function(data, isSorted){
var diameter = 2 * Math.PI * this.radius;
var localData = new Array();
var displacement = 0;
var oldBatchLength = 0;
$.each(data, function(index, value) {
var riseLevels = value.segments;
var riseLevelCount = riseLevels.length;
if(oldBatchLength !=undefined){
displacement+=oldBatchLength;
}
var arcBatchLength = 2*Math.PI;
var arcPartition = arcBatchLength/riseLevelCount;
$.each(riseLevels, function( ri, value ) {
var startAngle = (ri*arcPartition);
var endAngle = ((ri+1)*arcPartition);
if(index!=0){
startAngle+=displacement;
endAngle+=displacement;
}
riseLevels[ri]["startAngle"] = startAngle;
riseLevels[ri]["endAngle"] = endAngle;
});
oldBatchLength = arcBatchLength;
localData.push(riseLevels);
});
var finalArray = new Array();
$.each(localData, function(index, value) {
$.each(localData[index], function(i, v) {
finalArray.push(v);
});
});
return finalArray;
},
generateArcs: function(chart, data){
var that = this;
//_arc paths
//append previous value to it.
$.each(data, function(index, value) {
if(that.oldData[index] != undefined){
data[index]["previousEndAngle"] = that.oldData[index].endAngle;
}
else{
data[index]["previousEndAngle"] = 0;
}
});
var arcpaths = that.arcpaths.selectAll("path")
.data(data);
arcpaths.enter().append("svg:path")
.style("fill", function(d, i){
return colores_google(i);
})
.transition()
.ease(d3.easeElastic)
.duration(750)
.attrTween("d", arcTween);
arcpaths.transition()
.ease(d3.easeElastic)
.style("fill", function(d, i){
return colores_google(i);
})
.duration(750)
.attrTween("d",arcTween);
arcpaths.exit().transition()
.ease(d3.easeBounce)
.duration(750)
.attrTween("d", arcTween)
.remove();
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.endAngle = b.previousEndAngle;
var i = d3.interpolate(prev, b);
return function(t) {
return that.getArc()(i(t));
};
}
//_arc paths
var r = that.radius + 40;
var ir = that.radius - 30;
var legendHeight = this.legendPaddingTop;
var ySpace = 18;
var labelPadding = 3;
//draw labels legends
var labels = that.label_group.selectAll("text.labels")
.data(data);
labels.enter().append("svg:text")
.attr("class", "labels")
.attr("dy", function(d, i) {
legendHeight+=ySpace;
return (ySpace * i) + labelPadding;
})
.attr("text-anchor", function(d) {
return "start";
})
.text(function(d) {
return d.label;
});
labels.exit().remove();
var legend = that.legend_group.selectAll("circle").data(data);
legend.enter().append("svg:circle")
.attr("cx", 100)
.attr("cy", function(d, i) {
return ySpace * i;
})
.attr("r", 7)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
});
legend.exit().remove();
//reset legend height
//console.log("optimum height for legend", legendHeight);
$this.find('.legend').attr("height", legendHeight);
/*
//__labels
var starlabels = that.starlabels.selectAll("text")
.data(data);
starlabels.enter()
.append("text")
.attr("text-anchor", "middle")
starlabels.text(function(d) {
return d.label;
})
.each(function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (ir+((r-ir)/2));
d.cy = Math.sin(a) * (ir+((r-ir)/2));
d.x = d.x || Math.cos(a) * (r + 20);
d.y = d.y || Math.sin(a) * (r + 20);
var bbox = this.getBBox();
d.sx = d.x - bbox.width/2 - 2;
d.ox = d.x + bbox.width/2 + 2;
d.sy = d.oy = d.y + 5;
})
.transition()
.duration(300)
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
return d.y = Math.sin(a) * (r + 20);
});
starlabels.exit().remove();
//__labels
//__pointers
that.pointers.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3)
.style("fill", "#005a70");
var pointers = that.pointers.selectAll("path.pointer")
.data(data);
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "#005a70")
.attr("marker-end", "url(#circ)");
pointers
.transition()
.duration(300)
.attr("d", function(d) {
if(d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
pointers.exit().remove();
//__pointers
*/
},
setup: function(el, data, w, h){
var chart = d3.select(el).append("svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h)
var arcchart = chart.append("g")
.attr("class", "starchart")
.attr("transform", "translate("+w/4+","+h/2+")");
this.arcpaths = arcchart.append("g")
.attr("class", "arcpaths");
this.starlabels = arcchart.append("g")
.attr("class", "labels");
this.pointers = arcchart.append("g")
.attr("class", "pointer");
var margin = 25;
var padding = 15;
this.legendPaddingTop = 30;
var legend = chart.append("g")
.attr("class", "legend")
.attr("width", w/3)
.attr("height", h - 50)
.attr("transform", "translate(" + (w-20) + "," + (h/4) + ")");
this.label_group = legend.append("g")
.attr("class", "label_group")
.attr("transform", "translate(" + (-(w / 3) + 20) + "," + 0 + ")");
this.legend_group = legend.append("g")
.attr("class", "legend_group")
.attr("transform", "translate(" + (-(w / 3) - 100) + "," + 0 + ")");
var radiusControl = 16;
this.dataset = "big";//more than 2 results
if(data.length <=2){
radiusControl = 65;//make the radius smaller to compromise with there being less results
this.dataset = "small";
}
this.radius = w/4 - radiusControl;
this.generateArcs(chart, data);
},
getArc: function(){
var that = this;
var arc = d3.arc()
.innerRadius(function(d, i){
var threshold = 50;
if(that.dataset == "small"){
threshold = 20;
}
return that.radius-threshold;//negative makes it deeper
})
.outerRadius(function(d){
var maxHeight = 120;
var ratio = (d.value/maxHeight * 100)+that.radius;
return ratio;
})
.startAngle(function(d, i){
return d.startAngle;
})
.endAngle(function(d, i){
return d.endAngle;
});
return arc;
}
}
arcGenerator.init($this[0], data, w, h);
In your attrTween function instead of interpolating angle interpolate the value:
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.endAngle = b.previousEndAngle; <-- incorrect
var i = d3.interpolate(prev, b);
Interpolate outer radius like below
function arcTween(b) {
var prev = JSON.parse(JSON.stringify(b));
prev.value = 0;
var i = d3.interpolate(prev, b);
working code here
This my component code of vue js
<template>
<div class="grapha">
<div id="chart2"></div>
</div>
</template>
<script>
// var apiURL = 'https://jsonplaceholder.typicode.com/users';
var apiURL = 'http://localhost:3000/db';
export default {
name: 'grapha',
data () {
return {
users:[]
}
},
methods: {
fetchData: function () {
var self = this;
$.get( apiURL, function( data ) {
self.users = data;
});
}
},
created: function (){
this.fetchData();
}
}
</script>
Here is my d3 combo chart code , here is a variable named Data takes values and shows it on graph.
Now, I want to get data from self.users (vue js component) to pass it on data variable ( external function ). Could you suggest me what would be the possible way to do that ?
function getTextWidth(text, fontSize, fontName) {
c = document.createElement("canvas");
ctx = c.getContext("2d");
ctx.font = fontSize + ' ' + fontName;
return ctx.measureText(text).width;
}
function DataSegregator(array, on) {
var SegData;
OrdinalPositionHolder = {
valueOf: function () {
thisObject = this;
keys = Object.keys(thisObject);
keys.splice(keys.indexOf("valueOf"), 1);
keys.splice(keys.indexOf("keys"), 1);
return keys.length == 0 ? -1 : d3.max(keys, function (d) { return thisObject[d] })
}
, keys: function () {
keys = Object.keys(thisObject);
keys.splice(keys.indexOf("valueOf"), 1);
keys.splice(keys.indexOf("keys"), 1);
return keys;
}
}
array[0].map(function (d) { return d[on] }).forEach(function (b) {
value = OrdinalPositionHolder.valueOf();
OrdinalPositionHolder[b] = OrdinalPositionHolder > -1 ? ++value : 0;
})
SegData = OrdinalPositionHolder.keys().map(function () {
return [];
});
array.forEach(function (d) {
d.forEach(function (b) {
SegData[OrdinalPositionHolder[b[on]]].push(b);
})
});
return SegData;
}
Data = self.users.comboChart;
var margin = { top: 20, right: 30, bottom: 60, left: 40 },
width = 800 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var textWidthHolder = 0;
/// Adding Date in LineCategory
Data.forEach(function (d) {
d.LineCategory.forEach(function (b) {
b.Date = d.Date;
})
});
var Categories = new Array();
// Extension method declaration
// Categories.pro;
var Data;
var ageNames;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var XLine = d3.scale.ordinal()
.rangeRoundPoints([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var YLine = d3.scale.linear().range([height, 0])
.domain([0, d3.max(Data, function (d) { return d3.max(d.LineCategory, function (b) { return b.Value }) })]);
var color = d3.scale.ordinal()
.range(["#6aae6a", "#639ce4", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var line = d3.svg.line().x(function (d) {
return x0(d.Date) + x0.rangeBand() / 2;
}).y(function (d) { return YLine(d.Value) });
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
// var yAxis = d3.svg.axis()
// .scale(y)
// .orient("left")
// .tickFormat(d3.format(".2s"));
// var YLeftAxis = d3.svg.axis().scale(YLine).orient("right").tickFormat(d3.format(".2s"));
var svg = d3.select("#chart2").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Bar Data categories
Data.forEach(function (d) {
d.Categories.forEach(function (b) {
if (Categories.findIndex(function (c) { return c.Name===b.Name}) == -1) {
b.Type = "bar";
// console.log(JSON.stringify(b))
Categories.push(b)
}
})
});
// Line Data categories
Data.forEach(function (d) {
d.LineCategory.forEach(function (b) {
if (Categories.findIndex(function (c) { return c.Name === b.Name }) == -1) {
b.Type = "line";
// console.log(JSON.stringify(b))
Categories.push(b)
}
})
});
// Processing Line data
lineData = DataSegregator(Data.map(function (d) { return d.LineCategory }), "Name");
// Line Coloring
LineColor = d3.scale.ordinal();
LineColor.domain(Categories.filter(function (d) { return d.Type == "line" }).map(function (d) { return d.Name }));
LineColor.range(["#333471", "#386a07", "#7f8ed4", "#671919", "#0b172b"])
x0.domain(Data.map(function (d) { return d.Date; }));
XLine.domain(Data.map(function (d) { return d.Date; }));
x1.domain(Categories.filter(function (d) { return d.Type == "bar" }).map(function (d) { return d.Name})).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(Data, function (d) { return d3.max(d.Categories, function (d) { return d.Value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var state = svg.selectAll(".state")
.data(Data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function (d) { return "translate(" + x0(d.Date) + ",0)"; });
state.selectAll("rect")
.data(function (d) { return d.Categories; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function (d) { return x1(d.Name); })
.attr("y", function (d) { return y(d.Value); })
//.attr("height", function (d) { return height - y(d.Value); })
.style("fill", function (d) { return color(d.Name); })
.transition().delay(500).attrTween("height", function (d) {
var i = d3.interpolate(0, height - y(d.Value));
return function (t)
{
return i(t);
}
});
// drawaing lines
svg.selectAll(".lines").data(lineData).enter().append("g").attr("class", "line")
.each(function (d) {
Name=d[0].Name
d3.select(this).append("path").attr("d", function (b) { return line(b) }).style({ "stroke-width": "3px", "fill": "none" }).style("stroke", LineColor(Name)).transition().duration(1500);
})
// Legends
var LegendHolder = svg.append("g").attr("class", "legendHolder");
var legend = LegendHolder.selectAll(".legend")
.data(Categories.map(function (d) { return {"Name":d.Name,"Type":d.Type}}))
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) { return "translate(0," +( height+ margin.bottom/2 )+ ")"; })
.each(function (d,i) {
// Legend Symbols
d3.select(this).append("rect")
.attr("width", function () { return 18 })
.attr("x", function (b) {
left = (i+1) * 15 + i * 18 + i * 5 + textWidthHolder;
return left;
})
.attr("y", function (b) { return b.Type == 'bar'?0:7})
.attr("height", function (b) { return b.Type== 'bar'? 18:5 })
.style("fill", function (b) { return b.Type == 'bar' ? color(d.Name) : LineColor(d.Name) });
// Legend Text
d3.select(this).append("text")
.attr("x", function (b) {
left = (i+1) * 15 + (i+1) * 18 + (i + 1) * 5 + textWidthHolder;
return left;
})
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(d.Name);
textWidthHolder += getTextWidth(d.Name, "10px", "calibri");
});
// Legend Placing (center)
d3.select(".legendHolder").attr("transform", function (d) {
thisWidth = d3.select(this).node().getBBox().width;
return "translate(" + ((width) / 2 - thisWidth / 2) + ",0)";
})
// round the rectangle corners
svg.selectAll('rect').attr('rx', 5).attr('ry', 5);
You can achieve by using Using Javascript's custom event feature
We need to register an event, globally with document as follows
Registering Event
document.addEventListener("updateUser", function(e) {
console.info("Event is: ", e);
console.info("Custom data is: ", e.detail);
// Place your logic to operate with new data
})
The above snippet needs to be placed in your d3 script.
Emitting the custom event
var myEvent = new CustomEvent("updateUser", {
detail: data // Your data from vuejs part
});
// Trigger it!
document.dispatchEvent(myEvent);
I'm developing a legend toggling d3.js pie chart application using this jsfiddle as my latest version http://jsfiddle.net/Qh9X5/3328/ .
I am aiming to get a streamlined working example where the legend can toggle the slices, trying to deactivate all slices - resorts in a reset which reactivates all the slices. Splitting up presentation and application layer logic.
Tweening needs improvement too - as the slices pop into existence then re-tween smoothly.
How do I improve/fix the various bugs in this code base?
onLegendClick: function(dt, i){
//_toggle rectangle in legend
var completeData = jQuery.extend(true, [], methods.currentDataSet);
newDataSet = completeData;
if(methods.manipulatedData){
newDataSet = methods.manipulatedData;
}
d3.selectAll('rect')
.data([dt], function(d) {
return d.data.label;
})
.style("fill-opacity", function(d, j) {
var isActive = Math.abs(1-d3.select(this).style("fill-opacity"));
if(isActive){
newDataSet[j].total = completeData[j].total;
}else{
newDataSet[j].total = 0;
}
return isActive;
});
//animate slices
methods.animateSlices(newDataSet);
//stash manipulated data
methods.manipulatedData = newDataSet;
}
Here is the entire js code - I've used the tidyup. I wasn't sure about using the shortcuts as I'm not sure the values will be correct. The latest fiddle - http://jsfiddle.net/Qh9X5/3340/
$(document).ready(function () {
var pieChart = {
el: "",
init: function (el, options) {
var clone = jQuery.extend(true, {}, options["data"]);
pieChart.el = el;
pieChart.setup(clone, options["width"], options["height"], options["r"], options["ir"]);
},
getArc: function (radius, innerradius) {
var arc = d3.svg.arc()
.innerRadius(innerradius)
.outerRadius(radius);
return arc;
},
setup: function (dataset, w, h, r, ir) {
var padding = 80;
this.width = w;
this.height = h;
this.radius = r
this.innerradius = ir;
this.color = d3.scale.category20();
this.pie = d3.layout.pie()
.sort(null)
.value(function (d) {
return d.total;
});
this.arc = this.getArc(this.radius, this.innerradius);
this.svg = d3.select(pieChart.el["selector"]).append("svg")
.attr("width", this.width + padding)
.attr("height", this.height + padding);
this.holder = this.svg.append("g")
.attr("transform", "translate(" + ((this.width / 2) + (padding / 2)) + "," + ((this.height / 2) + (padding / 2)) + ")");
this.piec = this.holder.append("g")
.attr("class", "piechart");
this.segments = this.holder.append("g")
.attr("class", "segments");
this.labels = this.holder.append("g")
.attr("class", "labels");
this.pointers = this.holder.append("g")
.attr("class", "pointers");
this.legend = this.svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(" + -(this.width / 4) + "," + this.height + ")");
},
oldPieData: "",
pieTween: function (r, ir, d, i) {
var that = this;
var theOldDataInPie = pieChart.oldPieData;
// Interpolate the arcs in data space
var s0;
var e0;
if (theOldDataInPie[i]) {
s0 = theOldDataInPie[i].startAngle;
e0 = theOldDataInPie[i].endAngle;
} else if (!(theOldDataInPie[i]) && theOldDataInPie[i - 1]) {
s0 = theOldDataInPie[i - 1].endAngle;
e0 = theOldDataInPie[i - 1].endAngle;
} else if (!(theOldDataInPie[i - 1]) && theOldDataInPie.length > 0) {
s0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle;
e0 = theOldDataInPie[theOldDataInPie.length - 1].endAngle;
} else {
s0 = 0;
e0 = 0;
}
var i = d3.interpolate({
startAngle: s0,
endAngle: e0
}, {
startAngle: d.startAngle,
endAngle: d.endAngle
});
return function (t) {
var b = i(t);
return pieChart.getArc(r, ir)(b);
};
},
removePieTween: function (r, ir, d, i) {
var that = this;
s0 = 2 * Math.PI;
e0 = 2 * Math.PI;
var i = d3.interpolate({
startAngle: d.startAngle,
endAngle: d.endAngle
}, {
startAngle: s0,
endAngle: e0
});
return function (t) {
var b = i(t);
return pieChart.getArc(r, ir)(b);
};
},
animateSlices: function (dataSet) {
var r = $(pieChart.el["selector"]).data("r");
var ir = $(pieChart.el["selector"]).data("ir");
this.piedata = pieChart.pie(dataSet);
//__slices
this.path = pieChart.segments.selectAll("path.pie")
.data(this.piedata, function (d) {
return d.data.label
});
this.path.enter().append("path")
.attr("class", "pie")
.attr("fill", function (d, i) {
return pieChart.color(i);
})
.attr("stroke", "#ffffff")
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.pieTween(r, ir, d, i);
});
this.path.exit()
.transition()
.duration(300)
.attrTween("d", function (d, i) {
return pieChart.removePieTween(r, ir, d, i);
})
.remove();
//__slices
//__labels
var labels = pieChart.labels.selectAll("text")
.data(this.piedata, function (d) {
return d.data.label
});
labels.enter()
.append("text")
.attr("text-anchor", "middle")
labels.attr("x", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cx = Math.cos(a) * (ir + ((r - ir) / 2));
return d.x = Math.cos(a) * (r + 20);
})
.attr("y", function (d) {
var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
d.cy = Math.sin(a) * (ir + ((r - ir) / 2));
return d.y = Math.sin(a) * (r + 20);
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.text(function (d) {
return d.data.label;
})
.each(function (d) {
var bbox = this.getBBox();
d.sx = d.x - bbox.width / 2 - 2;
d.ox = d.x + bbox.width / 2 + 2;
d.sy = d.oy = d.y + 5;
})
.transition()
.duration(300)
labels.transition()
.duration(300)
labels.exit().remove();
//__labels
//__pointers
pieChart.pointers.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
var pointers = pieChart.pointers.selectAll("path.pointer")
.data(this.piedata, function (d) {
return d.data.label
});
pointers.enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)");
pointers.attr("d", function (d) {
if (d.cx > d.ox) {
return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
} else {
return "M" + d.ox + "," + d.oy + "L" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
})
.attr("opacity", function (d) {
var opacityLevel = 1;
if (d.value == 0) {
opacityLevel = 0;
}
return opacityLevel;
})
.transition()
.duration(300)
pointers.transition()
.duration(300)
pointers.exit().remove();
},
onToggle: function (sliceData, index) {
//_toggle rectangle in legend
//_toggle slice
var completeData = jQuery.extend(true, [], pieChart.currentDataSet);
var dataLength = completeData.length;
var newDataSet = completeData;
if (pieChart.manipulatedData) {
newDataSet = pieChart.manipulatedData;
}
d3.selectAll('rect')
.data([sliceData], function (d) {
return d.data.label;
})
.style("fill-opacity", function (d) {
var isActive = Math.abs(1 - d3.select(this).style("fill-opacity"));
if (isActive) {
newDataSet[index].total = completeData[index].total;
newDataSet[index].value = completeData[index].value;
} else {
newDataSet[index].total = 0;
newDataSet[index].value = 0;
}
return isActive;
});
//if all elements are to be not shown - reset to show all slices again.
//animate slices
pieChart.animateSlices(newDataSet);
//stash manipulated data
pieChart.manipulatedData = newDataSet;
},
update: function (el, dataSet) {
var that = this;
pieChart.el = el;
pieChart.svg = d3.select(pieChart.el["selector"] + " .piechart");
pieChart.segments = d3.select(pieChart.el["selector"] + " .segments");
pieChart.labels = d3.select(pieChart.el["selector"] + " .labels");
pieChart.pointers = d3.select(pieChart.el["selector"] + " .pointers");
pieChart.legend = d3.select(pieChart.el["selector"] + " .legend");
dataSet.forEach(function (d) {
d.total = +d.value;
});
pieChart.currentDataSet = dataSet;
pieChart.animateSlices(dataSet);
//__legends
var w = 200;
// add legend
var legend = pieChart.legend; //.append("g")
var legendRects = legend.selectAll('rect')
.data(this.piedata, function (d) {
return d.data.label
});
legendRects.enter()
.append("rect")
.attr("x", w - 65)
.attr("y", function (d, i) {
return i * 20;
})
.attr("width", 10)
.attr("height", 10)
.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.on('click', function(d, i){
pieChart.onToggle(d, i);
})
.transition()
.duration(300)
legendRects.style("fill", function (d, i) {
return pieChart.color(i);
})
.style("stroke", function (d, i) {
return pieChart.color(i);
})
.transition()
.duration(300)
legendRects.exit().remove();
var legendText = legend.selectAll('text.label')
.data(this.piedata, function (d) {
return d.data.label
});
legendText.enter()
.append("text")
.attr("class", "label")
.attr("x", w - 52)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.text(function (d) {
return d.data.label;
})
.transition()
.duration(300)
legendText.exit().remove();
var legendTextVals = legend.selectAll('text.vals')
.data(this.piedata, function (d) {
return d.data.label
});
legendTextVals.enter()
.append("text")
.attr("class", "vals")
.attr("x", w + 20)
.attr("y", function (d, i) {
return i * 20 + 9;
})
.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.text(function (d) {
return d.data.value;
})
.transition()
.duration(300)
legendTextVals.exit().remove();
//__pointers
this.oldPieData = this.piedata;
}
};
var dataCharts = [{
"data": [{
"segments": [{
"label": "apple",
"value": 53245
}, {
"label": "cherry",
"value": 145
}, {
"label": "pear",
"value": 2245
}, {
"label": "bananana",
"value": 15325
}]
}]
}, {
"data": [{
"segments": [{
"label": "milk",
"value": 122
}, {
"label": "cheese",
"value": 44
}, {
"label": "grapes",
"value": 533
}]
}]
}, {
"data": [{
"segments": [{
"label": "pineapple",
"value": 1532
}, {
"label": "orange",
"value": 1435
}, {
"label": "grapes",
"value": 22
}]
}]
}, {
"data": [{
"segments": [{
"label": "lemons",
"value": 133
}, {
"label": "mango",
"value": 435
}, {
"label": "melon",
"value": 2122
}]
}]
}];
var clone = jQuery.extend(true, {}, dataCharts);
//__invoke concentric
$('[data-role="piechart"]').each(function (index) {
var selector = "piechart" + index;
$(this).attr("id", selector);
var options = {
data: clone[0].data,
width: $(this).data("width"),
height: $(this).data("height"),
r: $(this).data("r"),
ir: $(this).data("ir")
}
pieChart.init($("#" + selector), options);
pieChart.update($("#" + selector), clone[0].data[0].segments);
});
$(".testers a").on("click", function (e) {
e.preventDefault();
var clone = jQuery.extend(true, {}, dataCharts);
var min = 0;
var max = 3;
//__invoke pie chart
$('[data-role="piechart"]').each(function (index) {
pos = Math.floor(Math.random() * (max - min + 1)) + min;
pieChart.update($("#" + $(this).attr("id")), clone[pos].data[0].segments);
});
});
});