JSFiddle - React, Tailwind, and code Playground
by Shawn Allen
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/document-register-element/0.5.3/document-register-element.js"></script>
<h1><x-bar></h1>
<x-bar min="0" max="100" value="50"></x-bar>
<x-bar min="-100" max="100" value="-50"></x-bar>
<x-bar min="-100" max="100" value="-200"></x-bar>
<x-bar min="-100" max="100" value="50"></x-bar>
<x-bar min="100" max="200" value="150"></x-bar>
<x-bar min="0" max="100" value="150"></x-bar>
<script>
var barData = [
{min: 0, max: 100, value: 50},
{min: -100, max: 100, value: -50},
{min: -100, max: 100, value: -200},
{min: -100, max: 100, value: 50},
{min: 100, max: 200, value: 150},
{min: 0, max: 100, value: 150},
]
</script>
<h1>document.createElement()</h1>
<div id="create-element"></div>
<script>
barData.forEach(function(d) {
var bar = this.appendChild(document.createElement('x-bar'));
bar.className = 'animate';
setTimeout(function() {
for (var key in d) bar[key] = d[key];
}, 100);
}, document.querySelector('#create-element'));
</script>
SCSS
h1 {
font-family: monospace;
margin: 0 0 .5em 0;
}
x-bar {
display: block;
border: 1px solid black;
height: 1em;
position: relative;
margin-bottom: .5em;
.rect {
background: green;
height: 100%;
left: 0;
right: 100%;
position: absolute;
}
&.animate .rect {
transition: left .2s, right .2s;
}
&[value^="-"] .rect {
background: red;
}
}
JavaScript
(function(exports) {
var XBar = document.registerElement('x-bar', {
prototype: Object.create(
HTMLElement.prototype,
{
createdCallback: {value: function() {
this.__rect = this.appendChild(document.createElement('div'));
this.__rect.className = 'rect';
}},
attachedCallback: {value: function() {
['min', 'max', 'value'].forEach(function(attr) {
if (this.hasAttribute(attr)) {
this[attr] = this.getAttribute(attr);
}
}, this);
}},
attributeChangedCallback: {value: attributeChanged},
min: numericProperty('min', 0, lazyRender),
max: numericProperty('max', 1, lazyRender),
value: numericProperty('value', 0, lazyRender)
}
)
});
exports.XBar = XBar;
function lazyRender() {
if (!this.__renderId) {
var _render = function() {
render.call(this);
delete this.____renderId;
}
this.__renderId = requestAnimationFrame(_render.bind(this));
}
}
function render() {
var min = this.min;
var max = this.max;
var x = function(v) {
return (v - min) / (max - min) * 100;
};
var value = Math.max(min, Math.min(this.value, max));
var left = Math.min(value, Math.max(0, min));
var right = Math.max(0, value);
var rect = this.__rect;
rect.style.setProperty('left', x(left) + '%');
rect.style.setProperty('right', 100 - x(right) + '%');
}
function attributeChanged(attr, previous, value) {
switch (attr) {
case 'min':
case 'max':
case 'value':
this[attr] = value;
break;
}
}
function numericProperty(name, defaultValue, change) {
var symbol = '__' + name;
return {
get: function() {
return (symbol in this)
? this[symbol]
: (this[symbol] = defaultValue);
},
set: function(value) {
value = isNaN(value) ? 0 : Number(value);
...