UNPKG

five-bells-visualization

Version:
351 lines (314 loc) 9.67 kB
<!-- Copyright (c) 2014 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 --> <!-- @group Polymer Core Elements @element core-layout-grid @status beta @homepage github.io TODO --> <link rel="import" href="../polymer/polymer.html"> <polymer-element name="core-layout-grid" attributes="nodes layout auto"> <script> (function() { Polymer('core-layout-grid', { nodes: null, layout: null, auto: false, created: function() { this.layout = []; }, nodesChanged: function() { this.invalidate(); }, layoutChanged: function() { this.invalidate(); }, autoNodes: function() { this.nodes = this.parentNode.children.array().filter( function(node) { switch(node.localName) { case 'core-layout-grid': case 'style': return false; } return true; } ); }, invalidate: function() { if (this.layout && this.layout.length) { // job debounces layout, only letting it occur every N ms this.layoutJob = this.job(this.layoutJob, this.relayout); } }, relayout: function() { if (!this.nodes || this.auto) { this.autoNodes(); } layout(this.layout, this.nodes); this.asyncFire('core-layout'); } }); // var lineParent; function line(axis, p, d) { var l = document.createElement('line'); var extent = (axis === 'left' ? 'width' : (axis === 'top' ? 'height' : axis)); l.setAttribute('extent', extent); if (d < 0) { axis = (axis === 'left' ? 'right' : (axis === 'top' ? 'bottom' : axis)); } p = Math.abs(p); l.style[axis] = p + 'px'; l.style[extent] = '0px'; lineParent.appendChild(l); } var colCount, colOwners, rowCount, rowOwners; function matrixillate(matrix) { // mesaure the matrix, must be rectangular rowCount = matrix.length; colCount = rowCount && matrix[0].length || 0; // transpose matrix var transpose = []; for (var i=0; i<colCount; i++) { var c = []; for (var j=0; j<rowCount; j++) { c.push(matrix[j][i]); } transpose.push(c); } // assign sizing control colOwners = findOwners(matrix); rowOwners = findOwners(transpose); //console.log('colOwners', colOwners); //console.log('rowOwners', rowOwners); } function findOwners(matrix) { var majCount = matrix.length; var minCount = majCount && matrix[0].length || 0; var owners = []; // for each column (e.g.) for (var i=0; i<minCount; i++) { // array of contained areas var contained = {}; // look at each row to find a containing area for (var j=0; j<majCount; j++) { // get the row vector var vector = matrix[j] // node index at [i,j] var nodei = vector[i]; // if a node is there if (nodei) { // determine if it bounds this column var owns = false; if (i === 0) { owns = (i === minCount-1) || (nodei !== vector[i+1]); } else if (i === minCount - 1) { owns = (i === 0) || (nodei !== vector[i-1]); } else { owns = nodei !== vector[i-1] && nodei !== vector[i+1]; } if (owns) { contained[nodei] = 1; } } // store the owners for this column owners[i] = contained; } } return owners; } var nodes; function colWidth(i) { for (var col in colOwners[i]) { col = Number(col); if (col === 0) { return 96; } var node = nodes[col - 1]; if (node.hasAttribute('h-flex') || node.hasAttribute('flex')) { return -1; } var w = node.offsetWidth; //console.log('colWidth(' + i + ') ==', w); return w; } return -1; } function rowHeight(i) { for (var row in rowOwners[i]) { row = Number(row); if (row === 0) { return 96; } var node = nodes[row - 1]; if (node.hasAttribute('v-flex') || node.hasAttribute('flex')) { return -1; } var h = node.offsetHeight; //console.log('rowHeight(' + i + ') ==', h); return h; } return -1; } var m = 0; function railize(count, sizeFn) { // // create rails for `count` tracks using // sizing function `sizeFn(trackNo)` // // for n tracks there are (n+1) rails // // |track|track|track| // 0|->sz0|->sz1|<-sz2|0 // // |track|track|track| // 0|->sz0| |<-sz2|0 // // there can be one elastic track per set // // |track|track|track|track| // 0|-->s0|-->s1|<--s1|<--s2|0 // // sz1 spans multiple tracks which makes // it elastic (it's underconstrained) // var rails = []; var a = 0; for (var i=0, x; i<count; i++) { rails[i] = {p: a, s: 1}; x = sizeFn(i) + m + m; if (x == -1) { break; } a += x; } if (i === count) { rails[i] = {p: 0, s: -1}; } var b = 0; for (var ii=count, x; ii>i; ii--) { rails[ii] = {p: b, s: -1}; x = sizeFn(ii - 1) + m + m; if (x !== -1) { b += x; } } return rails; } // TODO(sjmiles): this code tries to preserve actual position, // so 'unposition' is really 'naturalize' or something function unposition(box) { var style = box.style; //style.right = style.bottom = style.width = style.height = ''; style.position = 'absolute'; style.display = 'inline-block'; style.boxSizing = style.mozBoxSizing = 'border-box'; } function _position(style, maj, min, ext, a, b) { style[maj] = style[min] = ''; style[ext] = 'auto'; if (a.s < 0 && b.s < 0) { var siz = a.p - b.p - m - m; style[ext] = siz + 'px'; var c = 'calc(100% - ' + (b.p + siz + m) + 'px' + ')'; style[maj] = '-webkit-' + c; style[maj] = c; } else if (b.s < 0) { style[maj] = a.p + m + 'px'; style[min] = b.p + m + 'px'; } else { style[maj] = a.p + m + 'px'; style[ext] = b.p - a.p - m - m + 'px'; } } function position(elt, left, right, top, bottom) { _position(elt.style, 'top', 'bottom', 'height', rows[top], rows[bottom]); _position(elt.style, 'left', 'right', 'width', columns[left], columns[right]); } function layout(matrix, anodes, alineParent) { //console.group('layout'); lineParent = alineParent; nodes = anodes; matrixillate(matrix); nodes.forEach(unposition); columns = railize(colCount, colWidth); rows = railize(rowCount, rowHeight); if (alineParent) { //console.group('column rails'); columns.forEach(function(c) { //console.log(c.p, c.s); line('left', c.p, c.s); }); //console.groupEnd(); //console.group('row rails'); rows.forEach(function(r) { //console.log(r.p, r.s); line('top', r.p, r.s); }); //console.groupEnd(); } //console.group('rail boundaries'); nodes.forEach(function(node, i) { // node indices are 1-based var n = i + 1; // boundary rails var l, r, t = 1e10, b = -1e10; matrix.forEach(function(vector, i) { var f = vector.indexOf(n); if (f > -1) { l = f; r = vector.lastIndexOf(n) + 1; t = Math.min(t, i); b = Math.max(b, i) + 1; } }); if (l == undefined) { //console.log('unused'); node.style.position = 'absolute'; var offscreen = node.getAttribute('offscreen'); switch (offscreen) { case 'basement': node.style.zIndex = 0; break; case 'left': case 'top': node.style[offscreen] = node.offsetWidth * -2 + 'px'; break; case 'right': node.style.left = node.offsetParent.offsetWidth + node.offsetWidth + 'px'; break; case 'bottom': node.style.top = node.parentNode.offsetHeight + node.offsetHeight + 'px'; break; default: node.style[Math.random() >= 0.5 ? 'left' : 'top'] = '-110%'; } //node.style.opacity = 0; node.style.pointerEvents = 'none'; } else { node.style.pointerEvents = ''; //node.style.opacity = ''; //console.log(l, r, t, b); position(node, l, r, t, b); } }); //console.groupEnd(); //console.groupEnd(); } })(); </script> </polymer-element>