示例#1
0
文件: text.js 项目: trongtt/ndash
function prettifyNumber(number) {
  // show "billion" instead of "giga"
  return number > 10 ? format('.2s')(number).replace('G', 'B') : (''+number).slice(0, 3);
}
// FIXME fieldStats.max isn't always the longest
function getMaxNumberLength(encoding, et, fieldStats) {
  var format = encoding.numberFormat(et, fieldStats);

  return d3_format.format(format)(fieldStats.max).length;
}
示例#3
0
import { select, selectAll, event as currentEvent } from 'd3-selection';
import { scaleLinear } from 'd3-scale';

import { NETWORK_FAILURE_ALERT, LOADING_ICON, getParameterByName } from '../utils';

fetch('/data/statetax/data.min.json')
	.then(response => response.json())
	.then(data => {
		$(() => {			
			app(data);
		});
	})
	.catch(error => console.error('oops', error));


const dollars = format('$00');		//// format function for dollars

//// props
// https://derekswingley.com/2016/08/01/using-and-bundling-individual-d3-modules/

const app = (data) => {
	const $link = $('#link');
	const $stateMap = $('#state_map');
	
	const max = {};		//// maximum values for primary areas
	const min = {};
	const rgbs = {};
	const scales = {};	//// scaling functions by area
	const colorcode = {	//// color multipliers
		r: 0.2,
		g: 1,
示例#4
0
	render() {
		const kagiCalculator = kagi();
		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = kagiCalculator(initialData);
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={400}
					width={width}
					ratio={ratio}
					margin={{ left: 80, right: 80, top: 10, bottom: 30 }}
					type={type}
					seriesName="MSFT"
					data={data}
					xScale={xScale}
					xAccessor={xAccessor}
					displayXAccessor={displayXAccessor}
					xExtents={xExtents}>
				<Chart id={1}
						yExtents={d => [d.high, d.low]}
						padding={{ top: 10, bottom: 20 }}>
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<KagiSeries />
					<OHLCTooltip origin={[-40, 0]}/>
				</Chart>
				<Chart id={2}
						yExtents={d => d.volume}
						height={150} origin={(w, h) => [0, h - 150]}>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".0s")}/>

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries
						yAccessor={d => d.volume}
						stroke
						fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}
						opacity={0.5} />
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#5
0
	render() {
		const { type, width, ratio } = this.props;
		const { data, xExtents, xScale, xAccessor, displayXAccessor, brushEnabled } = this.state;

		const yExtents1 = isDefined(this.state.yExtents1)
			? this.state.yExtents1
			: [d => [d.high, d.low], ema26.accessor(), ema12.accessor()];

		const yExtents3 = isDefined(this.state.yExtents3)
			? this.state.yExtents3
			: macdCalculator.accessor();
		return (
			<ChartCanvas
				height={600}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>
				<Chart id={1} height={400}
					yPanEnabled={isDefined(this.state.yExtents1)}
					yExtents={yExtents1}
					padding={{ top: 10, bottom: 20 }}
				>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema26.accessor()} stroke={ema26.stroke()}/>
					<LineSeries yAccessor={ema12.accessor()} stroke={ema12.stroke()}/>

					<CurrentCoordinate yAccessor={ema26.accessor()} fill={ema26.stroke()} />
					<CurrentCoordinate yAccessor={ema12.accessor()} fill={ema12.stroke()} />

					<EdgeIndicator
						itemType="last"
						orient="right"
						edgeAt="right"
						yAccessor={d => d.close}
						fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>

					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema26.accessor(),
								type: ema26.type(),
								stroke: ema26.stroke(),
								windowSize: ema26.options().windowSize,
							},
							{
								yAccessor: ema12.accessor(),
								type: ema12.type(),
								stroke: ema12.stroke(),
								windowSize: ema12.options().windowSize,
							},
						]}
					/>
					<Brush
						ref={this.saveInteractiveNode(1)}
						enabled={brushEnabled}
						type={BRUSH_TYPE}
						onBrush={this.handleBrush1}/>
				</Chart>
				<Chart id={2} height={150}
					yExtents={[d => d.volume, smaVolume50.accessor()]}
					origin={(w, h) => [0, h - 300]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<AreaSeries yAccessor={smaVolume50.accessor()} stroke={smaVolume50.stroke()} fill={smaVolume50.fill()}/>
				</Chart>
				<Chart id={3} height={150}
					yExtents={yExtents3}
					yPanEnabled={isDefined(this.state.yExtents3)}
					origin={(w, h) => [0, h - 150]} padding={{ top: 10, bottom: 10 }}
				>
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={2} />
					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />
					<Brush
						ref={this.saveInteractiveNode(3)}
						enabled={brushEnabled}
						type={BRUSH_TYPE}
						onBrush={this.handleBrush3}/>
					<MACDSeries yAccessor={d => d.macd}
						{...macdAppearance} />
					<MACDTooltip
						origin={[-38, 15]}
						yAccessor={d => d.macd}
						options={macdCalculator.options()}
						appearance={macdAppearance}
					/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#6
0
 /**
  * Calculates percentage of value from total
  * @param  {Number}  value    Value to check
  * @param  {Number}  total    Sum of values
  * @param  {String}  decimals Specifies number of decimals https://github.com/d3/d3-format
  * @return {String}           Percentage
  */
 function calculatePercent(value, total, decimals) {
     return d3Format.format(decimals)(value / total * 100);
 }
示例#7
0
// @flow weak

import React, { PureComponent, PropTypes } from 'react';
import { format } from 'd3-format';
import palette from 'docs/src/utils/palette';
import { dims } from '../module';

const numberFormat = format(',');

class Tick extends PureComponent {
  static propTypes = {
    data: PropTypes.shape({
      val: React.PropTypes.number.isRequired,
    }).isRequired,
    duration: PropTypes.number.isRequired,
    prevScale: PropTypes.func.isRequired,
    currScale: PropTypes.func.isRequired,
    removeNode: PropTypes.func.isRequired,
  };

  tick = null; // Root node ref set in render method

  onAppear() {
    const { prevScale, currScale, data: { val }, duration } = this.props;

    return {
      tick: {
        opacity: [1e-6, 1],
        transform: [
          `translate(0,${prevScale(val)})`,
          `translate(0,${currScale(val)})`,
示例#8
0
	render() {
		const { type, data: initialData, width, ratio } = this.props;
		const { channels_1 } = this.state;

		const xScaleProvider = discontinuousTimeScaleProvider.inputDateAccessor(
			d => d.date
		);
		const { data, xScale, xAccessor, displayXAccessor } = xScaleProvider(
			initialData
		);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas ref={this.saveCanvasNode}
				height={400}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>
				<Chart
					id={1}
					yExtents={[d => [d.high, d.low]]}
					padding={{ top: 10, bottom: 20 }}
				>

					<YAxis axisAt="right" orient="right" ticks={5} />
					<XAxis axisAt="bottom" orient="bottom" />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")}
					/>
					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")}
					/>
					<CandlestickSeries />

					<EdgeIndicator
						itemType="last"
						orient="right"
						edgeAt="right"
						yAccessor={d => d.close}
						fill={d => (d.close > d.open ? "#6BA583" : "#FF0000")}
					/>

					<OHLCTooltip origin={[-40, 0]} />

					<StandardDeviationChannel
						ref={this.saveInteractiveNodes("StandardDeviationChannel", 1)}
						enabled={this.state.enableInteractiveObject}
						onStart={() => console.log("START")}
						onComplete={this.onDrawComplete}
						channels={channels_1}
					/>
				</Chart>
				<CrossHairCursor />
				<DrawingObjectSelector
					enabled={!this.state.enableInteractiveObject}
					getInteractiveNodes={this.getInteractiveNodes}
					drawingObjectMap={{
						StandardDeviationChannel: "channels"
					}}
					onSelect={this.handleSelection}
				/>
			</ChartCanvas>
		);
	}
示例#9
0
		PropTypes.array,
		PropTypes.func
	]).isRequired,
	fontFamily: PropTypes.string,
	fontSize: PropTypes.number,
	onClick: PropTypes.func,
	displayValues: PropTypes.func,
	volumeFormat: PropTypes.func,
	textFill: PropTypes.string,
	labelFill: PropTypes.string,
};

OHLCTooltip.defaultProps = {
	accessor: (d) => { return { date: d.date, open: d.open, high: d.high, low: d.low, close: d.close, volume: d.volume }; },
	xDisplayFormat: timeFormat("%Y-%m-%d"),
	volumeFormat: format(".4s"),
	ohlcFormat: format(".2f"),
	displayValues: displayValues,
	origin: [0, 0],
};

function displayValues(props, moreProps) {
	const { xDisplayFormat, accessor, volumeFormat, ohlcFormat } = props;
	const { displayXAccessor, currentItem } = moreProps;

	let displayDate, open, high, low, close, volume;

	displayDate = open = high = low = close = volume = "n/a";

	if (isDefined(currentItem)
			&& isDefined(accessor(currentItem))
      strokeWidth: 3,
      strokeDasharray: '2, 2'
    }
  },
  {
    name: 'Chevrolet',
    mileage: 5,
    price: 4,
    safety: 6,
    performance: 4,
    interior: 5,
    warranty: 6
  }
];

const basicFormat = format('.2r');
const wideFormat = format('.3r');

export default function BasicParallelCoordinates(props) {
  return (
    <ParallelCoordinates
      data={DATA}
      tickFormat={t => wideFormat(t)}
      margin={50}
      colorRange={['#172d47', '#911116', '#998965']}
      domains={[
        {name: 'mileage', domain: [0, 10]},
        {
          name: 'price',
          domain: [2, 16],
          tickFormat: t => `$${basicFormat(t)}`,
  render() {
    const {
      activeTile,
      tiles,
      loading,
      moreTilesLoading,
      settings: { date, weeks, bands },
      setRecentImagerySettings,
      setRecentImageryLoading,
      setModalMetaSettings,
      onClickClose,
      error
    } = this.props;
    const selected = this.state.selected || activeTile || {};

    return (
      <div className="c-recent-imagery-settings prompts-recent-imagery">
        <div className="top-section">
          <div className="recent-menu">
            <div className="title">Recent satellite imagery</div>
            <div className="recent-actions">
              <Button
                className="info-btn"
                theme="theme-button-tiny theme-button-grey-filled square"
                onClick={() =>
                  setModalMetaSettings({ metakey: 'recent_satellite_imagery' })
                }
              >
                <Icon icon={infoIcon} />
              </Button>
              <button className="close-btn" onClick={onClickClose}>
                <Icon icon={closeIcon} className="icon-close" />
              </button>
            </div>
          </div>
          <div className="dates">
            <div className="title">ACQUISITION DATE</div>
            <div className="buttons">
              <Dropdown
                theme="theme-dropdown-button"
                value={weeks}
                options={WEEKS}
                onChange={option => {
                  setRecentImagerySettings({ weeks: option });
                  track('recentImageryDateRange');
                }}
                native
              />
              <div className="before">before</div>
              <Datepicker
                date={date ? moment(date) : moment()}
                handleOnDateChange={d => {
                  setRecentImagerySettings({ date: d.format('YYYY-MM-DD') });
                  track('recentImageryDate');
                }}
                settings={{
                  minDate: '2013-01-01',
                  maxDate: moment().format('YYYY-MM-DD'),
                  hideKeyboardShortcutsPanel: true,
                  noBorder: true,
                  readOnly: true,
                  displayFormat: 'D MMM YYYY',
                  isOutsideRange: d =>
                    d.isAfter(moment()) || d.isBefore(moment('2000-01-01')),
                  block: true
                }}
              />
            </div>
          </div>
          <div className="clouds">
            <div className="title">MAXIMUM CLOUD COVER PERCENTAGE</div>
            <Slider
              className="theme-slider-green"
              value={this.state.clouds}
              marks={{
                0: '0%',
                25: '25%',
                50: '50%',
                75: '75%',
                100: '100%'
              }}
              marksOnTop
              step={5}
              dots
              onChange={this.handleCloundsChange}
              onAfterChange={d => {
                setRecentImagerySettings({ clouds: d });
                track('recentImageryClouds');
              }}
            />
          </div>
        </div>
        <div className="thumbnails">
          {tiles &&
            !!tiles.length && (
              <Fragment>
                <div key="thumbnails-header" className="header">
                  <div className="description">
                    <p>
                      {moment(selected.dateTime)
                        .format('DD MMM YYYY')
                        .toUpperCase()}
                    </p>
                    <p>{format('.0f')(selected.cloudScore)}% cloud coverage</p>
                    <p>{startCase(selected.instrument)}</p>
                  </div>
                  <Dropdown
                    className="band-selector"
                    theme="theme-dropdown-button"
                    value={bands}
                    options={BANDS}
                    onChange={option => {
                      setRecentImagerySettings({
                        bands: option,
                        selected: null,
                        selectedIndex: 0
                      });
                      track('recentImageryImageType');
                    }}
                    native
                  />
                </div>
                <div className="thumbnail-grid">
                  {tiles &&
                    !!tiles.length &&
                    tiles.map((tile, i) => (
                      <RecentImageryThumbnail
                        key={tile.id}
                        id={i}
                        tile={tile}
                        selected={!!activeTile && activeTile.id === tile.id}
                        handleClick={() => {
                          setRecentImagerySettings({
                            selected: tile.id,
                            selectedIndex: i
                          });
                        }}
                        handleMouseEnter={() => {
                          this.setState({
                            selected: tile
                          });
                        }}
                        handleMouseLeave={() => {
                          this.setState({ selected: null });
                        }}
                      />
                    ))}
                </div>
              </Fragment>
            )}
          {error && (
            <RefreshButton
              refetchFn={() => {
                setRecentImageryLoading({ loading: false, error: false });
                track('refetchDataBtn', {
                  label: 'Recent imagery'
                });
              }}
            />
          )}
          {!error &&
            (!tiles || !tiles.length) &&
            !loading && (
              <NoContent
                className="placeholder"
                message="We can't find additional images for the selection"
              />
            )}
          {loading && !moreTilesLoading && <Loader className="placeholder" />}
        </div>
      </div>
    );
  }
示例#12
0
const getExponent = x => {
    if (x === 0) {
        return 0;
    }
    return Math.floor(log10(Math.abs(x)));
};

const removeRedundantZeros = ((() => {
    const zerosAfterDot = /\.0+([^\d].*)?$/;
    const zerosAfterNotZero = /(\.\d+?)0+([^\d].*)?$/;
    return str => str
        .replace(zerosAfterDot, '$1')
        .replace(zerosAfterNotZero, '$1$2');
}))();

const d3Format3S = d3.format('.3s');
const shortNumFormat = num => removeRedundantZeros(d3Format3S(num));

const getNumberFormatter = (start, end) => {

    const max = Math.max(Math.abs(start), Math.abs(end));
    const absExp = getExponent(max);
    const diff = (start * end > 0 ? Math.abs(end - start) : max);
    const diffExp = getExponent(diff);
    const absExpVsDiffExp = Math.abs(absExp - diffExp);

    if (Math.abs(absExp) > 3 && absExpVsDiffExp <= 3) {
        // Short format
        // 1k, 500k, 1M.
        return shortNumFormat;
    }
示例#13
0
文件: boxplot.js 项目: lineCode/vx
import React from 'react';
import { Group } from '@vx/group';
import { ViolinPlot, BoxPlot } from '@vx/stats';
import { LinearGradient } from '@vx/gradient';
import { scaleBand, scaleLinear } from '@vx/scale';
import { genStats } from '@vx/mock-data';
import { withTooltip, Tooltip } from '@vx/tooltip';
import { extent } from 'd3-array';
import { format } from 'd3-format';
import { PatternLines } from '@vx/pattern';

const data = genStats(5);
const twoDecimalFormat = format('.2f');

// accessors
const x = d => d.boxPlot.x;
const min = d => d.boxPlot.min;
const max = d => d.boxPlot.max;
const median = d => d.boxPlot.median;
const firstQuartile = d => d.boxPlot.firstQuartile;
const thirdQuartile = d => d.boxPlot.thirdQuartile;
const outliers = d => d.boxPlot.outliers;

export default withTooltip(
  ({
    width,
    height,
    events = false,
    tooltipOpen,
    tooltipLeft,
    tooltipTop,
示例#14
0
	render() {
		const ema26 = ema()
			.id(0)
			.options({ windowSize: 26 })
			.merge((d, c) => { d.ema26 = c; })
			.accessor(d => d.ema26);

		const ema12 = ema()
			.id(1)
			.options({ windowSize: 12 })
			.merge((d, c) => {d.ema12 = c;})
			.accessor(d => d.ema12);

		const macdCalculator = macd()
			.options({
				fast: 12,
				slow: 26,
				signal: 9,
			})
			.merge((d, c) => {d.macd = c;})
			.accessor(d => d.macd);

		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = macdCalculator(ema12(ema26(initialData)));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas ref={this.saveCanvasNode}
				height={600}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>
				<Chart id={1} height={400}
					yExtents={[d => [d.high, d.low], ema26.accessor(), ema12.accessor()]}
					padding={{ top: 10, bottom: 20 }}
				>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={5} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema26.accessor()} stroke={ema26.stroke()}/>
					<LineSeries yAccessor={ema12.accessor()} stroke={ema12.stroke()}/>

					<CurrentCoordinate yAccessor={ema26.accessor()} fill={ema26.stroke()} />
					<CurrentCoordinate yAccessor={ema12.accessor()} fill={ema12.stroke()} />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>

					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema26.accessor(),
								type: ema26.type(),
								stroke: ema26.stroke(),
								windowSize: ema26.options().windowSize,
							},
							{
								yAccessor: ema12.accessor(),
								type: ema12.type(),
								stroke: ema12.stroke(),
								windowSize: ema12.options().windowSize,
							},
						]}
					/>
					<TrendLine
						ref={this.saveInteractiveNodes("Trendline", 1)}
						enabled={this.state.enableTrendLine}
						type="RAY"
						snap={false}
						snapTo={d => [d.high, d.low]}
						onStart={() => console.log("START")}
						onComplete={this.onDrawCompleteChart1}
						trends={this.state.trends_1}
					/>
				</Chart>
				<Chart id={2} height={150}
					yExtents={[d => d.volume]}
					origin={(w, h) => [0, h - 300]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
				</Chart>
				<Chart id={3} height={150}
					yExtents={macdCalculator.accessor()}
					origin={(w, h) => [0, h - 150]} padding={{ top: 10, bottom: 10 }}
				>
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={2} />

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />
					<TrendLine
						ref={this.saveInteractiveNodes("Trendline", 3)}
						enabled={this.state.enableTrendLine}
						type="RAY"
						snap={false}
						snapTo={d => [d.high, d.low]}
						onStart={() => console.log("START")}
						onComplete={this.onDrawCompleteChart3}
						trends={this.state.trends_3}
					/>
					<MACDSeries yAccessor={d => d.macd}
						{...macdAppearance} />
					<MACDTooltip
						origin={[-38, 15]}
						yAccessor={d => d.macd}
						options={macdCalculator.options()}
						appearance={macdAppearance}
					/>
				</Chart>
				<CrossHairCursor />
				<DrawingObjectSelector
					enabled={!this.state.enableTrendLine}
					getInteractiveNodes={this.getInteractiveNodes}
					drawingObjectMap={{
						Trendline: "trends"
					}}
					onSelect={this.handleSelection}
				/>
			</ChartCanvas>
		);
	}
示例#15
0
    return function module() {

        let margin = {
                top: 20,
                right: 20,
                bottom: 30,
                left: 40
            },
            width = 960,
            height = 500,
            ease = d3Ease.easeQuadInOut,
            data,
            chartWidth, chartHeight,
            xScale, yScale,
            numOfVerticalTicks = 6,
            xAxis, xAxisLabel,
            yAxis, yAxisLabel,
            xAxisLabelOffset = 45,
            yAxisLabelOffset = -20,
            xAxisPadding = {
                top: 0,
                left: 0,
                bottom: 0,
                right: 0
            },
            yTickPadding = 8,
            svg,

            valueLabel = 'value',
            nameLabel = 'key',

            maskGridLines,
            baseLine,

            // Dispatcher object to broadcast the mouse events
            // Ref: https://github.com/mbostock/d3/wiki/Internals#d3_dispatch
            dispatcher = d3Dispatch.dispatch('customMouseOver', 'customMouseOut', 'customMouseMove'),

            // Formats
            yAxisTickFormat = d3Format.format('.3'),

            // extractors
            getKey = ({key}) => key,
            getValue = ({value}) => value;


        /**
         * This function creates the graph using the selection as container
         * @param  {D3Selection} _selection A d3 selection that represents
         *                                  the container(s) where the chart(s) will be rendered
         * @param {StepChartData} _data The data to attach and generate the chart
         */
        function exports(_selection){
            _selection.each(function(_data){
                // Make space on the left of the graph for the y axis label
                chartWidth = width - margin.left - margin.right;
                chartHeight = height - margin.top - margin.bottom;
                data = cleanData(_data);

                buildScales();
                buildAxis();
                buildSVG(this);
                drawGridLines();
                drawSteps();
                drawAxis();
            });
        }

        /**
         * Creates the d3 x and y axis, setting orientations
         * @private
         */
        function buildAxis(){
            xAxis = d3Axis.axisBottom(xScale);

            yAxis = d3Axis.axisLeft(yScale)
                .ticks(numOfVerticalTicks)
                .tickPadding(yTickPadding)
                .tickFormat(yAxisTickFormat);
        }

        /**
         * Builds containers for the chart, the axis and a wrapper for all of them
         * Also applies the Margin convention
         * @private
         */
        function buildContainerGroups(){
            let container = svg
              .append('g')
                .classed('container-group', true)
                .attr('transform', `translate(${margin.left}, ${margin.top})`);

            container
              .append('g')
                .classed('grid-lines-group', true);
            container
              .append('g')
                .classed('chart-group', true);
            container
              .append('g')
                .classed('x-axis-group axis', true)
              .append('g')
                .classed('x-axis-label', true);
            container
              .append('g')
                .classed('y-axis-group axis', true)
              .append('g')
                .classed('y-axis-label', true);
            container
                .append('g').classed('metadata-group', true);
        }

        /**
         * Creates the x and y scales of the graph
         * @private
         */
        function buildScales(){
            xScale = d3Scale.scaleBand()
                .domain(data.map(getKey))
                .rangeRound([0, chartWidth])
                .paddingInner(0);

            yScale = d3Scale.scaleLinear()
                .domain([0, d3Array.max(data, getValue)])
                .rangeRound([chartHeight, 0]);
        }

        /**
         * Builds the SVG element that will contain the chart
         * @param  {HTMLElement} container DOM element that will work as the container of the graph
         * @private
         */
        function buildSVG(container){
            if (!svg) {
                svg = d3Selection.select(container)
                  .append('svg')
                    .classed('britechart step-chart', true);

                buildContainerGroups();
            }

            svg
                .attr('width', width)
                .attr('height', height);
        }

        /**
         * Cleaning data adding the proper format
         * @param  {StepChartData} data Data
         * @private
         */
        function cleanData(data) {
            return data.map((d) => {
                d.value = +d[valueLabel];
                d.key = String(d[nameLabel]);

                return d;
            });
        }

        /**
         * Draws the x and y axis on the svg object within their
         * respective groups
         * @private
         */
        function drawAxis(){
            svg.select('.x-axis-group.axis')
                .attr('transform', `translate(0, ${chartHeight})`)
                .call(xAxis);

            if (xAxisLabel) {
                svg.select('.x-axis-label')
                  .append('text')
                    .attr('text-anchor', 'middle')
                    .attr('x', chartWidth / 2)
                    .attr('y', xAxisLabelOffset)
                    .text(xAxisLabel);
            }

            svg.select('.y-axis-group.axis')
                .call(yAxis);

            if (yAxisLabel) {
                svg.select('.y-axis-label')
                  .append('text')
                    .attr('x', -chartHeight / 2)
                    .attr('y', yAxisLabelOffset)
                    .attr('text-anchor', 'middle')
                    .attr('transform', 'rotate(270 0 0)')
                    .text(yAxisLabel);
            }
        }

        /**
         * Draws the step elements within the chart group
         * @private
         */
        function drawSteps(){
            let steps = svg.select('.chart-group').selectAll('.step').data(data);

            // Enter
            steps.enter()
              .append('rect')
                .classed('step', true)
                .attr('x', chartWidth) // Initially drawing the steps at the end of Y axis
                .attr('y', ({value}) => yScale(value))
                .attr('width', xScale.bandwidth())
                .attr('height', (d) => (chartHeight - yScale(d.value)))
                .on('mouseover', function() {
                    dispatcher.call('customMouseOver', this);
                })
                .on('mousemove', function(d) {
                    dispatcher.call('customMouseMove', this, d, d3Selection.mouse(this), [chartWidth, chartHeight]);
                })
                .on('mouseout', function() {
                    dispatcher.call('customMouseOut', this);
                })
              .merge(steps)
                .transition()
                .ease(ease)
                .attr('x', ({key}) => xScale(key))
                .attr('y', function(d) {
                    return yScale(d.value);
                })
                .attr('width', xScale.bandwidth())
                .attr('height', function(d) {
                    return chartHeight - yScale(d.value);
                });

            // Exit
            steps.exit()
                .transition()
                .style('opacity', 0)
                .remove();
        }

        /**
         * Draws grid lines on the background of the chart
         * @return void
         */
        function drawGridLines(){
            maskGridLines = svg.select('.grid-lines-group')
                .selectAll('line.horizontal-grid-line')
                .data(yScale.ticks(numOfVerticalTicks))
                .enter()
                  .append('line')
                    .attr('class', 'horizontal-grid-line')
                    .attr('x1', (xAxisPadding.left))
                    .attr('x2', chartWidth)
                    .attr('y1', (d) => yScale(d))
                    .attr('y2', (d) => yScale(d));

            //draw a horizontal line to extend x-axis till the edges
            baseLine = svg.select('.grid-lines-group')
                .selectAll('line.extended-x-line')
                .data([0])
                .enter()
                  .append('line')
                    .attr('class', 'extended-x-line')
                    .attr('x1', (xAxisPadding.left))
                    .attr('x2', chartWidth)
                    .attr('y1', height - margin.bottom - margin.top)
                    .attr('y2', height - margin.bottom - margin.top);
        }

        /**
         * Chart exported to png and a download action is fired
         * @public
         */
        exports.exportChart = function(filename) {
            exportChart.call(exports, svg, filename);
        };

        /**
         * Gets or Sets the margin of the chart
         * @param  {object} _x Margin object to get/set
         * @return { margin | module} Current margin or Step Chart module to chain calls
         * @public
         */
        exports.margin = function(_x) {
            if (!arguments.length) {
                return margin;
            }
            margin = _x;
            return this;
        };

        /**
         * Gets or Sets the width of the chart
         * @param  {number} _x Desired width for the graph
         * @return { width | module} Current width or step Chart module to chain calls
         * @public
         */
        exports.width = function(_x) {
            if (!arguments.length) {
                return width;
            }
            width = _x;
            return this;
        };

        /**
         * Gets or Sets the height of the chart
         * @param  {number} _x Desired width for the graph
         * @return { height | module} Current height or Step Chart module to chain calls
         * @public
         */
        exports.height = function(_x) {
            if (!arguments.length) {
                return height;
            }
            height = _x;
            return this;
        };

        /**
         * Gets or Sets the number of vertical ticks on the chart
         * @param  {number} _x Desired width for the graph
         * @return { height | module} Current height or Step Chart module to chain calls
         * @public
         */
        exports.numOfVerticalTicks = function(_x) {
            if (!arguments.length) {
                return numOfVerticalTicks;
            }
            numOfVerticalTicks = _x;
            return this;
        };

        /**
         * Gets or Sets the text of the xAxisLabel on the chart
         * @param  {text} _x Desired text for the label
         * @return { text | module} label or Step Chart module to chain calls
         * @public
         */
        exports.xAxisLabel = function(_x) {
            if (!arguments.length) {
                return xAxisLabel;
            }
            xAxisLabel = _x;
            return this;
        };

        /**
         * Gets or Sets the offset of the xAxisLabel on the chart
         * @param  {integer} _x Desired offset for the label
         * @return { integer | module} label or Step Chart module to chain calls
         * @public
         */
        exports.xAxisLabelOffset = function(_x) {
            if (!arguments.length) {
                return xAxisLabelOffset;
            }
            xAxisLabelOffset = _x;
            return this;
        };

        /**
         * Gets or Sets the text of the yAxisLabel on the chart
         * @param  {text} _x Desired text for the label
         * @return { text | module} label or Step Chart module to chain calls
         * @public
         */
        exports.yAxisLabel = function(_x) {
            if (!arguments.length) {
                return yAxisLabel;
            }
            yAxisLabel = _x;
            return this;
        };

        /**
         * Gets or Sets the offset of the yAxisLabel on the chart
         * @param  {integer} _x Desired offset for the label
         * @return { integer | module} label or Step Chart module to chain calls
         * @public
         */
        exports.yAxisLabelOffset = function(_x) {
            if (!arguments.length) {
                return yAxisLabelOffset;
            }
            yAxisLabelOffset = _x;
            return this;
        };

        /**
         * Exposes an 'on' method that acts as a bridge with the event dispatcher
         * We are going to expose this events:
         * customMouseOver, customMouseMove and customMouseOut
         *
         * @return {module} Bar Chart
         * @public
         */
        exports.on = function() {
            let value = dispatcher.on.apply(dispatcher, arguments);

            return value === dispatcher ? exports : value;
        };

        /**
         * Chart exported to png and a download action is fired
         * @public
         */
        exports.exportChart = function(filename, title) {
            exportChart.call(exports, svg, filename, title);
        };

        return exports;
    };
	render() {
		const ema20 = ema()
			.id(0)
			.options({ windowSize: 20 })
			.merge((d, c) => {d.ema20 = c;})
			.accessor(d => d.ema20);

		const ema50 = ema()
			.id(2)
			.options({ windowSize: 50 })
			.merge((d, c) => {d.ema50 = c;})
			.accessor(d => d.ema50);

		const smaVolume70 = sma()
			.id(3)
			.options({ windowSize: 70, sourcePath: "volume" })
			.merge((d, c) => {d.smaVolume70 = c;})
			.accessor(d => d.smaVolume70);
		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = ema20(ema50(smaVolume70(initialData)));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={400}
					ratio={ratio}
					width={width}
					margin={{ left: 90, right: 90, top: 70, bottom: 30 }}
					type={type}
					seriesName="MSFT"
					data={data}
					xScale={xScale}
					xAccessor={xAccessor}
					displayXAccessor={displayXAccessor}
					xExtents={xExtents}>
				<Chart id={2}
						yExtents={[d => d.volume, smaVolume70.accessor()]}
						height={150} origin={(w, h) => [0, h - 150]}>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".0s")}/>

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<AreaSeries yAccessor={smaVolume70.accessor()} stroke={smaVolume70.stroke()} fill={smaVolume70.fill()}/>

					<CurrentCoordinate yAccessor={smaVolume70.accessor()} fill={smaVolume70.stroke()} />
					<CurrentCoordinate yAccessor={d => d.volume} fill="#9B0A47" />

					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={d => d.volume} displayFormat={format(".4s")} fill="#0F0F0F"/>
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.volume} displayFormat={format(".4s")} fill="#0F0F0F"/>
					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={smaVolume70.accessor()} displayFormat={format(".4s")} fill={smaVolume70.fill()}/>
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={smaVolume70.accessor()} displayFormat={format(".4s")} fill={smaVolume70.fill()}/>
				</Chart>
				<Chart id={1}
						yPan yExtents={[d => [d.high, d.low], ema20.accessor(), ema50.accessor()]}
						padding={{ top: 10, bottom: 20 }}>

					<XAxis axisAt="bottom" orient="bottom" />
					<XAxis axisAt="top" orient="top" flexTicks />
					<YAxis axisAt="right" orient="right" ticks={5} />

					<CandlestickSeries />

					<LineSeries yAccessor={ema20.accessor()} stroke={ema20.stroke()} highlightOnHover />
					<LineSeries yAccessor={ema50.accessor()} stroke={ema50.stroke()} highlightOnHover />

					<CurrentCoordinate yAccessor={ema20.accessor()} fill={ema20.stroke()} />
					<CurrentCoordinate yAccessor={ema50.accessor()} fill={ema50.stroke()} />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={ema20.accessor()} fill={ema20.fill()}/>
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={ema50.accessor()} fill={ema50.fill()}/>
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>
					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={ema20.accessor()} fill={ema20.fill()}/>
					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={ema50.accessor()} fill={ema50.fill()}/>
					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<MouseCoordinateX
						at="top"
						orient="top"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />
					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".2f")} />

					<OHLCTooltip origin={[-40, -65]}/>
					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema20.accessor(),
								type: ema20.type(),
								stroke: ema20.stroke(),
								windowSize: ema20.options().windowSize,
							},
							{
								yAccessor: ema50.accessor(),
								type: ema50.type(),
								stroke: ema50.stroke(),
								windowSize: ema50.options().windowSize,
							},
						]}
						/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#17
0
    render() {
        /*
        
        Styling the hard way

        const style = {
            in: {
                normal: {fill: "#A5C8E1"},
                highlighted: {fill: "#BFDFF6"},
                selected: {fill: "#2DB3D1"},
                muted: {fill: "#A5C8E1", opacity: 0.4}
            }
        };

        const altStyle = {
            out: {
                normal: {fill: "#FFCC9E"},
                highlighted: {fill: "#fcc593"},
                selected: {fill: "#2DB3D1"},
                muted: {fill: "#FFCC9E", opacity: 0.4}
            }
        };
       
        const combinedStyle = {
            in: {
                normal: {fill: "#A5C8E1"},
                highlighted: {fill: "#BFDFF6"},
                selected: {fill: "#2DB3D1"},
                muted: {fill: "#A5C8E1", opacity: 0.4}
            },
            out: {
                normal: {fill: "#FFCC9E"},
                highlighted: {fill: "#fcc593"},
                selected: {fill: "#2DB3D1"},
                muted: {fill: "#FFCC9E", opacity: 0.4}
            }
        };
        */

        const style = styler([
            { key: "in", color: "#A5C8E1", selected: "#2CB1CF" },
            { key: "out", color: "#FFCC9E", selected: "#2CB1CF" },
            {
                key: netTrafficColumnNames[1],
                color: "#A5C8E1",
                selected: "#2CB1CF"
            },
            {
                key: netTrafficColumnNames[2],
                color: "#FFCC9E",
                selected: "#2CB1CF"
            },
            {
                key: netTrafficColumnNames[3],
                color: "#DEB887",
                selected: "#2CB1CF"
            }
        ]);

        const formatter = format(".2s");
        const selectedDate = this.state.selection
            ? this.state.selection.event.index().toNiceString()
            : "--";
        const selectedValue = this.state.selection
            ? `${formatter(+this.state.selection.event.value(this.state.selection.column))}b`
            : "--";

        const highlight = this.state.highlight;
        let infoValues = [];
        let infoNetValues = [];
        if (highlight) {
            const trafficText = `${formatter(highlight.event.get(highlight.column))}`;
            infoValues = [{ label: "Traffic", value: trafficText }];
            infoNetValues = [{ label: "Traffic " + highlight.column, value: trafficText }];
        }

        return (
            <div>
                <div className="row">
                    <div className="col-md-12">
                        <b>October 2014 Total Traffic</b>
                        <p style={{ color: "#808080" }}>
                            Selected: {selectedDate} - {selectedValue}
                        </p>
                    </div>
                </div>

                <hr />

                <div className="row">
                    <div className="col-md-12">
                        <Resizable>
                            <ChartContainer
                                utc={false}
                                timeRange={this.state.timerange}
                                format="day"
                                enablePanZoom={true}
                                onTimeRangeChanged={this.handleTimeRangeChange}
                                onBackgroundClick={() => this.setState({ selection: null })}
                                maxTime={new Date(1414827330868)}
                                minTime={new Date(1412143472795)}
                                minDuration={1000 * 60 * 60 * 24 * 5}
                            >
                                <ChartRow height="150">
                                    <YAxis
                                        id="traffic"
                                        label="Traffic In (B)"
                                        min={0}
                                        max={max}
                                        width="70"
                                    />
                                    <Charts>
                                        <BarChart
                                            axis="traffic"
                                            style={style}
                                            columns={["in"]}
                                            series={octoberTrafficSeries}
                                            info={infoValues}
                                            infoTimeFormat={index =>
                                                moment(index.begin()).format("Do MMM 'YY")
                                            }
                                            highlighted={this.state.highlight}
                                            onHighlightChange={highlight =>
                                                this.setState({ highlight })
                                            }
                                            selected={this.state.selection}
                                            onSelectionChange={selection =>
                                                this.setState({ selection })
                                            }
                                        />
                                    </Charts>
                                    <YAxis
                                        id="traffic-rate"
                                        label="Avg Traffic Rate In (bps)"
                                        min={0}
                                        max={max / (24 * 60 * 60) * 8}
                                        width="70"
                                    />
                                </ChartRow>
                            </ChartContainer>
                        </Resizable>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-12">
                        <hr />
                        Alternatively we can display bars side by side using the 'spacing' and
                        'offset' props:
                        <hr />
                    </div>
                </div>

                <div className="row">
                    <div className="col-md-12">
                        <Resizable>
                            <ChartContainer
                                timeRange={octoberTrafficSeries.range()}
                                format="day"
                                onBackgroundClick={() => this.setState({ selection: null })}
                            >
                                <ChartRow height="150">
                                    <YAxis
                                        id="traffic-volume"
                                        label="Traffic (B)"
                                        classed="traffic-in"
                                        min={0}
                                        max={max}
                                        width="70"
                                        type="linear"
                                    />
                                    <Charts>
                                        <BarChart
                                            axis="traffic-volume"
                                            style={style}
                                            size={10}
                                            offset={5.5}
                                            columns={["in"]}
                                            series={octoberTrafficSeries}
                                            highlighted={this.state.highlight}
                                            info={infoValues}
                                            infoTimeFormat="%m/%d/%y"
                                            onHighlightChange={highlight =>
                                                this.setState({ highlight })
                                            }
                                            selected={this.state.selection}
                                            onSelectionChange={selection =>
                                                this.setState({ selection })
                                            }
                                        />
                                        <BarChart
                                            axis="traffic-volume"
                                            style={style}
                                            size={10}
                                            offset={-5.5}
                                            columns={["out"]}
                                            series={octoberTrafficSeries}
                                            info={infoValues}
                                            highlighted={this.state.highlight}
                                            onHighlightChange={highlight =>
                                                this.setState({ highlight })
                                            }
                                            selected={this.state.selection}
                                            onSelectionChange={selection =>
                                                this.setState({ selection })
                                            }
                                        />
                                    </Charts>
                                </ChartRow>
                            </ChartContainer>
                        </Resizable>
                    </div>
                </div>

                <div className="row">
                    <div className="col-md-12">
                        <hr />
                        Or of course you can stack them:
                        <hr />
                    </div>
                </div>

                <div className="row">
                    <div className="col-md-12">
                        <Resizable>
                            <ChartContainer
                                timeRange={octoberTrafficSeries.range()}
                                format="day"
                                onBackgroundClick={() => this.setState({ selection: null })}
                            >
                                <ChartRow height="150">
                                    <YAxis
                                        id="traffic-volume"
                                        label="Traffic (B)"
                                        classed="traffic-in"
                                        min={0}
                                        max={max}
                                        width="70"
                                        type="linear"
                                    />
                                    <Charts>
                                        <BarChart
                                            axis="traffic-volume"
                                            style={style}
                                            spacing={3}
                                            columns={["in", "out"]}
                                            series={octoberTrafficSeries}
                                            info={infoValues}
                                            highlighted={this.state.highlight}
                                            onHighlightChange={highlight =>
                                                this.setState({ highlight })
                                            }
                                            selected={this.state.selection}
                                            onSelectionChange={selection =>
                                                this.setState({ selection })
                                            }
                                        />
                                    </Charts>
                                </ChartRow>
                            </ChartContainer>
                        </Resizable>
                    </div>
                </div>

                <div className="row">
                    <div className="col-md-12">
                        <hr />
                        BarChart can display negative values as well, as shown below for a stacked
                        format. Note that all bars representing positive values are stacked together
                        above the x-axis and the bars for negative values are stacked below the
                        x-axis.
                        <hr />
                    </div>
                </div>

                <div className="row">
                    <div className="col-md-12">
                        <Resizable>
                            <ChartContainer
                                timeRange={octoberNetTrafficSeries.range()}
                                format="day"
                                onBackgroundClick={() => this.setState({ selection: null })}
                            >
                                <ChartRow height="150">
                                    <YAxis
                                        id="net-traffic-volume"
                                        label="Net Traffic (B)"
                                        classed="traffic-in"
                                        min={minTotalTraffic}
                                        max={maxTotalTraffic}
                                        width="70"
                                        type="linear"
                                    />
                                    <Charts>
                                        <BarChart
                                            axis="net-traffic-volume"
                                            style={style}
                                            spacing={3}
                                            columns={netTrafficColumnNames.slice(
                                                1,
                                                netTrafficColumnNames.length
                                            )}
                                            series={octoberNetTrafficSeries}
                                            info={infoNetValues}
                                            infoWidth={140}
                                            highlighted={this.state.highlight}
                                            onHighlightChange={highlight =>
                                                this.setState({ highlight })
                                            }
                                            selected={this.state.selection}
                                            onSelectionChange={selection =>
                                                this.setState({ selection })
                                            }
                                        />
                                    </Charts>
                                </ChartRow>
                            </ChartContainer>
                        </Resizable>
                    </div>
                </div>
            </div>
        );
    }
	render() {
		const { type, data: initialData, width, ratio } = this.props;
		const ema26 = ema()
			.id(0)
			.options({ windowSize: 26 })
			.merge((d, c) => { d.ema26 = c; })
			.accessor(d => d.ema26);

		const ema12 = ema()
			.id(1)
			.options({ windowSize: 12 })
			.merge((d, c) => {d.ema12 = c;})
			.accessor(d => d.ema12);

		const macdCalculator = macd()
			.options({
				fast: 12,
				slow: 26,
				signal: 9,
			})
			.merge((d, c) => {d.macd = c;})
			.accessor(d => d.macd);

		const smaVolume50 = sma()
			.id(3)
			.options({
				windowSize: 50,
				sourcePath: "volume",
			})
			.merge((d, c) => {d.smaVolume50 = c;})
			.accessor(d => d.smaVolume50);

		const calculatedData = smaVolume50(macdCalculator(ema12(ema26(initialData))));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		return (
			<ChartCanvas height={600}
					width={width}
					ratio={ratio}
					margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
					type={type}
					seriesName="MSFT"
					data={data}
					xScale={xScale}
					xAccessor={xAccessor}
					displayXAccessor={displayXAccessor}>
				<Chart id={1} height={400}
						yExtents={[d => [d.high, d.low], ema26.accessor(), ema12.accessor()]}
						padding={{ top: 10, bottom: 20 }}>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema26.accessor()} stroke={ema26.stroke()}/>
					<LineSeries yAccessor={ema12.accessor()} stroke={ema12.stroke()}/>

					<CurrentCoordinate yAccessor={ema26.accessor()} fill={ema26.stroke()} />
					<CurrentCoordinate yAccessor={ema12.accessor()} fill={ema12.stroke()} />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>
					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema26.accessor(),
								type: "EMA",
								stroke: ema26.stroke(),
								windowSize: ema26.options().windowSize,
							},
							{
								yAccessor: ema12.accessor(),
								type: "EMA",
								stroke: ema12.stroke(),
								windowSize: ema12.options().windowSize,
							},
						]}
						/>
				</Chart>
				<Chart id={2} height={150}
						yExtents={[d => d.volume, smaVolume50.accessor()]}
						origin={(w, h) => [0, h - 300]}>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".0s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<AreaSeries yAccessor={smaVolume50.accessor()} stroke={smaVolume50.stroke()} fill={smaVolume50.fill()}/>
				</Chart>
				<Chart id={3} height={150}
						yExtents={macdCalculator.accessor()}
						origin={(w, h) => [0, h - 150]} padding={{ top: 10, bottom: 10 }} >
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={2} />

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<MACDSeries yAccessor={d => d.macd}
						{...macdAppearance} />
					<MACDTooltip
						origin={[-38, 15]}
						yAccessor={d => d.macd}
						options={macdCalculator.options()}
						appearance={macdAppearance}
						/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#19
0
	render() {
		const ema26 = ema()
			.id(0)
			.options({ windowSize: 26 })
			.merge((d, c) => {d.ema26 = c;})
			.accessor(d => d.ema26);

		const ema12 = ema()
			.id(1)
			.options({ windowSize: 12 })
			.merge((d, c) => {d.ema12 = c;})
			.accessor(d => d.ema12);

		const smaVolume50 = sma()
			.id(3)
			.options({ windowSize: 50, sourcePath: "volume" })
			.merge((d, c) => {d.smaVolume50 = c;})
			.accessor(d => d.smaVolume50);

		const rsiCalculator = rsi()
			.options({ windowSize: 14 })
			.merge((d, c) => {d.rsi = c;})
			.accessor(d => d.rsi);

		const atr14 = atr()
			.options({ windowSize: 14 })
			.merge((d, c) => {d.atr14 = c;})
			.accessor(d => d.atr14);

		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = ema26(ema12(smaVolume50(rsiCalculator(atr14(initialData)))));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={600}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>

				<Chart id={1} height={300}
					yExtents={[d => [d.high, d.low], ema26.accessor(), ema12.accessor()]}
					padding={{ top: 10, bottom: 20 }}
				>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema26.accessor()} stroke={ema26.stroke()}/>
					<LineSeries yAccessor={ema12.accessor()} stroke={ema12.stroke()}/>

					<CurrentCoordinate yAccessor={ema26.accessor()} fill={ema26.stroke()} />
					<CurrentCoordinate yAccessor={ema12.accessor()} fill={ema12.stroke()} />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>

					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema26.accessor(),
								type: "EMA",
								stroke: ema26.stroke(),
								windowSize: ema26.options().windowSize,
							},
							{
								yAccessor: ema12.accessor(),
								type: "EMA",
								stroke: ema12.stroke(),
								windowSize: ema12.options().windowSize,
							},
						]}
					/>

				</Chart>
				<Chart id={2} height={150}
					yExtents={[d => d.volume, smaVolume50.accessor()]}
					origin={(w, h) => [0, h - 400]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<AreaSeries yAccessor={smaVolume50.accessor()} stroke={smaVolume50.stroke()} fill={smaVolume50.fill()}/>
				</Chart>
				<Chart id={3}
					yExtents={[0, 100]}
					height={125} origin={(w, h) => [0, h - 250]}
				>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right"
						orient="right"
						tickValues={[30, 50, 70]}/>
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<RSISeries yAccessor={d => d.rsi} />

					<RSITooltip origin={[-38, 15]}
						yAccessor={d => d.rsi}
						options={rsiCalculator.options()} />
				</Chart>
				<Chart id={8}
					yExtents={atr14.accessor()}
					height={125} origin={(w, h) => [0, h - 125]} padding={{ top: 10, bottom: 10 }}
				>
					<XAxis axisAt="bottom" orient="bottom" />
					<YAxis axisAt="right" orient="right" ticks={2}/>

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<LineSeries yAccessor={atr14.accessor()} stroke={atr14.stroke()}/>
					<SingleValueTooltip
						yAccessor={atr14.accessor()}
						yLabel={`ATR (${atr14.options().windowSize})`}
						yDisplayFormat={format(".2f")}
						/* valueStroke={atr14.stroke()} - optional prop */
						/* labelStroke="#4682B4" - optional prop */
						origin={[-40, 15]}/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
import { format } from 'd3-format'
import { isUndefined } from 'underscore'

const formatSingleDigitPrecision = format('.1f')
const formatInteger = format('.0f')

export function basicPrecisionPxFormatter (d) {
  if (isUndefined(d)) return null

  const res = d % 1
  return (
    (res < 0.05 || 1 - res < 0.05)
    ? formatInteger(d)
    : formatSingleDigitPrecision(d)
  ) + 'px'
}
	render() {
		const fi = forceIndex()
			.merge((d, c) => {d.fi = c;})
			.accessor(d => d.fi);

		const fiEMA13 = ema()
			.id(1)
			.options({ windowSize: 13, sourcePath: "fi" })
			.merge((d, c) => {d.fiEMA13 = c;})
			.accessor(d => d.fiEMA13);

		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = fiEMA13(fi(initialData));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={550}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 20, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>
				<Chart id={1}  height={300}
					yExtents={d => [d.high, d.low]}
					padding={{ top: 10, right: 0, bottom: 20, left: 0 }}
				>
					<YAxis axisAt="right" orient="right" ticks={5} />
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close}
						fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<OHLCTooltip origin={[-40, -10]}/>

				</Chart>
				<Chart id={2} height={150}
					yExtents={d => d.volume}
					origin={(w, h) => [0, h - 350]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>
					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries
						yAccessor={d => d.volume}
						fill={(d) => d.close > d.open ? "#6BA583" : "#FF0000"}
						opacity={0.5} />
				</Chart>
				<Chart id={3} height={100}
					yExtents={fi.accessor()}
					origin={(w, h) => [0, h - 200]}
					padding={{ top: 10, right: 0, bottom: 10, left: 0 }}
				>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={4} tickFormat={format(".2s")}/>
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".4s")} />

					<AreaSeries baseAt={scale => scale(0)} yAccessor={fi.accessor()} />
					<StraightLine yValue={0} />

					<SingleValueTooltip
						yAccessor={fi.accessor()}
						yLabel="ForceIndex (1)"
						yDisplayFormat={format(".4s")}
						origin={[-40, 15]}/>
				</Chart>
				<Chart id={4} height={100}
					yExtents={fiEMA13.accessor()}
					origin={(w, h) => [0, h - 100]}
					padding={{ top: 10, right: 0, bottom: 10, left: 0 }}
				>
					<XAxis axisAt="bottom" orient="bottom" />
					<YAxis axisAt="right" orient="right" ticks={4} tickFormat={format(".2s")}/>

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".4s")} />

					<AreaSeries baseAt={scale => scale(0)} yAccessor={fiEMA13.accessor()} />
					<StraightLine yValue={0} />

					<SingleValueTooltip
						yAccessor={fiEMA13.accessor()}
						yLabel={`ForceIndex (${fiEMA13.options().windowSize})`}
						yDisplayFormat={format(".4s")}
						origin={[-40, 15]}/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#22
0
function updateFeed(feed) {

    const filteredData = feed.data.filter(d => (filterByDateRange(d) && d.measurementValue > 0)),
        filteredTrendData = feed.trendData.filter(d => (filterByDateRange(d) && d.measurementValue > 0)),
        maxMeasurement = max(filteredData, d => d.measurementValue),
        minMeasurement = min(filteredData, d => d.measurementValue),
        yBase = feedPadding * (feedIndices[feed.feedInfo.feedId] + 1) + feedHeight * feedIndices[feed.feedInfo.feedId],
        yTickFormat = (maxMeasurement > 1000) ? ".2s" : ".3",
        measurementScale = scaleLinear().range([feedHeight, 0]).domain([minMeasurement, maxMeasurement]),
        baselineDataY = [yBase, yBase + feedHeight],
        labelData = [yBase + feedHeight],
        baseLine = select('#baseLine' + feed.feedInfo.feedId).selectAll('line.baseline').data(baselineDataY),
        label = select('#label' + feed.feedInfo.feedId).selectAll('text').data(labelData),
        measurements = select('#data' + feed.feedInfo.feedId).selectAll('circle').data(filteredData),
        trendLine = select('#trend' + feed.feedInfo.feedId).selectAll('path').data([filteredTrendData]),
        yAxis = select("#yAxis" + feed.feedInfo.feedId),
        yAxisSettings = axisLeft(measurementScale)
            .tickSize(-4)
            .tickFormat(format(yTickFormat))
            .ticks(5)
            .tickPadding(5);

    baseLine.enter().append('line')
        .attr('class', 'baseline')
        .attr("x1", 0)
        .attr("x2", timelineSize.width)
        .attr("stroke", "#eee")
        .attr("stroke-width", 1)
        .merge(baseLine)
        .attr("y1", d => d)
        .attr("y2", d => d);
    baseLine.exit().remove();

    label.enter().append('text')
        .attr("class", "feedLabel")
        .attr('text-anchor', 'end')
        .attr("x", -35)
        .on('click', function () {
                selectedFeed = feed.feedInfo.feedId;
                select('#timelineOuter').selectAll('text.selected').classed('selected', false);
                select(this).classed('selected', true);
                select('#timelineInner').selectAll('circle.selected').classed('selected', false);
                select('#timelineInner').selectAll('path.selected').classed('selected', false);
                select('#data' + feed.feedInfo.feedId).selectAll('circle').classed('selected', true);
                select('#trend' + feed.feedInfo.feedId).selectAll('path').classed('selected', true);
                dataFeedSelectedRef(feed);
            }
        )
        .merge(label)
        .attr("y", d => (d - feedHeight * 0.5))
        .text(feed.feedInfo.measurementLabel);
    label.exit().remove();

    measurements.enter().append('circle')
        .merge(measurements)  // merge causes below to be applied to new and existing data
        .classed('selected', feed.feedInfo.feedId === selectedFeed)
        .on('mouseover', function (d) {
            return measurementTooltip.show(d);
        })
        .on('mouseleave', function (d) {
            return measurementTooltip.hide(d);
        })
        .attr("cx", function (d) {
            return sharedTimeScale(d.timestamp);
        })
        .attr("cy", function (d) {
            return measurementScale(d.measurementValue) + yBase;
        });
    measurements.exit().remove();

    let interpLine = line()
        .x(function (d) {
            return sharedTimeScale(d.timestamp);
        })
        .y(function (d) {
            return measurementScale(d.measurementValue) + yBase;
        })
        .curve(curveLinear);

    trendLine.enter().append('path')
        .merge(trendLine)
        .classed('selected', feed.feedInfo.feedId === selectedFeed)
        .attr("d", d => interpLine(d));
    trendLine.exit().remove();

    yAxis.attr("transform", "translate(" + timelineMargin.left + "," + (timelineMargin.top / 2 + yBase) + ")");

    yAxis.select("g.axis-y")
        .call(yAxisSettings);

}
 test('loading d3-format', function(assert) {
   assert.equal(format('$,.2f')(1200.98), '$1,200.98', 'loaded d3 format')
 })
	render() {
		const { type, data: initialData, width, ratio } = this.props;
		const { mouseMoveEvent, panEvent, zoomEvent, zoomAnchor } = this.props;
		const { clamp } = this.props;

		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(initialData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		const margin = { left: 70, right: 70, top: 20, bottom: 30 };

		const height = 400;

		const gridHeight = height - margin.top - margin.bottom;
		const gridWidth = width - margin.left - margin.right;

		const showGrid = true;
		const yGrid = showGrid ? { innerTickSize: -1 * gridWidth, tickStrokeOpacity: 0.2 } : {};
		const xGrid = showGrid ? { innerTickSize: -1 * gridHeight, tickStrokeOpacity: 0.2 } : {};

		return (
			<ChartCanvas ref={this.saveNode} height={height}
				ratio={ratio}
				width={width}
				margin={{ left: 70, right: 70, top: 10, bottom: 30 }}

				mouseMoveEvent={mouseMoveEvent}
				panEvent={panEvent}
				zoomEvent={zoomEvent}
				clamp={clamp}
				zoomAnchor={zoomAnchor}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xExtents={xExtents}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
			>

				<Chart id={1}
					yExtents={d => [d.high, d.low]}
				>
					<XAxis axisAt="bottom"
						orient="bottom"
						zoomEnabled={!zoomEvent}
						{...xGrid} />
					<YAxis axisAt="right"
						orient="right"
						ticks={5}
						zoomEnabled={!zoomEvent}
						{...yGrid}
					/>

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<OHLCTooltip origin={[-40, 0]}/>
					<ZoomButtons />
				</Chart>
				<Chart id={2}
					yExtents={d => d.volume}
					height={150} origin={(w, h) => [0, h - 150]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".0s")} zoomEnabled={!zoomEvent} />

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={(d) => d.close > d.open ? "#6BA583" : "#FF0000"} />
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#25
0
	render() {
		const ema20 = ema()
			.options({
				windowSize: 20, // optional will default to 10
				sourcePath: "close", // optional will default to close as the source
			})
			.skipUndefined(true) // defaults to true
			.merge((d, c) => {d.ema20 = c;}) // Required, if not provided, log a error
			.accessor(d => d.ema20) // Required, if not provided, log an error during calculation
			.stroke("blue"); // Optional

		const sma20 = sma()
			.options({ windowSize: 20 })
			.merge((d, c) => {d.sma20 = c;})
			.accessor(d => d.sma20);

		const wma20 = wma()
			.options({ windowSize: 20 })
			.merge((d, c) => {d.wma20 = c;})
			.accessor(d => d.wma20);

		const tma20 = tma()
			.options({ windowSize: 20 })
			.merge((d, c) => {d.tma20 = c;})
			.accessor(d => d.tma20);

		const ema50 = ema()
			.options({ windowSize: 50 })
			.merge((d, c) => {d.ema50 = c;})
			.accessor(d => d.ema50);

		const smaVolume50 = sma()
			.options({ windowSize: 20, sourcePath: "volume" })
			.merge((d, c) => {d.smaVolume50 = c;})
			.accessor(d => d.smaVolume50)
			.stroke("#4682B4")
			.fill("#4682B4");

		const { type, data: initialData, width, ratio } = this.props;

		const calculatedData = ema20(sma20(wma20(tma20(ema50(smaVolume50(initialData))))));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={400}
				width={width}
				ratio={ratio}
				margin={{ left: 70, right: 70, top: 10, bottom: 30 }}
				type={type}
				seriesName="MSFT"
				data={data}
				xScale={xScale}
				xAccessor={xAccessor}
				displayXAccessor={displayXAccessor}
				xExtents={xExtents}
			>
				<Chart id={1}
					yExtents={[d => [d.high, d.low], sma20.accessor(), wma20.accessor(), tma20.accessor(), ema20.accessor(), ema50.accessor()]}
					padding={{ top: 10, bottom: 20 }}
				>
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={sma20.accessor()} stroke={sma20.stroke()}/>
					<LineSeries yAccessor={wma20.accessor()} stroke={wma20.stroke()}/>
					<LineSeries yAccessor={tma20.accessor()} stroke={tma20.stroke()}/>
					<LineSeries yAccessor={ema20.accessor()} stroke={ema20.stroke()}/>
					<LineSeries yAccessor={ema50.accessor()} stroke={ema50.stroke()}/>
					<CurrentCoordinate yAccessor={sma20.accessor()} fill={sma20.stroke()} />
					<CurrentCoordinate yAccessor={wma20.accessor()} fill={wma20.stroke()} />
					<CurrentCoordinate yAccessor={tma20.accessor()} fill={tma20.stroke()} />
					<CurrentCoordinate yAccessor={ema20.accessor()} fill={ema20.stroke()} />
					<CurrentCoordinate yAccessor={ema50.accessor()} fill={ema50.stroke()} />

					<OHLCTooltip origin={[-40, 0]}/>
					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: sma20.accessor(),
								type: "SMA",
								stroke: sma20.stroke(),
								windowSize: sma20.options().windowSize,
								echo: "some echo here",
							},
							{
								yAccessor: wma20.accessor(),
								type: "WMA",
								stroke: wma20.stroke(),
								windowSize: wma20.options().windowSize,
								echo: "some echo here",
							},
							{
								yAccessor: tma20.accessor(),
								type: "TMA",
								stroke: tma20.stroke(),
								windowSize: tma20.options().windowSize,
								echo: "some echo here",
							},
							{
								yAccessor: ema20.accessor(),
								type: "EMA",
								stroke: ema20.stroke(),
								windowSize: ema20.options().windowSize,
								echo: "some echo here",
							},
							{
								yAccessor: ema50.accessor(),
								type: "EMA",
								stroke: ema50.stroke(),
								windowSize: ema50.options().windowSize,
								echo: "some echo here",
							},
						]}
					/>
				</Chart>
				<Chart id={2}
					yExtents={[d => d.volume, smaVolume50.accessor()]}
					height={150} origin={(w, h) => [0, h - 150]}
				>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "red"} />
					<AreaSeries yAccessor={smaVolume50.accessor()} stroke={smaVolume50.stroke()} fill={smaVolume50.fill()}/>
					<CurrentCoordinate yAccessor={smaVolume50.accessor()} fill={smaVolume50.stroke()} />
					<CurrentCoordinate yAccessor={d => d.volume} fill="#9B0A47" />
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
	render() {
		const { type, data, width, ratio } = this.props;

		const xAccessor = d => d.date;
		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={400}
					ratio={ratio}
					width={width}
					margin={{ left: 80, right: 80, top: 10, bottom: 30 }}
					type={type}
					seriesName="MSFT"
					data={data}
					xScale={scaleTime()}
					xAccessor={xAccessor}
					xExtents={xExtents}>
				<Chart id={2}
						yExtents={[d => d.volume]}
						height={150} origin={(w, h) => [0, h - 150]}>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".0s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />

					<CurrentCoordinate yAccessor={d => d.volume} fill="#9B0A47" />

					<EdgeIndicator itemType="first" orient="left" edgeAt="left"
						yAccessor={d => d.volume} displayFormat={format(".4s")} fill="#0F0F0F"/>
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.volume} displayFormat={format(".4s")} fill="#0F0F0F"/>
				</Chart>
				<Chart id={1}
						yExtents={[d => [d.high, d.low]]}
						padding={{ top: 40, bottom: 20 }}>
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateX
						rectWidth={60}
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%H:%M:%S")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]} xDisplayFormat={timeFormat("%Y-%m-%d %H:%M:%S")}/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
	render() {
		const { type, data: initialData, width, ratio } = this.props;

		const ema20 = ema()
			.id(0)
			.options({ windowSize: 13 })
			.merge((d, c) => { d.ema20 = c; })
			.accessor(d => d.ema20);

		const ema50 = ema()
			.id(2)
			.options({ windowSize: 50 })
			.merge((d, c) => { d.ema50 = c; })
			.accessor(d => d.ema50);

		const buySell = algo()
			.windowSize(2)
			.accumulator(([prev, now]) => {
				const { ema20: prevShortTerm, ema50: prevLongTerm } = prev;
				const { ema20: nowShortTerm, ema50: nowLongTerm } = now;
				if (prevShortTerm < prevLongTerm && nowShortTerm > nowLongTerm) return "LONG";
				if (prevShortTerm > prevLongTerm && nowShortTerm < nowLongTerm) return "SHORT";
			})
			.merge((d, c) => { d.longShort = c; });

		const defaultAnnotationProps = {
			fontFamily: "Glyphicons Halflings",
			fontSize: 20,
			opacity: 0.8,
			onClick: console.log.bind(console),
		};

		const longAnnotationProps = {
			...defaultAnnotationProps,
			fill: "#006517",
			text: "\ue093",
			y: ({ yScale, datum }) => yScale(datum.low) + 20,
			tooltip: "Go long",
		};

		const shortAnnotationProps = {
			...defaultAnnotationProps,
			fill: "#E20000",
			text: "\ue094",
			y: ({ yScale, datum }) => yScale(datum.high),
			tooltip: "Go short",
		};

		const margin = { left: 80, right: 80, top: 30, bottom: 50 };
		const height = 400;

		const [yAxisLabelX, yAxisLabelY] = [width - margin.left - 40, margin.top + (height - margin.top - margin.bottom) / 2];

		const calculatedData = buySell(ema50(ema20(initialData)));
		const xScaleProvider = discontinuousTimeScaleProvider
			.inputDateAccessor(d => d.date);
		const {
			data,
			xScale,
			xAccessor,
			displayXAccessor,
		} = xScaleProvider(calculatedData);

		const start = xAccessor(last(data));
		const end = xAccessor(data[Math.max(0, data.length - 150)]);
		const xExtents = [start, end];

		return (
			<ChartCanvas height={height}
					width={width}
					ratio={ratio}
					margin={margin}
					type={type}
					seriesName="MSFT"
					data={data}
					xScale={xScale}
					xAccessor={xAccessor}
					displayXAccessor={displayXAccessor}
					xExtents={xExtents}>
				<Chart id={1}
						yExtents={[d => [d.high, d.low], ema20.accessor(), ema50.accessor()]}
						padding={{ top: 10, bottom: 20 }}>
					<XAxis axisAt="bottom" orient="bottom"/>

					<Label x={(width - margin.left - margin.right) / 2} y={height - 45}
						fontSize="12" text="XAxis Label here" />

					<YAxis axisAt="right" orient="right" ticks={5} />

					<Label x={yAxisLabelX} y={yAxisLabelY}
						rotate={-90}
						fontSize="12" text="YAxis Label here" />
					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema20.accessor()} stroke={ema20.stroke()}/>
					<LineSeries yAccessor={ema50.accessor()} stroke={ema50.stroke()}/>

					<CurrentCoordinate yAccessor={ema20.accessor()} fill={ema20.stroke()} />
					<CurrentCoordinate yAccessor={ema50.accessor()} fill={ema50.stroke()} />
					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>
					<MovingAverageTooltip
						onClick={e => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema20.accessor(),
								type: "EMA",
								stroke: ema20.stroke(),
								windowSize: ema20.options().windowSize,
							},
							{
								yAccessor: ema50.accessor(),
								type: "EMA",
								stroke: ema50.stroke(),
								windowSize: ema50.options().windowSize,
							},
						]}
						/>

					<Annotate with={LabelAnnotation} when={d => d.longShort === "LONG"}
						usingProps={longAnnotationProps} />
					<Annotate with={LabelAnnotation} when={d => d.longShort === "SHORT"}
						usingProps={shortAnnotationProps} />

				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}
示例#28
0
文件: index.js 项目: j143/react-vis
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {scaleLinear} from 'd3-scale';
import {format} from 'd3-format';

import {AnimationPropType} from 'animation';
import XYPlot from 'plot/xy-plot';
import {DISCRETE_COLOR_RANGE} from 'theme';
import {MarginPropType} from 'utils/chart-utils';
import PolygonSeries from 'plot/series/polygon-series';
import LabelSeries from 'plot/series/label-series';
import DecorativeAxis from 'plot/axis/decorative-axis';

const predefinedClassName = 'rv-radar-chart';
const DEFAULT_FORMAT = format('.2r');
/**
 * Generate axes for each of the domains
 * @param {Object} props
 - props.animation {Boolean}
 - props.domains {Array} array of object specifying the way each axis is to be plotted
 - props.style {object} style object for the whole chart
 - props.tickFormat {Function} formatting function for axes
 - props.startingAngle {number} the initial angle offset
 * @return {Array} the plotted axis components
 */
function getAxes(props) {
  const {
    animation,
    domains,
    startingAngle,
示例#29
0
	displayFormat: PropTypes.func.isRequired,
	origin: PropTypes.array.isRequired,
	displayValuesFor: PropTypes.func,
	onClick: PropTypes.func,
	fontFamily: PropTypes.string,
	fontSize: PropTypes.number,
	width: PropTypes.number, // "width" only be used, if layout is "horizontal" or "horizontalRows".
	verticalSize: PropTypes.number,  // "verticalSize" only be used, if layout is "vertical", "verticalRows".
	options: PropTypes.arrayOf( PropTypes.shape( {
		yLabel: PropTypes.oneOfType( [
			PropTypes.string,
			PropTypes.func] ).isRequired,
		yAccessor: PropTypes.func.isRequired,
		labelFill: PropTypes.string,
		valueFill: PropTypes.string,
		withShape: PropTypes.bool, // "withShape" is ignored, if layout is "horizontalInline" or "vertical".
	} ) ),
};

GroupTooltip.defaultProps = {
	className: "react-stockcharts-tooltip react-stockcharts-group-tooltip",
	layout: "horizontal",
	displayFormat: format( ".2f" ),
	displayValuesFor: displayValuesFor,
	origin: [0, 0],
	width: 60,
	verticalSize: 13,
};

export default GroupTooltip;
	render() {
		const { type, width, ratio } = this.props;
		const { data, ema26, ema12, macdCalculator, smaVolume50, xScale, xAccessor, displayXAccessor } = this.state;

		return (
			<ChartCanvas ratio={ratio} width={width} height={600}
					margin={{ left: 70, right: 70, top: 20, bottom: 30 }} type={type}
					seriesName="MSFT"
					data={data}
					xScale={xScale} xAccessor={xAccessor} displayXAccessor={displayXAccessor}
					onLoadMore={this.handleDownloadMore}>
				<Chart id={1} height={400}
						yExtents={[d => [d.high, d.low], ema26.accessor(), ema12.accessor()]}
						padding={{ top: 10, bottom: 20 }}>
					<XAxis axisAt="bottom" orient="bottom" showTicks={false} outerTickSize={0} />
					<YAxis axisAt="right" orient="right" ticks={5} />

					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<CandlestickSeries />
					<LineSeries yAccessor={ema26.accessor()} stroke={ema26.stroke()}/>
					<LineSeries yAccessor={ema12.accessor()} stroke={ema12.stroke()}/>

					<CurrentCoordinate yAccessor={ema26.accessor()} fill={ema26.stroke()} />
					<CurrentCoordinate yAccessor={ema12.accessor()} fill={ema12.stroke()} />

					<EdgeIndicator itemType="last" orient="right" edgeAt="right"
						yAccessor={d => d.close} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"}/>

					<OHLCTooltip origin={[-40, 0]}/>
					<MovingAverageTooltip
						onClick={(e) => console.log(e)}
						origin={[-38, 15]}
						options={[
							{
								yAccessor: ema26.accessor(),
								type: ema26.type(),
								stroke: ema26.stroke(),
								...ema26.options(),
							},
							{
								yAccessor: ema12.accessor(),
								type: ema12.type(),
								stroke: ema12.stroke(),
								...ema12.options(),
							},
						]}
						/>
				</Chart>
				<Chart id={2} height={150}
						yExtents={[d => d.volume, smaVolume50.accessor()]}
						origin={(w, h) => [0, h - 300]}>
					<YAxis axisAt="left" orient="left" ticks={5} tickFormat={format(".2s")}/>

					<MouseCoordinateY
						at="left"
						orient="left"
						displayFormat={format(".4s")} />

					<BarSeries yAccessor={d => d.volume} fill={d => d.close > d.open ? "#6BA583" : "#FF0000"} />
					<AreaSeries yAccessor={smaVolume50.accessor()} stroke={smaVolume50.stroke()} fill={smaVolume50.fill()}/>
				</Chart>
				<Chart id={3} height={150}
						yExtents={macdCalculator.accessor()}
						origin={(w, h) => [0, h - 150]} padding={{ top: 10, bottom: 10 }} >
					<XAxis axisAt="bottom" orient="bottom"/>
					<YAxis axisAt="right" orient="right" ticks={2} />

					<MouseCoordinateX
						at="bottom"
						orient="bottom"
						displayFormat={timeFormat("%Y-%m-%d")} />
					<MouseCoordinateY
						at="right"
						orient="right"
						displayFormat={format(".2f")} />

					<MACDSeries yAccessor={d => d.macd}
						{...macdAppearance} />
					<MACDTooltip
						origin={[-38, 15]}
						yAccessor={d => d.macd}
						options={macdCalculator.options()}
						appearance={macdAppearance}
						/>
				</Chart>
				<CrossHairCursor />
			</ChartCanvas>
		);
	}