【问题标题】:Adding legends to selfmade barchart为自制条形图添加图例
【发布时间】:2016-09-12 21:50:19
【问题描述】:

我知道您可能想知道自制的条形图?为什么不是现有的图书馆?好吧,我讨厌使用包含 20000 行代码的文件,而只需要 500 行。

哦,这很有趣 :) 主要目标是我将把这个脚本用于我将使用 Phonegap 制作的应用程序。所以尺寸越小越好。

所以我们的想法是实现以下目标:

我已经能够绘制条形图,确保它们的宽度相等,并且它们的高度取决于父容器的高度。正如您将在下面的代码中看到的那样,我还在选项中添加了字体大小。由于某些图表将扩展大约 300 像素的高度(例如,将使用默认的 16 像素)。有些只有 50 像素,字体大小为 12 或更小。所以我将条形图容器减少了 3 倍的字体大小(+ 剩余),以确保顶部(数量)和底部(图例 + 标题)有足够的空间

现在我不完全确定如何添加和居中金额。我尝试搜索现有的图表库以检查它是如何呈现的,不幸的是它们都使用画布或 SVG 容器。有什么建议吗?

/* dataset
   ------------------

   add legends
   add result / amount
   add bottom-border: 8px extra to both sides?
   add chart name

 */

(function ($) {

    var methods = {
        init : function(options) {
            return this.each(function() {

                var $this = $(this),
                    dataset = options.dataset,
                    fontSize = options.fontSize,
                    widthOfContainer = $this.width(),
                    heightOfContainer = $this.height() - (3 * (fontSize + 4)), // make room for title (bottom), legend (bottom), amounts (top)
                    widthOfBar = parseInt(widthOfContainer / options.dataset.length) - 2,
                    bar;

                $this.bind('draw', function(e) {
                    $this.empty();

                    var maxValueInDataset = Math.max.apply(Math, dataset.map(function(o){return o.a;})),
                        heightPerUnit = parseInt(heightOfContainer / maxValueInDataset);
                    for (var i = 0; i < dataset.length; i++) {
                        bar = $(document.createElement('div'));
                        bar.addClass('bar');
                        bar.css({
                            'height': parseInt(dataset[i].a * heightPerUnit) + 'px',
                            'width': parseInt(widthOfBar) + 'px',
                            'margin-left': parseInt(i * 2 + i * widthOfBar) + 'px',
                            'bottom': 2 * (fontSize + 4)
                        });
                        $this.append(bar);
                    }
                });

                $this.trigger('draw');
            });
        },
        draw : function(n) {
            $(this).trigger('draw');
        }
    };

    $.fn.chart = function(methodOrOptions) {
        if ( methods[methodOrOptions] ) {
            return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
            // Default to "init"
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.tooltip' );
        }
    };

    $(document).ready(function(){
        $('div.barchart').chart({
            // Add font-size?
            fontSize: 14,
            name: 'mana cost',
            dataset: [
                {a: 2, label: '0'},
                {a: 8, label: '1'},
                {a: 9, label: '2'},
                {a: 4, label: '3'},
                {a: 7, label: '4'},
                {a: 3, label: '5'},
                {a: 1, label: '6'},
                {a: 1, label: '7'},
                {a: 2, label: '8'},
                {a: 5, label: '9'}
            ]
        });
    });
}( jQuery ));
/* Barchart
   ========================================================================== */

.barchart {
  color: black;
}

/* Bar
   ========================================================================== */

.bar {
  position: absolute;
  height: 0px;
  width: 0px;
  margin-left: 0px;
  bottom: 0px;
  background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="padding: 20px;">
            <div class="barchart" style="height: 100px; position: relative"></div>
        </div>

【问题讨论】:

    标签: javascript jquery css jquery-plugins


    【解决方案1】:

    图表不错!它看起来很干净。我明白你的意思。我花了几个月的时间试图操纵 bxSlider 的布局,然后我意识到自己编写的代码更少。这是回答您的查询的尝试。我通过使用百分比使其宽度响应(不用担心;很容易改回来),为图例、值和计数添加了一个额外的 css 类,并修改了你的插件以包含你的名称选项(称为图例) .然后这些位被格式化和附加。希望这可以帮助。

    /* dataset
       ------------------
    
       add legends
       add result / amount
       add bottom-border: 8px extra to both sides?
       add chart name
    
     */
    
    (function ($) {
    
        var methods = {
            init : function(options) {
                return this.each(function() {
    
                    var $this = $(this),
                        dataset = options.dataset,
                        fontSize = options.fontSize,
                        legend = options.name,
                        widthOfContainer = $this.width(),
                        heightOfContainer = $this.height() - (3 * (fontSize + 4)), // make room for title (bottom), legend (bottom), amounts (top)
                        widthOfBar = parseInt(widthOfContainer / options.dataset.length) - 2,
                        widthOfBarPer = (widthOfBar / widthOfContainer) *100,
                        bar;
    
                    $this.bind('draw', function(e) {
                        $this.empty();
    
                        var maxValueInDataset = Math.max.apply(Math, dataset.map(function(o){return o.a;})),
                            heightPerUnit = parseInt(heightOfContainer / maxValueInDataset);
                        for (var i = 0; i < dataset.length; i++) {
                        		var dataVal = dataset[i].a;
                            bar = $(document.createElement('div'));
                            bar.addClass('bar');
                            bar.css({
                                'height': parseInt( dataVal * heightPerUnit) + 'px',
                                'width': widthOfBarPer + '%', // percentages to make more responsive?
                                'margin-left': (i + i * widthOfBarPer ) + '%', // no need to parseInt as you have already on widthOfBar. now your chart stretches with the width .
                                'bottom': 2 * (fontSize + 4)
                            });
                            bar.append('<p class="count">'+ i +'</p>');	// defines the bar count, this could be dataset[i].label but if you just use i then you don't need to type it out for each bar?
                            bar.append('<p class="value">'+ dataVal +'</p>');	// defines the bar value
                            $this.append(bar); // adds the bar count
                        }
                        var chartHeight = $this.height();
                        $('.bar .count').css({ bottom: fontSize - chartHeight * 0.5 });
                        $('.bar .value').css({ bottom: chartHeight * 0.5 - fontSize });
                        if(legend){
    												legend = '<p class="legend">'+legend+'</p>';
    											  $this.append(legend);
                      //      $this.css({ border: '1px solid #f90'}); // temp to see the current chart size
                            $this.find('.legend').css({ top: chartHeight - fontSize });
                        }
                    });
    
                    $this.trigger('draw');
                });
            },
            draw : function(n) {
                $(this).trigger('draw');
            }
        };
    
        $.fn.chart = function(methodOrOptions) {
            if ( methods[methodOrOptions] ) {
                return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
            } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
                // Default to "init"
                return methods.init.apply( this, arguments );
            } else {
                $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.tooltip' );
            }
        };
    
        $(document).ready(function(){
            $('div.barchart').chart({
                // Add font-size?
                fontSize: 14,
                name: 'mana cost',
                dataset: [
                    {a: 2, label: '0'},
                    {a: 8, label: '1'},
                    {a: 9, label: '2'},
                    {a: 4, label: '3'},
                    {a: 7, label: '4'},
                    {a: 3, label: '5'},
                    {a: 1, label: '6'},
                    {a: 1, label: '7'},
                    {a: 2, label: '8'},
                    {a: 5, label: '9'}
                ]
            });
        });
    }( jQuery ));
    /* Barchart
       ========================================================================== */
    
    .barchart {
      color: black;
    }
    
    /* Bar
       ========================================================================== */
    
    .bar {
      position: absolute;
      height: 0px;
      width: 0px;
      margin-left: 0px;
      bottom: 0px;
      background: black;
    }
    
    .count, .value{
      z-index: 7;
      position: absolute;
      text-align: center;
      width: 100%;
    }
    
    .legend{
      position: relative;
      text-align: center;
      width: 100%;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div style="padding: 20px;">
                <div class="barchart" style="height: 100px; position: relative"></div>
            </div>

    【讨论】:

      【解决方案2】:

      为避免不必要的代码量竖起大拇指——干净的条形图是不需要庞大库的完美示例。

      如果您使用&lt;table&gt; 作为创建条形图的基本结构,您可以轻松访问所需的格式选项,从而减少代码:

      • 值一行,标签一行
      • 可以通过设置每个值单元格的 border-bottom 样式来制作条形
      • 文本可以在表格单元格中居中
      • 为图例添加&lt;caption&gt;,默认居中,并通过caption-side 属性轻松定位在表格下方
      • 对值单元格的vertical-align 属性进行样式设置允许将值直接定位在条形上方(如下面的演示所示)或排列在顶部(如您的插图所示)——这在 js 的第 20 行中进行控制演示代码如下。

      毕竟,条形图只是表格数据的可视化,所以使用表格是有意义的。

      一个工作演示(大约 30 行 vanilla js 和几行 css,如果需要,您可以轻松适应您的 jquery 方法):

      function barchart(containerId, options) {
        var i, 
            html,
            valueRow = '', 
            labelRow = '',
            data = options.dataset,
            maxBarHeight = 60, /* in px, could be set from options */
            barWidth = 20,     /* in px, could be set from options */
            maxValue = Math.max.apply(
              Math,
              data.map(function(o) {
                return o.a;
              })
            );
        for(i = 0; i < data.length; i++){
          labelRow += '<td>' + data[i].label + '</td>';
          valueRow += '<td style="border-bottom:' +
              (data[i].a * maxBarHeight / maxValue) +
              'px solid black;vertical-align:' +
              'bottom' + /* set to 'top' to get value labels lined up */
              ';width: ' +
              barWidth + 'px">' +
              data[i].a + '</td>';
        }
        html = '<table class="barchart" ' + 
          'style="font-size:' + options.fontSize + 'px">' +
          '<caption>' + options.name + '</caption>' + 
          '<tr>' + valueRow + '</tr>' + 
          '<tr>' + labelRow + '</tr>' + 
          '</table>';
        document.getElementById(containerId)
          .innerHTML = html;
      }
      
      /* create a barchart */
      
      barchart('testdiv', {
        fontSize: 14,
        name: 'mana cost',
        dataset: [
          {a: 2, label: '0'},
          {a: 8, label: '1'},
          {a: 9, label: '2'},
          {a: 4, label: '3'},
          {a: 7, label: '4'},
          {a: 3, label: '5'},
          {a: 1, label: '6'},
          {a: 1, label: '7'},
          {a: 2, label: '8'},
          {a: 5, label: '9'}
        ]
      });
      .barchart td{
        text-align: center;
      }
      
      .barchart{
        font-family: 'arial narrow', sans-serif;
        caption-side: bottom;
      }
      &lt;div id="testdiv"&gt;&lt;/div&gt;

      【讨论】:

      • 这个答案也不错!谢谢,会看看。
      猜你喜欢
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-27
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 2020-11-05
      相关资源
      最近更新 更多