UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

379 lines (370 loc) 11.9 kB
<!doctype html> <!-- @license Copyright (c) 2017 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <html> <head> <title>data-table</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="../../../webcomponentsjs/webcomponents-lite.js"></script> <link rel="import" href="../../polymer.html"> </head> <body> <script> window.emojiByType = { a: '😎', b: '💰', c: '🚔', d: '💕', e: '👍', f: '🍌' }; </script> <dom-module id="data-popup"> <template strip-whitespace> <style> :host { display: inline-block; background: lightblue; border-radius: 10px; border-bottom-left-radius: 0; border: 1px solid #aaa; box-shadow: 3px 3px 5px #535353; padding: 5px; z-index: 1; } </style> <slot></slot> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'data-popup' }); }); </script> </dom-module> <dom-module id="data-cell"> <template strip-whitespace> <style> :host { flex: 1; border: 2px solid #aaa; padding: 5px; position: relative; background: #eee; } data-popup { display: none; position: absolute; bottom: calc(100% - 15px); left: calc(100% - 15px); } :host(:hover) data-popup { display: inline-block; } :host([change=up]) { background: #afa; } :host([change=down]) { background: #faa; } .type { display: inline-block; border-radius: 100%; box-sizing: border-box; padding: 3px 0; background: #aaa; margin-right: 5px; height: 30px; width: 30px; text-align: center; } </style> <div class="type">{{computeTypeIcon(type)}}</div> {{toFixed(value)}} <data-popup>{{value}}</data-popup> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'data-cell', properties: { type: { type: String, notify: true }, value: { type: Number, notify: true }, change: { reflectToAttribute: true, computed: 'computeChange(value)' } }, attached: function() { this.fire('register-cell'); }, computeChange: function(value) { var prev = this._prev; this._prev = value; return value > prev ? 'up' : (value < prev ? 'down' : 'none'); }, computeTypeIcon: function(type) { return emojiByType[type]; }, toFixed: function(value) { return Number(value).toFixed(2); } }); }); </script> </dom-module> <dom-module id="data-row"> <template strip-whitespace> <style> :host { display: flex; flex-direction: row; } .title-cell { flex: 1; } .title { font-weight: bold; } .dominant { font-size: 0.7em; } </style> <div class="title-cell"> <div class="title">{{title}}</div> <div class="dominant">Dominant: {{computeDominant(cells.*)}}</div> </div> <template is="dom-repeat" items="{{cells}}" as="cell"> <data-cell type="{{cell.type}}" value="{{cell.value}}"></data-cell> </template> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'data-row', properties: { title: { type: String, notify: true }, cells: { type: Array, notify: true } }, computeDominant: function(info) { var types = this.types = info.base.reduce(function(map, i) { return map[i.type] = (map[i.type] || 0) + 1, map; }, {}) return emojiByType[Object.keys(types).sort(function(a, b) { return types[b] - types[a]; })[0]]; } }); }); </script> </dom-module> <dom-module id="data-table"> <template strip-whitespace> <style> :host { display: block; } </style> Polymer: {{version}}<br> <button on-tap="toggleRunning">{{computeRunning(running)}}</button> <input value-as-number="{{tables::input}}" type="number" style="width:35px;" placeholder="tables"> <input value-as-number="{{rows::input}}" type="number" style="width:35px;" placeholder="rows"> <input value-as-number="{{columns::input}}" type="number" style="width:35px;" placeholder="columns"> <br><br> <select value="{{strategy::change}}"> <option value="reset">(Mutate in place x n), reset</option> <option value="reset-each">(Mutate in place, reset) x n</option> <option value="path">(Set path from top) x n</option> <option value="path-leaf">(Set path from leaf) x n</option> </select> n = <input value-as-number="{{mutations::input}}" type="number" style="width:35px;"> <br><br> <h3>FPS: {{fps}}</h3> <h3>Op time: {{toFixed(optime, 2)}}</h3> <div xhidden> <template is="dom-repeat" items="{{tableData}}"> <h3>Table {{index}}:</h3> <template is="dom-repeat" items="{{data}}" as="row"> <data-row title="{{row.title}}" cells="{{row.cells}}"></data-row> </template> </template> </div> </template> <script> HTMLImports.whenReady(function() { var params = document.location.search.substring(1).split('&').map(p=>p.split('=')) .reduce((m, p)=>{return m[p[0]] = p[1], m;}, {}); Polymer({ is: 'data-table', properties: { rows: { type: Number, value: Number(params.rows) || 6 }, columns: { type: Number, value: Number(params.columns) || 10 }, tables: { type: Number, value: Number(params.tables) || 2 }, mutations: { type: Number, value: Number(params.mutations) || 30 }, strategy: { type: String, value: params.strategy || 'reset' }, running: { type: Number, value: params.running === 'false' ? false : true }, tableData: { computed: 'computeTableData(tables)' }, optime: { value: 0 } }, observers: ['computeData(rows, columns)'], created: function() { this._fps = 0; this.end = performance.now() + 1000; var cells = this.cells = []; this.addEventListener('register-cell', function(e) { var cell = e.composedPath()[0]; cell.id = 'cell-' + cells.length; cells.push(cell); }); }, toggleRunning: function() { this.running = !this.running; if (this.running) { this.go(); } }, computeRunning: function(running) { return running ? 'Pause' : 'Run'; }, computeData: function(rows, columns) { var r = []; for (var i=0; i<rows; i++) { var c = []; for (var j=0; j<columns; j++) { c.push({ value: Math.random() * 10, type: ['a','b','c','d','e','f'][Math.floor(Math.random()*6)] }); } r.push({ cells: c, title: 'Row ' + i }) } this.data = r; }, computeTableData: function(tables) { return new Array(Number(tables)); }, toFixed: function(value, decimals) { return value.toFixed(decimals); }, ready: function() { this.version = Polymer.version || 'alacarte'; if (!this.setProperties) { this.setProperties = function(props) { for (var p in props) { this.set(p, props[p]); } } } this.go(); }, go: function() { var optime = 0; for (var i=0; i<this.mutations; i++) { var type = ['a','b','c','d','e','f'][Math.floor(Math.random()*6)]; var delta = (Math.random() > 0.5 ? -1 : 1) * (Math.random() * 5); var row = Math.floor(Math.random() * this.rows); var column = Math.floor(Math.random() * this.columns); var d = this.data[row].cells[column]; if (this.strategy == 'reset' || this.strategy == 'reset-each') { d.type = type; d.value += delta; if (this.strategy == 'reset-each') { var start = performance.now(); this.set('data', this.data); optime += (performance.now() - start); } } else if (this.strategy == 'path') { var path = ['data', row, 'cells', column].join('.'); var props = {}; props[path + '.type'] = type; props[path + '.value'] = d.value + delta; var start = performance.now(); this.setProperties(props); optime += (performance.now() - start); } else if (this.strategy == 'path-leaf') { var c = this.cells[Math.floor(this.cells.length * Math.random())]; var props = { type: type, value: c.value + delta }; var start = performance.now(); c.setProperties(props); optime += (performance.now() - start); } } if (optime) { this.optime = (this.optime * 9 + (optime / this.mutations)) / 10; // this.optime = optime / this.mutations; } if (this.strategy == 'reset') { var start = performance.now(); this.set('data', this.data); this.optime = (this.optime * 9 + (performance.now() - start)) / 10; // this.optime = performance.now() - start; } this._fps++; if (performance.now() > this.end) { this.fps = this._fps; this._fps = 0; this.end = performance.now() + 1000; } var self = this; if (this.running) { requestAnimationFrame(function() { self.go(); }); } } }); }); </script> </dom-module> <data-table id="table"></data-table> </body> </html>