d3.js——對柱狀圖和折線圖的封裝


一、js調用app

稍後加上dom

二、封裝的jssvg

function DrawChart(option) {
    //若是沒有參數,則返回
    if (!option) {
        return;
    }
    if (!option.data || !option.containerId || !option.chartSize || !option.serials || !option.xAxis) {
        return;
    }
    var dataset = option.data;
    //if (dataset.length < 2) {
    //    return;
    //}

    var serials = option.serials;
    if (serials.length == 0) {
        return;
    }

    //設置圖表的區域大小
    var margin = { top: 30, right: 40, bottom: 80, left: 50 };
    if (option.margin) {
        margin = option.margin;
    }
    var chartSize = option.chartSize;
    var w = chartSize.x - margin.left - margin.right;
    var h = chartSize.y - margin.top - margin.bottom;
    var legendSize = 20;
    var legendDistance = 40 + margin.top;


    //X軸處理
    //----------x軸數據範圍
    var xFactor = option.xAxis.xFactor;
    var i;
    var xRange = [];
    for (i = 0; i < dataset.length; i++) {
        xRange.push(xFactor(dataset[i]));
    }

    //----------x軸處理
    var tickCount = option.xAxis.tickCount ? option.xAxis.tickCount : 5;
    var xScale; //x軸尺度變換
    var xAxis; //X軸刻度
    var tickInterval = option.xAxis.allTick ? 1 : Math.round(xRange.length / tickCount); //刻度間距(時間刻度用)
    var rangeBand = w * 0.8 / dataset.length;
    switch (option.xAxis.type) {
        case "ordinal":
            //x軸的序數尺度變換
     
            switch (option.chartType) {
                case "bar":
                         xScale = d3.scale.ordinal()
                                      .domain(xRange)
                                      .rangeRoundBands([0, w], 0.1); //設置值域
                    break;
                    
                case "line":
                    xScale = d3.scale.ordinal()
                                 .domain(xRange)
                                 .rangePoints([0, w], 1);
                    break;
                default:
               
                    break;
            }
          
            xAxis = d3.svg.axis()
             .scale(xScale)  //設置x軸的尺度變換
             .orient("bottom").ticks(tickCount); //設置座標軸刻度方向
            
            break;
        case "number":
            break;
        case "date":
            xScale = d3.time.scale()
                .domain(d3.extent(xRange, function (d) { return d; }))
                .rangeRound([0, w]);

            //定義x軸 
            xAxis = d3.svg.axis()
                .scale(xScale)  //設置x軸的尺度變換
                .orient("bottom") //設置座標軸刻度方向
                .ticks(d3.time.day, tickInterval)
                .tickFormat(d3.time.format(option.xAxis.format));
            break;
    }

    //Y軸處理
    //---------y軸最小值
    var yMin = d3.min(dataset, function (d) {
        if (serials.length == 1) {
            return serials[0].yFactor(d);
        } else {
            var minValue = serials[0].yFactor(d);
            for (var j = 0; j < serials.length; j++) {
                var value = serials[j].yFactor(d);
                minValue = (minValue < value ? minValue : value);
            }
            return minValue;
        }
    });
    //---------y軸最大值
    var yMax = d3.max(dataset, function (d) {
        if (serials.length == 1) {
            return serials[0].yFactor(d);
        } else {
            var maxValue = serials[0].yFactor(d);
            for (var j = 0; j < serials.length; j++) {
                var value = serials[j].yFactor(d);
                maxValue = (maxValue > value ? maxValue : value);
            }
            return maxValue;
        }
    });

    var hasZeroY = false;
    switch(option.chartType) {
        case "bar":
            if (yMax >= 0 && yMin <= 0) {
                hasZeroY = true;
            } else if (yMax < 0) {
                yMax = 0;
                hasZeroY = false;
            } else if (yMin > 0) {
                yMin = 0;
                hasZeroY = false;
            }
                
            break;
        default:
            break;
            
    }
    //-----------上下增長5%,
  
    var rangeExtent = (yMax - yMin) * 0.05;
    if (yMin >= 0) {
        yMax = yMax + rangeExtent;
        yMin = yMin <= rangeExtent ? 0 : yMin - rangeExtent;
    } else if (yMax <= 0) {
        yMax = Math.abs(yMax) <= rangeExtent ? 0 : yMax + rangeExtent;
        yMin = yMin - rangeExtent;
    } else {
        yMax = yMax + rangeExtent;
        yMin = yMin - rangeExtent;
    }


    //-----------y軸尺度變換
    var yScale = d3.scale.linear()
        .domain([yMin, yMax]) //設置定義域爲【0,最大值】
        .range([h, 0]); //設置值域
    //-----------定義y軸  
    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left")
        .ticks(5); //設置最多有5個刻度

    //畫圖形
    var container = d3.select("#" + option.containerId);
    container.select("svg").remove();

    //Create SVG element
    var chart = container//選中DOM中的目標元素
        .append("svg")//爲目標元素附加上一個svg子元素
        .attr("width", w + margin.left + margin.right)//設置這個svg的寬
        .attr("height", h + margin.top + margin.bottom)//設置這個svg的高
       // .append("g")
      //  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
        .attr("style", "padding:20px;");

    var svg = chart.append("g")
       // .attr("width", w)
       // .attr("height", h)
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    //-----------畫標題
    //給圖表添加一個標題
    chart.append("text")
        .attr("x", (w / 2))
        .attr("y", 0)
        .attr("text-anchor", "middle")
        .attr("class", option.title.cls)
        .text(option.title.text);

    //-----------畫X軸
    //Create X axis  
    svg.append("g")
        .attr("class", "xAxis")
        .attr("transform", "translate(0," + h + ")")//設置距下邊界的距離  
        .call(xAxis)
        .selectAll("text").style("text-anchor", "end").attr("dx", "-.8em").attr("dy", ".15em").attr("transform", "rotate(-45)");

    //-----------畫Y軸
    //Create Y axis  
    svg.append("g")
        .attr("class", "yAxis")
        .attr("transform", "translate(0,0)")//設置軸距左邊界的距離
        .call(yAxis);
    
    switch(option.chartType) {
        case "bar":
            if (hasZeroY) {
                svg.append("g")
                    .attr("class", "xAxis")
                    .append("line")
                    .attr("y1", yScale(0))
                    .attr("y2", yScale(0))
                    .attr("x1", 0)
                    .attr("x2", w);
            }
            break;
        default:
            break;
    }

    
    //-----------畫序列
    var k, serial;
    for (k = 0; k < serials.length; k++) {
        serial = serials[k];
        var yFactor = serial.yFactor;
        
        var dataFormat = ",n";
        if (serial.dataFormat) {
            dataFormat = serial.dataFormat;
        }
        var d3Format = d3.format(dataFormat);
        
        switch (option.chartType) {
            case "line":

                //爲SVG添加折線
                var line = d3.svg.line()
                    // .interpolate("linear")
                    .x(function (d) {
                        return xScale(xFactor(d));
                    })
                    .y(function (d) {
                        return yScale(yFactor(d));
                    });

                svg.append("path")
                    .datum(dataset)
                    .attr("class", serial.g.pathCls)
                    .attr("d", line);

                //折線添加 圖標
                svg.selectAll(".circle")
                    .data(dataset)
                    .enter()
                    .append("circle")
                    .attr("cx", function (d) {
                        return xScale(xFactor(d));
                    })
                    .attr("cy", function (d) {
                        return yScale(yFactor(d));
                    })
                    .attr("r", 3)
                    .append("title")
                    .text(function (d) {
                        return serial.tip.replace("{0}", d3Format(yFactor(d)));//d3Format(yFactor(d))
                    });
                break;
                
            case "bar":
                //爲SVG添加條形
                svg.selectAll(".bar")
                    .data(dataset)
                    .enter().append("rect")
                    .attr("class", function (d) { return yFactor(d) < 0 ? "bar negative" : "bar positive"; })
                    .attr("x", function (d) { return xScale(xFactor(d)); })
                    .attr("width", rangeBand)
                    .attr("y", function (d) { return yScale(Math.max(yFactor(d), 0)); })
                    .attr("height", function (d) { return Math.abs(yScale(yFactor(d)) - yScale(0)); })
                    .append("title")
                    .text(function (d) {
                        return serial.tip.replace("{0}", d3Format(yFactor(d)));
                    });
                break;
        }
        

    }

    //-----------畫圖例
    var legendCount = serials.length;
    for (k = 0; k < serials.length; k++) {
        serial = serials[k];
        var legend = serial.legend;
        if (legend) {
            chart.append("rect")
                .attr("x", w * (k + 1) / (legendCount + 1))
                .attr("y", h + legendDistance)
                .attr("width", legendSize)
                .attr("height", legendSize)
                .attr("class", legend.cls);

            chart.append("text")
                .attr("x", w * (k + 1) / (legendCount + 1) + legendSize)
                .attr("y", h + legendDistance + 15)
                .style("font-size", "14px")
                .text(legend.text);
        }
    }
}
相關文章
相關標籤/搜索