2017-04-04 81 views
2

我想创建一个可滚动的列表。我已经看过这里的其他教程,但它似乎并没有工作。本质上,我将一个SVG附加到div。这个SVG内部是一个D3JS堆叠条形图。在这个条形图的右边,我在里面添加一个带有svg的'g'元素。我为这个正确的SVG设定了一个高度。在这个内部,我填充了一个将超出SVG高度的列表。我为这个svg设置了CSS'overflow-y:scroll'。动态创建可滚动的SVG

尽管所有这一切,我不能让这个svg滚动。相反,它只是增长到列表的大小,并延伸到预定范围。请参阅下面的代码。

var barSVG = d3.select("#documents_reviewed_bar_chart").append("svg") 
    .classed('barChart-docs-reviewed', true) 
    .attr('id', 'barSVG') 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr('id', 'gElement') 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");  

var count = 0; 

var graph = barSVG.append('g') 
    .attr('id', 'graphElement') 

color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Date"; })); 


data.forEach(function(d) { 
    var myDate = d.Date; //add to stock code 
    var y0 = 0; 

    d.people = color.domain().map(function(name) { return {myDate:myDate, name: name, y0: y0, y1: y0 += +d[name]}; }); 
    d.total = d.people[d.people.length - 1].y1; 
    count = isNaN(d.total) ? count : count + d.total 

}); 


x.domain(data.map(function(d) { return d.Date; })); 
y.domain([0, d3.max(data, function(d) { return d.total; })]); 

graph.append("g") 
    .attr("class", "x axis") 
    .attr("transform", "translate(0," + height + ")") 
    .call(xAxis) 
    .selectAll("text") 
     .style("text-anchor", "end") 
     .attr("dx", "-.8em") 
     .attr("dy", ".15em") 
     .attr("transform", "rotate(-65)") 
     .style("cursor", "pointer") 
     .on('click', renderHorizontalChart); 

graph.append("g") 
    .attr("class", "y axis") 
    .call(yAxis) 
    .append("text") 
    .attr("transform", "rotate(-90)") 
    .attr("y", 6) 
    .attr("dy", ".71em") 
    .style("text-anchor", "end"); 
    //.text("Population"); 

graph.append('text') 
    .text('Total: ' + count) 
    .attr('x', 20) 
    .attr('y', -10) 


var state = graph.selectAll(".state") 
    .data(data) 
    .enter().append("g") 
    .attr("class", "g") 
    .attr("transform", function(d) { return "translate(" + "0" + ",0)"; }); 
    //.attr("transform", function(d) { return "translate(" + x(d.Date) + ",0)"; }) 

state.selectAll("rect") 
    .data(function(d) { 
     return d.people; 
    }) 
    .enter().append("rect") 
    .attr("width", x.rangeBand()) 
    .attr("y", height) 
    .attr("x",function(d) { //add to stock code 
     return x(d.myDate) 
     }) 
    .attr("height", 0) 
    .style("fill", function(d) { return color(d.name); }) 
    .transition() 
    .duration(1000) 
    .attr("y", function(d) { return y(d.y1); }) 
    .attr("height", function(d) { return y(d.y0) - y(d.y1); }) 
    .attr("class", function(d) { 
     classLabel = d.name.replace(/,\s/g, ''); //remove spaces 
     return "class" + classLabel; 
    }); 


state.selectAll("rect") 
    .on("mouseover", function(d){ 

     var delta = d.y1 - d.y0; 
     var xPos = parseFloat(d3.select(this).attr("x")); 
     var yPos = parseFloat(d3.select(this).attr("y")); 
     var height = parseFloat(d3.select(this).attr("height")) 

     d3.select(this).attr("stroke","black").attr("stroke-width",2); 

     tooltip.style("visibility", "visible"); 
     tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px"); 
     tooltip.style('background', 'black') 
     tooltip.style('color', 'white') 
     tooltip.style('border-radius', '3px') 
     tooltip.style('padding', '5px') 
     tooltip.style('opacity', '0.8') 
     tooltip.style('font-size', '10px;') 


     tooltip.text(d.name +": "+ delta) 

    }) 
    .on("mouseout",function(){ 

     tooltip.style("visibility", "hidden"); 
     graph.select(".tooltip").remove(); 
     d3.select(this).attr("stroke","pink").attr("stroke-width",0.2); 

     }) 


var itemsAmount = 0 
var rightSVG = barSVG.append('svg').classed('rightSVG', true) 
    .attr('height', '390') 
    .attr('id', 'rightSVG') 



var legendSVG = rightSVG.append('svg').classed('legendSVG', true) 
    .attr('id', 'legendSVG') 


var legend = legendSVG.selectAll(".legend") 
    .data(color.domain().slice().reverse()) 
    .enter().append("g") 
    //.attr("class", "legend") 
    .attr("class", function (d) { 
     itemsAmount = itemsAmount + 1 
     legendClassArray.push(d.replace(/,\s/g, '')); //remove spaces 
     return "legend"; 
    }) 
    .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); 

//reverse order to match order in which bars are stacked  
legendClassArray = legendClassArray.reverse(); 

legend.append("rect") 
    .attr("x", width - 0) 
    .attr("width", 18) 
    .attr("height", 18) 
    .style("fill", color) 
    .attr("id", function (d, i) { 
     return "id#" + d.replace(/,\s/g, ''); 
    }) 
    .on("mouseover",function(){  


     if (active_link === "0") d3.select(this).style("cursor", "pointer"); 
     else { 
     if (active_link.split("class").pop() === this.id.split("id#").pop()) { 
      d3.select(this).style("cursor", "pointer"); 
     } else d3.select(this).style("cursor", "auto"); 
     } 
    }) 
    .on("click",function(d){  
     if (!this.id.includes('active')) { //nothing selected, turn on this selection 

     d3.select(this) 
      .attr('id', function(){ 
       return this.id + 'active' 
      }) 
      .style("stroke", "black") 
      .style("stroke-width", 2); 


      active_link = this.id.split("id#").pop(); 
      plotSingle(this); 

     } else { //deactivate 

      d3.select(this)   
      .classed("active", false) 
      .attr('id', function() { 
       return this.id.replace('active', '') 
      }) 
      .style("stroke", "none") 
      .style("stroke-width", 0); 

      plotSingle(this); 

     } 

    }); 

legend.append("text") 
    .attr("x", width - 6) 
    .attr("y", 9) 
    .attr("dy", ".35em") 
    .style("text-anchor", "end") 
    .text(function(d) { return d; }); 

legendSVG.append("text") 
    .classed('queryButton', true) 
    .attr("x", width - 6) 
    .attr("y", height) 
    .attr("dy", ".35em") 
    .style("text-anchor", "end") 
    .text('Run Query') 
    .on('click', function(){ 
     if (newArr.length > 0) { 
      d3.select('#barSVG').remove(); 
      runScript(newArr) 
     } 
    }); 

legendSVG.append("text") 
.classed('queryButton', true) 
.attr("x", width - 6) 
.attr("y", height + 18) 
.attr("dy", ".35em") 
.style("text-anchor", "end") 
.text('Reset') 

我想要滚动的特定SVG是'rightSVG'。

正如您在图像中看到的,名称被切断。应该有一个可以滚动的图例,我可以看到29个数据项。 Sample Stacked Bar chart

另外,我还增加了以下CSS:

#documents_reviewed_bar_chart, #gElement{ 
max-height: 390; 
overflow-y: scroll; 
} 
+0

你有没有考虑过使用[缩放行为](https://github.com/d3/d3-zoom/blob/master/README.md)?我认为如果您将最小/最大比例设置为1,则它变得非常接近滚动。 – transistor09

回答

2

简短的回答:你不能有另一个SVG内滚动SVG。 overflow-y: scroll适用于HTML元素,而不适用于SVG元素。

替代(和哈克)的答案:从技术上说,你想要什么是可能的,但你必须来包装你内心的SVG在一个HTML元素,它必须是一个foreignObject内。

这种选择是次优的,没有多大意义,并且在IE上不起作用。然而,只是为了好奇着想,这是你如何能做到这:

var outerSvg = d3.select("body") 
 
    .append("svg") 
 
    .attr("width", 500) 
 
    .attr("height", 200) 
 
    .style("background-color", "darkkhaki"); 
 
    
 
var foreign = outerSvg.append("foreignObject") 
 
    .attr("x", 300) 
 
    .attr("y", 10) 
 
    .attr("width", 150) 
 
    .attr("height", 180) 
 
    .append("xhtml:div") 
 
    .style("max-height", "180px") 
 
    .style("overflow-y", "scroll"); 
 
    
 
var innerSvg = foreign.append("svg") 
 
    .attr("width", 133) 
 
    .attr("height", 1000) 
 
    .style("background-color", "powderblue"); 
 
    
 
var color = d3.scaleOrdinal(d3.schemeCategory20); 
 
    
 
var texts = innerSvg.selectAll("foo") 
 
    .data(d3.range(65)) 
 
    .enter() 
 
    .append("text") 
 
    .attr("x", 40) 
 
    .attr("y", (d,i)=> 20 + 15*i) 
 
    .text("foo bar baz") 
 
    
 
var rects = innerSvg.selectAll("foo") 
 
    .data(d3.range(65)) 
 
    .enter() 
 
    .append("rect") 
 
    .attr("x", 10) 
 
    .attr("y", (d,i)=> 8 + 15*i) 
 
    .attr("width", 20) 
 
    .attr("height", 13) 
 
    .attr("fill", (d,i)=>color(i));
<script src="https://d3js.org/d3.v4.min.js"></script>

外SVG是浅褐色(或卡其色)。右边的内部SVG是蓝色的,它位于<div>overflow-y: scroll;之内。

+0

谢谢!我采取了基本的概念,并以一种不太古怪的方式开展工作。 +1 – Kerrin631

+0

很高兴知道你做了些什么*少hacky *。尽量避免'foreignObject' ... –

+0

@ Kerrin631我希望看到你提出的不太冒险的方式。 – Matt