A 2d function plotter powered by d3
Function Plot is a powerful library built on top of D3.js whose purpose is to render functions with little configuration (think of it as a little clone of Google's plotting utility: y = x * x
The library currently supports interactive line charts and scatterplots, whenever the graph scale is modified the function is evaluated again with the new bounds, result: infinite graphs!
Have a look at the homepage
$ npm install --save function-plotvar d3 = window.d3
var functionPlot = require('function-plot');
functionPlot({
// options below
})All the available options are described in the homepage
var functionPlot = require('function-plot');
params, All the params are optional unless otherwise stated
optionsoptions.target{string} the selector of the parent element to render the graph tooptions.title{string} If set the chart will have it as a title on the topoptions.xDomain{array} domain of the linear scale (used in the x axis)options.yDomain{array} domain of the linear scale (used in the y axis)options.xLabel{string} x axis labeloptions.yLabel{string} y axis labeloptions.disableZoom{boolean} true to disable drag and zoom on the graphoptions.tip{object} configuration passed tolib/tip, it's the helper shown on mouseover on the closest function to the current mose positionoptions.tip.xLine{boolean} true to show a line parallel to the X axis on mouseoveroptions.tip.yLine{boolean} true to show a line parallel to the Y axis on mouseoveroptions.tip.renderer{function} Function to be called to define custom rendering on mouseover, called with thexandf(x)of the function which is closest to the mouse position (args:x, y)
options.annotations{array} An array defining parallel lines to the y-axis or the x-axisoptions.annotations[i].x{number} x-coordinate of the line parallel to the y-axisoptions.annotations[i].y{number} y-coordinate of the line parallel to the x-axisoptions.annotations[i].text{string} text shown next to the parallel line
options.data{array} required An array defining the functions to be renderedoptions.data[i].title{string} title of the functionoptions.data[i].skipTip{boolean} true to avoid this function from being a target of the tipoptions.data[i].fnrequired {string} the function that represents the curve, this function is evaluated with values which are inrangelimiting the values to the screen min/max coordinates forx, i.e. at any given time the graph min/max x coordinates will limit the range of values to be plottedoptions.data[i].range{number[]} if given the function will only be evaluated with multiple values from this rangeoptions.data[i].samples{number} the fixed number of samples to be computed within the current domain endsoptions.data[i].implicit{boolean} true to creates samples for the function considering it implicit, it assumes that the function depends on the variables x and yoptions.data[i].secants{Object[]} Secants ofoptions.data[i].fnoptions.data[i].secants[j].x0{number} The abscissa of the first pointoptions.data[i].secants[j].x1{number} (optional ifupdateOnMouseMoveis set) The abscissa of the second pointoptions.data[i].secants[j].updateOnMouseMove{boolean} (optional) True to update the secant line by evaluatingoptions.data[i].fnwith the current mouse position (x0is the fixed point andx1is computed dynamically based on the current mouse position)
options.data[i].derivative{Object} Info of the instantaneous rate of change of y with respect to xoptions.data[i].derivative.fn{string} The derivative ofoptions.data[i].fnoptions.data[i].derivative.x0{number} The abscissa of the point which belongs to the curve represented byoptions.data[i].fnwhose tangent will be computed (i.e. the tangent line to the pointx0, fn(x0))options.data[i].derivative.updateOnMouseMove{boolean} True to compute the tangent line by evaluatingoptions.data[i].derivative.fnwith the current mouse position (i.e. letx0be the abscissa of the mouse position transformed to local coordinates, the tangent line to the pointx0, fn(x0))
options.data[i].graphOptions{Object} options passed to the the files located inlib/type/which plot the data generated by the library, the most useful property of this object istypewhich is used to determine the type of graph to be rendered for a function
options.plugins{array} An array describing plugins to be run when the graph is initialized, check out the examples on the main page
type{string} type of graph, currentlyline,scatterandintervalare supported,intervalis the default optionsampler{string} the sampler to use, currentlyintervalandbuiltInare supported (intervalshould be used withtype: 'interval'andbuiltInwithtype: 'line'ortype: 'scatter')
Depending on the type option:
options.closed{boolean} (only iftype: 'interval'ortype: 'line') True to close the path, for any segment of the closed area graphy0will be 0 andy1will bef(x)
xthe x-coordinate of a point to be sampled with a parametertythe y-coordinate of a point to be sampled with a parametertrange = [0, 2 * Math.PI]therangeproperty in parametric equations is used to determine the possible values oft, remember that the number of samples is set in the propertysamples
ra polar equation in terms ofthetarange = [-Math.PI, Math.PI]therangeproperty in polar equations is used to determine the possible values oftheta, remember that the number of samples is set in the propertysamples
fna function which needs to be expressed in terms ofxandy
instance.id{string} a random generated id made out of letters and numbersinstance.linkedGraphs{array} array of function-plot instances linked to the events of this instance, i.e. when the zoom event is dispatched on this instance it's also dispatched on all the instances of this arrayinstance.meta{object}instance.meta.margin{object} graph's left,right,top,bottom marginsinstance.meta.width{number} width of the canvas (minus the margins)instance.meta.height{number} height of the canvas (minus the margins)instance.meta.xScale{d3.scale.linear} graph's x-scaleinstance.meta.yScale{d3.scale.linear} graph's y-scaleinstance.meta.xAxis{d3.svg.axis} graph's x-axisinstance.meta.yAxis{d3.svg.axis} graph's y-axis
instance.root{d3.selection}svgelement that holds the graph (canvas + title + axes)instance.canvas{d3.selection}g.canvaselement that holds the area where the graphs are plotted (clipped with a mask)
Events
An instance can subscribe to any of the following events by doing instance.on([eventName], callback),
events can be triggered by doing instance.emit([eventName][, params])
mouseoverfired whenever the mouse is over the canvasmousemovefired whenever the mouse is moved inside the canvas, callback paramsx,y(in canvas space coordinates)mouseoutfired whenever the mouse is moved outside the canvasdrawemit this event to redraw the contents of the canvaszoom:scaleUpdatefired whenever the scale of another graph is updated, callback paramsxScale,yScale(x-scale and y-scale of another graph whose scales were updated)tip:updatefired whenever the tip position is updated, callback paramsx,y,index(in canvas space coordinates,indexis the index of the graph where the tip is on top of)evalfired whenever the sampler evaluates a function, callback paramsdata(an array of segment/points),index(the index of datum in thedataarray),isHelper(true if the data is created for a helper e.g. for the derivative/secant)
The following events are dispatched to all the linked graphs
all:mouseoversame asmouseoverbut it's dispatched in each linked graphall:mousemovesame asmousemovebut it's dispatched in each linked graphall:mouseoutsame asmouseoutbut it's dispatched in each linked graphall:drawsame asdrawbut it's dispatched in each linked graphall:zoom:scaleUpdatesame aszoom:scaleUpdatebut it's dispatched in each linked graphall:zoomfired whenever there's scaling/translation on the graph, dispatched on all the linked graphs
When the definite-integral plugin is included the instance will fire the following events
definite-integraldatum{object} The datum whose definite integral was computedi{number} The index of the datum in thedataarrayvalue{number} The value of the definite integrala{number} the left endpoint of the intervalb{number} the right endpoint of the interval
var y = functionPlot.eval.builtIn(datum, fnProperty, scope)Where datum is an object that has a function to be evaluated in the property fnProperty ,
to eval this function we need an x value which is sent through the scope
e.g.
var datum = {
fn: 'x^2'
}
var scope = {
x: 2
}
var y = functionPlot.eval.builtIn(datum, 'fn', scope)Every element of the data property sent to functionPlot is saved on instance.options.data,
if you want to get the evaluated values of all the elements here run
var instance = functionPlot( ... )
instance.options.data.forEach(function (datum) {
var datum = {
fn: 'x^2'
}
var scope = {
// a value for x
x: 2
}
var y = functionPlot.eval.builtIn(datum, 'fn', scope)
}Just call instance.programmaticZoom with the desired x and y domains
var instance = functionPlot( ... )
var xDomain = [-3, 3]
var yDomain = [-1.897, 1.897]
instance.programmaticZoom(xDomain, yDomain)After cloning the repo and running npm install
node site.js // generate the examples shown on index.html
npm startOpen 127.0.0.1:5555 and that's it! Local development server powered beefy
Plain demo: 127.0.0.1:5555/demo.html
2015 MIT © Mauricio Poppe