2017-09-02 109 views
0

嗨,我正在尝试将Matthew Izanuk的Unit Bar Chart with Brush and Zoom修改为我已经创建的随机生成的条形图。d3在条形图上使用缩放和笔刷

我与变焦功能的错误,线261上

enter image description here

线261

x.domain(t.rescaleX(x2).domain()); 

下面是代码和jsFiddle

<!DOCTYPE html> 
 

 
<body> 
 
    <style> 
 
    div { 
 
     display: inline-block; 
 
     vertical-align: top; 
 
    } 
 

 
    #bar_chart { 
 
     border: 2px solid lightgray; 
 
     border-radius: 15px; 
 
    } 
 

 
    #json { 
 
     max-height: 600px; 
 
     width: 200px; 
 
     overflow: scroll; 
 
     border: 2px solid gray; 
 
     border-radius: 15px; 
 
    } 
 

 
    .zoom { 
 
     cursor: move; 
 
     fill: none; 
 
     pointer-events: all; 
 
    } 
 
    </style> 
 
    <div id="bar_chart"> 
 
    </div> 
 

 
    <div id="json"></div> 
 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
 
    <script> 
 
    //************* generate data ************ 
 
    var data = []; 
 
    var space = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 
 
    var spaceLength = space.length; 
 
    makedata(); 
 

 
    function makedata() { 
 
     var obj = {}; 
 

 
     for (var i = 0; i < spaceLength; i++) { 
 
     obj = {}; 
 
     value = Math.floor(Math.random() * 500); 
 
     rand = Math.floor(Math.random() * space.length) 
 
     name = space.charAt(rand); 
 
     obj["name"] = name; 
 
     obj["val"] = value; 
 
     data.push(obj); 
 
     space = space.slice(0, rand) + space.slice(rand + 1, space.length) 
 
     } 
 
    } 
 

 
    // To display json in html page 
 
    document.getElementById("json").innerHTML = "<pre>" + JSON.stringify(data, null, 4) + "</pre>"; 
 

 
    var margin = { 
 
     top: 50, 
 
     right: 20, 
 
     bottom: 90, 
 
     left: 50 
 
     }, 
 
     margin2 = { 
 
     top: 530, 
 
     right: 20, 
 
     bottom: 30, 
 
     left: 50 
 
     }, 
 
     width = 1000 - margin.left - margin.right, 
 
     height = 600 - margin.top - margin.bottom, 
 
     height2 = 600 - margin2.top - margin2.bottom; 
 

 
    var x = d3.scaleBand() 
 
     .domain(data.map(function(d) { 
 
     return d.name 
 
     })) 
 
     .range([0, width]); 
 

 
    var x2 = d3.scaleBand() 
 
     .domain(data.map(function(d) { 
 
     return d.name 
 
     })) 
 
     .range([0, width]); 
 

 
    var y = d3.scaleLinear() 
 
     .domain([0, d3.max(data, function(d) { 
 
     return d.val 
 
     })]) 
 
     .range([height, 0]); 
 

 
    var y2 = d3.scaleLinear() 
 
     .domain([0, d3.max(data, function(d) { 
 
     return d.val 
 
     })]) 
 
     .range([height2, 0]); 
 

 
    var brush = d3.brushX() 
 
     .extent([ 
 
     [0, 0], 
 
     [width, height2] 
 
     ]) 
 
     .on("brush", brushed); 
 

 
    var zoom = d3.zoom() 
 
     .scaleExtent([1, Infinity]) 
 
     .translateExtent([ 
 
     [0, 0], 
 
     [width, height] 
 
     ]) 
 
     .extent([ 
 
     [0, 0], 
 
     [width, height] 
 
     ]) 
 
     .on("zoom", zoomed); 
 

 
    var svg = d3.select("#bar_chart") 
 
     // .data(data) 
 
     .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 + ")"); 
 

 
    svg.append("defs").append("clipPath") 
 
     .attr("id", "clip") 
 
     .append("rect") 
 
     .attr("width", width) 
 
     .attr("height", height); 
 

 
    var focus = svg.append("g") 
 
     .attr("class", "focus") 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 
    var context = svg.append("g") 
 
     .attr("class", "context") 
 
     .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); 
 

 
    var g0 = focus.append("g") 
 
     .attr("class", "focus") 
 
     .attr("transform", "translate(0,0)"); 
 

 
    var xAxis = d3.axisBottom(x); 
 
    var xAxis2 = d3.axisBottom(x2); 
 

 
    focus.append("g") 
 
     .attr("class", "x axis") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .call(xAxis); 
 

 
    // Add the Y Axis 
 
    focus.append("g") 
 
     .attr("class", "axis") 
 
     .call(d3.axisLeft(y) 
 
     .ticks(7)); 
 

 
    var tooltip = d3.select("#info") 
 
     .append("div") 
 
     .style("position", "absolute") 
 
     .style("z-index", "10") 
 
     .style("visibility", "hidden"); 
 

 
    svg.append("rect") 
 
     .attr("class", "zoom") 
 
     .attr("width", width) 
 
     .attr("height", height) 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
 
     .call(zoom); 
 

 
    var focus_group = focus.append("g"); 
 
    focus_group.attr("clip-path", "url(#clip)"); 
 

 
    var rects = focus_group.selectAll('rect') 
 
     .data(data); 
 

 
    //********* Bar Chart 1 **************** 
 
    var newRects1 = rects.enter(); 
 

 
    newRects1.append('rect') 
 
     .attr('class', 'bar mainBars') 
 
     .attr('x', function(d, i) { 
 
     return x(d.name); 
 
     }) 
 
     .attr('y', function(d, i) { 
 
     return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
     return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10) 
 
     .attr("transform", "translate(" + 4 + ",0)") 
 
     .style('fill', 'lightblue') 
 
     .style('stroke', 'gray'); 
 

 
    var focus_group = context.append("g"); 
 
    focus_group.attr("clip-path", "url(#clip)"); 
 

 
    var brushRects = focus_group.selectAll('rect') 
 
     .data(data); 
 

 
    //********* Brush Bar Chart **************** 
 
    var brushRects1 = brushRects.enter(); 
 

 
    brushRects1.append('rect') 
 
     .attr('class', 'bar mainBars') 
 
     .attr('x', function(d, i) { 
 
     return x2(d.name); 
 
     }) 
 
     .attr('y', function(d, i) { 
 
     return y2(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
     return height2 - y2(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10) 
 
     .attr("transform", "translate(" + 4 + ",0)") 
 
     .style('fill', 'lightblue') 
 
     .style('stroke', 'gray'); 
 

 
    //append brush xAxis2 
 
    context.append("g") 
 
     .attr("class", "axis x-axis") 
 
     .attr("transform", "translate(0," + height2 + ")") 
 
     .call(xAxis2); 
 

 
    context.append("g") 
 
     .attr("class", "brush") 
 
     .call(brush) 
 
     .call(brush.move, x.range()); 
 

 
    //create brush function redraw scatterplot with selection 
 
    function brushed() { 
 
     if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom 
 
     var s = d3.event.selection || x2.range(); 
 
     x.domain(s.map(x2.invert, x2)); 
 
     focus.selectAll(".mainBars") 
 
     .attr("x", function(d) { 
 
      return x(d.name); 
 
     }) 
 
     .attr("y", function(d) { 
 
      return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
      return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10); 
 
     focus.select(".x-axis").call(xAxis); 
 
     svg.select(".zoom").call(zoom.transform, d3.zoomIdentity 
 
     .scale(width/(s[1] - s[0])) 
 
     .translate(-s[0], 0)); 
 
    } 
 

 
    function zoomed() { 
 
     if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush 
 
     var t = d3.event.transform; 
 
     x.domain(t.rescaleX(x2).domain()); 
 
     focus.selectAll(".mainBars") 
 
     .attr("x", function(d) { 
 
      return x(d.name); 
 
     }) 
 
     .attr("y", function(d) { 
 
      return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
      return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10); 
 
     focus.select(".x-axis").call(xAxis); 
 
     context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); 
 
    } 
 
    </script>

任何帮助将不胜感激,

感谢

+1

'invert'不存在在'scaleBand'类型上。参考:https://github.com/d3/d3-scale#scaleBand –

+0

谢谢,我实际上不知道这行代码的作用。有什么办法可以解决它吗?谢谢 –

回答

1

作为评价所提到的,只有invert存在连续范围。您的scaleBand是由谨慎值组成的序数量表。我已经围绕这个工作的一种方法是简单地计算在选择我的域名落入值:

function brushed() { 
    if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; 
    // ignore brush-by-zoom 

    // get bounds of selection 
    var s = d3.event.selection, 
     nD = []; 

    // for each "tick" in our domain is it in selection 
    x2.domain().forEach((d)=>{ 
    var pos = x2(d) + x2.bandwidth()/2; 
    if (pos > s[0] && pos < s[1]){ 
     nD.push(d); 
    } 
    }); 

    // set new domain 
    x.domain(nD); 

    // redraw 
    focus.selectAll(".mainBars") 
    // hide bars not in domain 
    .style("opacity", function(d){ 
     return x.domain().indexOf(d.name) === -1 ? 0 : 100; 
    }) 
    .attr("x", function(d) { 
     return x(d.name)+ x.bandwidth()/2 - 5; 
    }) 
    .attr("y", function(d) { 
     return y(d.val); 
    }) 
    .attr('height', function(d, i) { 
     return height - y(d.val) 
    }) 
    .attr('opacity', 0.85) 
    .attr('width', 10); 


    focus.select(".x.axis").call(xAxis); 

    svg.select(".zoom").call(zoom.transform, d3.zoomIdentity 
    .scale(width/(s[1] - s[0])) 
    .translate(-s[0], 0)); 
} 

运行代码:

<!DOCTYPE html> 
 

 
<head> 
 
    <style> 
 
    div { 
 
     display: inline-block; 
 
     vertical-align: top; 
 
    } 
 
    
 
    #bar_chart { 
 
     border: 2px solid lightgray; 
 
     border-radius: 15px; 
 
    } 
 
    
 
    #json { 
 
     max-height: 600px; 
 
     width: 200px; 
 
     overflow: scroll; 
 
     border: 2px solid gray; 
 
     border-radius: 15px; 
 
    } 
 
    
 
    .zoom { 
 
     cursor: move; 
 
     fill: none; 
 
     pointer-events: all; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 
    <div id="bar_chart"> 
 
    </div> 
 

 
    <div id="json"></div> 
 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
 
    <script> 
 
    //************* generate data ************ 
 
    var data = []; 
 
    var space = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 
 
    var spaceLength = space.length; 
 
    makedata(); 
 

 
    function makedata() { 
 
     var obj = {}; 
 

 
     for (var i = 0; i < spaceLength; i++) { 
 
     obj = {}; 
 
     value = Math.floor(Math.random() * 500); 
 
     rand = Math.floor(Math.random() * space.length) 
 
     name = space.charAt(rand); 
 
     obj["name"] = name; 
 
     obj["val"] = value; 
 
     data.push(obj); 
 
     space = space.slice(0, rand) + space.slice(rand + 1, space.length) 
 
     } 
 
    } 
 

 
    // To display json in html page 
 
    document.getElementById("json").innerHTML = "<pre>" + JSON.stringify(data, null, 4) + "</pre>"; 
 

 
    var margin = { 
 
     top: 50, 
 
     right: 20, 
 
     bottom: 90, 
 
     left: 50 
 
     }, 
 
     margin2 = { 
 
     top: 530, 
 
     right: 20, 
 
     bottom: 30, 
 
     left: 50 
 
     }, 
 
     width = 1000 - margin.left - margin.right, 
 
     height = 600 - margin.top - margin.bottom, 
 
     height2 = 600 - margin2.top - margin2.bottom; 
 

 
    var x = d3.scaleBand() 
 
     .domain(data.map(function(d) { 
 
     return d.name 
 
     })) 
 
     .range([0, width]); 
 

 
    var x2 = d3.scaleBand() 
 
     .domain(data.map(function(d) { 
 
     return d.name 
 
     })) 
 
     .range([0, width]); 
 

 
    var y = d3.scaleLinear() 
 
     .domain([0, d3.max(data, function(d) { 
 
     return d.val 
 
     })]) 
 
     .range([height, 0]); 
 

 
    var y2 = d3.scaleLinear() 
 
     .domain([0, d3.max(data, function(d) { 
 
     return d.val 
 
     })]) 
 
     .range([height2, 0]); 
 

 
    var brush = d3.brushX() 
 
     .extent([ 
 
     [0, 0], 
 
     [width, height2] 
 
     ]) 
 
     .on("brush", brushed); 
 

 
    var zoom = d3.zoom() 
 
     .scaleExtent([1, Infinity]) 
 
     .translateExtent([ 
 
     [0, 0], 
 
     [width, height] 
 
     ]) 
 
     .extent([ 
 
     [0, 0], 
 
     [width, height] 
 
     ]) 
 
     .on("zoom", zoomed); 
 

 
    var svg = d3.select("#bar_chart") 
 
     // .data(data) 
 
     .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 + ")"); 
 

 
    svg.append("defs").append("clipPath") 
 
     .attr("id", "clip") 
 
     .append("rect") 
 
     .attr("width", width) 
 
     .attr("height", height); 
 

 
    var focus = svg.append("g") 
 
     .attr("class", "focus") 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 
    var context = svg.append("g") 
 
     .attr("class", "context") 
 
     .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); 
 

 
    var xAxis = d3.axisBottom(x); 
 
    var xAxis2 = d3.axisBottom(x2); 
 

 
    focus.append("g") 
 
     .attr("class", "x axis") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .call(xAxis); 
 

 
    // Add the Y Axis 
 
    focus.append("g") 
 
     .attr("class", "axis") 
 
     .call(d3.axisLeft(y) 
 
     .ticks(7)); 
 

 
    var tooltip = d3.select("#info") 
 
     .append("div") 
 
     .style("position", "absolute") 
 
     .style("z-index", "10") 
 
     .style("visibility", "hidden"); 
 

 
    svg.append("rect") 
 
     .attr("class", "zoom") 
 
     .attr("width", width) 
 
     .attr("height", height) 
 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
 
     .call(zoom); 
 

 
    var focus_group = focus.append("g"); 
 
    focus_group.attr("clip-path", "url(#clip)"); 
 

 
    var rects = focus_group.selectAll('rect') 
 
     .data(data); 
 

 
    //********* Bar Chart 1 **************** 
 
    var newRects1 = rects.enter(); 
 

 
    newRects1.append('rect') 
 
     .attr('class', 'bar mainBars') 
 
     .attr('x', function(d, i) { 
 
     return x(d.name) + x.bandwidth()/2; 
 
     }) 
 
     .attr('y', function(d, i) { 
 
     return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
     return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10) 
 
     .style('fill', 'lightblue') 
 
     .style('stroke', 'gray'); 
 

 
    var focus_group = context.append("g"); 
 
    focus_group.attr("clip-path", "url(#clip)"); 
 

 
    var brushRects = focus_group.selectAll('rect') 
 
     .data(data); 
 

 
    //********* Brush Bar Chart **************** 
 
    var brushRects1 = brushRects.enter(); 
 

 
    brushRects1.append('rect') 
 
     .attr('class', 'bar mainBars') 
 
     .attr('x', function(d, i) { 
 
     return x2(d.name); 
 
     }) 
 
     .attr('y', function(d, i) { 
 
     return y2(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
     return height2 - y2(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10) 
 
     .attr("transform", "translate(" + 4 + ",0)") 
 
     .style('fill', 'lightblue') 
 
     .style('stroke', 'gray'); 
 

 
    //append brush xAxis2 
 
    context.append("g") 
 
     .attr("class", "axis x-axis") 
 
     .attr("transform", "translate(0," + height2 + ")") 
 
     .call(xAxis2); 
 

 
    context.append("g") 
 
     .attr("class", "brush") 
 
     .call(brush) 
 
     .call(brush.move, x.range()); 
 

 
    //create brush function redraw scatterplot with selection 
 
    function brushed() { 
 
     if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom 
 

 
     // get bounds of selection 
 
     var s = d3.event.selection, 
 
      nD = []; 
 
     x2.domain().forEach((d)=>{ 
 
     var pos = x2(d) + x2.bandwidth()/2; 
 
     if (pos > s[0] && pos < s[1]){ 
 
      nD.push(d); 
 
     } 
 
     }); 
 
     
 
     x.domain(nD); 
 
     
 
     focus.selectAll(".mainBars") 
 
     .style("opacity", function(d){ 
 
      return x.domain().indexOf(d.name) === -1 ? 0 : 100; 
 
     }) 
 
     .attr("x", function(d) { 
 
      return x(d.name)+ x.bandwidth()/2 - 5; 
 
     }) 
 
     .attr("y", function(d) { 
 
      return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
      return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10); 
 

 
     
 
     focus.select(".x.axis").call(xAxis); 
 
     
 
     svg.select(".zoom").call(zoom.transform, d3.zoomIdentity 
 
     .scale(width/(s[1] - s[0])) 
 
     .translate(-s[0], 0)); 
 
    } 
 

 
    function zoomed() { 
 
     /* 
 
     if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush 
 
     var t = d3.event.transform; 
 
     
 
     x.domain(t.rescaleX(x2).domain()); 
 
     focus.selectAll(".mainBars") 
 
     .attr("x", function(d) { 
 
      return x(d.name) + x.bandwidth()/2; 
 
     }) 
 
     .attr("y", function(d) { 
 
      return y(d.val); 
 
     }) 
 
     .attr('height', function(d, i) { 
 
      return height - y(d.val) 
 
     }) 
 
     .attr('opacity', 0.85) 
 
     .attr('width', 10); 
 
     focus.select(".x-axis").call(xAxis); 
 
     context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); 
 
     */ 
 
    } 
 
    </script>

+0

非常感谢您的答复。等不及要试试这个。会告诉你这件事的进展的。 –

+0

这很好,谢谢 –