javascript - 动态垂直轴可容纳 Google 折线图中的趋势线

标签 javascript linechart google-visualization trendline

我是编码新手,但在过去的几个月里,我设法摸索着创建了一个网站,该网站利用 Google 折线图和嵌入式线性趋势线来显示历史平均海平面和平均海平面率新西兰和太平洋地区各地的水位上升。每个位置都有自己的 Google 折线图,其中包含线性趋势线,以显示用户所选期间的平均海平面变化率。我现在想要扩展每个 Google 折线图的功能,使线性趋势线和多项式趋势线都延伸到 2120 年(它们目前只显示到 2018 年),即使计算它们的可用数据使用观测到的数据到 2018 年。这将允许用户预测到 2020 年的海平面高度。我意识到这个解释可能会令人困惑,所以请访问我的网站 www.sealevel.nz 查看现有的图表,我希望这些图表能够帮助理解我的问题。

下面是图表的扩展版本的代码,它显示了线性和二次多项式趋势线,其中 Google 折线图的 x 轴现在显示 2120 年。我的问题是我需要 y 轴无论用户选择哪个时间段,动态调整以显示两条趋势线的整体。例如,如果您从日期范围 slider 中选择 1971 年和 2018 年,则两条趋势线将分别在 2017 年(线性)和 2031 年(多项式)处截止。我需要能够看到截至 2120 年的趋势线及其值。

请原谅我的新手编码能力。我的代码:

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://unpkg.com/mathjs/dist/math.min.js"></script>
<script type="text/javascript">

google.load('visualization', 'current', {'packages':['controls','corechart']});
google.setOnLoadCallback(initialize);
function initialize() {
  var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1vn1iuhsG33XzFrC4QwkTdUnxOGdcPQOj-cuaEZeX-eA/edit#gid=0');
  query.send(drawDashboard);
}
function drawDashboard(response) {
  var data = response.getDataTable();
//Asign units of 'mm' to data.
    var formatMS = new google.visualization.NumberFormat({
    pattern: '# mm'
  });
  // format into data mm..
  for (var colIndex = 1; colIndex < data.getNumberOfColumns(); colIndex++) {
    formatMS.format(data, colIndex);
  }
 var YearPicker = new google.visualization.ControlWrapper({
    'controlType': 'NumberRangeFilter',
    'containerId': 'filter_div',
    'options': {
      'filterColumnLabel': 'Year',
        'ui': {
       cssClass: 'filter-date',
          'format': { pattern: '0000' },
      'labelStacking': 'vertical',
      'allowTyping': false,
      'allowMultiple': false    
      }
    },
  });
  var MSLChart = new google.visualization.ChartWrapper({
    'chartType': 'LineChart',
    'containerId': 'chart_div',
    'options': {  
    'fontSize': '14', 
    'title': 'Timbucktoo Annual Mean Sea Level Summary',
        hAxis: {title: 'Year', format:'0000', maxValue: 2120},
        vAxis: {title: 'Height above Chart Datum (mm)', format:'0000'},
        'height': 600,
    chartArea: {height: '81%', width: '85%', left: 100},
    'legend': {'position': 'in', 'alignment':'end', textStyle: {fontSize: 13} },
    colors: ['blue'],
    trendlines: {
            0: {
                type: 'polynomial',
                degree: 2,
                color: 'green',
                visibleInLegend: true,
            },
            1: {
                type: 'linear',
                color: 'black',
                visibleInLegend: true,
            },
        },
        series: {
            0: { visibleInLegend: true },
            1: { visibleInLegend: false },
        },    
    },
    'view': {'columns': [0,1,2]}
  });

  var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div')).
    bind(YearPicker, MSLChart).

  draw(data)
 </script>

最佳答案

首先,我不知道为什么图表会画一条不可见的趋势线
这使得这有点棘手,因为我们首先必须绘制图表,
为了找到最小和最大 y 轴值。

但是有图表methods我们可以用它来找到最大值。

首先,我们得到图表的布局界面。

var chartLayout = MSLChart.getChart().getChartLayoutInterface();

由于我们使用的是 ChartWrapper,因此我们必须从包装器中获取图表 (MSLChart.getChart())。

接下来,我们使用方法 getBoundingBox 来查找每行的最小值和最大值。

var yAxisCoords = {min: null, max: null};
var lineIndex = 0;
var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
do {
  yAxisCoords.max = yAxisCoords.max || boundsLine.top;
  yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
  yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
  yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
  lineIndex++;
  boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
} while (boundsLine !== null);

然后我们使用方法 getVAxisValue 来确定每个 y 轴值应该是什么,
在 y 轴上设置 viewWindow,然后重新绘制图表。

MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
MSLChart.draw();

我们在一个函数中完成所有这些。
我们在图表包装器上使用一次性 'ready' 事件进行第一次计算。
再说一遍,在图表上。

google.visualization.events.addOneTimeListener(MSLChart, 'ready', filterChange);

function filterChange() {
  // get chart layout
  var chartLayout = MSLChart.getChart().getChartLayoutInterface();

  // get y-axis bounds
  var yAxisCoords = {min: null, max: null};
  var lineIndex = 0;
  var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
  do {
    yAxisCoords.max = yAxisCoords.max || boundsLine.top;
    yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
    yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
    yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
    lineIndex++;
    boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
  } while (boundsLine !== null);

  // re-draw chart
  MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
  MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
  MSLChart.draw();
  google.visualization.events.addOneTimeListener(MSLChart.getChart(), 'ready', filterChange);
}

请参阅以下工作片段...
(运行代码片段时,单击右上角的“整页”)

google.charts.load('current', {
  packages: ['controls']
}).then(initialize);

function initialize() {
  var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1vn1iuhsG33XzFrC4QwkTdUnxOGdcPQOj-cuaEZeX-eA/edit#gid=0');
  query.send(drawDashboard);
}

function drawDashboard(response) {
  var data = response.getDataTable();

  //Asign units of 'mm' to data.
  var formatMS = new google.visualization.NumberFormat({
    pattern: '# mm'
  });

  // format into data mm..
  for (var colIndex = 1; colIndex < data.getNumberOfColumns(); colIndex++) {
    formatMS.format(data, colIndex);
  }

  var YearPicker = new google.visualization.ControlWrapper({
    controlType: 'NumberRangeFilter',
    containerId: 'filter_div',
    options: {
      filterColumnLabel: 'Year',
      ui: {
        cssClass: 'filter-date',
        format: {pattern: '0000'},
        labelStacking: 'vertical',
        allowTyping: false,
        allowMultiple: false
      }
    },
  });

  var MSLChart = new google.visualization.ChartWrapper({
    chartType: 'LineChart',
    containerId: 'chart_div',
    dataTable: data,
    options: {
      fontSize: '14',
      title: 'Timbucktoo Annual Mean Sea Level Summary',
      hAxis: {title: 'Year', format: '0000', maxValue: 2120},
      vAxis: {title: 'Height above Chart Datum (mm)', format:'###0'},
      height: 600,
      chartArea: {height: '81%', width: '85%', left: 100},
      legend: {position: 'in', alignment: 'end', textStyle: {fontSize: 13}},
      colors: ['blue'],
      trendlines: {
        0: {
          type: 'polynomial',
          degree: 2,
          color: 'green',
          visibleInLegend: true,
        },
        1: {
          type: 'linear',
          color: 'black',
          visibleInLegend: true,
        },
      },
      series: {
        0: { visibleInLegend: true },
        1: { visibleInLegend: false },
      },
    },
    view: {columns: [0,1,2]}
  });

  google.visualization.events.addOneTimeListener(MSLChart, 'ready', filterChange);

  function filterChange() {
    // get chart layout
    var chartLayout = MSLChart.getChart().getChartLayoutInterface();

    // get y-axis bounds
    var yAxisCoords = {min: null, max: null};
    var lineIndex = 0;
    var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
    do {
      yAxisCoords.max = yAxisCoords.max || boundsLine.top;
      yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
      yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
      yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
      lineIndex++;
      boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
    } while (boundsLine !== null);

    // re-draw chart
    MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
    MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
    MSLChart.draw();
    google.visualization.events.addOneTimeListener(MSLChart.getChart(), 'ready', filterChange);
  }

  var dashboard = new google.visualization.Dashboard(
    document.getElementById('dashboard_div')
  ).bind(YearPicker, MSLChart).draw(data);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
  <div id="chart_div"></div>
  <div id="filter_div"></div>
</div>


注意:您似乎正在使用旧的 load 语句来加载 Google 图表。
请参阅上面的更新片段...

关于javascript - 动态垂直轴可容纳 Google 折线图中的趋势线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58685844/

相关文章:

javascript - 用于表格谷歌可视化的工具提示 Html

javascript - 如何隐藏谷歌图表中的列

javascript - 折线图无法在 create-react-app 中使用react-d3-components

javascript - GWT + Google 可视化 API = Firefox 插件

javascript - 使用 jest fake 计时器测试 redux-saga debounce

javascript - AngularJS 发布到 Controller 并重定向到另一个页面

d3.js - 需要帮助绘制多元线之间的区域 - 而不是从轴到线

kendo-ui - 剑道实时图表

javascript - 在 Javascript 中添加转换速度

javascript - 抛出异常 : Node. js 与 Gevent