自动截断长类别轴标签,但在图例中显示完整标签?

时间:2017-10-26 11:37:28

标签: javascript amcharts

我正在使用amchart作为图表。以下是代码,

var chart = AmCharts.makeChart("chartdiv", {
    "theme": "light",
    "type": "serial",
    "startDuration": 2,
    "dataProvider": [{
        "country": "This is Sample Data with long label",
        "visits": 4025,
        "color": "#FF0F00"
    }, {
        "country": "This is Sample Data with long label1",
        "visits": 1882,
        "color": "#FF6600"
    }, {
        "country": "This is Sample Data with long label2",
        "visits": 1809,
        "color": "#FF9E01"
    }, {
        "country": "This is Sample Data with long label3",
        "visits": 1322,
        "color": "#FCD202"
    }, {
        "country": "This is Sample Data with long label4",
        "visits": 1122,
        "color": "#F8FF01"
    }, {
        "country": "This is Sample Data with long label5",
        "visits": 1114,
        "color": "#B0DE09"
    }, {
        "country": "This is Sample Data with long label6",
        "visits": 984,
        "color": "#04D215"
    }, {
        "country": "This is Sample Data with long label7",
        "visits": 711,
        "color": "#0D8ECF"
    }, {
        "country": "This is Sample Data with long label8",
        "visits": 665,
        "color": "#0D52D1"
    }, {
        "country": "This is Sample Data with long label9",
        "visits": 580,
        "color": "#2A0CD0"
    }, {
        "country": "This is Sample Data with long label10",
        "visits": 443,
        "color": "#8A0CCF"
    }, {
        "country": "This is Sample Data with long label11",
        "visits": 441,
        "color": "#CD0D74"
    }, {
        "country": "This is Sample Data with long label12",
        "visits": 395,
        "color": "#754DEB"
    }, {
        "country": "This is Sample Data with long label13",
        "visits": 386,
        "color": "#DDDDDD"
    }, {
        "country": "This is Sample Data with long label14",
        "visits": 338,
        "color": "#333333"
    }],
    "valueAxes": [{
        "position": "left",
        "axisAlpha":0,
        "gridAlpha":0
    }],
    "graphs": [{
        "balloonText": "[[category]]: <b>[[value]]</b>",
        "colorField": "color",
        "fillAlphas": 0.85,
        "lineAlpha": 0.1,
        "type": "column",
        "topRadius":1,
        "valueField": "visits"
    }],
    "depth3D": 40,
    "angle": 30,
    "chartCursor": {
        "categoryBalloonEnabled": false,
        "cursorAlpha": 0,
        "zoomable": false
    },
    "categoryField": "country",
    "categoryAxis": {
        "gridPosition": "start",
        "axisAlpha":0,
        "gridAlpha":0

    },
  "labelFunction": function(label, item, axis) {
      var chart = axis.chart;
      if ( (chart.realWidth <= 300 ) && ( label.length > 5 ) )
        return label.substr(0, 5) + '...';
      if ( (chart.realWidth <= 500 ) && ( label.length > 10 ) )
        return label.substr(0, 10) + '...';
      return label;
    },
  "legend": {
    "useGraphSettings": true
  },
    "export": {
        "enabled": true
     }

}, 0);

然而,Xaxis标签非常冗长,我想自动截断长类别轴标签,如this example,并启用图例。但启用图例并不起作用,自动截断似乎也不起作用。有人可以帮帮我吗?提前谢谢。

这是codepen [1]的链接。

[1] https://codepen.io/gknathkumar/pen/OxKGev

3 个答案:

答案 0 :(得分:2)

如下所示制作labelFunction

"labelFunction": function(label, item, axis) {

        var chart = axis.chart;
         console.log("CHART:", chart.realWidth, label.length, label );
          if ( ( label.length > 5 ) ){
            console.log("CHARTLABEL:", label.substr(0, 5) + '...');
            return label.substr(0, 7) + '...';            
          }
          if ( ( label.length > 10 ) ){
            return label.substr(0, 10) + '...';
          }
          return label;
        },

您的代码无效,因为您必须将标签功能放在categoryAxis

最终工作解决方案:https://codepen.io/anon/pen/aLerBZ?editors=0010

答案 1 :(得分:2)

您的代码中存在一些小错误:

  • labelFunction不在categoryAxis
  • 图表的大小永远不会低于500px,因此标签永远不会像示例中那样进行修剪
  • 可以将一些代码放入变量中以便于调试

我已将某些代码分开,并为标签添加了最大长度(15个字符),与图表宽度无关

View the full example on Codepen

// keep the data object separate from the call
var dataProvider = [
  {
    country: "This is Sample Data with long label",
    visits: 4025,
    color: "#FF0F00"
  },
  {
    country: "This is Sample Data with long label1",
    visits: 1882,
    color: "#FF6600"
  },
  {
    country: "This is Sample Data with long label2",
    visits: 1809,
    color: "#FF9E01"
  },
  {
    country: "This is Sample Data with long label3",
    visits: 1322,
    color: "#FCD202"
  }
];

var chart = AmCharts.makeChart(
  "chartdiv",
  {
    theme: "light",
    type: "serial",
    startDuration: 2,
    dataProvider: dataProvider,
    valueAxes: [
      {
        position: "left",
        axisAlpha: 0,
        gridAlpha: 0
      }
    ],
    graphs: [
      {
        balloonText: "[[category]]: <b>[[value]]</b>",
        colorField: "color",
        fillAlphas: 0.85,
        lineAlpha: 0.1,
        type: "column",
        topRadius: 1,
        valueField: "visits"
      }
    ],
    depth3D: 40,
    angle: 30,
    chartCursor: {
      categoryBalloonEnabled: false,
      cursorAlpha: 0,
      zoomable: false
    },
    categoryField: "country",
    categoryAxis: {
      gridPosition: "start",
      axisAlpha: 0,
      gridAlpha: 0,
      labelFunction: trimLabel,
    },
    legend: {
      useGraphSettings: true
    },
    export: {
      enabled: true
    }
  },
  0
);

// function to trim the labels
function trimLabel(label, item, axis) {
  var chartWidth = axis.chart.realWidth;
  var maxLabelLength = 15; // not counting the dots...

  // trim when the width of the chart is smalled than 300px
  if (chartWidth <= 300 && label.length > 5)
    return label.substr(0, 5) + "...";

  // trim when the width of the chart is smalled than 500px
  if (chartWidth <= 500 && label.length > 10)
    return label.substr(0, 10) + "...";

  // trim when label is longer than maxLabelLength regardless of chart width
  return label.length >= 15 ? label.substr(0, 14) + "...": label;
}

答案 2 :(得分:2)

正如其他人所说,labelFunction是categoryAxis的一部分,所以它需要进入那里。我对kuzyn实现中的方法不感兴趣,但选择你想要的方法。

对于图例,它是由图形对象按设计生成的。由于有一个图形对象,因此只有一个标记。为每列添加标记需要添加自定义代码,以修改图例的data数组以生成自定义标记。 AmCharts有一个knowledge base article for generating markers for each column。相关代码如下:

/*
  Plugin to generate legend markers based on category
  and fillColor/lineColor/color field from the chart data by using 
  the legend's custom data array. Also allows for toggling markers
  by completely removing/adding columns from the chart

  The plugin assumes there is  only one graph object. 
*/
AmCharts.addInitHandler(function(chart) { 

  //method to handle removing/adding columns when the marker is toggled
  function handleCustomMarkerToggle(legendEvent) {
      var dataProvider = legendEvent.chart.dataProvider;
      var itemIndex; //store the location of the removed item

      //Set a custom flag so that the dataUpdated event doesn't fire infinitely, in case you have
      //a dataUpdated event of your own
      legendEvent.chart.toggleLegend = true; 
      // The following toggles the markers on and off.
      // The only way to "hide" a column and reserved space on the axis is to remove it
      // completely from the dataProvider. You'll want to use the hidden flag as a means
      // to store/retrieve the object as needed and then sort it back to its original location
      // on the chart using the dataIdx property in the init handler
      if (undefined !== legendEvent.dataItem.hidden && legendEvent.dataItem.hidden) {
        legendEvent.dataItem.hidden = false;
        dataProvider.push(legendEvent.dataItem.storedObj);
        legendEvent.dataItem.storedObj = undefined;
        //re-sort the array by dataIdx so it comes back in the right order.
        dataProvider.sort(function(lhs, rhs) {
          return lhs.dataIdx - rhs.dataIdx;
        });
      } else {
        // toggle the marker off
        legendEvent.dataItem.hidden = true;
        //get the index of the data item from the data provider, using the 
        //dataIdx property.
        for (var i = 0; i < dataProvider.length; ++i) { 
          if (dataProvider[i].dataIdx === legendEvent.dataItem.dataIdx) {
            itemIndex = i;
            break;
          }
        }
        //store the object into the dataItem
        legendEvent.dataItem.storedObj = dataProvider[itemIndex];
        //remove it
        dataProvider.splice(itemIndex, 1);
      }
      legendEvent.chart.validateData(); //redraw the chart
  }

  //check if legend is enabled and custom generateFromData property
  //is set before running
  if (!chart.legend || !chart.legend.enabled || !chart.legend.generateFromData) {
    return;
  }

  var categoryField = chart.categoryField;
  var colorField = chart.graphs[0].lineColorField || chart.graphs[0].fillColorsField || chart.graphs[0].colorField;
  var legendData =  chart.dataProvider.map(function(data, idx) {
    var markerData = {
      "title": data[categoryField] + ": " + data[chart.graphs[0].valueField], 
      "color": data[colorField],
      "dataIdx": idx //store a copy of the index of where this appears in the dataProvider array for ease of removal/re-insertion
    };
    if (!markerData.color) {
      markerData.color = chart.graphs[0].lineColor;
    }
    data.dataIdx = idx; //also store it in the dataProvider object itself
    return markerData;
  });

  chart.legend.data = legendData;

  //make the markers toggleable
  chart.legend.switchable = true;
  chart.legend.addListener("clickMarker", handleCustomMarkerToggle);

}, ["serial"]);

此插件要求您在图例中将自定义generateFromData标记设置为true,而其他内容(useGraphSettings不兼容):

  "legend": { 
    "generateFromData": true //custom property for the plugin
  },

这是一个利用kuzyn的trim方法和上述插件的演示:

/*
  Plugin to generate legend markers based on category
  and fillColor/lineColor/color field from the chart data by using 
  the legend's custom data array. Also allows for toggling markers
  by completely removing/adding columns from the chart
  
  The plugin assumes there is  only one graph object. 
*/
AmCharts.addInitHandler(function(chart) { 
  
  //method to handle removing/adding columns when the marker is toggled
  function handleCustomMarkerToggle(legendEvent) {
      var dataProvider = legendEvent.chart.dataProvider;
      var itemIndex; //store the location of the removed item

      //Set a custom flag so that the dataUpdated event doesn't fire infinitely, in case you have
      //a dataUpdated event of your own
      legendEvent.chart.toggleLegend = true; 
      // The following toggles the markers on and off.
      // The only way to "hide" a column and reserved space on the axis is to remove it
      // completely from the dataProvider. You'll want to use the hidden flag as a means
      // to store/retrieve the object as needed and then sort it back to its original location
      // on the chart using the dataIdx property in the init handler
      if (undefined !== legendEvent.dataItem.hidden && legendEvent.dataItem.hidden) {
        legendEvent.dataItem.hidden = false;
        dataProvider.push(legendEvent.dataItem.storedObj);
        legendEvent.dataItem.storedObj = undefined;
        //re-sort the array by dataIdx so it comes back in the right order.
        dataProvider.sort(function(lhs, rhs) {
          return lhs.dataIdx - rhs.dataIdx;
        });
      } else {
        // toggle the marker off
        legendEvent.dataItem.hidden = true;
        //get the index of the data item from the data provider, using the 
        //dataIdx property.
        for (var i = 0; i < dataProvider.length; ++i) { 
          if (dataProvider[i].dataIdx === legendEvent.dataItem.dataIdx) {
            itemIndex = i;
            break;
          }
        }
        //store the object into the dataItem
        legendEvent.dataItem.storedObj = dataProvider[itemIndex];
        //remove it
        dataProvider.splice(itemIndex, 1);
      }
      legendEvent.chart.validateData(); //redraw the chart
  }

  //check if legend is enabled and custom generateFromData property
  //is set before running
  if (!chart.legend || !chart.legend.enabled || !chart.legend.generateFromData) {
    return;
  }
  
  var categoryField = chart.categoryField;
  var colorField = chart.graphs[0].lineColorField || chart.graphs[0].fillColorsField || chart.graphs[0].colorField;
  var legendData =  chart.dataProvider.map(function(data, idx) {
    var markerData = {
      "title": data[categoryField] + ": " + data[chart.graphs[0].valueField], 
      "color": data[colorField],
      "dataIdx": idx //store a copy of the index of where this appears in the dataProvider array for ease of removal/re-insertion
    };
    if (!markerData.color) {
      markerData.color = chart.graphs[0].lineColor;
    }
    data.dataIdx = idx; //also store it in the dataProvider object itself
    return markerData;
  });
  
  chart.legend.data = legendData;
  
  //make the markers toggleable
  chart.legend.switchable = true;
  chart.legend.addListener("clickMarker", handleCustomMarkerToggle);
  
}, ["serial"]);


// keep the data object separate from the call
var dataProvider = [
  {
    country: "This is Sample Data with long label",
    visits: 4025,
    color: "#FF0F00"
  },
  {
    country: "This is Sample Data with long label1",
    visits: 1882,
    color: "#FF6600"
  },
  {
    country: "This is Sample Data with long label2",
    visits: 1809,
    color: "#FF9E01"
  },
  {
    country: "This is Sample Data with long label3",
    visits: 1322,
    color: "#FCD202"
  }
];

var chart = AmCharts.makeChart(
  "chartdiv",
  {
    theme: "light",
    type: "serial",
    startDuration: 2,
    dataProvider: dataProvider,
    valueAxes: [
      {
        position: "left",
        axisAlpha: 0,
        gridAlpha: 0
      }
    ],
    graphs: [
      {
        balloonText: "[[category]]: <b>[[value]]</b>",
        colorField: "color",
        fillAlphas: 0.85,
        lineAlpha: 0.1,
        type: "column",
        topRadius: 1,
        valueField: "visits"
      }
    ],
    depth3D: 40,
    angle: 30,
    chartCursor: {
      categoryBalloonEnabled: false,
      cursorAlpha: 0,
      zoomable: false
    },
    categoryField: "country",
    categoryAxis: {
      gridPosition: "start",
      axisAlpha: 0,
      gridAlpha: 0,
      labelFunction: trimLabel,
    },
    legend: { 
      generateFromData: true //custom property for the plugin
    },
    export: {
      enabled: true
    }
  },
  0
);

// function to trim the labels
function trimLabel(label, item, axis) {
  var chartWidth = axis.chart.realWidth;
  var maxLabelLength = 15; // not counting the dots...

  // trim when the width of the chart is smalled than 300px
  if (chartWidth <= 300 && label.length > 5)
    return label.substr(0, 5) + "...";

  // trim when the width of the chart is smalled than 500px
  if (chartWidth <= 500 && label.length > 10)
    return label.substr(0, 10) + "...";

  // trim when label is longer than maxLabelLength regardless of chart width
  return label.length >= 15 ? label.substr(0, 14) + "...": label;
}
#chartdiv {
  width: 990px;
  height: 365px;
  border-radius: 3px;
  margin: 0px;
  border: 1px dotted #728FCE;
}
<script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="https://www.amcharts.com/lib/3/serial.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
<link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" />
<script src="https://www.amcharts.com/lib/3/themes/light.js"></script>
<input type="button" value="Set width to 300px" onclick="document.getElementById('chartdiv').style.width='300px';" />
<input type="button" value="Set width to 500px" onclick="document.getElementById('chartdiv').style.width='500px';" />
<input type="button" value="Set width to 700px" onclick="document.getElementById('chartdiv').style.width='700px';" />
<div id="chartdiv"></div>

请注意,如果您希望修剪标记上的标签,则还必须在initHandler中创建标记标题时调用trim。