<section id="bar-chart-1">
<div class="intro">
<h1>Character Counter</h1>
<form id="story_form">
<label for="story">Feed me (some text), Seymour:</label>
<textarea id="story" name="story" rows="10" cols="60"></textarea>
<button type="button" id="story_submit">Computer, analyze</button>
</form>
</div>
<div class="outputBlock">
<div class="text">
<h2>The graph</h2>
<p>click a bar to see the count writ large</p>
</div>
<div id="svgOutput"></div>
<h2>The results</h2>
<div id="output"></div>
</div>
</section>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="../../js/components/bar-chart-1.js"></script>
<section id="bar-chart-1">
<div class="intro">
<h1>Character Counter</h1>
<form id="story_form">
<label for="story">Feed me (some text), Seymour:</label>
<textarea id="story" name="story" rows="10" cols="60"></textarea>
<button type="button" id="story_submit">Computer, analyze</button>
</form>
</div>
<div class="outputBlock">
<div class="text">
<h2>The graph</h2>
<p>click a bar to see the count writ large</p>
</div>
<div id="svgOutput"></div>
<h2>The results</h2>
<div id="output"></div>
</div>
</section>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="{{ path '/js/components/bar-chart-1.js' }}"></script>
/* No context defined. */
(function () {
document.addEventListener('DOMContentLoaded', function () {
console.log("bar-chart-1 active");
// Let's get this party started.
console.log("Hello from the main app file");
const button = document.querySelector("#story_submit");
button.addEventListener("click", function () {
const textarea = document.querySelector("#story");
const output = document.querySelector("#output");
if (document.querySelector('svg')) {
const svgToRemove = document.querySelector('svg');
svgToRemove.parentNode.removeChild(svgToRemove);
}
let textToAnalyze = textarea.value;
textToAnalyze = textToAnalyze.toLowerCase();
textToAnalyze = textToAnalyze.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()?!\."'“”’‘\[\]\n ]/g,"");
textToAnalyze = textToAnalyze.replace(/\s{2,}/g," ");
let results = {};
for (let i = 0; i < textToAnalyze.length; i++) {
let curChar = textToAnalyze.charAt(i);
if (results.hasOwnProperty(curChar)) {
results[curChar] += 1;
} else {
results[curChar] = 1;
}
}
let html = '<ul>';
for (var prop in results) {
if (Object.prototype.hasOwnProperty.call(results, prop)) {
html += '<li>'
html += prop + ': ' + results[prop];
html += '</li>'
}
}
output.innerHTML = html;
let resultsArray = [];
for (var prop in results) {
if (Object.prototype.hasOwnProperty.call(results, prop)) {
resultsArray.push({
'char': prop,
'count': results[prop]
})
}
}
resultsArray.sort(function(x, y){
return d3.ascending(x.count, y.count);
})
// the d3 part
const w = 1000;
const h = 500;
const aspect = w / h
const padding = 60;
const viewbox = `0 0 ${w} ${h}`;
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(resultsArray, (d) => d.count)])
.range([25, h - padding]);
svg.selectAll("rect.bar")
.data(resultsArray)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', (d, i) => {
return i * (w / resultsArray.length) + 2;
})
.attr("y", (d) => {
return h - yScale(d.count);
})
.attr("width", () => {
return (w / resultsArray.length) - 4;
})
.attr("height", (d) => {
return yScale(d.count);
})
.attr("data-count", (d) => (d.count))
.on("click", barClickHandler);
svg.selectAll("text.title")
.data(resultsArray)
.enter()
.append("text")
.attr('class', 'title')
.text((d) => (d.char))
.attr('x', (d, i) => {
return i * (w / resultsArray.length) + 10;
})
.attr("y", (d) => {
return h - 10;
})
.style('font-family', 'Courier New')
.style('font-size', '0.75rem')
.style('font-weight', 'bold')
.style('fill', 'white');
svg.selectAll("text.count")
.data(resultsArray)
.enter()
.append("text")
.attr('class', 'count')
.text((d) => (d.count))
.attr('x', (d, i) => {
return i * (w / resultsArray.length) + 20;
})
.attr("y", (d) => {
return h - yScale(d.count) - 10;
})
.style('font-size', '0.75rem')
.style('font-weight', 'bold')
.style('font-family', 'Courier New')
.style('fill', 'navy')
.attr('transform', (d, i) => {
return `rotate(-90 ${i * (w / resultsArray.length) + 20} ${h - yScale(d.count) - 10}) `
});
function barClickHandler(d, i) {
console.log("click handled");
if (svg.select('.selected').size() > 0) {
svg.select('.selected').classed('selected', false);
}
d3.select(this).classed('selected', true);
svg.select('text.bigLabel').remove();
svg.append('text')
.attr("x", "25")
.attr("y", "150")
.attr('class', 'bigLabel')
.style('font-family', 'Georgia, serif')
.style('font-size', '10rem')
.style('font-weight', 'bold')
.style('fill', 'navy')
.text(d.char + " ∙ " + d.count);
}
})
});
})();
#bar-chart-1 {
margin: 1rem;
padding: 1rem;
background-color: antiquewhite;
font-family: 'Helvetica Neue', sans-serif;
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: normal;
> * {
margin-bottom: 2rem;
}
#story_form {
flex: 0 1 auto;
display: flex;
flex-flow: column nowrap;
align-items: flex-start;
justify-content: normal;
label {
margin-bottom: 0.25rem;
font-weight: bold;
}
textarea {
margin-bottom: 0.75rem;
font-size: 1rem;
font-family: serif;
padding: 0.25rem;
border: 1px solid navy;
}
button {
font-size: 1.125rem;
background-color: azure;
border: 2px solid navy;
padding: 0.25rem 0.75rem;
align-self: flex-end;
}
}
#output {
font-family: 'Courier New';
width: 100%;
ul {
list-style: none;
display: grid;
padding: 0;
width: 100%;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
grid-gap: 1rem 1rem;
li {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: normal;
border: 1px dotted cornsilk;
padding: 0.25rem 0;
}
}
}
#svgOutput {
width: 100%;
}
svg {
background: aliceblue;
border: 1px solid navy;
width: 100%;
height: auto;
rect {
fill: cadetblue;
transition: fill 0.25s ease;
stroke: darkcyan;
stroke-width: 1px;
&.selected {
fill: aqua;
}
&:hover {
fill: cornflowerblue;
&.selected {
fill: aqua;
}
}
}
}
.intro {
display: grid;
grid-template-columns: min-content 1fr;
grid-gap: 1rem;
border: 1px solid azure;
padding: 2rem;
h1 {
text-align: right;
text-transform: uppercase;
}
}
.outputBlock {
width: 100%;
display: grid;
grid-template-columns: 150px 1fr;
grid-gap: 2rem;
}
}
No notes defined.