Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 47 additions & 40 deletions static/bargraph/barchart.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,34 +496,49 @@ function makeBarGraph(args) {
}
}
}
function replaceTextWithSidecarData(d3TextElem) {
/*
* Wraps the text element in a href from the sidecar data.
* Precondition: this candidate must have sidecar data
*/
function replaceTextWithSidecarData(d3TextElem, textShift = 0) {
d3TextElem.each(function() {
const textElem = d3.select(this),
name = textElem.text(),
data = candidateSidecarData['info'][name],
href = data['moreinfo_url'],
party = data['party'],
let textElem = d3.select(this),
name = textElem.text(),
data = candidateSidecarData['info'][name],
href = null,
party = null,
isIncumbent = null;
if (data) {
href = data['moreinfo_url'];
party = data['party'];
isIncumbent = data['incumbent'];

const link = textElem.text(null)
.append("a")
}

// Clear existing content and set common attributes on <text>
textElem
.text(null)
.attr("x", textShift)
.attr("text-anchor", "start")
.attr("dy", ".32em");

if (href != null) {
const link = textElem.append("a")
.attr("href", href)
.attr("target", "_blank")
.attr("dy", ".32em")
.style("fill", "#1c5f99")
.text(name);

if (isIncumbent) {
link.classed("dataLabelIncumbent", true);
}
} else {
textElem.append("tspan")
.style("fill", "#1c5f99")
.text(name);
}

if (party != null) {
textElem.append("tspan")
.attr("dx", "5px")
.style("fill", "#999")
.text(party);

if (isIncumbent) {
link.classed("dataLabelIncumbent", true);
}
}
});
}

Expand Down Expand Up @@ -606,33 +621,25 @@ function makeBarGraph(args) {
.attr("cy", 0)
.attr("r", imageSize/2);

const candidatesWithoutSidecarData = candidateWrapper.selectAll(".tick")
.filter(d => candidateSidecarData['info'][d] === undefined);

const candidatesWithSidecarData = candidateWrapper.selectAll(".tick")
.filter(d => candidateSidecarData['info'][d] !== undefined);

candidatesWithSidecarData.selectAll(".tick text")
.call(c => replaceTextWithSidecarData(c));
const candidates = candidateWrapper.selectAll(".tick");
const textShift = imageSize + 10;
candidates.selectAll(".tick text")
.call(c => replaceTextWithSidecarData(c, textShift));

candidatesWithSidecarData
candidates
.append("image")
.attr("href", d => candidateSidecarData['info'][d]['photo_url'])
.attr("href", d => {
const info = candidateSidecarData['info'][d];
let photoUrl = null;
if (info) {
photoUrl = info['photo_url'];
}
return photoUrl ? photoUrl : null;
})
.attr("clip-path", `url(#${circleDefId})`)
.attr("width", imageSize)
.attr("height", imageSize)
.attr("y", -imageSize/2);

// Shift the text over and word wrap
const textShift = imageSize + 10;
candidatesWithoutSidecarData.selectAll(".tick text")
.attr("text-anchor", "start")
.attr("x", textShift)
.call(magicWordWrap);
candidatesWithSidecarData.selectAll("a")
.attr("text-anchor", "start")
.attr("x", textShift)
.call(magicWordWrap);
}
else
{
Expand Down Expand Up @@ -853,4 +860,4 @@ function makeBarGraph(args) {
$('[data-toggle="tooltip"]').tooltip();

return transitions;
}
}
6 changes: 6 additions & 0 deletions testData/bp-sidecar-medium.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
"photo_url": "/static/visualizer/logo-white.png",
"moreinfo_url": "https://ballotpedia.org/Link",
"party": "(Green)"
},
"Vanilla" : {
"incumbent": null,
"photo_url": null,
"moreinfo_url": null,
"party": null
}
},
"order": [
Expand Down
9 changes: 5 additions & 4 deletions visualizer/sidecar/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import json

from visualizer import common


Expand Down Expand Up @@ -62,10 +63,10 @@ def _assert_valid(self, graph):
self._expect_in(expectedNames, "the actual candidates", candidate)
self._expect_in(info, "the candidate info", 'incumbent')

assert isinstance(info['incumbent'], bool)
assert isinstance(info['photo_url'], str)
assert isinstance(info['moreinfo_url'], str)
assert isinstance(info['party'], str)
assert info['incumbent'] is None or isinstance(info['incumbent'], bool)
assert info['photo_url'] is None or isinstance(info['photo_url'], str)
assert info['moreinfo_url'] is None or isinstance(info['moreinfo_url'], str)
assert info['party'] is None or isinstance(info['party'], str)

@classmethod
def _expect_in(cls, data, dataDescriptor, field):
Expand Down
Loading