d3.js 如何让条形图上的条形直接向下浮动,但仅在滚动到该元素时?

rhfm7lfc  于 2023-05-29  发布在  其他
关注(0)|答案(1)|浏览(109)

我使用D3创建一个条形图,看起来像这样:

目前,这些条从左上角***(由于D3坐标系)以Angular 浮动。我希望条形图***直接向下浮动,但***仅当用户滚动到页面的该部分时***(注意:该页面相当长,并且用户滚动到该元素将花费几分钟)。
下面是我的代码:

let data = [
{"color": "Blue", "plotValue": 11},
{"color": "Red", "plotValue": 20},
{"color": "Orange", "plotValue": 21},
{"color": "Purple", "plotValue": 30},
{"color": "Green", "plotValue": 35},
{"color": "Violet", "plotValue": 40},
               ]

        vis.margin = {top: 70, right: 90, bottom: 90, left: 80};
        vis.width = 800 - vis.margin.left - vis.margin.right;

        // initialize the drawing area
        vis.svg = d3.select('#' + vis.parentElement).append('svg')
            .attr('width', vis.width + vis.margin.left + vis.margin.right)
            .attr('height', vis.height + vis.margin.top + vis.margin.bottom)
            .append('g')
            .attr('transform', `translate (${vis.margin.left}, ${vis.margin.top})`);

        // scales and axes
        vis.xScale = d3.scaleBand()
            .range( [ 0, vis.width ] )
            .padding(0.4);

        vis.yScale = d3.scaleLinear()
            .range( [ vis.height, 0 ] );

        vis.xAxis = d3.axisBottom()
            .scale(vis.xScale);

        vis.yAxis = d3.axisLeft()
            .scale(vis.yScale);

        // add chart title
        vis.svg.append('g')
            .attr('class', 'title bar-chart-title')
            .append('text')
            .text(vis.chartTitle)
            .attr('transform', `translate(${vis.width / 2 + 45}, -50)`)
            .attr('text-anchor', 'middle');

        // tooltip
        vis.tooltip = d3.select('body').append('div')
            .attr('class', 'tooltip')
            .attr('id', 'barChartTooltip');

        // create the axis groups
        vis.xAxisGroup = vis.svg.append('g')
            .attr('class', 'x-axis axis')
            .attr('transform', 'translate(0, ' + vis.height + ')');

        vis.yAxisGroup = vis.svg.append('g')
            .attr('class', 'y-axis axis');


        let vis = this;

        // update the domains
        vis.xScale.domain(vis.data.map(function (d) { return d.color; }));
        vis.yScale.domain( [ 0, 100 ] );

        // draw the bars
        vis.bars = vis.svg.selectAll('.bar')
            .data(vis.data)

        vis.bars.exit().remove();

        vis.bars
            .enter()
            .append('rect')
            .attr('class', 'bar')
            .on('mouseover', function(event, d) {
                d3.select(this)
                    .attr('stroke-width', '2px')
                    .attr('stroke', 'grey')
                    .attr('fill', 'blue')

                vis.tooltip
                    .style('opacity', 1)
                    .style('left', event.pageX + 20 + 'px')
                    .style('top', event.pageY + 'px')
                    .html(`
                    <div style='border: thin solid grey; border-radius: 5px; background: lightgrey; padding: 20px'>
                    <h3>${d.color}</h3>
                    <h4> ${100- d.plotValue.toLocaleString()}% decline </h4>
                    </div>
                                        
                    `)

            })
            .on('mouseout', function(event, d) {
                d3.select(this)
                    .attr('stroke-width', 1)
                    .attr('stroke', '#456983')
                    .attr('fill', function(d) {
                        return 'red'
                    })

                vis.tooltip
                    .style('opacity', 0)
                    .style('left', 0)
                    .style('top', 0)
                    .html(``);

            })
            .merge(vis.bars)
            .transition()
            .duration(1200)
            .attr('x', d => vis.xScale(d.color) )
            .attr('y', d => vis.yScale(d.plotValue) )
            .attr('width', vis.xScale.bandwidth() )
            .attr('height', function(d) { return vis.height - vis.yScale(d.plotValue); })
            .attr('fill', 'red')
//            .attr('stroke', 'grey');

        // add the axes
        vis.xAxisGroup
            .transition()
            .duration(500)
            .style('font-size', '15px')
            .style('color', 'blue')
            .call(d3.axisBottom((vis.xScale)))
            .selectAll('text')
            .attr('y', 30)
            .attr('x', -35)
            .attr('dy', '.35em')
            .attr('transform', 'rotate(-30)')
        ;

        vis.yAxisGroup
            .transition()
            .duration(500)
            .style('font-size', '15px')
            .style('color', 'blue')
            .call(d3.axisLeft(vis.yScale));

        vis.text = vis.svg.selectAll('.text')
            .data(vis.data)

        vis.text
            .enter()
            .append('text')
            .attr('class', 'text')
            .attr('text-anchor', 'middle')
            .attr('x', d => vis.xScale(d.color) + 27)
            .attr('y', d => vis.yScale(d.plotValue) - 10)
            .text( function (d) {
                return '-' + (100 - d.plotValue) + '%';
            })

我该如何修改代码,使条形图直接向下浮动,并且仅在用户滚动到页面的该部分时触发?
提前感谢您给予的任何建议!

pcww981p

pcww981p1#

没有像 *D3坐标系 * 这样的东西,那只是SVG坐标系:0,0是左上角。
为了解决这个问题,您只需要在条形输入时设置xywidth属性,然后更改过渡上的yheight属性。我相信显示向上的条形对用户来说更好,但是从顶部显示它们是微不足道的(只需更改原始的y位置):

const vis = {};

vis.data = [{
    "color": "Blue",
    "plotValue": 11
  },
  {
    "color": "Red",
    "plotValue": 20
  },
  {
    "color": "Orange",
    "plotValue": 21
  },
  {
    "color": "Purple",
    "plotValue": 30
  },
  {
    "color": "Green",
    "plotValue": 35
  },
  {
    "color": "Violet",
    "plotValue": 40
  },
];

vis.margin = {
  top: 70,
  right: 90,
  bottom: 90,
  left: 80
};
vis.width = 800 - vis.margin.left - vis.margin.right;
vis.height = 400 - vis.margin.left - vis.margin.right;

// initialize the drawing area
vis.svg = d3.select("body").append('svg')
  .attr('width', vis.width + vis.margin.left + vis.margin.right)
  .attr('height', vis.height + vis.margin.top + vis.margin.bottom)
  .append('g')
  .attr('transform', `translate (${vis.margin.left}, ${vis.margin.top})`);

// scales and axes
vis.xScale = d3.scaleBand()
  .range([0, vis.width])
  .padding(0.4);

vis.yScale = d3.scaleLinear()
  .range([vis.height, 0]);

vis.xAxis = d3.axisBottom()
  .scale(vis.xScale);

vis.yAxis = d3.axisLeft()
  .scale(vis.yScale);

// add chart title
vis.svg.append('g')
  .attr('class', 'title bar-chart-title')
  .append('text')
  .text(vis.chartTitle)
  .attr('transform', `translate(${vis.width / 2 + 45}, -50)`)
  .attr('text-anchor', 'middle');

// tooltip
vis.tooltip = d3.select('body').append('div')
  .attr('class', 'tooltip')
  .attr('id', 'barChartTooltip');

// create the axis groups
vis.xAxisGroup = vis.svg.append('g')
  .attr('class', 'x-axis axis')
  .attr('transform', 'translate(0, ' + vis.height + ')');

vis.yAxisGroup = vis.svg.append('g')
  .attr('class', 'y-axis axis');

// update the domains
vis.xScale.domain(vis.data.map(function(d) {
  return d.color;
}));
vis.yScale.domain([0, 100]);

// draw the bars
vis.bars = vis.svg.selectAll('.bar')
  .data(vis.data)

vis.bars.exit().remove();

vis.bars
  .enter()
  .append('rect')
  .attr('class', 'bar')
  .attr('x', d => vis.xScale(d.color))
  .attr('y', d => vis.yScale(0))
  .attr('width', vis.xScale.bandwidth())
  .attr("height", 0)
  .on('mouseover', function(event, d) {
    d3.select(this)
      .attr('stroke-width', '2px')
      .attr('stroke', 'grey')
      .attr('fill', 'blue')

    vis.tooltip
      .style('opacity', 1)
      .style('left', event.pageX + 20 + 'px')
      .style('top', event.pageY + 'px')
      .html(`
                    <div style='border: thin solid grey; border-radius: 5px; background: lightgrey; padding: 20px'>
                    <h3>${d.color}</h3>
                    <h4> ${100- d.plotValue.toLocaleString()}% decline </h4>
                    </div>
                                        
                    `)

  })
  .on('mouseout', function(event, d) {
    d3.select(this)
      .attr('stroke-width', 1)
      .attr('stroke', '#456983')
      .attr('fill', function(d) {
        return 'red'
      })

    vis.tooltip
      .style('opacity', 0)
      .style('left', 0)
      .style('top', 0)
      .html(``);

  })
  .merge(vis.bars)
  .transition()
  .duration(1200)
  .attr('y', d => vis.yScale(d.plotValue))
  .attr('height', function(d) {
    return vis.height - vis.yScale(d.plotValue);
  })
  .attr('fill', 'red')
//            .attr('stroke', 'grey');

// add the axes
vis.xAxisGroup
  .transition()
  .duration(500)
  .style('font-size', '15px')
  .style('color', 'blue')
  .call(d3.axisBottom((vis.xScale)))
  .selectAll('text')
  .attr('y', 30)
  .attr('x', -35)
  .attr('dy', '.35em')
  .attr('transform', 'rotate(-30)');

vis.yAxisGroup
  .transition()
  .duration(500)
  .style('font-size', '15px')
  .style('color', 'blue')
  .call(d3.axisLeft(vis.yScale));

vis.text = vis.svg.selectAll('.text')
  .data(vis.data)

vis.text
  .enter()
  .append('text')
  .attr('class', 'text')
  .attr('text-anchor', 'middle')
  .attr('x', d => vis.xScale(d.color) + 27)
  .attr('y', d => vis.yScale(d.plotValue) - 10)
  .text(function(d) {
    return '-' + (100 - d.plotValue) + '%';
  })
<script src="https://d3js.org/d3.v7.min.js"></script>

关于只在用户到达SVG时才做动画,这是一个完全不同的问题,请在SO每个问题只保留一个问题。因此,您可以针对该单独问题发布另一个问题(您不需要在该新问题中使用d3.js标签)。

相关问题