Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chartBuilder - a component that associates components with the chartLayout #188

Merged
merged 2 commits into from
Jan 6, 2015
Merged

chartBuilder - a component that associates components with the chartLayout #188

merged 2 commits into from
Jan 6, 2015

Conversation

ColinEberhardt
Copy link
Member

Currently resizing the chart, or updating the data, requires quite a lot of structural code:

https://github.com/ScottLogic/d3-financial-components/blob/gh-pages/getting-started.md#rendering-dynamic-charts

My suggestion is to use our chartLayout component to manage the axes, series and any other components that make up a chart.

In order to render a chart, you construct axes, scales, series and add these to the layout. It is then responsible for setting the axis/scale ranges and invoking 'call' on each component.

I like the way that the components still follow the D3 pattern and remain unchanged. Furthermore, it should be possible to wrap up the resize logic so that a chart layout can resize itself automatically.

Here's a chart that supports re-sizing with my changes:

// create the chart layout
var chartLayout = fc.utilities.chartLayout();

// Render the initial layout
d3.select('#structured-chart')
    .call(chartLayout);

// Create some data
var startDate = new Date(2014, 1, 1),
    dayCount = 100;
var gsData = fc.utilities.dataGenerator()
    .seedDate(startDate)
    .generate(dayCount);

// Create scales
var xScale = fc.scale.dateTime() 
    .domainFromValues(gsData, ['date']);
var yScale = fc.scale.linear()
    .domainFromValues(gsData, ['low', 'high']);

// Create axes
var bottomAxis = d3.svg.axis()
    .scale(xScale)
    .orient('bottom')
    .ticks(10);
var leftAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left')
    .ticks(5);

// Create some series
var ohlc = fc.series.ohlc()
    .xScale(xScale)
    .yScale(yScale);
var bollinger = fc.indicators.bollingerBands()
    .xScale(xScale)
    .yScale(yScale);

// add gridlines
var gridlines = fc.scale.gridlines()
    .xScale(xScale)
    .yScale(yScale);

// ############### New code below

// Add axis to the chartLayout. The layout is now responsible
// for setting the range of the scales associated with each axis
chartLayout.addAxisToContainer('bottom', bottomAxis);
chartLayout.addAxisToContainer('left', leftAxis);

// Add plot area components
chartLayout.addComponentsToPlotArea([ohlc, gridlines, bollinger]);

// Bind the data
chartLayout.getPlotArea()
    .datum(gsData)

function renderComponents() {
  // Render the chart, this ultimately involves invoking the 'call' method on the
  // various selections for the components added above
  chartLayout.render();
}

// perform an initial render
renderComponents();

// handle resize events, telling the chart to re-render
d3.select(window).on('resize', renderComponents); 

@markjose
Copy link
Contributor

Is this maybe getting a little high level for what we were trying to achieve with this project?

This is not a criticism, the changes make the users life a lot easier and from an architectural point of view is very tidy.

The other view is that as the Chart Layout component is essentially a utility and not a D3 component as such, maybe this is a useful change.

Thoughts?

@markjose
Copy link
Contributor

Every time we create a component we pass it the X and Y scales using the xScale and yScale setters.

If we used the approach suggested in this PR then we could allow the components to grab the default X and Y scales from the plotArea.

Also, I'm not sure the xScale and yScale values should have default values, maybe they should be undefined and log some form of error if not set.

@ColinEberhardt
Copy link
Member Author

Is this maybe getting a little high level for what we were trying to achieve with this project?

Perhaps - however, this change only effects chart layout, it doesn't have any impact on how the other components are written, other than the fact that they must adhere to the D3 component pattern.

@ColinEberhardt ColinEberhardt changed the title WIP: Suggestion - Chart layout manages components chartBuilder - a component that associates components with the chartLayout Jan 5, 2015
@ColinEberhardt
Copy link
Member Author

As discuss in our meeting, this concept has been split out into a separate component. Here's what it looks like from a user-perspective:

// create the chart layout
var chartLayout = fc.utilities.chartLayout();

// create a builder that organises charting components
var chartBuilder = fc.utilities.chartBuilder(chartLayout);

// Render the initial layout
d3.select('#structured-chart')
    .call(chartBuilder);

// Create some data
var startDate = new Date(2014, 1, 1),
    dayCount = 100;
var gsData = fc.utilities.dataGenerator()
    .seedDate(startDate)
    .generate(dayCount);

// Create scales
var xScale = fc.scale.dateTime() 
    .domain(fc.utilities.extents(gsData, 'date'));
var yScale = fc.scale.linear()
    .domain(fc.utilities.extents(gsData, ['low', 'high']));

// Create axes
var bottomAxis = d3.svg.axis()
    .scale(xScale)
    .orient('bottom')
    .ticks(10);
var leftAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left')
    .ticks(5);

// Create some series
var ohlc = fc.series.ohlc()
    .xScale(xScale)
    .yScale(yScale);
var bollinger = fc.indicators.bollingerBands()
    .xScale(xScale)
    .yScale(yScale);

// add gridlines
var gridlines = fc.scale.gridlines()
    .xScale(xScale)
    .yScale(yScale);

// Add axis to the chart builder.
chartBuilder.setAxis('bottom', bottomAxis);
chartBuilder.setAxis('left', leftAxis);

// Add plot area components
chartBuilder.addToPlotArea([ohlc, gridlines, bollinger]);

// Bind the data
chartBuilder.setData(gsData)

// perform an initial render
chartBuilder.render();

// handle resize events, telling the chart to re-render
d3.select(window).on('resize', chartBuilder.render); 

@tlsim tlsim mentioned this pull request Jan 6, 2015
ColinEberhardt added a commit that referenced this pull request Jan 6, 2015
chartBuilder - a component that associates components with the chartLayout
@ColinEberhardt ColinEberhardt merged commit 1210515 into d3fc:master Jan 6, 2015
@ColinEberhardt ColinEberhardt deleted the resizing branch January 10, 2015 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants