如何在散点图 google 图表上绘制自定义多边形?

How to draw a custom polygon over a Scatter Series google chart?

我有一个带有一组点的散点系列,就像这里显示的那样。 https://developers.google.com/chart/interactive/docs/gallery/scatterchart

点被分组,每组以不同的颜色显示。我想在每个组(凸包)周围绘制一个多边形。看起来没有一种直接的方法可以将每个具有 n 个边界点的多边形添加到图表中。

如果你有找到边界点的算法,
您可以使用 ComboChart 绘制散点图和线系列...
使用选项 seriesType 设置默认类型
使用选项 series 自定义特定系列的类型

在以下工作片段中,
使用的算法来自 --> Convex Hull | Set 1 (Jarvis’s Algorithm or Wrapping)
(从 Java 版本转换而来)

google.charts.load('current', {
  packages: ['corechart']
}).then(function () {
  var groupA = [
    [0,3],[2,3],[1,1],[2,1],[3,0],[0,0],[3,3],[2,2]
  ];

  var groupB = [
    [11,11],[12,12],[12,10],[12,14],[13,13],[14,12],[15,12],[16,12]
  ];

  var data = new google.visualization.DataTable();
  data.addColumn('number', 'x');
  data.addColumn('number', 'y');
  data.addRows(groupA);
  data.addRows(groupB);

  addGroup('A', data, groupA)
  addGroup('B', data, groupB)

  var options = {
    chartArea: {
      bottom: 48,
      height: '100%',
      left: 36,
      right: 24,
      top: 36,
      width: '100%'
    },
    height: '100%',
    seriesType: 'line',
    series: {
      0: {
        type: 'scatter'
      }
    },
    width: '100%'
  };

  var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));

  drawChart();
  window.addEventListener('resize', drawChart, false);

  function drawChart() {
    chart.draw(data, options);
  }

  function addGroup(group, dataTable, points) {
    var polygon = convexHull(points);
    var colIndex = dataTable.addColumn('number', group);
    for (var i = 0; i < polygon.length; i++) {
      var rowIndex = dataTable.addRow();
      dataTable.setValue(rowIndex, 0, polygon[i][0]);
      dataTable.setValue(rowIndex, colIndex, polygon[i][1]);
    }
  }

  function orientation(p, q, r) {
    var val = (q[1] - p[1]) * (r[0] - q[0]) -
              (q[0] - p[0]) * (r[1] - q[1]);

    if (val == 0) {
      return 0;  // collinear
    } else if (val > 0) {
      return 1;  // clock wise
    } else {
      return 2;  // counterclock wise
    }
  }

  function convexHull(points) {
    // must be at least 3 rows
    if (points.length < 3) {
      return;
    }

    // init
    var l = 0;
    var p = l;
    var q;
    var hull = [];

    // find leftmost point
    for (var i = 1; i < points.length; i++) {
      if (points[i][0] < points[l][0]) {
        l = i;
      }
    }

    // move counterclockwise until start is reached
    do {
      // add current point to result
      hull.push(points[p]);

      // check orientation (p, x, q) of each point
      q = (p + 1) % points.length;
      for (var i = 0; i < points.length; i++) {
        if (orientation(points[p], points[i], points[q]) === 2) {
          q = i;
        }
      }

      // set p as q for next iteration
      p = q;
    } while (p !== l);

    // add back first hull point to complete line
    hull.push(hull[0]);

    // set return value
    return hull;
  }
});
html, body, #chart_div {
  height: 100%;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>