Example #1
0
export default (...args) => {
    const { xScale, yScale, xAxis, yAxis } = getArguments(...args);

    let xLabel = functor('');
    let yLabel = functor('');
    let xAxisHeight = functor(null);
    let yAxisWidth = functor(null);
    let yOrient = functor('right');
    let xOrient = functor('bottom');
    let canvasPlotArea = seriesCanvasMulti();
    let svgPlotArea = seriesSvgMulti();
    let xAxisStore = store('tickFormat', 'ticks', 'tickArguments', 'tickSize', 'tickSizeInner', 'tickSizeOuter', 'tickValues', 'tickPadding', 'tickCenterLabel');
    let xDecorate = () => { };
    let yAxisStore = store('tickFormat', 'ticks', 'tickArguments', 'tickSize', 'tickSizeInner', 'tickSizeOuter', 'tickValues', 'tickPadding', 'tickCenterLabel');
    let yDecorate = () => { };
    let decorate = () => { };

    const containerDataJoin = dataJoin('d3fc-group', 'cartesian-chart');
    const xAxisDataJoin = dataJoin('d3fc-svg', 'x-axis')
        .key(d => d);
    const yAxisDataJoin = dataJoin('d3fc-svg', 'y-axis')
        .key(d => d);
    const xLabelDataJoin = dataJoin('div', 'x-label')
        .key(d => d);
    const yLabelDataJoin = dataJoin('div', 'y-label')
        .key(d => d);

    const propagateTransition = maybeTransition => selection =>
        maybeTransition.selection ? selection.transition(maybeTransition) : selection;

    const cartesian = (selection) => {

        const transitionPropagator = propagateTransition(selection);

        selection.each((data, index, group) => {
            const container = containerDataJoin(select(group[index]), [data]);

            container.enter()
                .attr('auto-resize', '')
                .html(
                    '<d3fc-svg class="plot-area"></d3fc-svg>' +
                    '<d3fc-canvas class="plot-area"></d3fc-canvas>'
                );

            xLabelDataJoin(container, [xOrient(data)])
                .attr('class', d => `x-label ${d}-label`)
                .text(xLabel(data));

            yLabelDataJoin(container, [yOrient(data)])
                .attr('class', d => `y-label ${d}-label`)
                .text(yLabel(data));

            xAxisDataJoin(container, [xOrient(data)])
                .attr('class', d => `x-axis ${d}-axis`)
                .style('height', xAxisHeight(data))
                .on('measure', (d, i, nodes) => {
                    const { width, height } = event.detail;
                    if (d === 'top') {
                        select(nodes[i])
                            .select('svg')
                            .attr('viewBox', `0 ${-height} ${width} ${height}`);
                    }
                    xScale.range([0, width]);
                })
                .on('draw', (d, i, nodes) => {
                    const xAxisComponent = d === 'top' ? xAxis.top(xScale) : xAxis.bottom(xScale);
                    xAxisComponent.decorate(xDecorate);
                    transitionPropagator(select(nodes[i]))
                        .select('svg')
                        .call(xAxisStore(xAxisComponent));
                });

            yAxisDataJoin(container, [yOrient(data)])
                .attr('class', d => `y-axis ${d}-axis`)
                .style('width', yAxisWidth(data))
                .on('measure', (d, i, nodes) => {
                    const { width, height } = event.detail;
                    if (d === 'left') {
                        select(nodes[i])
                            .select('svg')
                            .attr('viewBox', `${-width} 0 ${width} ${height}`);
                    }
                    yScale.range([height, 0]);
                })
                .on('draw', (d, i, nodes) => {
                    const yAxisComponent = d === 'left' ? yAxis.left(yScale) : yAxis.right(yScale);
                    yAxisComponent.decorate(yDecorate);
                    transitionPropagator(select(nodes[i]))
                        .select('svg')
                        .call(yAxisStore(yAxisComponent));
                });

            container.select('d3fc-canvas.plot-area')
                .on('draw', (d, i, nodes) => {
                    const canvas = select(nodes[i])
                        .select('canvas')
                        .node();
                    canvasPlotArea.context(canvas.getContext('2d'))
                        .xScale(xScale)
                        .yScale(yScale);
                    canvasPlotArea(d);
                });

            container.select('d3fc-svg.plot-area')
                .on('draw', (d, i, nodes) => {
                    svgPlotArea.xScale(xScale)
                        .yScale(yScale);
                    transitionPropagator(select(nodes[i]))
                        .select('svg')
                        .call(svgPlotArea);
                });

            container.each((d, i, nodes) => nodes[i].requestRedraw());

            decorate(container, data, index);
        });
    };

    const scaleExclusions = exclude(
        /range\w*/,   // the scale range is set via the component layout
        /tickFormat/  // use axis.tickFormat instead (only present on linear scales)
    );
    rebindAll(cartesian, xScale, scaleExclusions, prefix('x'));
    rebindAll(cartesian, yScale, scaleExclusions, prefix('y'));
    rebindAll(cartesian, xAxisStore, prefix('x'));
    rebindAll(cartesian, yAxisStore, prefix('y'));

    cartesian.xOrient = (...args) => {
        if (!args.length) {
            return xOrient;
        }
        xOrient = functor(args[0]);
        return cartesian;
    };
    cartesian.yOrient = (...args) => {
        if (!args.length) {
            return yOrient;
        }
        yOrient = functor(args[0]);
        return cartesian;
    };
    cartesian.xDecorate = (...args) => {
        if (!args.length) {
            return xDecorate;
        }
        xDecorate = args[0];
        return cartesian;
    };
    cartesian.yDecorate = (...args) => {
        if (!args.length) {
            return yDecorate;
        }
        yDecorate = args[0];
        return cartesian;
    };
    cartesian.xLabel = (...args) => {
        if (!args.length) {
            return xLabel;
        }
        xLabel = functor(args[0]);
        return cartesian;
    };
    cartesian.yLabel = (...args) => {
        if (!args.length) {
            return yLabel;
        }
        yLabel = functor(args[0]);
        return cartesian;
    };
    cartesian.xAxisHeight = (...args) => {
        if (!args.length) {
            return xAxisHeight;
        }
        xAxisHeight = functor(args[0]);
        return cartesian;
    };
    cartesian.yAxisWidth = (...args) => {
        if (!args.length) {
            return yAxisWidth;
        }
        yAxisWidth = functor(args[0]);
        return cartesian;
    };
    cartesian.canvasPlotArea = (...args) => {
        if (!args.length) {
            return canvasPlotArea;
        }
        canvasPlotArea = args[0];
        return cartesian;
    };
    cartesian.svgPlotArea = (...args) => {
        if (!args.length) {
            return svgPlotArea;
        }
        svgPlotArea = args[0];
        return cartesian;
    };
    cartesian.decorate = (...args) => {
        if (!args.length) {
            return decorate;
        }
        decorate = args[0];
        return cartesian;
    };

    return cartesian;

};
Example #2
0
export default () => {

    let x = (d) => d.x;
    let y = (d) => d.y;
    let xScale = scaleIdentity();
    let yScale = scaleIdentity();

    const point = seriesCanvasPoint();

    const horizontalLine = annotationLine();

    const verticalLine = annotationLine()
        .orient('vertical');

    // The line annotations and point series used to render the crosshair are positioned using
    // screen coordinates. This function constructs an identity scale for these components.
    const xIdentity = scaleIdentity();
    const yIdentity = scaleIdentity();

    const multi = seriesCanvasMulti()
        .series([horizontalLine, verticalLine, point])
        .xScale(xIdentity)
        .yScale(yIdentity)
        .mapping((data) => [data]);

    const instance = (data) => {

        data.forEach(d => {
            // Assign the identity scales an accurate range to allow the line annotations to cover
            // the full width/height of the chart.
            xIdentity.range(xScale.range());
            yIdentity.range(yScale.range());

            point.crossValue(x)
                .mainValue(y);

            horizontalLine.value(y);

            verticalLine.value(x);

            multi(d);
        });
    };

    // Don't use the xValue/yValue convention to indicate that these values are in screen
    // not domain co-ordinates and are therefore not scaled.
    instance.x = (...args) => {
        if (!args.length) {
            return x;
        }
        x = args[0];
        return instance;
    };
    instance.y = (...args) => {
        if (!args.length) {
            return y;
        }
        y = args[0];
        return instance;
    };
    instance.xScale = (...args) => {
        if (!args.length) {
            return xScale;
        }
        xScale = args[0];
        return instance;
    };
    instance.yScale = (...args) => {
        if (!args.length) {
            return yScale;
        }
        yScale = args[0];
        return instance;
    };

    const lineIncludes = include('label', 'decorate');
    rebindAll(instance, horizontalLine, lineIncludes, prefix('y'));
    rebindAll(instance, verticalLine, lineIncludes, prefix('x'));
    rebind(instance, point, 'decorate');
    rebind(instance, multi, 'context');

    return instance;
};