如何使用JSON响应来更新d3.js甜甜圈值

时间:2019-11-05 13:21:22

标签: javascript json d3.js

我只是从javascript和d3.js v3开始。我制作了一个甜甜圈图,希望它使用来自Google API的JSON数据。 应该使用JSON响应中的“得分”数据更新HTML中的data-value属性。

我知道可以使用d3.json(url, callback);提取JSON数据,但是我不确定如何正确设置它。

以及如何更改代码,以便在初始化图表之前更新data-value

HTML:

<div class="ui">
      <ul class="ui__downloadList">
        <li class="ui__downloadList__item red" id="red" data-value=25 data-type=performance>
          <div class="ui__downloadList__graphic" width=154 height=160></div>
          <h2 class="ui__downloadList__headline">Performance</h2>
          <h3 class="ui__downloadList__subHeadline">120 Files</h3>
        <li class="ui__downloadList__item purple" id="purple" data-value=50 data-type=accessibility>
          <div class="ui__downloadList__graphic" width=154 height=160></div>
          <h2 class="ui__downloadList__headline">Accessibility</h2>
          <h3 class="ui__downloadList__subHeadline">65 Files</h3>
        <li class="ui__downloadList__item cyan" id="cyan" data-value=75 data-type=best-practices>
          <div class="ui__downloadList__graphic" width=154 height=160></div>
          <h2 class="ui__downloadList__headline">Best-Practices</h2>
          <h3 class="ui__downloadList__subHeadline">98 Files</h3>
      </ul>
</div>

API的JSON示例:

{"lighthouseResult":{"categories":{"performance":{"score":1.0},"accessibility":{"score":0.9},"best-practices":{"score":0.92}}}}

Javascript:

;( function( d3 ) {
  /**
   * Function to kick of all fancy download circles
   */
  function visualizeDownloadCircles ( selector ) {

    var d3items    = d3.selectAll( selector ),
        d3graphics = d3items.select( '.ui__downloadList__graphic' ),

        svgElements;

    // remove old svg for the case there was one
    d3graphics.select( 'svg' ).remove();

    d3items.each( function( svg, index ) { 
      var d3item = d3.select( this );

      index++;

      drawDownloadCircle( d3item, index );
    } );
  }

  /**
   * Function to draw one particular 
   * download circle
   */
  function drawDownloadCircle( d3item, index ) {
    var d3container = d3item.select( '.ui__downloadList__graphic' ),
        value       = d3item.attr( 'data-value' ),
        type        = d3item.attr( 'data-type' ),
        width       = d3container.attr( 'width' ),
        height      = d3container.attr( 'height' ),

        // circle stuff
        twoPi  = 2 * Math.PI,
        radius = Math.min( width, height ) / 2 - 5,
        arcBackground = d3.svg.arc()
                          .startAngle( 0 )
                          .endAngle( function( d ) { return d.value * twoPi; } )
                          .outerRadius( radius - 10 )
                          .innerRadius( radius - 35 ),
        arcForeground = d3.svg.arc()
                          .startAngle( 0 )
                          .endAngle( function( d ) { return d.value * twoPi; } )
                          .outerRadius( radius )
                          .innerRadius( radius - 27 ),

        // value stuff
        currentValue = 0,
        progress     = 0,

        // animation stuff,
        duration = 3000;

    // string to number
    value = +value;

    // append new svg
    var svg = d3container.append( 'svg' )
                          .attr( 'width', width )
                          .attr( 'height', height )
                          .append( 'g' )
                          .attr(
                            'transform',
                            'translate(' + width / 2 + ',' + height / 2 + ')'
                          );

    // filter stuff
    /* For the drop shadow filter... */
    var defs = svg.append( 'defs' );

    var filter = defs.append( 'filter' )
                      .attr( 'id', 'dropshadow' )

    filter.append( 'feGaussianBlur' )
          .attr( 'in', 'SourceAlpha' )
          .attr( 'stdDeviation', 2 )
          .attr( 'result', 'blur' );
    filter.append( 'feOffset' )
          .attr( 'in', 'blur' )
          .attr( 'dx', 2 )
          .attr( 'dy', 3 )
          .attr( 'result', 'offsetBlur' );

    var feMerge = filter.append( 'feMerge' );

    feMerge.append( 'feMergeNode' )
            .attr( 'in", "offsetBlur' )
    feMerge.append( 'feMergeNode' )
            .attr( 'in', 'SourceGraphic' );
    // end filter stuff

    // gradient stuff    
    var gradientBackgroundRed = defs.append( 'linearGradient' )
                                    .attr( 'id', 'gradientBackgroundRed' )
                                    .attr( 'x1', '0' )
                                    .attr( 'x2', '0' )
                                    .attr( 'y1', '0' )
                                    .attr( 'y2', '1' );
    gradientBackgroundRed.append( 'stop' )
                        .attr( 'class', 'redBackgroundStop1' )
                        .attr( 'offset', '0%' );

    gradientBackgroundRed.append( 'stop' )
                        .attr( 'class', 'redBackgroundStop2' )
                        .attr( 'offset', '100%' ); 

    var gradientBackgroundPurple = defs.append( 'linearGradient' )
                                      .attr( 'id', 'gradientBackgroundPurple' )
                                      .attr( 'x1', '0' )
                                      .attr( 'x2', '0' )
                                      .attr( 'y1', '0' )
                                      .attr( 'y2', '1' );

    gradientBackgroundPurple.append( 'stop' )
                            .attr( 'class', 'purpleBackgroundStop1' )
                            .attr( 'offset', '0%' );

    gradientBackgroundPurple.append( 'stop' )
                            .attr( 'class', 'purpleBackgroundStop2' )
                            .attr( 'offset', '100%' ); 

    var gradientBackgroundCyan = defs.append( 'linearGradient' )
                                    .attr( 'id', 'gradientBackgroundCyan' )
                                    .attr( 'x1', '0' )
                                    .attr( 'x2', '0' )
                                    .attr( 'y1', '0' )
                                    .attr( 'y2', '1' );

    gradientBackgroundCyan.append( 'stop' )
                          .attr( 'class', 'cyanBackgroundStop1' )
                          .attr( 'offset', '0%' );

    gradientBackgroundCyan.append( 'stop' )
                          .attr( 'class', 'cyanBackgroundStop2' )
                          .attr( 'offset', '100%' );     

    var gradientForegroundRed = defs.append( 'linearGradient' )
                                    .attr( 'id', 'gradientForegroundRed' )
                                    .attr( 'x1', '0' )
                                    .attr( 'x2', '0' )
                                    .attr( 'y1', '0' )
                                    .attr( 'y2', '1' );
    gradientForegroundRed.append( 'stop' )
                        .attr( 'class', 'redForegroundStop1' )
                        .attr( 'offset', '0%' );

    gradientForegroundRed.append( 'stop' )
                        .attr( 'class', 'redForegroundStop2' )
                        .attr( 'offset', '100%' ); 

    var gradientForegroundPurple = defs.append( 'linearGradient' )
                                        .attr( 'id', 'gradientForegroundPurple' )
                                        .attr( 'x1', '0' )
                                        .attr( 'x2', '0' )
                                        .attr( 'y1', '0' )
                                        .attr( 'y2', '1' );

    gradientForegroundPurple.append( 'stop' )
                .attr( 'class', 'purpleForegroundStop1' )
                .attr( 'offset', '0%' );

    gradientForegroundPurple.append( 'stop' )
                .attr( 'class', 'purpleForegroundStop2' )
                .attr( 'offset', '100%' ); 

    var gradientForegroundCyan = defs.append( 'linearGradient' )
                            .attr( 'id', 'gradientForegroundCyan' )
                            .attr( 'x1', '0' )
                            .attr( 'x2', '0' )
                            .attr( 'y1', '0' )
                            .attr( 'y2', '1' );

    gradientForegroundCyan.append( 'stop' )
                .attr( 'class', 'cyanForegroundStop1' )
                .attr( 'offset', '0%' );

    gradientForegroundCyan.append( 'stop' )
                .attr( 'class', 'cyanForegroundStop2' )
                .attr( 'offset', '100%' );     
    // end gradient stuff



    var meter = svg.append( 'g' )
                    .attr( 'class', 'progress-meter' );

    meter.append( 'title' )
          .text( 'Progress meter showing amount of space used for ' + type );

    meter.data(
            [
              { value : .0,  index : .5 }
            ]
          )
          .append( 'path' )
          .attr( 'class', 'ui__downloadList__backgroundCircle' )
          .attr( 'd', arcBackground )
          .attr( 'filter', 'url(#dropshadow)' )
          .transition()
          .duration( duration )
          .attrTween( 'd', tweenArcBackground( { value : 1 } ) );


    var foreground = meter.data(
                            [
                              { value : .0, index: .5 }
                            ]
                          )
                          .append( 'path' )
                          .attr( 'stroke', '#fff' )
                          .attr( 'class', 'ui__downloadList__foregroundCircle' )
                          .attr( 'd', arcForeground )
                          .attr( 'filter', 'url(#dropshadow)' )
                          .transition()
                          .attr( 'stroke', '#aaa' )
                          .delay( 100 * index )   
                          .duration( duration )
                          .attrTween( 'd', tweenArcForeground({ value : value / 100 } ) );


    meter.data( [ 0 ] )
          .append( 'text' )
          .text ( 0 )
          .attr( 'font-size', '25px' )
          .attr( 'x', 0 )
          .attr( 'y', 0 )
          .attr( 'fill', '#fff' )
          .attr( 'text-anchor', 'middle' )
          .attr( 'filter', 'url(#dropshadow)' )
          .transition()
          .delay( 100 * index )
          .duration( duration )
          .tween( 'text', tweenText( value ) );

    meter.append( 'text' )
          .attr( 'fill', '#fff' )
          .attr( 'x', 0 )
          .attr( 'y', 20 ) 
          .attr( 'text-anchor', 'middle' )
          .attr( 'filter', 'url(#dropshadow)' )
          .text( '%' );


    // Helper functions!!!
    function tweenArcForeground( b ) {
      return function( a ) {
        var i = d3.interpolate( a, b );

        return function( t ) {
          return arcForeground( i ( t ) );
        };
      };
    }

    function tweenArcBackground( b ) {
      return function( a ) {
        var i = d3.interpolate( a, b );

        return function( t ) {
          return arcBackground( i ( t ) );
        };
      };
    }

    function tweenText( b ) {
      return function( a ) {
        var i = d3.interpolateRound( a, b );

        return function(t) {
          this.textContent = i(t);
        };
      }
    }
  }

  function kickoff() {
    visualizeDownloadCircles( '.ui__downloadList__item' );
  }

  // yeah, let's kick things off!!!
  kickoff();
} )( d3 );

0 个答案:

没有答案