Polymer 1.x:页面加载后调整图表大小

Polymer 1.x: Resizing chart after page load

TLDR; Here is the jsBin.

如何在我的布局边界内绘制我的 <google-chart> geochart 元素并防止它在第一次绘制时 "spilling over"?

在我的自定义元素中,我使用 google-chart 元素,该元素又使用 Google GeoChart 和 API。当它第一次出现在屏幕上时,它看起来像这样。 (请注意右侧如何溢出 paper-card 的边缘?)

首先绘制外边界

我在第一次油漆时实际看到的。 (突出显示的状态是声明式预设的。)

在我 select 一个州(例如,在这种情况下是加利福尼亚州)之后,图表会自行重新绘制并最终在边界内正确绘制,就像我想要的那样。

点击状态后重新绘制内部边界

我希望在第一次油漆时看到的东西。而在 selecting 状态之后。

重现问题

按照以下步骤操作:

  1. Open this jsBin.
  2. 单击标有 显示图表
  3. 的按钮
  4. ❌ 请注意,图表现在首先出现 大于 paper-card (100px) 的最大宽度。
  5. 点击一个州。
  6. 请注意图表会调整大小以适应 paper-card 的宽度。

问题出在 "div" 标签的 "hidden" 属性上

问题(在实施@ScottMiles 建议的以下解决方案时)在这里:
<div id="chart" hidden> <!-- "hidden" attribute is the problem -->
  <x-element color="red"
             selected='["Colorado", "South Dakota"]'>
  </x-element>
</div>

如果删除 hidden 属性,第一次绘制会按需要进行。但是,出于用户体验的原因,我需要在页面加载时使用 hidden 属性。

到目前为止,我尝试了两种解决方案均未成功。

解决方案尝试 1:在 Attached 上手动重绘

attached: function() {
  this.$.geochart.drawChart(); // Called manually to handle page resizes
}

解决方案尝试 2:IronResizableBehavior

behaviors: [
  Polymer.IronResizableBehavior,
],
listeners: {
  'iron-resize': '_onIronResize',
},
_onIronResize: function() {
  this.$.geochart.drawChart(); // Called manually to handle page resizes
},
attached: function() {
  this.async(this.notifyResize, 1);
},

来源

http://jsbin.com/zumireradi/1/edit?html,输出
<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <base href="https://polygit.org/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link href="polymer/polymer.html" rel="import">
  <link href="google-chart/google-chart.html" rel="import">
  <link href="paper-card/paper-card.html" rel="import">
</head>

<body>
  <dom-module id="x-element">
    <template>
      <style>
        google-chart {
          width: 100%;
        }
      </style>
      <br><br><br><br>
      <button on-tap="_show">Show Values</button>
      <button on-tap="clearAll">Clear All</button>
      <button on-tap="selectAll">Select All</button>
      <div>[[selectedString]]</div>
      <google-chart id="geochart"
                    type="geo"
                    options="[[options]]"
                    data="[[data]]"
                    on-google-chart-select="_onGoogleChartSelect">
      </google-chart>
    </template>
    <script>
      (function() {
        // Monkey patch for google-chart
        var gcp = Object.getPrototypeOf(document.createElement('google-chart'));
        gcp.drawChart = function() {
          if (this._canDraw) {
            if (!this.options) {
              this.options = {};
            }
            if (!this._chartObject) {
              var chartClass = this._chartTypes[this.type];
              if (chartClass) {
                this._chartObject = new chartClass(this.$.chartdiv);
                google.visualization.events.addOneTimeListener(this._chartObject,
                    'ready', function() {
                        this.fire('google-chart-render');
                    }.bind(this));
                google.visualization.events.addListener(this._chartObject,
                    'select', function() {
                        this.selection = this._chartObject.getSelection();
                        this.fire('google-chart-select', { selection: this.selection });
                    }.bind(this));
                if (this._chartObject.setSelection){
                  this._chartObject.setSelection(this.selection);
                }
              }
            }
            if (this._chartObject) {
              this._chartObject.draw(this._dataTable, this.options);
            } else {
              this.$.chartdiv.innerHTML = 'Undefined chart type';
            }
          }
        };
        Polymer({
          is: 'x-element',
          /** /
           * Fired when user selects chart item.
           *
           * @event us-map-select
           * @param {object} detail Alpabetized array of selected state names.
          /**/
          properties: {
            items: {
              type: Array,
              value: function() {
                return [ 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming', ].sort();
              },
            },
            color: {
              type: String,
              value: 'blue',
            },
            options: {
              type: Object,
              computed: '_computeOptions(color)',
            },
            selected: {
              type: Array,
            },
            data: {
              type: Array,
              computed: '_computeData(items, selected.length)'
            },
            selectedString: {
              type: String,
              computed: '_computeSelectedString(selected.length)',
            },
          },
          attached: function() {
            if (this.selected === undefined) {
              this.async(function() {
                this.selected = [];
              }, 0);
            }
          },
          _computeOptions: function() {
            return {
              region: 'US',
              displayMode: 'regions',
              resolution: 'provinces',
              legend: 'none',
              defaultColor: 'white',
              colorAxis: {
                colors: ['#E0E0E0', this.color],
                minValue: 0,  
                maxValue: 1,
              }
            }
          },    
          // On select event, compute 'selected'
          _onGoogleChartSelect: function(e) {
            var string = e.path[0].textContent.split('Select')[0].trim(), // e.g. 'Ohio'
                selected = this.selected, // Array of selected items
                index = selected.indexOf(string);
            // If 'string' is not in 'selected' array, add it; else delete it
            if (index === -1) {
              this.push('selected', string);
            } else {
              this.splice('selected', index, 1);
            }
          },
          _computeSelectedString: function(selectedInfo) {
            var selected = this.selected.sort();
            this.fire('us-map-select', selected);
            return selected.join(', ');
          },
          // After 'items' populates or 'selected' changes, compute 'data'
          _computeData: function(items, selectedInfo) {
            var data = [],
                selected = this.selected,
                i = items.length;
            while (i--) {
              data.unshift([items[i], selected.indexOf(items[i]) > -1 ? 1 : 0]);
            }
            data.unshift(['State', 'Select']);
            return data;
          },
          clearAll: function() {
            this.set('selected', []);
          },
          selectAll: function() {
            this.set('selected', this.items.slice());
          },
          _show: function() {
            //console.log('items', this.items);
            console.log('selected', this.selected);
            //console.log('data', this.data);
          },
        });
      })();
    </script>
  </dom-module>
  <br /><br /><br />
  <paper-card style="max-width:100px;">
    <button onclick="unhide()">Reveal Chart</button>
    <div id="chart" hidden>
      <x-element color="red"
                 selected='["Colorado", "South Dakota"]'>
      </x-element>
    </div>
  </paper-card>
  <script>
    function unhide() {
      document.getElementById('chart').hidden = false;
    }
  </script>
</body>

</html>

Polymer 在首次绘制之前尽可能多地生成您的应用程序,以避免闪烁和 FOUC。如果 google-chart 之类的元素在绘制已经发生之前就被渲染了(因为某些测量值尚不可用),则它们会令人不快。

可以尝试推迟 google-chart 的初始绘制,如下所示:

  1. 保留 selected 未初始化。这将阻止 chartData 计算并防止图表过早绘制。

    selected: {
      type: Array
     }
    
  2. attached:

    异步初始化 selected
    attached: function() {
      if (this.selected === undefined) {
        this.async(function() {
          this.selected = []; 
        }, 0);
      }
    }
    

这有点乱七八糟,但是调用 this.async(.., 0) 应该能让你超越第一次绘制。那时我们给 selected 一个值,它触发 chartData 计算和图表绘制。

HTH

根据 OP 发布的 JSbin 进行更新:取消隐藏后强制重新绘制图表修复了问题:http://jsbin.com/pekahix/edit?html

document.querySelector('#chart').hidden = false;
document.querySelector('x-element').$.geochart.drawChart();

我很幸运 Polymer.IronResizableBehavior,但我相信问题出在 drawChart() 上,试试 redraw()。我能够使用您的努力 + demo of the component 来简单地调整大小。我将图表的宽度设置为 100%,它可以平滑地缩放到它所在的卡片(它具有适合页面的自动边距)

<google-chart
    id="marketchart"
    type="column"
    options='{"title": "Responsive chart",
              "vAxis": {"minValue" : 0, "maxValue": 10}}'
    cols='[{"label": "Data", "type": "string"},{"label": "Value", "type": "number"}]'
    rows='[ ["Col1", 5.0],["Col2", 5.0],["Col3", 5.0] ]'>
  </google-chart>

  <script>
Polymer({
  is: 'my-dashboard',

  behaviors: [
    Polymer.IronResizableBehavior
  ],

  listeners: {
    'iron-resize': '_onIronResize'
  },

  attached: function() {
    this.async(this.notifyResize, 1);
  },

  get parent() {
    if (this.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
      return this.parentNode.host;
    }
    return this.parentNode;
  },

  _onIronResize: function() {
    this.$.marketchart.redraw();
  }

});