简体   繁体   中英

d3.js brush fill color histogram

i have created some histogram with d3.js . I managed to change fill color of rect depending on the position of the brush . But i would like to change the color inside a rect . For example if the brush start is in the middle of the rect i would like to have my rect with two color.

At the moment this is what i have :
在此处输入图片说明

And this is what i would like to have :
在此处输入图片说明

I have seen some examples like Here . I'm new to d3 and i try to understand the code.
I see that they use clip-path that certainly hide the background bar when their is no brush and show them when their is one depending on the range of the brush.

Here is a JS Bin

Update

I have read in details the code provided in the link . And i found that they dont create <rect> element to make chart but barPath like follow :

function barPath(groups) {
        var path = [],
            i = -1,
            n = groups.length,
            d;
        while (++i < n) {
          d = groups[i];
          path.push("M", x(d.key), ",", height, "V", y(d.value), "h9V", height);
        }
        return path.join("");
      }

But i didn't event understand what happend in this function and how to dot it in this way if their is no other way to do this.

Instead of trying to draw partial bars (as your edit seems to suggest), I would instead append the bars twice, once gray on bottom and then steelblue on top. You can then just apply a clip-path to the blue bars and when they are clipped you'll see the gray below.

Full code:

 <!DOCTYPE html> <html> <head> <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script> <style> .charts { padding: 10px 0; } .chart { padding-left: 20px; padding-top: 10px; } .axis text { font: 10px sans-serif; fill: black; } .chart text { font: 10px sans-serif; fill: black; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } /*dont display yAxis for categorical variable*/ #chart .y.axis g { display: none; } /*Labels in categorical chart */ text#catTitle.catTitle { font: 10px sans-serif; fill: white; } /*Color for the brush */ .brush rect.extent { fill: steelblue; fill-opacity: .125; } /*Color for the brush resize path*/ .brush .resize path { fill: #eee; stroke: #666; } /*Color for the hidden object*/ .hidden { fill: grey; } .bar { fill: steelblue; } </style> </head> <body> <svg class="chart" id="chart"></svg> <script> var data = [{ key: 1, value: 37 }, { key: 1.5, value: 13 }, { key: 2.5, value: 1 }, { key: 3, value: 4 }, { key: 3.5, value: 14 }, { key: 4, value: 18 }, { key: 4.5, value: 21 }, { key: 5, value: 17 }, { key: 5.5, value: 16 }, { key: 6, value: 5 }, { key: 6.5, value: 4 }]; var margin = { top: 10, right: 41, bottom: 42, left: 10 }; var width = 400 - margin.left - margin.right, height = 250 - margin.top - margin.bottom; var y = d3.scale.linear() .domain([0, d3.max(data, function(d) { return d.value })]) .range([height, 0]); var x = d3.scale.linear() .domain([0, d3.max(data, function(d) { return d.key; }) + 1]) .rangeRound([0, width]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var chart = d3.select(".chart#chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .style("margin-left", 15 + "px"); chart.append("defs") .append("clipPath") .attr("id", "clip") .append("rect") .attr("x", 0) .attr("y", 0) .attr("width", width) .attr("height", height); var brush = d3.svg.brush() .x(x) .on("brush", brushed) .on("brushend", brushend); function brushend() { if (brush.empty()){ chart.select("#clip>rect") .attr("x", 0) .attr("width", width); } } function brushed() { var e = brush.extent(); chart.select("#clip>rect") .attr("x", x(e[0])) .attr("width", x(e[1]) - x(e[0])); } chart.selectAll(".hidden") .data(data) .enter().append("rect") .attr("class", "hidden") .attr("x", function(d) { return x(d.key); }) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .attr("width", x(0.5)) .style("stroke", "white") .append("title") .text(function(d) { return d.key; }); chart.selectAll(".bar") .data(data) .enter().append("rect") .attr("clip-path", "url(#clip)") .attr("class", "bar") .attr("x", function(d) { return x(d.key); }) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .attr("width", x(0.5)) .style("stroke", "white") .append("title") .text(function(d) { return d.key; }); chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); chart.append("text") //Add chart title .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")") .style("text-anchor", "middle") .text("Petal Length"); chart.append("g") .attr("class", "y axis") .call(yAxis); chart.append("g") .attr("class", "x brush") .call(brush) //call the brush function, causing it to create the rectangles .selectAll("rect") //select all the just-created rectangles .attr("y", -6) .attr("height", (height + margin.top)) //set their height function resizePath(d) { var e = +(d == "e"), x = e ? 1 : -1, y = height / 3; return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.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); } chart.selectAll(".resize").append("path").attr("d", resizePath); </script> </body> </html>

For anyone looking to bring @Mark's answer to v6:

 const data = [{ key: 1, value: 37 }, { key: 1.5, value: 13 }, { key: 2.5, value: 1 }, { key: 3, value: 4 }, { key: 3.5, value: 14 }, { key: 4, value: 18 }, { key: 4.5, value: 21 }, { key: 5, value: 17 }, { key: 5.5, value: 16 }, { key: 6, value: 5 }, { key: 6.5, value: 4 }]; // svg sizes const width = 400, height = 200; const m = 50; const margin = { top: m, right: m, bottom: m, left: m, }; const y = d3.scaleLinear() .domain(d3.extent(data, d => d.value)) .range([height - margin.bottom, margin.top]); const x = d3.scaleLinear() .domain(d3.extent(data, d => d.key).map((v, i) => i==0 ? v - 1 : v + 1)) .rangeRound([margin.left, width - margin.right]); const svg = d3.select('svg') .attr('width', width) .attr('height', height) .attr('viewBox', `0 0 ${width} ${height}`) const rects = svg.append('g').attr('class', 'rects'); const clips = svg.append('g').attr('class', 'clips'); svg.append('g') .attr('class', 'x-axis') .attr('transform', `translate(0,${height - margin.bottom})`) .call(d3.axisBottom(x)); svg.append('g') .attr('class', 'y-axis') .style('display', 'none') .attr('transform', `translate(${margin.left},0)`) .call(d3.axisLeft(y)); svg.append('defs') .append('clipPath') .attr('id', 'clip') .append('rect') .attr('x', margin.left) .attr('y', margin.top) .attr('width', width - margin.right) .attr('height', height - margin.bottom); const brush = d3.brushX() .extent([ [x.range()[0], margin.top], [x.range()[1], height - margin.bottom] ]) .on('brush', brushed) .on('start', brushed) .on('end', brushend); function brushend(e) { if (!e.selection || !e.selection.length) { svg.select('#clip>rect') .attr('x', margin.left) .attr('width', width - margin.right); } } function brushed(e) { svg.select('#clip>rect') .attr('x', e.selection[0]) .attr('width', e.selection[1] - e.selection[0]); const selected = { x0: x.invert(e.selection[0]), x1: x.invert(e.selection[1]), } } rects.selectAll('rect') .data(data) .enter().append('rect') .attr('x', d => x(d.key)) .attr('y', d => y(d.value)) .attr('height', d => height - y(d.value) - margin.bottom) .attr('width', 20) .style('stroke', 'white') .style('fill', 'gray') .append('title') .text(d => d.key); clips.selectAll('rect') .data(data) .enter().append('rect') .attr('clip-path', 'url(#clip)') .attr('x', d => x(d.key)) .attr('y', d => y(d.value)) .attr('height', d => height - y(d.value) - margin.bottom) .attr('width', 20) .style('stroke', 'white') .append('title') .text(d => d.key); svg.append('g') .attr('class', 'x brush') .call(brush) // initialize the brush .selectAll('rect') .attr('y', 0) .attr('height', height)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script> <svg/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM