React和API构建30天比特币价格交互式图表

在本教程中了解React,交互式图表以及使用API。不关心后台怎么完成,跨过比特币价格图表。包含所有代码的GitHub存储库链接在本文的底部。

为什么?

上周我发布了一个关于使用React JS进行简单数据可视化的教程。 该教程引导您构建一个简单的折线图:

是的,好吧,这很无聊。但是,该教程的重点不在于构建令人兴奋的东西,而是在React中学习SVG的基础知识。

在评论中,Kris Morf询问如何在图表中添加区域填充,以CoinBase为例向我展示。以下是这些图表的样子:

是的,这比我的蹩脚线图要冷得多。回答Kris Morf之后如何添加填充到折线图中,我想为什么我不克隆它呢?这就是我周末所做的。

这是我构建的内容,以及我将在本文中介绍的内容:

这里有demo如果你想体验它。注意:加载可能需要一秒钟,因为它当前部署在now.sh的免费层上。

项目结构

这是我的项目结构的样子。有四种react组件。

  • app.js:父组件。
  • InfoBox.js:自上个月以来我们的实时比特币价格和变化。
  • ToolTip.js:显示工具提示,显示悬停位置的日期和价格。
  • LineChart.js:Renders实际折线图。返回单个SVG元素。

API

对于这个项目,我能找到的最好的API是CoinDesk API。如果你有更好的比特币API,请让我知道!

CoinDesk API提供实时和历史比特币价格数据。对于这个项目,我在左上角显示实时比特币价格(InfoBox.js)。它每90秒更新一次。

历史价格是我用来为图表提供数据的价格。历史数据端点是:https://api.coindesk.com/v1/bpi/historical/close.json

API返回一个如下所示的对象:

1
2
3
4
5
6
7
8
9
10
{
“bpi”: {
“2017–06–24”: 2619.1188,
”2017–06–25": 2594.4538,
”2017–06–26": 2485.3588,
”2017–06–27": 2593.17,
”2017–06–28": 2584.5638,
// ...
}
}

一旦我获得了数据,我就会遍历它并将其格式化为一个对象数组:

1
2
3
4
5
6
7
8
for (let date in bitcoinData.bpi){
sortedData.push({
d: moment(date).format('MMM DD'),
p: bitcoinData.bpi[date].toLocaleString(),
x: count,
y: bitcoinData.bpi[date]
});
}
  • d :格式化日期(例如:7月31日)
  • p :格式化货币字符串(例如:$2,000.46)
  • x :计数(数字,从0开始)
  • y :无格式价格(2000.46738——用于图表)

然后将数据发送到构建图表的子组件。以下是数据流的更高级别概述。

基本数据流

该项目的数据流非常简单:

  • 1.app.js从CoinDesk API获取历史数据并将其格式化为对象数组。
  • 2.数据传递给LineChart.js组件,该组件根据app.js提供的数据呈现图表。
  • 3.当在LineChart.js渲染的SVG组件被悬停时,会发生以下三件事:LineChart.js在光标坐标上绘制一条垂直线。它确定与光标最接近的数据点,并绘制一个圆圈以突出显示该数据点。最后,数据被传递回app.js指示悬停位置和最近点。
  • 4.app.js将数据发送到ToolTip.js以便工具提示可以在正确的位置呈现,并使用正确的数据。
  • 5.InfoBox.js独立于其他组件运行,每90秒从CoinDesk API获取实时数据。格式化数据,然后显示给用户。

打破图表

图形不仅仅是绘制到屏幕上的一个形状。它是单个SVG元素中的形状和线条的集合。如果你看一下LineChart.js,你会看到最多有八个函数调用用于创建我们的图:

1
2
3
4
5
6
7
8
this.makeAxis()         Makes Graph Axis
this.makePath() Makes Graph Line
this.makeArea() Makes Shaded Graph Area (under line)
this.makeLabels() Makes Graph Labels
this.getCoords(e) When Hovered Gets Coords of Hover
this.createLine() When Hovered Makes Vertical Line
this.makeActivePoint() When Hovered Finds Closest Point
this.stopHover() Clears Line and Point When Hover Stops

我们来看一个例子。 如果我们删除所有内容并且只运行makePath()我们只会在数据点上留下一条SVG行。这是看起来像:

同样,我们可以删除除makeArea()makeAxis()之外的所有内容。这将绘制我们的两条轴线和阴影形状。这是结果:

直到我们开始添加多个形状和线条,我们的图形才开始变得有趣。makeAxis()悬停效果,这是我们使用makeAxis()makePath()makeLabels()makeArea()

当SVG元素悬停时,会发生有趣的事情。 在悬停时,我运行一个函数,在图形上获取鼠标的坐标。 为此,我们需要两条信息:

  • 1.页面中SVG图的位置
  • 2.鼠标的位置

这是代码的样子:

1
2
3
const svgLocation = document.getElementsByClassName("linechart")[0].getBoundingClientRect();
const adjustment = (svgLocation.width - svgWidth) / 2; //takes padding into consideration
const relativeLoc = e.clientX - svgLocation.left - adjustment;

我首先获得折线图的svgLocation。然后,我调整图表可能具有的任何填充。最后,我取出鼠标的x位置并减去SVG图表左侧的像素。这给了我鼠标相对于折线图的位置。

更新状态,并在鼠标的X坐标图形上绘制垂直线:

同时,我可以简单地遍历图表上的坐标,以确定哪一个具有最接近鼠标的X值:

1
2
3
4
5
6
7
8
let {svgWidth} = this.props;
let closestPoint = {};
for(let i = 0, c = svgWidth; i < svgData.length; i++){
if ( Math.abs(svgData[i].svgX — this.state.hoverLoc) <= c ){
c = Math.abs(svgData[i].svgX — this.state.hoverLoc);
closestPoint = svgData[i];
}
}

注意:正如Francesco Zuppichini在评论中指出的那样,二进制搜索比简单地循环数组更好。

找到最接近的X值后,我们在该点绘制一个SVG圆:

1
2
3
4
5
6
7
8
9
10
11
12
makeActivePoint(){
const {color, pointRadius} = this.props;
return (
<circle
className='linechart_point'
style={{stroke: color}}
r={pointRadius}
cx={this.state.activePoint.svgX}
cy={this.state.activePoint.svgY}
/>
);
}

结果是这样的:

工具提示

等式的最后一部分是工具提示。工具提示是一个完全不同的组件,但就像我们的垂直线一样。工具提示需要两条信息才能工作:

  • 1.当前鼠标位置
  • 2.最接近的数据点

这两条信息都是从LineChart.js收到的。然后,ToolTip.js只返回一个位于鼠标上方的<div>元素。使用来自最近数据点的格式化数据。

1
2
3
4
5
6
7
8
9
10
11
let placementStyles = {};
let width = 100;
placementStyles.width = width + 'px';
placementStyles.left = hoverLoc + svgLocation.left - (width/2);
return (
<div className='hover' style={ placementStyles }>
<div className='date'>{ activePoint.d }</div>
<div className='price'>{activePoint.p }</div>
</div
)
...

代码在哪里?

很高兴你问。该项目的所有代码都是开源的,可以在我的GitHub Repo中找到。演示来到这里

如果这个项目的SVG元素让感兴趣,我将在上一篇文章中详细介绍图形:使用React JS进行简单数据可视化或者svg教程d3.js数据可视化。如果真的想深入了解React并学习如何构建很酷的东西,请查看React JS课程

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文React和API构建比特币价格30天交互式图表