d3&骨干 - 解析错误d =“”

时间:2014-03-24 21:06:35

标签: json backbone.js graph d3.js area

我正在尝试使用来自服务器,d3和backbone.js的数据绘制一个简单的区域图表。我收到了错误

  

解析d =“”

时出现问题

每当抽出实际区域路径时。错误出现两次。控制台中的错误如下:

Error: Problem parsing d="" d3.v3.js:585
attrFunction d3.v3.js:585
(anonymous function) d3.v3.js:868
d3_selection_each d3.v3.js:874
d3_selectionPrototype.each d3.v3.js:867
d3_selectionPrototype.attr d3.v3.js:567
GraphBase.extend.renderData backboney.html:242
Backbone.View.extend.render backboney.html:153
(anonymous function) backboney.html:128
fire jquery-2.0.2.js:2939
self.fireWith jquery-2.0.2.js:3051
done jquery-2.0.2.js:7428
(anonymous function)

以下是我正在使用的代码:

<!DOCTYPE html>
<html>
<head>
    <title>BONEZY</title>
     <style>

            body {
                font: .7em sans-serif;
            }

            #graph {
                height: 600px;
                width: 800px;
            }

            /* Styles axes of graph */
            .axis path {
                fill: none;
                stroke: #c9c9c9;
                shape-rendering: crispEdges;
            }

            .axis line {
                fill: none;
                stroke: none;
                shape-rendering: crispEdges;
            }

            /* Fill of graph */
            .area {
                fill: #49decf;
            }

     </style>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<div id="graph"></div>

<script src="jquery-2.0.2.js"></script>
<script type="text/javascript" src="d3.v3.js"></script>
<script type="text/javascript" src="underscore.js"></script>
<script type="text/javascript" src="backbone.js"></script>
<script>
(function ($) {

    var Entry = Backbone.Model.extend({});

    var Entries = Backbone.Collection.extend({
        url: 'http://sensors.metabolic.nl/api/v1/entry/?format=json',
        model: Entry,
        parse: function(response, xhr) {
            // Get objects array from JSON response (actual entries)
            //return response.objects;
            //console.log('Response object value',response.objects[0].value);
            _.each(response.objects, function (object) {
                // Convert each value attribute to an actual array
                object.value = toArray(object.value);
                // Actually fuck it, just extract numerical value and set as value
                // FIX WHEN NEW DATA STRUC EXISTS
                object.value = object.value[1];
            });
            console.log('finished parsing', response.objects);
            return response.objects;
        }
    });

        // Used to convert the shitty sensor value strings to arrays
        function toArray(str) {

            var trimRegEx = /[\'\[\]\s\*C\%]/g;
            var newStr = str.replace(trimRegEx, "");

            var commaIndex = newStr.indexOf(",");      // Index of the comma (divider between values)

            var sensorName = newStr.slice(0, commaIndex);
            var sensorValue = newStr.slice(commaIndex + 1);

            return new Array(sensorName, parseFloat(sensorValue));
        }


    // Base of the graph that we will draw with d3
    // MAD HELPS found at http://jtuulos.github.io/bayd3-may2013/
    var GraphBase = Backbone.View.extend({

        defaults: {
            xAttr: "x",
            yAttr: "y",
            margin: { top: 20, right: 20, bottom: 20, left: 50 }
        },

        initialize: function(options) {

            var self = this;
            // Constructor options no longer automatically copied
            self.options = options;
            self.collection = new Entries();
            _.bindAll(self, 'render');
            //self.collection.on('add', self.render(self.options));

            // Populate collection
            self.collection.fetch({
                data: { /*offset: 20, limit: 20 */},
                add: true,
                reset: true,
                success: function(collection, response) {
                    console.log('Collection fetch success', response);
                    console.log('Collection models: ', collection.models);
                },
                error: function() {
                    console.log('alas, failure');
                }
            }).complete(function() {
                console.log('complete!');
                self.render(self.options);
            });
        },

        render: function(options) {
            console.log('render graph base');

            this.options = options;
            var margin = this.options.margin;
            this.width = this.$el.width() - margin.left - margin.right;
            this.height = this.$el.height() - margin.top - margin.bottom;
            console.log("height", this.height);

            this.svg = d3.select(this.el).append('svg')
                        .attr("width", this.width + margin.left + margin.right)
                        .attr("height", this.height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

            this.scales = {
                x: this.getXScale(),
                y: this.getYScale()
            };

            this.renderAxes();
            this.renderData();

            return this;
        }
    });

    // Extension of GraphBase View, contains everything related to data
    var AreaGraph = GraphBase.extend({

        defaults: _.defaults({
            /*ex barPadding: 0.1 */
        }, GraphBase.prototype.defaults),

        // Calculate and return scale and domain of X axis
        getXScale: function () {
            //console.log('x scale', this.collection.models[1].get('at')/*this.collection.pluck(this.options.at)*/);
            console.log('Get X scale');
            var xAttr = this.options.xAttr;
            return d3.time.scale()
                    .range([0, this.width])
                    //.domain(this.collection.models.pluck(this.options.xAttr));
                    .domain(this.collection.map( function(model) {
                        return model.get(xAttr);
                    }));
        },
        // Calculate and return scale and domain of Y axis
        getYScale: function() {
            console.log('Get Y scale');
            var yAttr = this.options.yAttr;
            return d3.scale.linear()
                    .range([this.height, 0])
                    //.domain([0, 1.2 * d3.max(this.collection.pluck(this.options.yAttr))]);
                    .domain([0, 1.2 * d3.max(this.collection.map(function(model) {
                            return model.get(yAttr);
                        }
                    ))]);
        },

        // Render the X and Y axis
        renderAxes: function() {
            console.log('render axes');

            var xAxis = d3.svg.axis()
                        .scale(this.scales.x)
                        .orient('bottom');

            var yAxis = d3.svg.axis()
                        .scale(this.scales.y)
                        .orient('left');
                        /*.tickFormat(d3.format("") Option to modify ticks on axis*/

            //console.log('svg', this.svg);

            // Adds X axis to graph
            this.svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + this.height + ")")
                .call(xAxis);

            // Adds Y axis to graph (ignore label for now)
            this.svg.append("g")
                .attr("class", "y axis")
                .call(yAxis);

        },

        // Render the actual data for the graph
        renderData: function() {
            console.log('render data');

            var chart = this,
                x = this.scales.x,
                y = this.scales.y;

            // Calculate area under path
            var area = d3.svg.area()
                        .x(function(d) { return x(d.at); })
                        .y0(chart.height)
                        .y1(function(d) { return y(d.value); });

            console.log(this.collection.models);
            this.svg.selectAll("path")
                .data(this.collection.models)
                .attr("class", "area")
                //.attr("d", area);
                .attr("d", function(d) {
                    // Generate area
                    var dArray = new Array();
                    dArray[x] = d.get('at');
                    dArray[y] = d.get('value');
                    //return area(d.attributes);
                    return area(dArray);
                });
        }
    });

    // Graph object (AreaGraph inherits GraphBase)
    var graph = new AreaGraph({

        // Backbone view options
        el: '#graph',
        // These are the data attributes to be read to determine values
        xAttr: "at",
        yAttr: "value",
        margin: { top: 20, right: 20, bottom: 20, left: 50 }

    });

})(jQuery);

</script>
</body>
</html>

非常感谢任何见解!

1 个答案:

答案 0 :(得分:0)

如果你把你的代码放到jsFiddle中会更容易调试,但是一个明显的错误:

.attr("d", function(d) {
    // Generate area
    var dArray = new Array();
    dArray[x] = d.get('at');
    dArray[y] = d.get('value');
    //return area(d.attributes);
    return area(dArray);
 });

这段代码对我来说没有任何意义。你的x,y是比例,而不是数组索引。这意味着路径的“d”属性将变为垃圾(即,d =“”)。您应该使用注释掉的代码:

.attr("d", area);

绘制您的区域并确保数据数组中的每个元素都具有“.at”和“.value”属性。