<section id="bars-with-percentages">
    <h1>Bars with percentages</h1>
    <p>the bar height is the total count and then a percentage of the bar is overlaid on top of the bar</p>

    <button id="trigger">Load data</button>

    <div class="block">
        <h2>The SVG Output</h2>
        <p>Hover on bars for property title</p>
        <div id="svgOutput"></div>
    </div>

</section>

<div class="templates">
    <template id="result_box">
        <div class="results_box">
            <div class="result">
                <span class="property"></span>: <span class="count"></span>
            </div>
        </div>
    </template>
</div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="../../js/components/bars-with-percentages.js"></script>
<section id="bars-with-percentages">
    <h1>Bars with percentages</h1>
    <p>the bar height is the total count and then a percentage of the bar is overlaid on top of the bar</p>

    <button id="trigger">Load data</button>

    <div class="block">
        <h2>The SVG Output</h2>
        <p>Hover on bars for property title</p>
        <div id="svgOutput"></div>
    </div>

{{!--
    <div class="block">
        <h2>The text output</h2>
        <div id="outputBox"></div>
    </div>
--}}
</section>

<div class="templates">
    <template id="result_box">
        <div class="results_box">
            <div class="result">
                <span class="property"></span>: <span class="count"></span>
            </div>
        </div>
    </template>
</div>

<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="{{ path '/js/components/bars-with-percentages.js' }}"></script>
/* No context defined. */
  • Content:
    (function () {
      document.addEventListener('DOMContentLoaded', function () {
        console.log("bars-with-percentages active");
    
        const button = document.querySelector('#trigger');
        // const outputBox = document.querySelector('#outputBox');
        const svgOutput = document.querySelector('#svgOutput');
    
        button.addEventListener('click', function() {
          const spinnerA = document.createElement('div');
          spinnerA.classList.add('spinner');
          // outputBox.appendChild(spinnerA);
    
          const spinnerB = document.createElement('div');
          spinnerB.classList.add('spinner');
          svgOutput.appendChild(spinnerB);
    
          fetch('https://my.api.mockaroo.com/chart_data_2.json?count=10&key=0b401b10')
            .then(response => response.json())
            .then(data => {
              // outputBox.removeChild(spinnerA);
              svgOutput.removeChild(spinnerB);
    
              data.sort(function (x, y) {
                return d3.ascending(x.date, y.date);
              })
    
              // d3 version of results
    
              const w = 1000;
              const h = 500;
              const padding = 40;
    
              const svg = d3.select("#svgOutput")
                .append("svg");
    
              svg.attr("viewBox", [0, 0, w, h])
                .attr("preserveAspectRatio", "xMidYMid meet");
    
              // const yScale = d3.scaleLinear()
              //   .domain([0, d3.max(data, (d) => d.count)])
              //   .range([h - padding, padding]);
    
              const yScale = d3.scaleLinear()
                .domain([0, 900])
                .range([h - padding, padding]);
    
              const xScale = d3.scaleLinear()
                .domain([0, data.length])
                .range([padding, w - (0.25 * padding)]);
    
              console.log(xScale(0));
              console.log(xScale(5));
              console.log(xScale(10));
    
              svg.selectAll("rect.bar")
                .data(data)
                .join('rect')
                  .attr('class', 'bar')
                  .attr('x', (d, i) => {
                    return i * ((w - (1.25 * padding)) / data.length) + 1 + padding;
                  })
                  .attr("y", (d) => {
                    return yScale(d.count);
                  })
                  .attr("width", () => {
                    return ((w - (1.25 * padding)) / data.length) - 4;
                  })
                  .attr("height", (d) => {
                    return yScale(0) - yScale(d.count);
                  })
                  .attr("data-count", (d) => (d.count))
                  .append('title')
                  .text((d) => d.date);
    
              svg.selectAll("rect.percentage-bar")
                .data(data)
                .join('rect')
                  .attr('class', 'percentage-bar')
                  .attr('x', (d, i) => {
                    return i * ((w - (1.25 * padding)) / data.length) + padding;
                  })
                  .attr("y", (d) => {
                    return yScale(d.count);
                  })
                  .attr("width", () => {
                    return ((w - (1.25 * padding)) / data.length) - 2;
                  })
                  .attr("height", (d) => {
                    return (yScale(0) - yScale(d.count)) * d.percentage;
                  })
                  .append('title')
                  .text((d) => d.percentage);
    
              svg.selectAll("text.count")
                .data(data)
                .join("text")
                  .attr('class', 'count')
                  .text((d) => (d.count))
                  .attr('x', (d, i) => {
                    return i * ((w - (1.25 * padding)) / data.length) - 4 + padding + 10;
                  })
                  .attr("y", (d) => {
                    return yScale(d.count) - 10;
                  })
                  .style('font-size', '1rem')
                  .style('font-weight', 'bold')
                  .style('font-family', 'Courier New')
                  .style('fill', 'navy');
    
              svg.selectAll("text.date")
                .data(data)
                .join("text")
                  .attr('class', 'date')
                  .text((d) => (d.date))
                  .attr('x', (d, i) => {
                    return i * ((w - (1.25 * padding)) / data.length) - 4 + padding + 10;
                  })
                  .attr("y", (d) => {
                    return h - 20;
                  })
                  .style('font-size', '0.75rem')
                  .style('font-weight', 'bold')
                  .style('font-family', 'Courier New')
                  .style('fill', 'navy');
    
    
              // xAxis
    
              const xAxis = d3.axisBottom(xScale);
    
              svg.append("g")
                .attr("transform", "translate(0, " + (h - padding) + ")")
                .call(xAxis)
                .call(g => {
                  console.dir(g);
                  g.selectAll(".tick text")
                    .attr("dy", "10000");
                });
    
              // yAxis - adding last so it appears above the bars
    
              const yAxis = d3.axisRight(yScale)
                .tickSize(w - (padding * 1.25));
    
              svg.append("g")
                .attr("transform", "translate(" + padding + ", 0)")
                .call(yAxis)
                .call(g => g.selectAll(".tick:not(:first-of-type) line")
                  .attr("stroke-opacity", 0.5)
                  .attr("stroke-dasharray", "4,8"))
                .call(g => g.selectAll(".tick line"))
                .attr("stroke", "navy")
                .call(g => g.selectAll(".tick text")
                  .attr("x", -24)
                  .attr("dy", -4));
    
    
              // text version of results
    
              // data.forEach(function(item) {
              //   let template = document.querySelector('#result_box');
              //   let resultBox = document.importNode(template.content, true);
              //
              //   resultBox.querySelector('.date').innerHTML = item.date;
              //   resultBox.querySelector('.count').innerHTML = item.count;
              //
              //   outputBox.appendChild(resultBox);
              // })
            })
        })
      });
    })();
    
  • URL: /components/raw/bars-with-percentages/bars-with-percentages.js
  • Filesystem Path: components/01-misc/08-bars-with-percentages/bars-with-percentages.js
  • Size: 5.8 KB
  • Content:
    #bars-with-percentages {
      @keyframes spin {
        0% {
          transform: rotate(0);
        }
    
        100% {
          transform: rotate(180deg);
        }
      }
    
      #outputBox {
        margin: 2rem 0;
        padding: 2rem;
        border: 2px solid aliceblue;
      }
    
      .spinner {
        width: 4px;
        height: 40px;
        background-color: darkcyan;
        animation: 0.75s ease-in-out both alternate infinite spin;
      }
    
      .results_box {
        margin: 0 0 1rem 0;
        .property {
          font-weight: bold;
        }
      }
    
      #svgOutput {
        margin: 2rem 0;
      }
    
      svg {
        display: block;
        width: calc(100% - 2px - 2rem);
        margin: auto;
        height: auto;
        border: 1px solid navy;
        background-color: azure;
    
        .bar {
          fill: yellow;
          fill-opacity: 0.8;
          stroke: darkslategray;
          stroke-width: 1px;
        }
    
        .percentage-bar {
          fill: yellowgreen;
          fill-opacity: 1;
        }
      }
    
      .block {
        margin: 2rem 0;
        padding: 2rem 0;
        border-top: 1px solid cadetblue;
      }
    }
    
  • URL: /components/raw/bars-with-percentages/bars-with-percentages.scss
  • Filesystem Path: components/01-misc/08-bars-with-percentages/bars-with-percentages.scss
  • Size: 967 Bytes
  • Handle: @bars-with-percentages
  • Preview:
  • Filesystem Path: components/01-misc/08-bars-with-percentages/bars-with-percentages.hbs

No notes defined.