Reputation: 958
I have some D3.js visualizations I want to server on a Github Pages website I made using Hugo. I'm struggling how to include the visualization (html and js file) within the markdown file. Is this possible? If not, can I just use a standalone html file on Hugo?
Edit:
I implemented the example @timur suggested but the plot still doesn't show.
Upvotes: 3
Views: 2213
Reputation: 14577
It's doable, as long as you can include javascript files for D3 itself and your chart definition:
Consider a slightly cut down version of this example:
margin = ({top: 20, right: 0, bottom: 30, left: 40})
height = 500
width = 500
data = [
{name: "E", value: 0.12702},
{name: "T", value: 0.09056},
{name: "A", value: 0.08167},
{name: "O", value: 0.07507},
{name: "I", value: 0.06966},
{name: "N", value: 0.06749},
{name: "S", value: 0.06327},
{name: "H", value: 0.06094},
{name: "R", value: 0.05987},
{name: "D", value: 0.04253},
{name: "L", value: 0.04025},
{name: "C", value: 0.02782},
{name: "U", value: 0.02758},
{name: "M", value: 0.02406},
{name: "W", value: 0.0236},
{name: "F", value: 0.02288},
{name: "G", value: 0.02015},
{name: "Y", value: 0.01974},
{name: "P", value: 0.01929},
{name: "B", value: 0.01492}
]
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([margin.left, width - margin.right])
.padding(0.1)
function zoom(svg) {
const extent = [[margin.left, margin.top], [width - margin.right, height - margin.top]];
svg.call(d3.zoom()
.scaleExtent([1, 8])
.translateExtent(extent)
.extent(extent)
.on("zoom", zoomed));
function zoomed() {
x.range([margin.left, width - margin.right].map(d => d3.event.transform.applyX(d)));
svg.selectAll(".bars rect").attr("x", d => x(d.name)).attr("width", x.bandwidth());
svg.selectAll(".x-axis").call(xAxis);
}
}
const svg = d3.select(".visualisation")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
svg.append("g")
.attr("class", "bars")
.attr("fill", "steelblue")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", d => x(d.name))
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth());
svg.append("g")
.attr("class", "x-axis")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis")
.call(yAxis);
---
title: "D3.js bars"
date: 2020-03-24T00:00:00Z
draft: false
---
### Hello
<div class="visualisation"> </div> <!-- Hugo supports html in markdown -->
<script src = "https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.js"></script> <!-- load d3.js from CDN. you could potentially load it from /static folder as well-->
<script src = "/example.js"></script> <!-- this will pick our scipt up and render the chart -->
This structure might not be ideal as you could probably stick javascript references into reusable layout of some sort and potentially parametrise the chart definition so you didn't have to repeat it for every page. Without knowing your specifics it's however a bit hard to make these suggestions. I'm just hoping it gives you a good enough hint to keep going.
UPD I'm pretty sure the code itself is working: see this jsfiddle. Hugo has different file layout, but point I'm trying to make here is it should all be a matter of ensuring both your javascript files get loaded.
UPD2 starting version 0.60.0 Hugo will not by default allow unsafe html content (such as tags). To get it to work you need to enable it:
markup:
goldmark:
renderer:
unsafe: true
Upvotes: 5