A toolkit to enable the manipulation of data graphics
dragit is an extension to the D3.js library to enable the direct manipulation of SVG data visualization. It is designed to be seamlessly included in an existing D3 visualization. It is also designed to be highly customizable and extensible.
Romain Vuillemot, Charles Perin. Investigating the Direct Manipulation of Ranking Tables. Proceedings of the 2015 Annual Conference on Human Factors in Computing Systems (CHI 2015), Apr 2015, Seoul, Korea. ACM.
More advanced ones:
One of the library design goal to be included quasi-seamlessly in a current data visualization, i.e. without much change. To use it, insert the following snippets in the header of your code, right after D3:
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="dragit.js" charset="utf-8"></script>
You are, however, very likely to structure the chart as follows to make sure dragit is informed on the existing temporal data and the current state of the visualization. Two functions (names don't matter) are to be created:
init()
which is called only once during startupupdate()
which is called once time has changedThose two functions will make sure the library's internal state is always up to date, regardless how you update the data visualization (using regular slider or direct manipulation).
Here are a few concepts that are important to grasp:
Here are the names using for the various objects:
dragit.data
: is a time-cube defined where each row are data points and columns time steps.You may want to generate a random time cube (of nb_data_points
x nb_time_steps
). The x
and y
values should reflect the exact position of the data poin on screen. Example as below:
var timecube = d3.range(nb_data_points).map(function(d, i) {
return d3.range(nb_time_steps).map(function(e, j) {
return {x: i, y: Math.random(), t: j};
});
})
Example (rows are data, columns are time steps):
[ d0 [ t0 ] [ t1 ] ... [ tm ] ]
[ d1 [ t0 ] [ t1 ] ... [ tm ] ]
...
[ dn [ t0 ] [ t1 ] ... [ tm ] ]
Where di are dimensions, as ti are time points.
Some other Ways to generate a dataset that can be dragged:
A series of private variables for internal use. Can be set using publication functions, such as:
dragit.init(container)
: set the DOM element containing all the trajectories (can be shared with the visualization)dragit.time.current
: the current time (default: 0)dragit.time.min
: the minimal time point (default: 0)dragit.time.max
: the maximal time point (default: 0)dragit.time.step
: increment (default: 1)dragit.time.speed
: for the playback (default)Example:
dragit.time = {min: d3.min(data, function(d) { return parseInt(d[i]);}),
max: d3.max(data, function(d) { return parseInt(d[i]);}),
step: 1,
current: 0
}
The object of interest, or the handle the user interacts with to start the interaction and thus start the time change.
dragit.object.activate
activates dragging for the selected element. It creates the necessary mouse events (drag). Example: .call(dragit.object.activate)
.absolute (default)
does not translate the current chartrelative
does translate the current chart to keep it centered around the current focus pointBelow are the different drag-type
strategies:
horizontal
or vertical
flow
flow dragging method. Usually well suited for background * motion.free
dragging with no constraints on the activated element, returns to its original positioncurvilinear
(not implemented)focus
restricts closest point finding to the current trajectory, thus only change time.selected
expands the scope to all currently displayed trajectories, thus may change time and the current focus.Handles trajectories drawing.
dragit.trajectory.display(class)
: displays the currently dragged element's trajectorydragit.trajectory.displayUpdate
: update the trajectorydragit.trajectory.displayAll(class)
: displays all trajectoriesdragit.trajectory.toggle(class)
: toggle the display of current trajectorydragit.trajectory.toggleAll(class)
: toggle the display of all trajectoriesdragit.trajectory.remove(class)
: removes the created trajectorydragit.trajectory.removeAll(class)
: removes all trajectoriesEvents management mechanism to register and trigger functions.
dragit.evt.register(event, function, context)
: register a function for a given event
or an array of multiple event
dragit.evt.call(event)
: trigger registered functions
dragit.statemachine.current_state
: the current state of the interaction (e.g mouseenter, dragstart)dragit.statemachine.current_id
: the id of the currently manipulated elementdragit.statemachine.setState(event)
: sets the current state of the state machinedragit.statemachine.getState()
: gets the current state of the state machineDefine the type of design for the focus point vars.custom_focus
(default) and trajectories vars.custom_trajectory
(default).
dragit.custom.line
dragit.custom.point
For each object, this allows to set some expected positions when multiple are available. This can be used in multiple scenarios:
To filter out a space and only make visible a specific trajectory
When multiple permutations are possible and we need to decide whiche one
dragit.constraint
: array of constraints
A collection of useful functions for path calculation and animation.
dragit.utils.animateTrajectory(path, star_time, duration)
: animates the path from start_time and with a given durationdragit.utils.closestPoint
dragit.utils.closestValue
dragit.utils.findYgivenX
dragit.utils.translateAlong(path, duration)
dragit.utils.slider(el, play_button)
: automatically creates a slider to browse all the time points