Custom Element with Shadow and Template

by stevenkaspar

HTML

<xy-graph x='10' y='20'></xy-graph>

<graph-axis-button axis='x' value='1'>x +1</graph-axis-button>
<graph-axis-button axis='x' value='-1'>x -1</graph-axis-button>
<graph-axis-button axis='y' value='1'>y +1</graph-axis-button>
<graph-axis-button axis='y' value='-1'>y -1</graph-axis-button>

<template data-xy-graph-styling>
  <style>
    x-axis {
      width: 1px;
      height: 100%;
      background: #444;
    }
    y-axis {
      width: 100%;
      height: 1px;
      background: #444;
    }
  </style>
</template>

CSS

body {
  min-height: 300px;
}
xy-graph {
  width: 100%;
  background: white;
}

JavaScript

class XAxis extends HTMLElement {
  constructor(){
    super();
  }
  
  connectedCallback(){
    this.style.position = 'absolute';
    this.style.display = 'block';
  }
  
  static get observedAttributes() {
    return ['index'];
  }
  attributeChangedCallback(attr, oldValue, newValue) {
    if (attr === 'index') {
    	this.style.left = (newValue * 10) + 'px';
    }
  }
}

class YAxis extends HTMLElement {
  constructor(){
    super();
  }
  connectedCallback(){
    this.style.position = 'absolute';
    this.style.display = 'block';
  }
  static get observedAttributes() {
    return ['index'];
  }
  attributeChangedCallback(attr, oldValue, newValue) {
    if (attr === 'index') {
    	this.style.top = (newValue * 10) + 'px';
    }
  }
}

class XyGraph extends HTMLElement {
  constructor(){
    super();
  	this.shadow = this.attachShadow({mode: 'open'});
    this.shadow.appendChild(document.querySelector('[data-xy-graph-styling]').content.querySelector('style'));
  }
  connectedCallback(){
    this.style.position = 'relative';
    this.style.display  = 'block';
  }
  
  static get observedAttributes() {
    return ['x', 'y'];
  }
  attributeChangedCallback(attr, oldValue, newValue) {
    if (attr === 'x' && oldValue !== newValue) {
    	var diff = newValue - oldValue;
      if(diff > 0){
      	while(diff > 0){
        	let x = document.createElement('x-axis');
          x.setAttribute('index', this.shadow.querySelectorAll('x-axis').length);
          this.shadow.appendChild(x);
          diff += -1;
        }
      }
      else if(diff < 0){
      	while(diff < 0){
          let x_axes = this.shadow.querySelectorAll('x-axis');
          x_axes[x_axes.length - 1].parentNode.removeChild(x_axes[x_axes.length - 1]);
          diff += 1;
        }
      }
    }
    else if (attr === 'y' && oldValue !== newValue) {
      this.style.height = (((newValue-1) * 10) + 1) + 'px';
    	var diff = newValue - oldValue;
      if(diff > 0){
      	while(diff > 0){
        	let y...