流畅响应的线条图

时间:2018-10-15 19:54:26

标签: javascript jquery responsive linechart

我正在尝试弄清楚如何使jquery.peity.js库中的折线图响应灵敏。这是我目前拥有的完整代码:

                (function ($, document, Math, undefined) {
                  var peity = $.fn.peity = function (type, options) {
                    if (svgSupported) {
                      this.each(function () {
                        var $this = $(this)
                        var chart = $this.data('_peity')

                        if (chart) {
                          if (type) chart.type = type
                          $.extend(chart.opts, options)
                        } else {
                          chart = new Peity(
                            $this,
                            type,
                            $.extend({},
                              peity.defaults[type],
                              $this.data('peity'),
                              options)
                          )

                          $this
                            .change(function () {
                              chart.draw()
                            })
                            .data('_peity', chart)
                        }

                        chart.draw()
                      });
                    }

                    return this;
                  };

                  var Peity = function ($el, type, opts) {
                    this.$el = $el
                    this.type = type
                    this.opts = opts
                  }

                  var PeityPrototype = Peity.prototype

                  var svgElement = PeityPrototype.svgElement = function (tag, attrs) {
                    return $(
                      document.createElementNS('http://www.w3.org/2000/svg', tag)
                    ).attr(attrs)
                  }

                  // https://gist.github.com/madrobby/3201472
                  var svgSupported = 'createElementNS' in document && svgElement('svg', {})[0].createSVGRect

                  PeityPrototype.draw = function () {
                    var opts = this.opts
                    peity.graphers[this.type].call(this, opts)
                    if (opts.after) opts.after.call(this, opts)
                  }

                  PeityPrototype.fill = function () {
                    var fill = this.opts.fill

                    return $.isFunction(fill) ?
                      fill :
                      function (_, i) {
                        return fill[i % fill.length]
                      }
                  }

                  PeityPrototype.prepare = function (width, height) {
                    if (!this.$svg) {
                      this.$el.hide().after(
                        this.$svg = svgElement('svg', {
                          "class": "peity"
                        })
                      )
                    }

                    return this.$svg
                      .empty()
                      .data('_peity', this)
                      .attr({
                        height: height,
                        width: width
                      })
                  }

                  PeityPrototype.values = function () {
                    return $.map(this.$el.text().split(this.opts.delimiter), function (value) {
                      return parseFloat(value)
                    })
                  }

                  peity.defaults = {}
                  peity.graphers = {}

                  peity.register = function (type, defaults, grapher) {
                    this.defaults[type] = defaults
                    this.graphers[type] = grapher
                  }

                  peity.register(
                    'pie', {
                      fill: ['#ff9900', '#fff4dd', '#ffc66e'],
                      radius: 8
                    },
                    function (opts) {
                      if (!opts.delimiter) {
                        var delimiter = this.$el.text().match(/[^0-9\.]/)
                        opts.delimiter = delimiter ? delimiter[0] : ","
                      }

                      var values = $.map(this.values(), function (n) {
                        return n > 0 ? n : 0
                      })

                      if (opts.delimiter == "/") {
                        var v1 = values[0]
                        var v2 = values[1]
                        values = [v1, Math.max(0, v2 - v1)]
                      }

                      var i = 0
                      var length = values.length
                      var sum = 0

                      for (; i < length; i++) {
                        sum += values[i]
                      }

                      if (!sum) {
                        length = 2
                        sum = 1
                        values = [0, 1]
                      }

                      var diameter = opts.radius * 2

                      var $svg = this.prepare(
                        opts.width || diameter,
                        opts.height || diameter
                      )

                      var width = $svg.width(),
                        height = $svg.height(),
                        cx = width / 2,
                        cy = height / 2

                      var radius = Math.min(cx, cy),
                        innerRadius = opts.innerRadius

                      if (this.type == 'donut' && !innerRadius) {
                        innerRadius = radius * 0.5
                      }

                      var pi = Math.PI
                      var fill = this.fill()

                      var scale = this.scale = function (value, radius) {
                        var radians = value / sum * pi * 2 - pi / 2

                        return [
                          radius * Math.cos(radians) + cx,
                          radius * Math.sin(radians) + cy
                        ]
                      }

                      var cumulative = 0

                      for (i = 0; i < length; i++) {
                        var value = values[i],
                          portion = value / sum,
                          $node

                        if (portion == 0) continue

                        if (portion == 1) {
                          if (innerRadius) {
                            var x2 = cx - 0.01,
                              y1 = cy - radius,
                              y2 = cy - innerRadius

                            $node = svgElement('path', {
                              d: [
                                'M', cx, y1,
                                'A', radius, radius, 0, 1, 1, x2, y1,
                                'L', x2, y2,
                                'A', innerRadius, innerRadius, 0, 1, 0, cx, y2
                              ].join(' '),
                              'data-value': value,
                            })
                          } else {
                            $node = svgElement('circle', {
                              cx: cx,
                              cy: cy,
                              'data-value': value,
                              r: radius
                            })
                          }
                        } else {
                          var cumulativePlusValue = cumulative + value

                          var d = ['M'].concat(
                            scale(cumulative, radius),
                            'A', radius, radius, 0, portion > 0.5 ? 1 : 0, 1,
                            scale(cumulativePlusValue, radius),
                            'L'
                          )

                          if (innerRadius) {
                            d = d.concat(
                              scale(cumulativePlusValue, innerRadius),
                              'A', innerRadius, innerRadius, 0, portion > 0.5 ? 1 : 0, 0,
                              scale(cumulative, innerRadius)
                            )
                          } else {
                            d.push(cx, cy)
                          }

                          cumulative += value

                          $node = svgElement('path', {
                            d: d.join(" "),
                            'data-value': value,
                          })
                        }

                        $node.attr('fill', fill.call(this, value, i, values))

                        $svg.append($node)
                      }
                    }
                  )

                  peity.register(
                    'donut',
                    $.extend(true, {}, peity.defaults.pie),
                    function (opts) {
                      peity.graphers.pie.call(this, opts)
                    }
                  )

                  var graphContainerWidth = $("#cardholdersLi").resize().width()
                  var graphContainerHeight = $(".peity-line-height").resize().height();

                  peity.register(
                    "line", {
                      delimiter: ",",
                      fill: "#c6d9fd",
                      height: graphContainerHeight,
                      min: 0,
                      stroke: "#3D6DC7",
                      strokeWidth: 1.5,
                      width: graphContainerWidth
                    },
                    function (opts) {
                      var values = this.values()
                      if (values.length == 1) values.push(values[0])
                      var max = Math.max.apply(Math, opts.max == undefined ? values : values.concat(opts.max)),
                        min = Math.min.apply(Math, opts.min == undefined ? values : values.concat(opts.min))

                      var $svg = this.prepare(opts.width, opts.height),
                        strokeWidth = opts.strokeWidth,
                        width = $svg.width(),
                        height = $svg.height() - strokeWidth,
                        diff = max - min

                      var xScale = this.x = function (input) {
                        return input * (width / (values.length - 1))
                      }

                      var yScale = this.y = function (input) {
                        var y = height

                        if (diff) {
                          y -= ((input - min) / diff) * height
                        }

                        return y + strokeWidth / 2
                      }

                      var zero = yScale(Math.max(min, 0)),
                        coords = [0, zero]

                      for (var i = 0; i < values.length; i++) {
                        coords.push(
                          xScale(i),
                          yScale(values[i])
                        )
                      }

                      coords.push(width, zero)

                      if (opts.fill) {
                        $svg.append(
                          svgElement('polygon', {
                            fill: opts.fill,
                            points: coords.join(' ')
                          })
                        )
                      }

                      if (strokeWidth) {
                        $svg.append(
                          svgElement('polyline', {
                            fill: 'none',
                            points: coords.slice(2, coords.length - 2).join(' '),
                            stroke: opts.stroke,
                            'stroke-width': strokeWidth,
                            'stroke-linecap': 'square'
                          })
                        )
                      }
                    }
                  );

                  peity.register(
                    'bar', {
                      delimiter: ",",
                      fill: ["#4D89F9"],
                      height: 16,
                      min: 0,
                      padding: 0.1,
                      width: 32
                    },
                    function (opts) {
                      var values = this.values(),
                        max = Math.max.apply(Math, opts.max == undefined ? values : values.concat(opts.max)),
                        min = Math.min.apply(Math, opts.min == undefined ? values : values.concat(opts.min))

                      var $svg = this.prepare(opts.width, opts.height),
                        width = $svg.width(),
                        height = $svg.height(),
                        diff = max - min,
                        padding = opts.padding,
                        fill = this.fill()

                      var xScale = this.x = function (input) {
                        return input * width / values.length
                      }

                      var yScale = this.y = function (input) {
                        return height - (
                          diff ?
                          ((input - min) / diff) * height :
                          1
                        )
                      }

                      for (var i = 0; i < values.length; i++) {
                        var x = xScale(i + padding),
                          w = xScale(i + 1 - padding) - x,
                          value = values[i],
                          valueY = yScale(value),
                          y1 = valueY,
                          y2 = valueY,
                          h

                        if (!diff) {
                          h = 1
                        } else if (value < 0) {
                          y1 = yScale(Math.min(max, 0))
                        } else {
                          y2 = yScale(Math.max(min, 0))
                        }

                        h = y2 - y1

                        if (h == 0) {
                          h = 1
                          if (max > 0 && diff) y1--
                        }

                        $svg.append(
                          svgElement('rect', {
                            'data-value': value,
                            fill: fill.call(this, value, i, values),
                            x: x,
                            y: y1,
                            width: w,
                            height: h
                          })
                        )
                      }
                    }
                  );
                })(jQuery, document, Math);

                function myFunction() {
                  var w = window.outerWidth;
                  var h = window.outerHeight;
                  var txt = "Window size: width=" + w + ", height=" + h;
                  document.getElementById("demo").innerHTML = txt;
                }

我要解决的唯一问题是“行”的“ peity.register”部分。我将变量添加到宽度和高度,并将其与SVG的容器元素匹配,但仍然没有运气。这是上面的代码,仅缩减至所需的部分:

            var graphContainerWidth = $("#testId").resize().width()
            var graphContainerHeight = $(".peity-line-height").resize().height();

            peity.register(
                "line", {
                delimiter: ",",
                fill: "#c6d9fd",
                height: graphContainerHeight,
                min: 0,
                stroke: "#3D6DC7",
                strokeWidth: 1.5,
                width: graphContainerWidth
                },
                function (opts) {
                var values = this.values()
                if (values.length == 1) values.push(values[0])
                var max = Math.max.apply(Math, opts.max == undefined ? values : values.concat(opts.max)),
                    min = Math.min.apply(Math, opts.min == undefined ? values : values.concat(opts.min))

                var $svg = this.prepare(opts.width, opts.height),
                    strokeWidth = opts.strokeWidth,
                    width = $svg.width(),
                    height = $svg.height() - strokeWidth,
                    diff = max - min

                var xScale = this.x = function (input) {
                    return input * (width / (values.length - 1))
                }

                var yScale = this.y = function (input) {
                    var y = height

                    if (diff) {
                    y -= ((input - min) / diff) * height
                    }

                    return y + strokeWidth / 2
                }

                var zero = yScale(Math.max(min, 0)),
                    coords = [0, zero]

                for (var i = 0; i < values.length; i++) {
                    coords.push(
                    xScale(i),
                    yScale(values[i])
                    )
                }

                coords.push(width, zero)

                if (opts.fill) {
                    $svg.append(
                    svgElement('polygon', {
                        fill: opts.fill,
                        points: coords.join(' ')
                    })
                    )
                }

                if (strokeWidth) {
                    $svg.append(
                    svgElement('polyline', {
                        fill: 'none',
                        points: coords.slice(2, coords.length - 2).join(' '),
                        stroke: opts.stroke,
                        'stroke-width': strokeWidth,
                        'stroke-linecap': 'square'
                    })
                    )
                }
                }
            );

在此DIV的span标记内正在生成以下折线图:

            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12" style="padding: 0;">
                <div style="padding: 0;" class="stat-boxes partnerDashboardBoxes fade-in-slow-2">
                    <a id="cardholdersCTA" data-toggle="tab" href="#desktopCardholders" data-target="#desktopCardholders, #cardholdersCBSA" onClick="cardholderAggregateDetails('${pageContext.request.contextPath}');">
                        <div id="cardholdersLi" class="col-xs-10 col-xs-offset-1 well well-lg cta-box well-hover cta-hover fade-in-slow-2">
                            <!-- SELECTED -->
                            <ul id="cta-header-links" style=" padding: 0; font-size: 14px; width: 100%;">
                                <li title="Display aggregate cardholder details in the table located below." class="stat-boxes" style="float: left; text-align: left; font-weight: bold;">
                                    <a style="margin: 0; padding: 0;">Cardholders</a>
                                </li>
                                <li title="Display aggregate cardholder details in the table located below." class="stat-boxes" style="text-align: center;">
                                    <a class="text-hidden" style="margin: 0; padding: 0;">Orders</a>
                                </li>
                                <li title="Display aggregate cardholder details in the table located below." class="stat-boxes" style="float: right; text-align: right;">
                                    <a class="text-hidden" style="margin: 0; padding: 0;">Transactions</a>
                                </li>
                            </ul>
                            <tr>
                                <div id="testId" class="left peity-line-style peity-line-height" title="Blue equals total cardholders enrolled and red equals total cardholders registered per day.">
                                    <span id="cardholder-span-enrolled"  class="peity-line fade-in-slow-2" data-height="500" data-width="500" data-fill='["#ADD8E6"]'>&nbsp;</span>
                                    <span id="cardholder-span" class="peity-line fade-in-slow-2" data-peity='{ "fill": false, "stroke": "red"}'>&nbsp;</span>
                                </div>
                            </tr>
                            <tr>
                                <div id="total-cardholders" class="stat-boxes" title="Total cardholders enrolled." style="font-weight: bold; float: left; margin: 5px 0 5px 18px; font-size: 14px;">&nbsp;</div>
                            </tr>
                        </div>
                    </a>
                </div>
            </div>

为提供帮助,这里有一些直观的文档,可以使您更好地了解上面列出的所有代码的直观表示形式。这是页面加载时将浏览器设置为400px左右的完整元素:

Browser set to 400px on page load.

调整浏览器大小时,除Peity折线图外,每个元素都会正确缩放和调整大小。这是同一元素,现在的大小约为480px:

Browser resized to 480px.

再举一个例子,这是与“页面加载”外观相同的元素,浏览器的缩放比例约为768px:

Browser set to 768 on page load.

...同样,当我将浏览器缩放到900px的宽度时,相同的元素及其外观:

Browser resized to 900px.

这是正确的道路,但还不完全正确。我一直在努力使如何使用jQuery调整大小功能有意义,但是没有运气:

"jQuery Resize"

$( window ).resize(function() {
});

请让我知道您的想法以及是否有解决方案。我将不胜感激。

侧面注意:请忽略内联样式标签。这是一个在制品,将被清理并归类或根据ID重新调整。

0 个答案:

没有答案