Modifying a view in Introduction to Views
- EXERCISE: Change
viewof stroke
in Introduction to Views so that it reports the mouse position as its value - SOLUTION
- Put the next line right above this line:
canvas.dispatchEvent(new CustomEvent("input"));
canvas.value = [event.type, event.layerX, event.layerY]
- Put the next line right above this line:
Turn a brush into a view
- EXERCISE: Turn Empty Brush Selection into a "view"
- SOLUTION:
- Change
chart
toviewof chart
- In
function brushed()
on the last line, add:svg.property("value", selection).dispatch("input");
- Note: you can do this as a copy and paste, without really understanding what's going on. Hence the next exercise.
- Change
Same as above, but without D3.
- EXERCISE: Repeat Exercise 1, but this time without using D3.
- SOLUTION:
- Instead of this line:
svg.property("value", selection).dispatch("input");
- Use the following 2 lines:
svg.node().value = selection;
svg.node().dispatchEvent(new CustomEvent("input"));
- Instead of this line:
Report events with a mutable
- EXERCISE: Use mutable values to report event types and mouse location when clicking the button in the mutable values notebook.
- SOLUTION:
- Add a mutable:
mutable z = 42
- Then modify the
button.onclick
line to button.onclick = (event) => { ++mutable x; mutable z = [event.type, event.clientX, event.clientY] }
- Add a mutable:
Report mouse events and ":hover"ed element with a mutable.
- EXERCISE: Use mutable values to report event types and the element being hovered over when you're moving the mouse over the brush. for Empty Brush Selection
- SOLUTION:
- Add a mutable cell, e.g.:
mutable z = 42
- Change:
- Add a mutable cell, e.g.:
const circle = svg.append("g")
.attr("fill-opacity", 0.2)
.selectAll("circle")
.data(Float64Array.from({length: 800}, Math.random))
.join("circle")
.attr("transform", d => `translate(${x(d)},${y()})`)
.attr("r", 3.5);
to
const g = svg.append("g")
g.call(brush)
.call(brush.move, [0.3, 0.5].map(x));
g.on('mousemove', mousemoved)
function mousemoved(event) {
mutable z = ['MOUSEMOVE', event.type, d3.select(this).select(":hover").attr('class')];
}
- The following elements should be selectable with ":hover"
.overlay
.handle--custom
.selection
Custom brush styling.
- EXERCISE: Adapt the Empty Brush Selection so that it looks like a 2-handle range slider.
- Hint: First remove the data and axes, then add the blue & gray slider channels.
- Note: This is worth doing in class -- debugging errors encountered in the solution could be informative.
- SOLUTION:
- Remove the
circle
(i.e., random data visualization) and axes - Add slider channels (gray and blue parts)
- Remove the
// Add the background slider channel (the gray/unselected part)
const strokeWidth = 1;
g.insert('rect', '.overlay') // Add the slider channel
.attr("x", margin.left)
.attr("y", margin.top + radius / 2 + strokeWidth)
.attr("height", radius - 2 * strokeWidth)
.attr("width", width - margin.right - margin.left)
.attr("rx", radius / 2)
.attr("fill", "#ddd")
.attr("stroke", "#aaa") // default gray stroke
.attr("stroke-width", strokeWidth)
// Add the "selected" slider channel (blue part)
const channel = g.insert('rect', '.overlay')
.attr('class', 'custom-channel')
.attr("x", margin.left)
.attr("y", margin.top + radius / 2)
.attr("height", radius)
.attr("width", width - margin.right - margin.left)
.attr("rx", radius / 2)
.attr("fill", 'steelblue')
* NOTE: You can change the size of the blue part pretty easily (something to do with the brush)
- Set the size of the blue part of the channel according to the brush selection
- In
function brushed
, add this line:
- In
channel.attr('x', selection[0]).attr('width', selection[1] - selection[0]);
* Note: this will throw an error because "channel" is not defined.
* ReferenceError: Cannot access 'channel' before initialization
* The error points to this line: `.call(brush.move, [0.3, 0.5].map(x));`
* That's because this line invokes `function brush`, which references "channel"
* Fix it by moving the line above below the splot where "channel" is defined.
- The rest of the styling can be done for homework.