chart = {
const chart = html`
<div id="target">
${style}
<div id="nav-container">
<div id="pubDropdown"></div>
</div>
<div><p>Click on a square to select a state and see how it moves.</p></div>
<div id="vis"></div>
</div>
`;
let colIndex = 0;
var svg = d3.select(chart).select("#vis")
.append("svg")
.attr("width", _width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var grid = svg.append("g")
.attr("class", "gridlines")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var row = grid.selectAll(".row")
.data(gridData)
.enter()
.append("g")
.attr("class", "row");
var column = row.selectAll(".cell")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("class", "cell")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", function(d) { return d.width; })
.attr("height", function(d) { return d.height; })
.style("fill", "white")
.style("stroke", "lightgrey");
var gridMap = svg.append("g")
.attr("class", "gridmap")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
yield chart;
// Do the drawing
const [data, links] = attachments;
// function ready(data, links) {
// group data by publication
var nest = d3.nest()
.key(function(d) { return d.publication; })
.entries(data);
// create dropdown menu and populate with publication names
var pubMenu = d3.select(chart).select("#pubDropdown");
pubMenu
.append("select")
.attr("id", "pubMenu")
.selectAll("option")
.data(links)
.enter()
.append("option")
.attr("value", function(d, i) { return i; })
.text(function(d) { return d.publication; });
// set example link
var source = d3.select("#nav-container")
.append("div")
.attr("id", "source")
.html("<a target='_blank' href=" + links[0].source + ">Example</a>");
function redraw() {
// find which publication was selected from dropdown
var selectedPub = pubMenu
.select("select")
.property("value");
source.html("<a target='_blank' href=" + links[selectedPub].source + ">Example</a>")
updateGridMap(links[selectedPub].publication);
}
// loop
let i = 0;
// Autoupdate the selector
const interval = setInterval(() => {
const j = Math.floor(Math.random()*(links.length-1));
pubMenu.select("select").property("selectedIndex", i = j + (j >= i));
console.log("interval", j, i);
redraw();
}, 1500);
// update grid map and example link when dropdown selection changes
pubMenu.on("change", () => {
clearInterval(interval);
redraw();
});
// draw initial grid map
drawGridMap(links[0].publication);
// function to create initial map
function drawGridMap(publication) {
// filter data to return the object of publication of interest
var selectPub = nest.find(function(d) {
return d.key == publication;
});
// use a key function to bind rects to states
var states = gridMap.selectAll(".state")
.data(selectPub.values, function(d) { return d.code; });
// draw state rects
states.enter()
.append("rect")
.attr("class", function(d) { return "state " + d.code; })
.attr("x", function(d) { return (d.col - 1) * cellSize; })
.attr("y", function(d) { return (d.row - 1) * cellSize; })
.attr("width", cellSize)
.attr("height", cellSize)
// keep track of whether square is clicked through toggling class
// cycle through five colours each time square is made active
.on("click", function(d) {
var square = d3.select(this);
square.classed("active", !square.classed("active"));
if (square.classed("active")) {
square.style("opacity", 1);
colIndex++;
switch(colIndex%5) {
case 0:
square.style("fill", highlight[0])
break;
case 1:
square.style("fill", highlight[1])
break;
case 2:
square.style("fill", highlight[2])
break;
case 3:
square.style("fill", highlight[3])
break;
case 4:
square.style("fill", highlight[4])
break;
}
} else {
square.style("fill", "#c0c0c0").style("opacity", 0.2);
}
});
var labels = gridMap.selectAll(".label")
.data(selectPub.values, function(d) { return d.code; });
// add state labels
labels.enter()
.append("text")
.attr("class", function(d) { return "label " + d.code; })
.attr("x", function(d) {
return ((d.col - 1) * cellSize) + (cellSize / 2);
})
.attr("y", function(d) {
return ((d.row - 1) * cellSize) + (cellSize /2 + 5);
})
.style("text-anchor", "middle")
.text(function(d) { return d.code; });
}
function updateGridMap(publication) {
// filter data to return the object of publication of interest
var selectPub = nest.find(function(d) {
return d.key == publication;
});
// update the data and transition
var states = gridMap.selectAll(".state")
.data(selectPub.values, function(d) { return d.code; });
// update existing states
states.transition()
.duration(500)
.attr("x", function(d) { return (+d.col - 1) * cellSize; })
.attr("y", function(d) { return (+d.row - 1) * cellSize; })
.style("opacity", function(d) {
if (d3.select(this).classed("active")) { return 1; } else {return 0.2; }
});
// enter extra states
states.enter()
.append("rect")
.attr("class", function(d) { return "state " + d.code; })
.attr("x", function(d) { return (+d.col - 1) * cellSize; })
.attr("y", function(d) { return (+d.row - 1) * cellSize; })
.attr("width", cellSize)
.attr("height", cellSize)
.on("click", function(d) {
var square = d3.select(this);
square.classed("active", !square.classed("active"));
if (square.classed("active")) {
square.style("opacity", 1);
colIndex++;
switch(colIndex%5) {
case 0:
square.style("fill", highlight[0])
break;
case 1:
square.style("fill", highlight[1])
break;
case 2:
square.style("fill", highlight[2])
break;
case 3:
square.style("fill", highlight[3])
break;
case 4:
square.style("fill", highlight[4])
break;
}
} else {
square.style("fill", "#c0c0c0").style("opacity", 0.2);
}
});
// hide extra state by setting opacity to zero
states.exit()
.style("opacity", 0);
// update labels
var labels = gridMap.selectAll(".label")
.data(selectPub.values, function(d) { return d.code; });
labels.transition()
.duration(500)
.attr("x", function(d) {
return ((d.col - 1) * cellSize) + (cellSize / 2);
})
.attr("y", function(d) {
return ((d.row - 1) * cellSize) + (cellSize /2 + 5);
})
.style("opacity", 1);
labels.enter()
.append("text")
.attr("class", function(d) { return "label " + d.code; })
.attr("x", function(d) {
return ((d.col - 1) * cellSize) + (cellSize / 2);
})
.attr("y", function(d) {
return ((d.row - 1) * cellSize) + (cellSize /2 + 5);
})
.style("text-anchor", "middle")
.text(function(d) { return d.code; });
labels.exit()
.style("opacity", 0);
}
// }; // ready
chart.redraw = redraw;
invalidation.then(() => clearInterval(interval))
return chart;
}