zoukankan      html  css  js  c++  java
  • d3js 折线图+柱图

     

    <!DOCTYPE html>
    <html>
    <body>
    <div id="vis"><svg></svg></div>
    <div id="text"></div>
    
    <style>
      div.CCMixed-tooltip {
        border-radius: 5px;
        visibility:hidden;
        background: rgba(255,255,255,0.9);
        position: absolute;
        padding: 8px;
        box-shadow: 0px 0px 5px #888888;
        font-family: Arial, serif;
        font-size: 12px;
        color: #777;
      }
    
      .CCMixed-axis, .legend {
        font-family: Arial, serif;
        font-size: 12px;
        fill: #777;
      }
    
      .CCMixed-axis path,
      .CCMixed-axis line {
        fill: none;
        stroke: #DDD;
        stroke-width: 2;
      }
    </style>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script>
    
      var CCMixedChart = {}; 
    
      CCMixedChart.draw = function(elem, config){
        var colorFunction = config.colorFunction;
    
        var canvas = d3.select("#" + elem);
        canvas.select("svg").selectAll("*").remove();
        var margin = {top: 20, right: 40, bottom: 40, left: 50};
        var width = +config.width - margin.left - margin.right;
        var height = +config.height - margin.top - margin.bottom - config.addtionalXAxisSpace;
    
        var svg = canvas.select("svg")
          .attr("width", config.width)
          .attr("height", config.height + config.addtionalXAxisSpace)
          .append("g").attr("class", "canvas")
          .attr("transform", "translate(" +  margin.left + "," + margin.top + ")");
    
        // draw legends
        if(config.showLegend){
          height = height - drawLegends() * 20 - 10;
        }
    
        var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.5).domain(config.xAxis);
        var yLeftMax = 0;
        var yRightMax = 0;
        for(var i=0; i<config.series.length; i++){
          config.series[i].visible = true;
          for(var j=0; j<config.series[i].data.length; j++){
            if(config.series[i].yAxis == "left" && yLeftMax < config.series[i].data[j]){
              yLeftMax = config.series[i].data[j];
            }
            if(config.series[i].yAxis == "right" && yRightMax < config.series[i].data[j]){
              yRightMax = config.series[i].data[j];
            }
          }
        }
    
        var yLeft = d3.scale.linear().range([height, 0]).domain([0, yLeftMax]);
        var yRight = d3.scale.linear().range([height, 0]).domain([0, yRightMax]);
    
        // draw xAxis
        drawXAxis(x);
    
        // draw left yAxis
        drawYAxis(yLeft, "left", config.yAxisLeft);
        drawYAxis(yRight, "right", config.yAxisRight);
    
        // draw charts
        for(var i=0; i<config.series.length; i++){
          var chart = config.series[i];
          if(chart.type == 'bar'){
            drawBarChart(chart);
          } else if(chart.type == 'line'){
            drawLineChart(chart)
          }
        }
    
        // draw tooltip
        var tooltip = canvas.append("div").attr("class", "CCMixed-tooltip");
    
        // draw invisible bars for hover/click events
        svg.append("g").attr("class", "bars bars-action").selectAll(".bar-hover")
          .data(config.xAxis)
          .enter().append("rect")
            .attr("class", "bar-hover")
            .attr("x", function(d) { return x(d)-x.rangeBand()/2; })
            .attr("y", 0)
            .attr("width", x.rangeBand()*2)
            .attr("height", height)
            .style("opacity", "0")
            .style("fill", "gold")
            .style("cursor", "pointer")
            .on("mouseover", function(d, i){mouseOver(this, d.replace(/ /g, '_'), i)})
            .on("mouseout", function(d, i){mouseOut(this, d.replace(/ /g, '_'), i)})
            .on("mousemove", function(){updateTooltipPos(d3.event)})
            .on("click", function(d, i){
              if(config.clickFunction){
                config.clickFunction(config, d, i);
              }
              // stop the propagation of event
              d3.event.stopPropagation();
            });
    
        function drawLegends(){
          var legend = svg.append("g").attr("class", "legends CCMixed-legend");
      
          var lx = 0;
          var ly = 0;
          var rows = 1;
          
          for(var i=0; i<config.series.length; i++){
            var chart = config.series[i];
            if(chart.type == 'bar'){
              drawBarLegend(chart);
            } else if(chart.type == 'line'){
              drawLineLegend(chart)
            }
          }
    
          var tx = 0;
          if(rows == 1){
            tx = (width - lx) / 2;
          }
          legend.attr("transform", "translate(" + tx + ", "+ (config.height+config.addtionalXAxisSpace-(rows+1)*20) + ")");
    
          function drawBarLegend(chart){
            var barLegend = legend.append("g")
              .attr("class", "legend legend-"+chart.label.replace(/ /g, '_'))
              .style("cursor", "pointer")
              .attr("transform", getLegendTransfrom(chart))
              .style("fill", colorFunction(chart.colorKey));
            barLegend.append("rect")
              .attr("x",  0)
              .attr("y",  0)
              .attr("width", 12)
              .attr("height", 12);
            barLegend.append("text")
              .attr("x",  10)
              .attr("y",  0)
              .attr("dy", "0.85em")
              .attr("dx", "0.4em")
              .style("text-anchor", "begin")
              .text(chart.label);
            barLegend.on("mouseover", function(){
              svg.select(".bars-"+chart.label.replace(/ /g, '_')).selectAll(".bar")
                .style("stroke","gold").style("stroke-width", 3);
            }).on("mouseout", function(){
              svg.select(".bars-"+chart.label.replace(/ /g, '_')).selectAll(".bar")
                .style("stroke-width", 0);
            }).on("click", function(){
              toggleVisibility(chart);
            });
          }
    
          function drawLineLegend(chart){
            var lineLegend = legend.append("g")
              .attr("class", "legend legend-"+chart.label.replace(/ /g, '_'))
              .style("cursor", "pointer")
              .style("fill", colorFunction(chart.colorKey))
              .attr("transform", getLegendTransfrom(chart));
            lineLegend.append("circle")
              .attr("r", 4)
              .attr("cx", 6)
              .attr("cy", 6)
            lineLegend.append("line")
              .attr("x1", 0)
              .attr("y1", 6)
              .attr("x2", 12)
              .attr("y2", 6)
              .style("stroke", colorFunction(chart.colorKey))
              .style("stroke-width", 2)
            lineLegend.append("text")
              .attr("x",   10)
              .attr("y",  0)
              .attr("dy", "0.85em")
              .attr("dx", "0.4em")
              .style("text-anchor", "begin")
              .text(chart.label)
            lineLegend.on("mouseover", function(d){
              svg.select(".line-"+chart.label.replace(/ /g, '_'))
                .style("stroke-width", 4);
              svg.select(".circles-"+chart.label.replace(/ /g, '_')).selectAll(".circle")
                .attr("r", 6).style("stroke","gold").style("stroke-width", 2);
            }).on("mouseout", function(d){
              svg.select(".line-"+chart.label.replace(/ /g, '_'))
                .style("stroke-width", 2);
              svg.select(".circles-"+chart.label.replace(/ /g, '_')).selectAll(".circle")
                .attr("r", 4).style("stroke-width", 0);
            }).on("click", function(){
              toggleVisibility(chart);
            });
          }
    
          function toggleVisibility (chart){
            if(chart.type == "bar"){
              var elem = svg.select(".bars-"+chart.label.replace(/ /g, '_'));
              toggle(elem, chart);
            } else if(chart.type == "line"){
              var elem = svg.select(".line-"+chart.label.replace(/ /g, '_'));
              toggle(elem, chart);
              elem = svg.select(".circles-"+chart.label.replace(/ /g, '_'));
              toggle(elem, chart);
            }
    
            var showLeft = false;
            var showRight = false;
            for(var i=0; i<config.series.length; i++){
              if(config.series[i].yAxis == "left" && config.series[i].visible){
                showLeft = true;
              }
              if(config.series[i].yAxis == "right" && config.series[i].visible){
                showRight = true;
              }
            }
    
            if(showLeft){
              svg.select(".axis-left").selectAll(".tick").select("text").style("visibility", "visible");
              svg.select(".axis-left").select(".title").style("visibility", "visible");
            } else {
              svg.select(".axis-left").selectAll(".tick").select("text").style("visibility", "hidden");
              svg.select(".axis-left").select(".title").style("visibility", "hidden");
            }
    
            if(showRight){
              svg.select(".axis-right").selectAll(".tick").select("text").style("visibility", "visible");
              svg.select(".axis-right").select(".title").style("visibility", "visible");
            } else {
              svg.select(".axis-right").selectAll(".tick").select("text").style("visibility", "hidden");
              svg.select(".axis-right").select(".title").style("visibility", "hidden");
            }
            
            function toggle(elem, chart){
              if(elem.style("visibility") == "visible"){
                elem.style("visibility", "hidden");
                chart.visible = false;
                var legend = svg.select(".legends").select(".legend-"+chart.label.replace(/ /g, '_')).style("fill", "#777");
                if(chart.type == "line"){
                  legend.select("line").style("stroke", "#777");
                }
              } else {
                elem.style("visibility", "visible");
                chart.visible = true;
                var legend = svg.select(".legends").select(".legend-"+chart.label.replace(/ /g, '_')).style("fill", colorFunction(chart.colorKey));
                if(chart.type == "line"){
                  legend.select("line").style("stroke", colorFunction(chart.colorKey));
                }
              }
            }  
          };
    
          function getLegendTransfrom(chart){
            var translate = "translate(" +  lx + "," + ly + ")";
            lx = lx + chart.label.length * 5 + 30;
            if(chart.type == "line"){
              lx = lx + 15;
            } else if(chart.type == "bar"){
              lx = lx - 10;
            }
            if(lx + chart.label.length * 5  >= width){
              lx = 0;
              ly = ly + 20;
              rows = rows + 1;
            }
            return translate;
          }
    
          return rows;
        }
    
        function drawBarChart(chart){
          var yScale = yLeft;
          if(chart.yAxis == "right"){
            yScale = yRight;
          }
    
          svg.append("g")
            .attr("class", function(d, i){return "bars bars-"+chart.label.replace(/ /g, '_');})
          .selectAll(".bar")
            .data(chart.data)
            .enter().append("rect")
              .attr("class", function(d, i){return "bar bar-"+config.xAxis[i].replace(/ /g, '_');})
              .attr("x", function(d, i) { return x(config.xAxis[i]); })
              .attr("y", function(d) { return yScale(d); })
              .attr("width", x.rangeBand())
              .attr("height", function(d) { return height - yScale(d); })
              .style("fill", colorFunction(chart.colorKey));
        }
    
        function drawLineChart(chart){
          var yScale = yLeft;
          if(chart.yAxis == "right"){
            yScale = yRight;
          }
    
          var line = d3.svg.line()
            .x(function(d, i) {
              return x(config.xAxis[i]) + x.rangeBand()/2;
            })
            .y(function(d) {
              return yScale(d);
            });
    
          svg.append("g").append("path")
            .style("stroke", colorFunction(chart.colorKey))
            .attr("class", function(d, i){return "line-"+chart.label.replace(/ /g, '_');})
            .style("stroke-width", 2)
            .style("fill", "none")
            .attr("d", line(chart.data));
    
          svg.append("g")
            .attr("class", function(d, i){return "circles circles-"+chart.label.replace(/ /g, '_');})
          .selectAll(".circle")
            .data(chart.data)
            .enter().append("circle")
            .attr("class", function(d, i){return "circle circle-"+config.xAxis[i].replace(/ /g, '_');})
            .attr("r", 4)
            .style("fill", colorFunction(chart.colorKey))
            .attr("cx", function(d, i){return x(config.xAxis[i]) + x.rangeBand()/2;})
            .attr("cy", function(d){return yScale(d);});
    
        }
    
        function mouseOver(elem, d, i){
          d3.select(elem).style("opacity", "0.3");
          svg.select(".axis-x").select(".axis-"+d).style("font-weight","bold").style("font-size","14px");
          svg.selectAll(".circles").select(".circle-"+d).attr("r", 7).style("stroke","gold").style("stroke-width",2);
          svg.selectAll(".bars").select(".bar-"+d).style("stroke","gold").style("stroke-width", 2);
    
          var html;
          if(config.tooltipFunction){
            html = config.tooltipFunction(config, d, i);
          } else {
            html = getTooltips(d, i);
          }
    
          tooltip.html(html).style("visibility", "visible");
          
          function getTooltips(d, i){
            var html = d + "<br/>";
            for(var j=0; j<config.series.length; j++){
              html = html + "<b>" + config.series[j].label + "</b>: " + config.series[j].data[i] + "<br/>";
            }
            return html;
          }
        };
    
        function mouseOut(elem, d, i){
          d3.select(elem).style("opacity", "0");
          svg.select(".axis-x").select(".axis-"+d).style("font-weight","normal").style("font-size","12px");
          svg.selectAll(".circles").select(".circle-"+d).attr("r", 4).style("stroke-width",0);
          svg.selectAll(".bars").select(".bar-"+d).style("stroke-width",0);
          tooltip.style("visibility", "hidden");
        }
    
        function updateTooltipPos (e){
          tooltip.style("top", (e.pageY + 15) + "px")
            .style("left", (e.pageX + 15) + "px");
        };
    
        function drawXAxis(x){
          // draw x
          svg.append("g")
            .attr("class", "CCMixed-axis axis-x")
            .attr("transform", "translate(0," + height + ")")
            .call(customXAxis)
          .selectAll("text")
            .data(config.xAxis)
            .attr("class", function(d, i){return "axis-"+config.xAxis[i].replace(/ /g, '_');})
            .style("text-anchor", "end")
            .attr("dy", "0.3em")
            .attr("dx", "-0.7em")
            .attr("transform", "rotate(-45)")
            .text(function(d, i){
              // skip one if too many ticks
              //alert(config.xAxis.length);
              if(config.xAxis.length >= 10 && i % 2 == 1){
                return "";
              } else {
                return d
              }
            });
          function customXAxis(g) {
            var xAxis = d3.svg.axis()
              .scale(x)
              .orient("bottom");
            g.call(xAxis);
            g.select(".domain").remove();
          }
        }
    
        function drawYAxis(y, orient, setting){
          var axisY = svg.append("g")
            .attr("class", "CCMixed-axis axis-"+orient)
            .style("fill", colorFunction(setting.colorKey))
            .call(customYAxis)
          if(orient == 'right'){
            axisY.attr("transform", "translate(" + width + ", 0)")
          }
          if(setting.title){
            var axisYLabel = axisY.append("text")
              .text(setting.title)
              .attr("class", "title")
            if(orient == "left"){
              axisYLabel.attr("transform", "rotate(-90)")
                .attr("y", -30)
                .attr("x", -1*height/2)
                .attr("dx", setting.title.length * 0.25 + "em")
                .style("text-anchor", "end")
            } else {
              axisYLabel.attr("transform", "rotate(90)")
              .attr("y", -30)
              .attr("x", height/2)
              .attr("dx", -1 * setting.title.length * 0.25 + "em")
              .style("text-anchor", "begin")
            }
          }
    
          function customYAxis(g) {
            var yAxis = d3.svg.axis()
              .scale(y)
              .orient(orient)
              .tickSize(orient=="left"? -1*width : 0)
              .ticks(config.yAxisTicks);
            g.call(yAxis);
            g.select(".domain").remove();
            g.selectAll(".tick:not(:first-of-type) line").attr("stroke", "#030303");
          }
        }
      };
    
      var colorFunction1 = function(key){
        return key;
      }
    
      var clickFunction1 = function(config, d, i){
        var html = d + "<br/>";
        for(var j=0; j<config.series.length; j++){
          html = html + "<b>" + config.series[j].label + "</b>: " + config.series[j].data[i] + "<br/>";
        }
        $("#text").html(html);
      }
    
      $(document).ready(function(){
        var vis = $("#vis");
    
        var config = {
          "addtionalXAxisSpace": 0,  // OPTIONAL. if the labels for xAxis is too long can add more space between xAxis and legend
          "width": 600, // width of canvas
          "height": 400, // height of canvas
          "showLegend": true, // OPTIONAL.
          "colorFunction": colorFunction1,  // color function, accept a key and return a color, can use d3.scale.category20()
          "clickFunction": clickFunction1,  // OPTIONAL. handles click event when clicking a day
          //"tooltipFunction": tooltipFunction  // OPTIONAL. if not provided default function will be used
          "xAxis": ["1-Jul", "2-Jul", "3-Jul", "4-Jul", "5-Jul"],
          "xAxisData": [1, 2, 3, 4, 5],  // OPTIONAL. can store additional data to be used by the click event. e.g. xAxis is the date string but xAxisData is the timestamp
          "yAxisTicks": 5, // number of horizontal lines
          "yAxisLeft": {  // config the left y axis, MUST if any series need to use this axis
            "title": "Number of Non-responding Nodes",
            "colorKey": "cornflowerblue"
          },
          "yAxisRight": { // config the right y axis, MUST if any series need to use this axis
            "title": "Percentage (%)",
            "colorKey": "yellowgreen"
          },
          "series":[  // array of chart config. one element correspond to one chart. bar charts are NOT stacked and will OVERLAP
            {
              "colorKey": " cornflowerblue",
              "type": "bar",  // chart type - bar or line
              "data": [10, 20, 50, 100, 30],
              "yAxis": "left",   // associate the chart to left or right axis 
              "label": "label 1"  // used in legends and tooltips
            },
            {
              "colorKey": "yellowgreen",
              "type": "line",
              "data": [10, 20, 50, 100, 30],
              "yAxis": "right",
              "label": "label 2"
            },
            {
              "colorKey": "yellow",
              "type": "line",
              "data": [30, 24, 64, 40, 39],
              "yAxis": "right",
              "label": "label 3"
            }
          ]
        };
    
        CCMixedChart.draw("vis", config);
      });
    
    
    </script>
    </body>
    </html>
  • 相关阅读:
    游标、锁
    树形背包浅谈
    金字塔
    Codeforces Round #652 (Div. 2) 题解
    NOI1999 棋盘分割
    NEERC2002 Folding
    HDU4283 You Are the One
    Codeforces Round #646 (Div. 2) 题解
    洛谷 P1679 神奇的四次方数
    UVA12563 劲歌金曲
  • 原文地址:https://www.cnblogs.com/songfei90/p/11648493.html
Copyright © 2011-2022 走看看