org-howto/d3/drag3/fx_view.js

135 lines
3.9 KiB
JavaScript

!function() {
/* module for displaying a function f(x) using svg,
* together with a draggable point that's constrained to lie on the function
*
* uses: module point.js
*/
/* view elements - things we see on the screen */
var fx_view
= { /* procedure to setup this view */
draw: null,
/* svg bounding box */
box: null,
/* svg path representing points {x,f(x)} */
fx_path: null,
/* function to generate a path from a vector of points */
svg_line_fn: null,
/* function to respond to a new selection point */
fx_update_select_circle: null,
/* svg element to display a selected point on f(x) */
fx_select_circle: null,
/* function to update selection given mouse coords */
fx_update_select: null,
/* function to invoke when a drag event occurs */
drag_function : null
};
/* function to create an SVG approximation to a parametric function
* using a series of straight line segments
*/
fx_view.svg_line_fn = (d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear"));
/* create/update selection circle - intended to mark
* location of selected point pt
*/
fx_view.fx_update_select_circle
= function(pt)
{
var dd = [{center: pt, radius: 4}];
fx_view.fx_select_circle = (fx_view.box.selectAll(".fxselect")
.data(dd));
/* create draggable circle representing a selected point on f(x) */
fx_view.fx_select_circle
.enter()
.append("svg:circle")
.attr("class", "fxselect")
.call(fx_view.drag_function)
.attr("r", function(d) { return d.radius; })
.style("fill", "black");
fx_view.fx_select_circle
.attr("cx", function(d) { return d.center.x; })
.attr("cy", function(d) { return d.center.y; });
} /*fx_update_select_circle*/
/* parent_id :: string. pass this to d3.select() to get selection for parent
* at which to attach svg box
* box_pt :: Point. size of svg bounding box
*/
fx_view.draw = function(parent_id, box_pt, target_pt_v) {
/* create an svg bounding box, to contain interactive drawing area */
fx_view.box = (d3.select(parent_id)
.append("svg")
.attr("class", "box")
.attr("width", box_pt.x)
.attr("height", box_pt.y));
/* border, so bounding box is visible */
fx_view.border = (fx_view.box.append("svg:rect")
.attr("class", "border")
.attr("x", 1)
.attr("y", 1)
.attr("width", box_pt.x - 2)
.attr("height", box_pt.y - 2)
.attr("stroke", "blue")
.attr("stroke-width", 3)
.style("fill", "none"));
/* create path representing our target function f(x) */
fx_view.fx_path = (fx_view.box.append("path")
.attr("d", fx_view.svg_line_fn(target_pt_v))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none")
);
fx_view.fx_update_select_circle(pt.find_closest(pt.scale_pt(0.5, box_pt),
target_pt_v));
} /*draw*/
/* update selection circle
* for an event at Point pt
*/
fx_view.fx_update_select
= function(p, target_pt_v)
{
/* find point on {x,f(x)} that's closest to
* mouse location (i.e. to d3.event)
*/
var best_fx_pt = pt.find_closest(p, target_pt_v);
fx_view.fx_update_select_circle(best_fx_pt)
} /*fx_update_select*/
fx_view.init_drag_function
= (function(target_pt_v) {
fx_view.drag_function
= (d3.behavior.drag()
.on("dragstart",
function() {
fx_view.fx_select_circle
.style("fill", "red")
.attr("r", 5);
})
.on("drag",
function() {
fx_view.fx_update_select(d3.event, ex.target_pt_v);
})
.on("dragend",
function() {
fx_view.fx_select_circle
.style("fill", "black")
.attr("r", 4);
})
);
});
this.fx_view = fx_view;
}();