Skip to content

Commit

Permalink
Replaced glow effect with fadein/fadeout animation
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitrievkv-grapecity committed Dec 23, 2019
1 parent d42e1b9 commit 5e9b71f
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 226 deletions.
15 changes: 10 additions & 5 deletions packages/stock-charts/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class App extends React.Component {
});
});


this.state = {
chartPeriod: ChartPeriod.m12,
chartColor: null
Expand Down Expand Up @@ -69,13 +68,13 @@ class App extends React.Component {
switch(this.state.chartName) {
case 'hloc':
return <HlocChart period={this.state.chartPeriod}
onPeriodChange={(p) => this.changeChartPeriod(p)}
onInitialize={(p, c) => this.handleChartInitialize(p, c)}
onColorChange={(c) => this.changeChartColor(c)}
storageKey={Config.HLOC_STGKEY} />;

case 'trendline':
return <TrendlineChart period={this.state.chartPeriod}
onPeriodChange={(p) => this.changeChartPeriod(p)}
onInitialize={(p, c) => this.handleChartInitialize(p, c)}
onColorChange={(c) => this.changeChartColor(c)}
storageKey={Config.TRENDLINE_STGKEY} />;

Expand All @@ -85,9 +84,8 @@ class App extends React.Component {
}

render() {
const chartColor = this.state.chartColor
const headerStyle = {
boxShadow: chartColor ? '0px 0px 20px ' + chartColor : 'none'
backgroundColor: this.state.chartColor
};
return (
<div className="panel panel-default">
Expand Down Expand Up @@ -119,6 +117,13 @@ class App extends React.Component {
return this.state.chartPeriod === value;
}

handleChartInitialize(period, color) {
this.setState({
chartPeriod: period,
chartColor: color
});
}

changeChartPeriod(value) {
this.setState({
chartPeriod: value
Expand Down
137 changes: 137 additions & 0 deletions packages/stock-charts/src/chartController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { ChannelName, ChannelTopics } from 'stock-core';

const fin = window.fin;

export class ChartController {

_channelPromise;

/**
* Indicates that disconnection occured and currently connection is in progress.
* It is used to avoid multiple connections in such cases.
*/
_reconnecting = false;

constructor(props) {
this.props = props;
this.currentSymbol = null;

this._initChannel();
}

_initChannel() {
if (typeof fin === 'undefined') {
console.warn('Channels cannot be initialized because "fin" is undefined.');
return;
}

this._channelPromise = fin.InterApplicationBus.Channel.connect(ChannelName)
.then(channel => this._handleConnect(channel));
}

_handleConnect(channel) {
this._reconnecting = false;
console.log('Channels: connected');
this._loadItems(channel);
channel.register(ChannelTopics.CurrentChanged, symbol => this._currentChanged(symbol));
channel.register(ChannelTopics.ItemAdded, item => this._itemAdded(item));
channel.register(ChannelTopics.ItemRemoved, item => this._itemRemoved(item));
channel.register(ChannelTopics.ItemChanged, item => { /* do nothing */ });
channel.onDisconnection(channelInfo => this._handleDisconnect(channelInfo));
return channel;
}

_handleDisconnect(channelInfo) {
if (this._reconnecting) {
return;
}
this._reconnecting = true;
// handle the channel lifecycle here - we can connect again which will return a promise
// that will resolve if/when the channel is re-created.
console.log('Channels: disconnected');
this._initChannel();
}

_loadItems(channel) {
channel.dispatch(ChannelTopics.LoadItems).then(response => {
const current = response.current;
const items = response.items;
console.log('Channels: received response "loadItems". Items: ' + items.length);
items.forEach(item => {
let prices = this.props.parsePrices(item.prices);
this.props.portfolio.addItem(item.symbol, item.chart, item.name, item.color, prices);
});
window.setTimeout(() => {
this._currentChanged(current);
});
});

console.log('Channels: sent message "loadItems"');
}

_itemAdded(item) {
console.log('Channels: received message "itemAdded"');

let prices = this.props.parsePrices(item.prices);
this.props.portfolio.addItem(item.symbol, item.chart, item.name, item.color, prices);
}

_itemRemoved(item) {
console.log('Channels: received message "itemRemoved"');

this.props.portfolio.removeItem(item.symbol);
}

// update chart selection to match portfolio selection
_currentChanged(symbol) {
console.log('Channels: received message "currentChanged"');

const chartElement = this.props.chartRef.current;
if (!chartElement) {
return;
}

if (!this.currentSymbol) {
this.currentSymbol = symbol;
this.changeCurrent(this.currentSymbol);
return;
}

/* eslint-disable-next-line eqeqeq */
if (symbol == this.currentSymbol) {
return;
}

this.currentSymbol = symbol;

chartElement.classList.remove('fadein', 'fadeout');
chartElement.classList.add('fadein');
}

handleAnimationStart() {
// do nothing here
}

handleAnimationEnd() {
const chartElement = this.props.chartRef.current;
if (chartElement.classList.contains('fadeout')) {

chartElement.classList.remove('fadeout');
} else if (chartElement.classList.contains('fadein')) {

chartElement.classList.remove('fadein');
chartElement.style.visibility = 'hidden';

this.changeCurrent(this.currentSymbol);

chartElement.style.visibility = 'visible';
chartElement.classList.add('fadeout');
}
}

changeCurrent(symbol) {
/* eslint-disable-next-line eqeqeq */
const current = this.props.portfolio.view.items.find(pi => pi.symbol == symbol);
this.props.handleCurrentChange(current);
}
}
133 changes: 32 additions & 101 deletions packages/stock-charts/src/hloc-chart/chart.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,34 @@
import React from 'react';
import * as wjChart from "@grapecity/wijmo.react.chart";
import * as wjChartAnalysis from "@grapecity/wijmo.react.chart.analytics";
import { ChannelName, ChannelTopics, Portfolio } from 'stock-core';
import { Portfolio } from 'stock-core';
import { ChartController } from '../chartController';
import './chart.css';

const fin = window.fin;

class Chart extends React.Component {
_portfolio;
_channelPromise;

/**
* Indicates that disconnection occured and currently connection is in progress.
* It is used to avoid multiple connections in such cases.
*/
_reconnecting = false;

constructor(props) {
super(props);

this.state = {
current: null
};

this.chartRef = React.createRef();

// create portfolio
this._portfolio = new Portfolio({
this.portfolio = new Portfolio({
storageKey: this.props.storageKey,
mapToChartData: this._mapToChartData
mapToChartData: this.mapToChartData
});

this.controller = new ChartController({
chartRef: this.chartRef,
portfolio: this.portfolio,
parsePrices: this.parsePrices,
handleCurrentChange: this.handleCurrentChange.bind(this)
});

this.props.onPeriodChange(this._portfolio.chartPeriod);
this.props.onColorChange(null);
this.state = {
current: null
};

this._initChannel();
this.props.onInitialize(this.portfolio.chartPeriod, null);
}

renderChartContent() {
Expand Down Expand Up @@ -60,51 +56,22 @@ class Chart extends React.Component {
}

render() {
this._portfolio.chartPeriod = this.props.period;
this.portfolio.chartPeriod = this.props.period;
return (
<wjChart.FlexChart binding="high,low,open,close" bindingX="date" chartType="HighLowOpenClose">
{this.renderChartContent()}
<wjChart.FlexChartAxis wjProperty="axisY" format="n0" majorGrid={true} majorTickMarks={0}></wjChart.FlexChartAxis>
<wjChart.FlexChartAxis wjProperty="axisX" format="MMM-yyyy" majorGrid={true} majorTickMarks={0}></wjChart.FlexChartAxis>
<wjChart.FlexChartLegend position="None"></wjChart.FlexChartLegend>
</wjChart.FlexChart>
<div ref={this.chartRef} className="chart-container"
onAnimationStart={this.controller.handleAnimationStart.bind(this.controller)}
onAnimationEnd={this.controller.handleAnimationEnd.bind(this.controller)}>
<wjChart.FlexChart chartType="HighLowOpenClose" binding="high,low,open,close" bindingX="date">
{this.renderChartContent()}
<wjChart.FlexChartAxis wjProperty="axisY" format="n0" majorGrid={true} majorTickMarks={0}></wjChart.FlexChartAxis>
<wjChart.FlexChartAxis wjProperty="axisX" format="MMM-yyyy" majorGrid={true} majorTickMarks={0}></wjChart.FlexChartAxis>
<wjChart.FlexChartLegend position="None"></wjChart.FlexChartLegend>
</wjChart.FlexChart>
</div>
);
}

_initChannel() {
if (typeof fin === 'undefined') {
console.warn('Channels cannot be initialized because "fin" is undefined.');
return;
}

this._channelPromise = fin.InterApplicationBus.Channel.connect(ChannelName)
.then(channel => this._handleConnect(channel));
}

_handleConnect(channel) {
this._reconnecting = false;
console.log('Channels: connected');
this._loadItems(channel);
channel.register(ChannelTopics.CurrentChanged, symbol => this._currentChanged(symbol));
channel.register(ChannelTopics.ItemAdded, item => this._itemAdded(item));
channel.register(ChannelTopics.ItemRemoved, item => this._itemRemoved(item));
channel.register(ChannelTopics.ItemChanged, item => { /* do nothing */ });
channel.onDisconnection(channelInfo => this._handleDisconnect(channelInfo));
return channel;
}

_handleDisconnect(channelInfo) {
if (this._reconnecting) {
return;
}
this._reconnecting = true;
// handle the channel lifecycle here - we can connect again which will return a promise
// that will resolve if/when the channel is re-created.
console.log('Channels: disconnected');
this._initChannel();
}

_mapToChartData(first, price) {
mapToChartData(first, price) {
return {
date: price.date,
high: price.high,
Expand All @@ -114,7 +81,7 @@ class Chart extends React.Component {
};
}

_parsePrices(prices) {
parsePrices(prices) {
return prices.map(p => {
return {
date: new Date(p.date),
Expand All @@ -126,47 +93,11 @@ class Chart extends React.Component {
});
}

_loadItems(channel) {
channel.dispatch(ChannelTopics.LoadItems).then(response => {
const current = response.current;
const items = response.items;
console.log('Channels: received response "loadItems". Items: ' + items.length);
items.forEach(item => {
let prices = this._parsePrices(item.prices);
this._portfolio.addItem(item.symbol, item.chart, item.name, item.color, prices);
});
window.setTimeout(() => {
this._currentChanged(current);
});
});

console.log('Channels: sent message "loadItems"');
}

_itemAdded(item) {
console.log('Channels: received message "itemAdded"');

let prices = this._parsePrices(item.prices);
this._portfolio.addItem(item.symbol, item.chart, item.name, item.color, prices);
}

_itemRemoved(item) {
console.log('Channels: received message "itemRemoved"');

this._portfolio.removeItem(item.symbol);
}

// update chart selection to match portfolio selection
_currentChanged(symbol) {
console.log('Channels: received message "currentChanged"');

/* eslint-disable-next-line eqeqeq */
const current = this._portfolio.view.items.find(pi => pi.symbol == symbol);

this.props.onColorChange(current.color);
handleCurrentChange(current) {
this.setState({
current
});
this.props.onColorChange(current ? current.color : null);
}
}

Expand Down
Loading

0 comments on commit 5e9b71f

Please sign in to comment.