Releases: palantir/plottable
Typescript Upgrades and Bugfixes
Good Afternoon,
This release took care of a lot of requested bugfixes, cleaned up the visual appearance of Axis.Time
further, and contains several Typescript upgrades. It also contains several breaking changes in preparation for v1.0, so please look at the breaking changes section if you were using Axis.Time
or are developing in TypeScript.
Features
- Setting a reversed domain on a
Scale.Time
will now throw an error.
Bugfixes
- Components are now hidden when the SVG is hidden in Firefox (#1033).
- AreaPlot and LinePlot now retain their respective path classes after class is set via a project call (#1286).
Interaction.Drag
'sdragend()
call is now constrained within itsComponent
's hitbox (#1445).- The
end-tick-mark
class is now accessible on TimeAxis end ticks (#1575). - TimeAxis rendering issues have been fixed (#1609).
API-Breaking Changes
- As per the migration to use the "type" structure, the
TimeAxisConfiguration
interface has been converted to just be an aliased type of aTimeAxisTierConfiguration
array. Thus theTimeAxisConfiguration
no longer has a "tierConfiguration" parameter that holds the array. - The
listenable
field of aBroadcaster
has been made private (and renamed to_listenable
).
Typescript API Breaks
- As of now, we are now incorporating features from Typescript 1.4 that did not exist in Typescript 1.3. As a result, our library is now incompatible with Typescript 1.3.
- Many "interfaces" have been converted to the more simpler "type" structure using the type aliasing feature introduced in Typescript 1.4 (http://blogs.msdn.com/b/typescript/archive/2015/01/16/announcing-typescript-1-4.aspx), and thus cannot be extended or implemented as an interface would be.
Broadcaster
changes:
- The
Listenable
type has been removed, andBroadcaster
s can now broadcast about arbitrary types. Broadcaster
s now use generics to specify what they are broadcasting about; for example, aBroadcaster<Dataset>
will pass aDataset
to its callbacks.- The
listenable
field of aBroadcaster
has been made private (and renamed to_listenable
).
Other notes
- Typescript users - Union typing has now been introduced into the library as it is introduced in Typescript 1.4 (http://blogs.msdn.com/b/typescript/archive/2015/01/16/announcing-typescript-1-4.aspx). This gives us a bit more flexibility in how we write and design our API endpoints.
Upgrade Instructions
- If you were using a
TimeAxisConfiguration
object to store your tier configurations, they no longer have the configurations stored in a "tierConfiguration" parameter. Instead theTimeAxisTierConfigration
array is instead itself aTimeAxisConfiguration
. - Typescript users - Please upgrade to Typescript 1.4
- Typescript users - Remove any references to the
Listenable
type.Broadcaster
s should be initialized with a generic type corresponding to what they are broadcasting about.
Hotfix for Axis.Time
Tick marks showing the ends of the first and last time periods on Axis.Time
were not being drawn. This release contains a hotfix for that bug (#1606).
Ordinal Scale Revamp, Origin Methods
Good afternoon,
This release features some major changes to Scale.Ordinal
, as well as methods for querying the origin of Component
s.
Features
Scale.Ordinal
revamp
Scale.Ordinal
used to have two modes for how they map their domain onto the range: "points" and "bands". Not only did this create confusion, but somePlot
s would render inconsistently if theScale
was in the wrong mode.Scale.Ordinal
now has only one mode.- The
scale()
method onScale.Ordinal
now scales to the center of the band, not the start:
innerPadding()
andouterPadding()
are now defined as proportion of the band width.innerPadding
is defined as the padding in between bands.outerPadding
is defined as the padding between the outer bands and the edge of the scale.fullBandStartAndWidth()
has been removed in favor ofstepWidth()
.stepWidth()
method returns the distance between successive values on the scale, in pixels.
Component
Origin Methods
Two methods have been added to Component
s:
origin()
gets the location of the Component's upper-left-corner relative to its parent.originToSVG()
gets the location of the Component's upper-left corner relative to the root<svg>
node.
Bugfixes
Bar
plots now account for the ends of theScale
when automatically computing bar widths.Axis
labels are now confined to theAxis
's bounding-box within the<svg>
(#1501)- End ticks are consistently visible on both ends of an
Axis.Time
(#1509) - Tick labels now show up at regular intervals (#1196)
API Breaks
innerPadding()
andscale()
methods onScale.Ordinal
now behave very differently.fullBandStartAndWidth
has been renamed and revamped intostepWidth()
Upgrade Instructions
- The
innerPadding()
method onScale.Ordinal
used to return the padding in pixels; now it returns the padding as a proportion of the band width.ordinalScale.bandWidth() * ordinalScale.innerPadding()
will calculate the padding in pixels. - Since
scale()
now returns the position corresponding to the middle of the band,ordinalScale.scale(value) - ordinalScale.rangeBand() / 2
will yield the position at the start of the band. fullBandStartAndWidth()
can be replaced by the above calculation andstepWidth()
.
Future Changes
- As we have upgraded our library to use Typescript 1.4, we are moving in the near future to actually use some of its features like union typing. Our library as of the current moment should still be compatible with Typescript 1.3, but we will not be compatible with it in the near future.
InterpolatedColorLegend, getAllSelections()
Good afternoon,
Today's release adds a legend for InterpolatedColor
scales, as well as an API point for retrieving the DOM nodes forming a Plot
's visualization.
Features
InterpolatedColorLegend
InterpolatedColorLegend
has been added. This Component
visualizes a Scale.InterpolatedColor
, providing some context as to what the colors represent. The constructor:
constructor(interpolatedColorScale: Scale.InterpolatedColor, orientation?: string, formatter?: Formatter);
The InterpolatedColorLegend
supports three orientations: "horizontal" (default, shown above), "left", and "right":
`"left"` | `"right"` |
It also accepts a Formatter
(the same kind passed to an Axis
), which can be used to format the labels:
As with other Plottable Component
s, CSS can be used to restyle it:
getAllSelections()
The getAllSelections()
method has been added to Plot
s. This method retrieves the DOM nodes associated with a Plot
's visualization as a D3.Selection
: on a Plot.Line
, it will retrieve the <path>
elements, on a Plot.Scatter
it will retrieve the <circle>
s, etc. This API point should open up more possibilities for dynamic styling and interactivity.
Bugfixes
Plot.Pie
now displays warnings in the console when if populated with negative data values (1505). As before, console warnings can be suppressed by setting Plottable.Config.SHOW_WARNINGS
to false
.
API-Breaking Changes
barPlot.getAllBars()
has been removed in favor of getAllSelections()
.
Other notes
The color of text in Legend
and InterpolatedColorLegend
has been changed to match that used on Axis
. See plottable.css for details.
Upgrade Instructions
If you were using barPlot.getAllBars()
, please replace that call with barPlot.getAllSelections()
.
Future Changes
To go with getAllSelections()
, we plan to implement methods for retrieving selections associated with specific Dataset
s, or associated with specific pixel positions / ranges (similar to the existing getBars()
API point on Bar
plots).
PanZoom and Scale.Color bugfixes
Good evening,
Tonight's release includes fixes for Interaction.Panzoom
and Scale.Color
:
Interaction.Panzoom
now properly updates when the domain of either of itsScale
s changes (#1388).Scale.Color
now works with named colors ("blue", "green", etc) in its range (#1527).
Other notes
As of this release, Plottable is now using Typescript 1.4, which introduces union types, amongst other things. Details can be found here: http://blogs.msdn.com/b/typescript/archive/2015/01/16/announcing-typescript-1-4.aspx
Unified Plot.Bar, StackedPlot dataset update
Good morning,
This release includes a bugfix for stacked Plot
s (StackedArea
, StackedBar
), as well as the removal of Plot.VerticalBar
and Plot.HorizontalBar
from the API.
Bugfixes
Scales on stacked Plot
s now update correctly when Dataset
s are updated (#1246).
API Breaks
Plot.VerticalBar
and Plot.HorizontalBar
have been removed from the codebase, as warned in the release notes for v0.40.0. Please use Plot.Bar
from this point forward.
Upgrade Instructions
As noted in the previous release, you will need to change references to Plot.VerticalBar
and Plot.HorizontalBar
as follows:
new Plot.VerticalBar(xScale, yScale) → new Plot.Bar(xScale, yScale, true)
new Plot.HorizontalBar(xScale, yScale) → new Plot.Bar(xScale, yScale, false)
In addition, invocations of barAlignment()
on Plot.HorizontalBar
also should be updated:
horizontalBarPlot.barAlignment("top") → barPlot.barAlignment("left")
horizontalBarPlot.barAlignment("bottom") → barPlot.barAlignment("right")
Improved Layout, Improved Text, and Unified Bar Plot
Features
Unified Plot.Bar
Plot.HorizontalBar
andPlot.VerticalBar
have been merged into a single classPlot.Bar
. In order to choose between the two, an additional parameter has been added to thePlot.Bar
constructor specifying if thePlot.Bar
should be vertical (default true):
/**
* Constructs a Bar plot.
*
* @constructor
* @param {Scale} xScale The x scale to use.
* @param {Scale} yScale The y scale to use.
* @param {boolean} isVertical if the plot if vertical.
*/
constructor(xScale: Scale.AbstractScale<X, number>,
yScale: Scale.AbstractScale<Y, number>,
isVertical = true) {
The classes Plot.HorizontalBar
and Plot.VerticalBar
have been deprecated.
Bugfixes
svg-typewriter
Writing text in SVG has always been tricky. The svg text spec indicates that "SVG performs no automatic line breaking or word wrapping", meaning that developers have to implement this functionality themselves; In addition, it is difficult to accurately measure the size of text without writing it.
We have switched to using svg-typewriter to resolve these problems. Consequently, a number of issues related to text have been fixed.
SVG Typewriter was developed by @endrjuskr. The library is inlined within Plottable as part of our build process, so there are no changes required to develop using Plottable.
Improved Layout Engine
@endrjuskr has updated our layout engine, which powers the Table
Component. In conjunction with the switch to svg-typewriter, this change solves some strange behavior on Axis.Category
, as well as other bugs such as #936
API Breaks
Aside from the now-deprecated Plot.HorizontalBar
, the barAlignment()
method on Bar Plots now only accepts "left"
, "center"
, and "right"
as alignment choices, regardless of if the Plot
is vertical or horizontal.
Typescript API Breaks
Plot.AbstractBar
has been renamed to Plot.Bar
. References to Plot.AbstractBar
should be changed to references to Plot.Bar
.
Upgrade Instructions
You will need to change references to Plot.VerticalBar
and Plot.HorizontalBar
as follows:
new Plot.VerticalBar(xScale, yScale) → new Plot.Bar(xScale, yScale, true)
new Plot.HorizontalBar(xScale, yScale) → new Plot.Bar(xScale, yScale, false)
In addition, invocations of barAlignment()
on Plot.HorizontalBar
also should be updated:
horizontalBarPlot.barAlignment("top") → barPlot.barAlignment("left")
horizontalBarPlot.barAlignment("bottom") → barPlot.barAlignment("right")
Release Song
Time to Say Goodbye (to layout bugs).
Legend Upgrades
Good afternoon,
This release features upgrades to Legend
.
Legend upgrades
HorizontalLegend
andLegend
have been merged into a single class,Legend
.Legend
now features amaxEntriesPerRow(numEntries)
API point. TheLegend
will draw at most numEntries entries per row (default 1), although it may draw fewer if the space is constrained. SettingmaxEntriesPerRow(Infinity)
on aLegend
will replicate the behavior ofHorizontalLegend
.Legend
also features agetEntry(<Point>)
method, which can be used to retrieve theLegend
entry under a given point. This method should be useful in implementing customInteraction
behavior onLegend
; see "API-Breaking changes and Upgrade Instructions", below.- The order of entries on a
Legend
can now be set using thesortFunction()
method, which takes a compareFunction similar to that supplied to the nativesort
function. Example comparators:
function alphabetize(a, b) {
return (a < b) ? -1 : 1;
}
function reverseDomain(a, b) {
var domain = colorScale.domain();
return domain.indexOf(b) - domain.indexOf(a);
}
Other features
- The
foreground
,background
, andhitBox
Selections onComponent
can now be retrieved withforeground()
,background()
, andhitBox()
. - A Plottable object's ID can now be retrieved through the
getID()
API call. The IDs are unique per loading of the Plottable library.
Bugfixes
Component
s in aGroup
now respect the alignments set usingxAlign()
andyAlign()
(#1255).automaticallyAdjustXScaleOverVisiblePoints
andautomaticallyAdjustYScaleOverVisiblePoints
now work onPlot.StackedBar
andPlot.StackedArea
.
Typescript Upgrade
One month ago, Typescript 1.3 was released. We have now upgraded to the 1.3 compiler to take advantage of its new features, in particular the protected keyword. We have now changed class fields to the protected scope where appropriate. If you are developing on Plottable, please be sure to upgrade to Typescript 1.3.
API-Breaking changes and Upgrade Instructions
HorizontalLegend
has been merged intoLegend
. All uses ofHorizontalLegend
should be replaced withLegend
. You will need to callmaxEntriesPerRow(Infinity)
on theLegend
to get the behavior ofHorizontalLegend
.Legend
no longer has built-in API points for setting click and hover callbacks. While this structure was convenient, the correct way to build click and hover interactivity is usingInteraction
s, not by attaching the logic toLegend
. Click interactivity on Legend can be reconstructed as follows:
var click = new Plottable.Interaction.Click();
click.callback(function(point) {
var entry = legend.getEntry(point);
if (!entry.empty()) {
// entry is a D3 selection, so apply classes, etc
...
var data = entry.data()[0]; // retrieve the data
...
}
});
legend.registerInteraction(click);
- We plan to extend the capabilities of
Interaction.Hover
toLegend
shortly. For details on a workaround, please contact us.
Release Song
Hover Interactivity for Stacked Area, API Changes for Consistency
Good afternoon,
Today's release adds hover interactivity to stacked area plots, and features some updates to improve the consistency of our API. Read on for more details.
Features
Interaction.Hover
now works with Plot.StackedArea
. Note that, as for Plot.StackedBar
, the original data value will be returned, not the stacked value.
Whenever a domain value is scaled with Plottable.Scale.Color
and the domain's length is greater than the range length, the returned scale value will be lightened in accordance to how many times the range has looped around to reach the scaled value.
API Breaking Changes
Removal of default accessors
Previously, most Plot
s were packaged with default accessors that looked for "x" and "y" attributes on the data. Essentially, the following lines were run when a Plot
was constructed:
this.project("x", "x", xScale); // default accessor
this.project("y", "y", yScale); // default accessor
While sometimes convenient, the default accessors would sometimes return undefined or invalid data. Their presence made it difficult for the Plottable code to reason about when the user had completed setting up a Plot
and it was safe to autodomain the scales or calculate the stacking offsets. Rather than try to reason about if a given projector was valid (a tricky problem if, for instance, the user meant to plot null
or undefined
values), we now operate under the assumption that if the user calls project()
, the supplied accessor is valid.
Similarly, the default value
accessor has been removed from Plot.Pie
.
deselectAll() removed
The deselectAll()
method has been removed from Bar plots. deselectAll()
removed the "selected" CSS class from all bars in a bar Plot
; With the removal of selectBar()
in v0.37.0, deselectAll()
no longer made sense.
Typescript API-Breaking Changes
Plot.StackedArea
now extends from Plot.Area
instead of Plot.AbstractStacked
.
Other notes
Plottable has a number of protected/private internal variables and methods. We have now prefixed these fields with an underscore to indicate to the user that they should not be using them. Be warned that using/accessing these fields may result in behavior that you may not expect, as changes to these fields may break your code silently. Please use such variables/methods with extreme caution.
Upgrade Instructions
- If you were previously relying on the default accessor behavior, as described above, add the following two lines after an XY-
Plot
is created:
xyPlot.project("x", "x", xScale);
xyPlot.project("y", "y", yScale);
- Similarly, if you were relying on the default accessor behavior for
Plot.Pie
, add the following line after creating thePlot.Pie
:
piePlot.project("value", "value");
- If you were using
deselectAll()
, please replace it with the following line:
barPlot.getAllBars().classed("selected", false);
Future Changes
- We are planning to lighten up the
Plot
constructors by having them no longer takeScale
s as arguments. ThexScale
andyScale
arguments to thePlot
are essentially redundant since the scales will be applied during the relevantproject()
calls, meaning that the constructor arguments are not particularly useful. - @endrjuskr has been working on a library for manipulating SVG text. We are looking to start using this library in Plottable, which should improve the behavior of text in
Axis
,Legend
, and other places within Plottable.
Release Song
Resizeable Drag Boxes, Bar Selection Improvements, Metadata, Time Axis Configuration
Good evening,
Tonight's release features improvements to bar selection, metadata in accessors, and configurable time axes.
Features
Resizeable Dragboxes
Drag boxes created with Interaction.DragBox
, Interaction.XDragBox
, and Interaction.YDragBox
can be resized by dragging the sides or the corners of the box.
This feature can be enabled by calling resizeEnabled(true)
. Here is an example:
http://jsfiddle.net/2q1kojwn/
Bar Selection
getBars()
has been added to Bar Plots. The function takes in x and y pixel values or extents ({min: number, max: number}
) and returns aD3.Selection
consisting of any bars under the point/line/area. UnlikeselectBar()
, the bars will not receive theselected
class.getAllBars()
has been added to Bar Plots. When called,getAllBars()
will return aD3.Selection
that contains all the bars in that plot.
These two methods should make it easier to write Interaction
callbacks.
Plot Metadata
Accessors passed to the project()
call on Plot
s can now take up to four arguments:
(datum: any, index?: number, userMetadata?: any, plotMetadata?: Plot.PlotMetadata) => any;
The third argument, userMetadata
, consists of metadata that has been added to a Dataset
object; see the "Bugfixes" section for more details.
The fourth argument, plotMetadata
, contains plot-specific information. Currently, it contains only datasetKey
, the key associated with the Dataset
being plotted. This feature can be used to differentiate datasets in a Plot
:
var colorScale = new Plottable.Scale.Color("Category20b");
var dataset = new Plottable.Dataset(data);
var plot = new Plottable.Plot.Scatter(xScale, yScale)
.addDataset(dataset)
.project("fill", function (d, i, u, m) { return m.datasetKey; }, colorScale);
Time Axis Intervals
We've been meaning for a while to provide more control over the ticks on the multi-tiered Axis.Time
.
axisConfigurations()
can be used to get or set the current configurations of the axis. Currently, a TimeAxisConfiguration
consists of an array of TimeAxisTierConfiguration
s, one for each tier of the Axis:
interface TimeAxisConfiguration {
tierConfigurations: TimeAxisTierConfiguration[];
}
Currently, up to two tiers are supported. A TimeAxisTierConfiguration
specifies how the Axis should generate ticks and how to format the corresponding labels. A TimeAxisTierConfiguration
consists of an interval (a time unit), a step (the number of units), and a formatter:
interface TimeAxisTierConfiguration {
interval: D3.Time.Interval;
step: number;
formatter: Formatter;
};
For example, the following TimeAxisTierConfiguration
:
{interval: d3.time.hour, step: 3, formatter: Formatters.time("%I %p")}
will produce a tier with ticks every three hours, formatted as 12-hour time: 12 AM, 3AM, 6AM, etc.
Given an array of TimeAxisConfiguration
s, the Axis.Time
will iterate through the array to find the first TimeAxisConfiguration
until it finds one where the first generated tick will fit. It will then draw using that configuration, hiding any tick labels that do not fit.
For more on how ticks are generated please refer to D3 Time Scales.
Bugfixes
Dataset
metadata is now correctly passed to accessors (see "Plot Metadata", above). Thus, an alternative way of coloring a series in a plot is:
var dataset = new Plottable.Dataset(data, { color: red } );
var plot = new Plottable.Plot.Scatter(xScale, yScale)
.addDataset(dataset)
.project("fill", function (d, i, u, m) { return u.color; });
API Breaks
- BarHoverInteraction has been removed, as per the warning in v0.34.0's release notes.
Formatters.time()
has been moved toFormatters.multiTime()
.Formatters.time()
now pipes through tod3.time.format
. For more on specifiers, please see https://github.com/mbostock/d3/wiki/Time-Formatting#format.- 'selectBar()' has been removed from
AbstractBarPlot
and has been restructured into 'getBars()'.
Other notes
We're bringing back release songs.
Upgrade Instructions
If you were using Interaction.BarHover
, you should instead attach an Interaction.Hover
onto an Bar Plot like so:
var hoverInteraction = new Plottable.Interaction.Hover();
hoverInteraction.onHoverOver(hoverOverCallback);
hoverInteraction.onHoverOut(hoverOutCallback);
barPlot.hoverMode("point"); // or "line"; "point" by default
barPlot.registerInteraction(hoverInteraction);
- Replace all previous uses of
Formatters.time()
withFormatters.multiTime()
. - The old behavior of 'selectBar()' can be replicated by using the new 'getBars()' API and then applying the
selected
class as appropriate:
var barToSelect = barPlot.getBars(x, y);
barToSelect.classed("selected", true);