Releases: palantir/plottable
Scatterplot + Legend Symbols on IE
v0.51.0
Good afternoon,
Since non-scaling-stroke
does not work on Internet Explorer, we had to change our approach to drawing symbols. A SymbolFactory
now draws a particular symbol given a size; see below for what changes this causes to the API.
Bugfixes
- Stroke-width can now be set on symbols in Internet Explorer. Demo here: http://jsfiddle.net/ghcejh4z/
API-Breaking Changes
- The
SymbolGenerators
module has been renamed toSymbolFactories
- A
SymbolFactory
is now a function with the following signature:
(symbolSize: number) => string
where symbolSize is the edge-length of a square drawn as a tight bound around the symbol.
Legend
ssymbolGenerator
API has been reworked intosymbolFactoryAccessor
which takes in an accessor function that returns aSymbolFactory
. It has the following signature:
public symbolFactoryAccessor((datum: any, index: number) => SymbolFactory)
This allows selection of the SymbolFactory
to use based on the Legend
entry.
Upgrade Instructions
- Instead of using the
d3Symbol
SymbolFactory, one of the following endpoints should be used instead:
Plottable.SymbolFactories.square();
Plottable.SymbolFactories.circle();
Plottable.SymbolFactories.diamond();
Plottable.SymbolFactories.cross();
Plottable.SymbolFactories.triangleUp();
Plottable.SymbolFactories.triangleDown();
project()
calls for symbols have to be adjusted:
var squareGenerator = Plottable.SymbolFactories.square();
scatterplot.project("symbol", function(d, i) { return squareGenerator; });
- To set the size of points on
Plot.Scatter
,project()
on "size" instead of "r":
// before: project("r", 3);
scatterplot.project("size", 6); // size of square containing symbol, instead of radius of symbol
Release Song
Gold Rays -- Vinyl Pinups
https://www.youtube.com/watch?v=Izl8zFCWSjA
Interaction and API tweaks
v0.50.0
Features
component.above
and component.below
API
Before, there was a merge
API that allowed users to place components into a component group for the sake of the components sharing the same cell in the Plottable table.
However, this merge
API does not describe where the components will render in terms of which component will be on top and which component will be on bottom visually.
In fact, merge
essentially placed the calling component below the argument component (even though this is not well described).
Thus, merge
has been renamed to below
and above
has been created as its foil, where a.above(b)
will place a
on top of b
and a.below(b)
will place a
below b
.
The signatures of both API are as follows:
public above(c: AbstractComponent): Component.Group;
public below(c: AbstractComponent): Component.Group;
Bugfixes
- If undefined points are handed to
Plot.Scatter
, those points are not rendered as consistent with previous behavior. - As consistent with other browsers, the
stroke-width
on symbols onPlot.Scatter
does not scale with the transform by default.
API-Breaking Changes
Component.merge
has been renamed intoComponent.below
andComponent.above
now exists as its foil.
Typescript API-Breaking Changes
Interaction.DoubleClick
no longer extends fromInteraction.Click
as we are modifying the architecture ofInteraction.Click
without disrupting the behavior ofInteraction.DoubleClick
Other notes
Interaction.Hover
has been deprecated due toInteraction.Pointer
being released in the last release, which uses the newInteraction
architecture / structure.
Upgrade Instructions
- For those who want to keep existing functionality while using
Component.merge
, please replace all occurrences withComponent.below
. However, if a user wanted to place a component above another component instead while keeping the same code structure, replaceComponent.merge
withComponent.above
appropriately.
Future Changes
Coming Shortly:
Interaction.Click
Interaction.Drag
Interaction.Pan
+Interaction.Zoom
Release Song
"All the Small Things" --Blink 182
https://vimeo.com/32122929
Plot.Grid upgrades, Closest-Point methods, and Interaction upgrades
Good afternoon,
This release features an improved Plot.Grid
, a method for retrieving the closest PlotData
from a Plot
, a new Interaction
, and an upgrade to Dispatcher.Mouse
.
Features
The new Plot.Grid
built on Plot.Rectangle
Plot.Rectangle
is a new type of plot that draws rectangles given values for x1/x2
and y1/y2
. We are going to be gradually migrating all rectangle-based plots to this; in the meantime, there probably won't be a need for you to use Plot.Rectangle
directly unless you're doing some really crazy stuff (and if you are, we would love to hear about it!)
Plot.Grid
has been rearchitected to leverage Plot.Rectangle
. As a consequence, Plot.Grid
can now be used on both Category
and Quantitative
Scale
s. Plot.Grid
is initialized with an xScale, a yScale, and a colorScale. Projections on Plot.Grid
from various scales are as follows
Scale.Category
- In order to project data onto aGridPlot
using aScale.Category
, we need to project thex
/y
attribute on thexScale
/yScale
.Quantitative
Scale
s - In order to project data onto aGridPlot
using aQuantitative
Scale
(could includeScale.Time
,Scale.Linear
,Scale.ModifiedLog
), you have to project the lower bound asx/y
and the upper bound asx2/y2
.
Existing instances of Plot.Grid
should continue to work with no modification needed; this feature simply added more functionality to the existing API points.
Examples of Plot.Grid
with (1) a Scale.Time
on the X-axis and a Scale.Linear
on the Y-axis and (2) a Scale.Time
on the X-axis and a Scale.Category
on the Y-axis can be found at the following link: http://jsfiddle.net/L861y4s1/1/
getClosestPlotData()
on Plot
s
Similar to how Plot
s have a getAllPlotData
API, there is now a getClosestPlotData()
API on Plot
s. The signature is
public getClosestPlotData(queryPoint: Point, withinDistance = Infinity, datasetKeys: string | string[] = this.datasetOrder())
As seen from the signature above, getClosestPlotData
takes in a Point
to find the PlotData
closest to that point within the withinDistance
for all Dataset
s listed in datasetKeys
.
The calculation is done by looping through each of the pixelPoint
s from getAllPlotData()
, finding the closest point, and reporting the appropriate selection
/ data
information under the given circumstances.
This method treats all Plot
s as though their data values are represented by a single point (because it uses the pixelPoint
property of the PlotData
for computing distance); for example, it does not take the shape of the bars into account when finding the closest PlotData
on Plot.Bar
. getAllPlotData()
can be used to implement alternative closest-point algorithms, in conjunction with generateProjectors()
to account for additional shape information.
Interaction.Pointer
Interaction.Pointer
has been added. This Interaction
triggers callbacks when the user mouses into a Component
, moves the mouse within the Component
, or mouses out of the Component
. Example usage:
var pointerInteraction = new Plottable.Interaction.Pointer();
pointerInteraction.onPointerMove(function(p) {
// do something with the point p, maybe call getClosestPlotData()
});
pointerInteraction.onPointerExit(function(p) {
// some code that cleans up
});
plot.registerInteraction(pointerInteraction);
onWheel()
API on Dispatcher.Mouse
The onWheel()
method has been added Dispatcher.Mouse
. This method can be used to register callbacks to be called when the scroll-wheel on the mouse is activated. The signature is
public onWheel(key: any, callback: MouseCallback): Dispatcher.Mouse
Wheel data can be retrieved from the Event
passed to the MouseCallback
.
Bugfixes
Plot.Line
used to return one<line>
selection per datum in itsPlotData
, even though the line represents the entireDataset
. Now it returns only one<line>
selection perDataset
.
Upgrade SVG Typewriter version
This brings the version of D3 used by SVG Typewriter in line with that used by Plottable.
Symbols, and Backgrounds, and Data, oh my!
v0.48.0
Features
SymbolGenerator
s
A SymbolGenerator
is a function that, given a datum and index, returns a String
representing the d
attribute of an SVG <path>
element:
type SymbolGenerator = (datum: any, index: number) => string;
The SymbolGenerator
produces a path-string assuming the <path>
has a 100px by 100px space in which to render.
Some default SymbolGenerator
s have been included under Plottable.SymbolGenerators.d3Symbol()
; for example,
Plottable.SymbolGenerators.d3Symbol("square");
returns a SymbolGenerator
that draws squares. The supported symbol types are "circle", "square", "cross", "diamond", "triangle-up", and "triangle-down".
Symbols on Plot.Scatter
Plot.Scatter
now uses a SymbolGenerator
to determine the type of symbol rendered, rather than always rendering circles. project()
-ing on to the "symbol"
property will change the type of symbol drawn. For example:
scatterPlot.project("symbol", Plottable.SymbolGenerators.d3Symbol("square"));
will cause the Plot.Scatter
to draw squares. As usual, the projector can be data-dependent:
var upVsDown = Plottable.SymbolGenerators.d3Symbol(function(d, i) {
if (d.y > 0) {
return "triangle-up";
} else {
return "triangle-down";
}
});
scatterPlot.project("symbol", upVsDown);
The above code will cause different types of symbols to be shown depending on the y
property of each datum:
Plot.Scatter
will use a circle as the default symbol if one is not specified.
Symbols on Legend
Similarly, Legend
s now take a SymbolGenerator
:
legend.symbolGenerator(Plottable.SymbolGenerators.d3Symbol.d3Symbol("square"));
Will cause the Legend
to display squares instead of circles. The SymbolGenerator
is passed the Legend
entries as arguments, allowing different symbols to be displayed for different entries:
colorScale.domain(["good", "neutral", "bad"]);
var legend = new Plottable.Component.Legend(colorScale);
var nameToSymbol = {
"good": "triangle-up",
"neutral": "square",
"bad": "triangle-down"
};
var generator = Plottable.SymbolGenerators.d3symbol(function(entryName, i) {
return nameToSymbol[entryName];
});
legend.symbolGenerator(generator);
Symbols on Legend
are marked with the legend-symbol
CSS class if users want to style them.
background-fill
on Component
s
Component
s now feature a <rect>
in their background container that allows their background to be colored. For example, this CSS
.plottable .plot .background-fill {
fill: pink;
}
Will color the background of all Plot
s pink:
If multiple Plot
s are in a Group
, a more specific rule needs to be used to color only the background-fill
of the Group
:
.plottable .component-group > .background-container background-fill {
fill: pink;
}
content()
accessor
Component
s now have a content()
method that retrieves the D3.Selection
that they draw in, in the event that users want to use D3 to manipulate elements the Component
has drawn. See below for an example use case.
Legend
s no longer apply CSS classes based on entry names
Legend
s no longer apply the name of the entry as a CSS class to the entry's <g>
. To restore this behavior, add the following code:
legend.content().selectAll("." + Plottable.Component.Legend.LEGEND_ENTRY_CLASS)
.each(function(d) {
d3.select(this).classed(mySanitizingFunction(d), true);
});
This allows users to specify their preferred CSS sanitizing function (for removing spaces from the applied names, for example).
Exclude argument in getAllSelections()
plot.getAllSelections()
now takes an exclude argument:
public getAllSelections(datasetKeys?: string | string[], exclude = false): D3.Selection
The optional exclude
argument that defaults to false. If exclude
is set to true, then all Dataset
s in the Plot
will be queried except the ones specified by the datasetKeys
argument.
getAllPlotData()
plot.getAllPlotData()
returns a PlotData
object containing all of the data, pixelPoints, and the selections for the specified Dataset
(s):
export type PlotData = {
data: any[];
pixelPoints: Point[];
selection: D3.Selection;
}
The pixelPoints
property will depend on the type of Plot
. For example, the returned Point
s will be in the center of the symbols on a Plot.Scatter
, but on a Plot.Bar
the Point
s in the center-top of the bars (or center-bottom if the bar has a negative value).
generateProjectors()
When a user passes projector information through plot.project
, Plottable stores this "projector" information to render those attributes on the plot (along with defaults if those attributes have not been set). Users now have access to this information through the generateProjectors()
call. This API point allow access to the "projected" information the plot uses, such as the x and y pixel values corresponding to the positions of data points, without having to inspect the rendered <svg>
.
The signature is:
public generateProjectors(datasetKey: string): AttributeToAppliedProjector
An AttributeToAppliedProjector
is an object maps attribute strings to a projector, which is a function that takes in a datum and an index that returns an arbitrary value:
type AttributeToAppliedProjector = { [attrToSet: string]: AppliedProjector; };
type AppliedProjector = (datum: any, index: number) => any;
An example usage:
var projectors = linePlot.generateProjectors(datasetKey);
var xProjector = projectors["x"];
var yProjector = projectors["y"];
var pixelPositions = linePlotData.map(function(datum, index) {
return {
x: xProjector(datum, index),
y: yProjector(datum, index)
};
});
// use the pixelPositions to calculate a closest point or something...
API-Breaking Changes
Scale.Ordinal
has been renamed toScale.Category
because its function deviates from the vanilla D3 ordinal scale (#1210).- The animators on
Plot.Scatter
have been renamed from "circles"/"circles-reset" to "symbols"/"symbols-reset" asPlot.Scatter
now renders symbols instead of circles.
Other notes
- Plottable has upgraded D3 to v3.5.5.
Restoring Interaction.Hover on mobile
This release fixes a regression caused in our last release, where Interaction.Hover
stopped responding to Touch events as we switched from using D3 to writing our own implementation. We wrote Dispatcher.Touch
to solve this problem. Mobile functionality for Interaction.Hover
should now resemble functionality from v0.45.0 and before.
This release is occurring off-schedule in order to supply a fix for the regression as soon as possible. Note the version number change, which reflects the addition of new API points (see below).
v0.47.0
Features
Dispatcher.Touch
Dispatcher.Touch
has been added. This Dispatcher
reports the first touch position relative to the <svg>
on touchstart
, touchmove
, and touchend
events. Example usage:
var touchDispatcher = Plottable.Dispatcher.Touch.getDispatcher(svgElement);
touchDispatcher.onTouchStart("dispatcherKey", touchStartCallback);
touchDispatcher.onTouchMove("dispatcherKey", touchMoveCallback);
touchDispatcher.onTouchEnd("dispatcherKey", touchEndCallback);
Events passed to Dispatcher
callbacks.
Dispatcher
callbacks are now passed the original Event
object, to allow for more customization of behavior. One example might be to call preventDefault()
to suppress text-selection or other behavior.
Bugfixes
Interaction.Hover
now responds totouchstart
events. Initiating the touch event will have the same effect as moving the mouse to that position.Scale.Time
no longer locks up if both ends of the domain are set to the same value (#1689).
Upgrade Instructions:
Typescript Users: Please add the touch-events
type definitions to your project.
Progress towards Improved Interactions
v0.46.0
Features
onMouseDown()
and onMouseUp()
added to Dispatcher.Mouse
Users can now register callbacks to Dispatcher.Mouse
to be called when mousedown
and mouseup
events occur, using onMouseDown()
and onMouseUp()
:
var md = Plottable.Dispatcher.Mouse.getDispatcher(svgElement);
var downCallback = function(point) {
// do something with the point on mousedown
};
var upCallback = function(point) {
// do something with the point on mouseup
};
md.onMouseDown("callbackKey", downCallback);
md.onMouseUp("callbackKey", upCallback);
...
md.onMouseDown("callbackKey", null); // to remove the callback
md.onMouseUp("callbackKey", null); // to remove the callback
Bugfixes
- When
Axis.Category
labels are rotated, the text wrapping that is applied is far less aggressive than before. (#1526). - Right oriented
Axis.Category
respects tick marks now. (#1646). Scale.Time
no longer locks up if both ends of the domain are set to the same value (#1689).
Other notes
The new Dispatcher.Mouse
doesn't trigger events correctly on mobile devices. We expect a fix in 1-2 weeks.
Future
This week we began work on:
Interaction.Dragbox
- an API endpoint which will return the closest data point to any position on the graph.
Expect to see these soon!
Hotfix for Axis.Category
Category Y-Axes were doing incorrect space calculations when next to an empty cell. This caused the text to not show up in certain cases.
Hotfix for Dispatcher.Mouse
Good afternoon,
This release includes a hotfix for Dispatcher.Mouse
. The measure-rect
it uses to compute the mouse position has been styled to visibility: hidden
, to prevent accidental selection of text arising from clicking on the measure-rect
.
Dispatchers, getAllSelections, and Flipped Axes
TL;WR
- You can now use getAllSelections to get just one dataset, instead of all data associated with a plot.
- Hover (
Dispatcher.Mouse
) and Key (Dispatcher.Key
) interactions now work correctly even when aComponent
orPlot
is scaled with CSS. Axis.Numeric
now supports reversed scales.
v0.45.0
Features
getAllSelections()
Plot.getAllSelections
now take in a string or an array of strings as arguments to the API endpoint. The input should be the dataset key(s) that allow the plot to retrieve the selections associated with that dataset. If no input is given, then all selections will be retrieved as per previous behavior. If a single string is given, then only that dataset will be retrieved. If an array is given, all specified datasets will be retrieved. Invalid dataset keys are ignored.areaPlot.getAllSelections
now retrieves the line path elements on an areaPlot as well as the area path elements.
Dispatchers
A number of major changes have occurred on Dispatcher
s:
General
Dispatcher
s now use a factory pattern. Instead of invoking the constructor directly, use the staticgetDispatcher()
method of the class.Dispatcher
s no longer have to beconnect()
ed anddisconnect()
ed manually.
Dispatcher.Mouse
Dispatcher.Mouse
now uses a different method of computing the mouse position. A givenDispatcher.Mouse
is associated with a particular<svg>
and will now account for CSStransform: scale()
effects applied to that<svg>
(or one of its ancestor nodes).Dispatcher.Mouse
will report the new mouse position relative to its<svg>
every time the mouse position changes. It is up to users to confirm that this position is inside aComponent
of interest, using theComponent
'swidth()
,height()
, andoriginToSVG()
methods.
Dispatcher.Key
Dispatcher.Keypress
has been refactored asDispatcher.Key
.Dispatcher.Key
now reportskeydown
events that occur anywhere on the page. It can be used in conjunction with focus-testing orDispatcher.Mouse
to implement more complex behaviors.
NumericAxis
- NumericAxis now handles inverted domains. For example, if a NumericAxis is constructed with a
LinearScale
with domain set asscale.domain([6, 0])
, the axis will be rendered from 6 to 0, left to right.
Bugfixes
- When
Axis.Category
does its space calculation, it used to report that it would only want more space if the labels did fit and would not want more space if labels did not fit... This has been corrected such that when labels that do not fit,Axis.Category
will try to get more space. - Ticks are now only rendered on a valid domain (#1578)
API-Breaking Changes
- There are a number of breaking changes related to
Dispatcher
s; please see the "Upgrade Instructions" for more details:- constructors should no longer be invoked directly
connect()
anddisconnect()
calls removedmouseover()
,mousemove()
, andmouseout()
calls removed in favor ofonMouseMove()
(Dispatcher.Mouse
)Dispatcher.Keypress
renamed toDispatcher.Key
,onKeyDown
now takes different arguments.
ResizeBroadcaster
has been removed, and theresize()
method ofAbstractComponent
has been renamedredraw()
. We find that the user often has a better sense of when to redraw, and with an exposed API point for redraws, users should be able to write this implementation themselves. For example, the following is a way to replicate the original ResizeBroadcaster behavior on a pie chart that occupies the entire screen:
var plot = new Plottable.Plot.Pie().addDataset(data).project("value", "value").renderTo(svg);
window.addEventListener('resize', function(event) {
plot.redraw();
});
Broadcaster
now passes correctly arguments to its callbacks one at a time, rather than as an array ofany[]
s (#1583).
Upgrade Instructions
- Here is the new way to use a
Dispatcher.Mouse
:
svgElement = d3.select("#mySVG").node(); // get the <svg>
var md = Plottable.Dispatcher.Mouse.getDispatcher(svgElement);
var callback = function(point) {
// do something with the point
};
md.onMouseMove("callbackKey", callback);
...
md.onMouseMove("callbackKey", null); // to remove the callback
- Here is the new way to use a
Dispatcher.Key
:
var kd = Plottable.Dispatcher.Key.getDispatcher();
var callback = function(keyCode) {
if (keyCode === keyCodeOfInterest) {
// do something;
}
}
kd.onKeyDown("callbackKey", callback);
...
kd.onKeyDown("callbackKey", null); // to remove the callback
ResizeBroadcaster
has been removed. An example of how to replicate its behavior:
var plot = new Plottable.Plot.Pie().addDataset(data).project("value", "value").renderTo(svg);
window.addEventListener('resize', function(event) {
plot.redraw();
});