# d3visual
**Repository Path**: Young_Ya/d3visual
## Basic Information
- **Project Name**: d3visual
- **Description**: 基于Vite搭建的React脚手架,使用d3数据驱动文档绘制的大屏可视化项目
- **Primary Language**: JavaScript
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2023-11-29
- **Last Updated**: 2024-01-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: D3, JavaScript, React, vite
## README
import * as d3 from 'd3';
import BorderCom from "../BorderCom/BorderCom.jsx";
import {useEffect} from "react";
/**
* 闭包函数创建tooltip
* @return {function(): *}
*/
const gen = () => {
let instance = void 0;
return () => {
if (!instance) {
instance = d3.select(self.document.body)
.append('div')
.classed("tooltip", true)
.style('position', 'absolute')
.style('z-index', '100000')
.style('color', '#ff7f0e')
.style('visibility', 'hidden') // 一开始设置为不可见
.style('text-anchor', 'middle')
.style('font-size', '20px')
.style('border', 'solid #acacac 1px')
.style('padding', '10px 20px')
.style('background', '#fff')
.style('border-radius', '10px')
.text('123213');
}
return instance;
}
}
const handle = gen()
/**
* 柱状图
* @return {JSX.Element}
* @constructor
*/
const BarGraph = () => {
// 全局变量
let data;
let svgWidth = 400, svgHeight = 380;
let intervalId = null; // 用于存储更新的定时器ID
let currentRectCount = 0;
let rectHeight = 14;
let rectMargin = 1;
/**
* 创建图表的函数
*/
function createChart() {
// 确定图表的宽度和高度
const xAxis = d3.axisLeft(d3.scaleBand(data.map(d => d.shortName), [0, svgHeight]))
const yAxis = d3.axisBottom(d3.scaleLinear([d3.min(data, d => d.openPrice), d3.max(data, d => d.openPrice)], [0, svgHeight]))
// 选择SVG元素并设置其宽度和高度
const chart = d3.select("#bar_chart")
.attr("width", svgWidth)
.attr("height", svgHeight)
.style('margin', 20)
chart.append('g')
.style('transform', 'translate(60px, -30px)')
.call(xAxis)
.attr('stroke', '#fff')
.attr('stroke-width', 0.4)
chart.append('g')
.style('transform', `translate(90px, ${svgHeight - 20}px)`)
.call(yAxis)
.attr('stroke', '#d3d8f0')
.select('path').remove();
// 更新矩形
updateData();
}
/**
* 更新数据的函数
*/
function updateData() {
// 计算下一组数据的起始索引和结束索引
const startIndex = currentRectCount;
const endIndex = startIndex + 26; // 每秒更新17个数据
const newData = data.slice(startIndex, endIndex);
d3.select('.bar_title').remove();
d3.select("#bar_chart")
.append('g')
.classed('bar_title', true)
.style('transform', `translate(0, ${svgHeight}px)`)
.append('text')
.classed("bar_title", true)
.text(newData[0].dateTime)
.attr('color', "#02a6b5")
.attr('stroke', "#02a6b5")
// 创建矩形并添加动画效果
const rectangles = d3.select("#bar_chart").selectAll("rect")
.data(newData)
// .enter()
.join("rect")
.attr("x", 80)
.attr("y", (d, i) => i * (rectHeight + rectMargin) - 50)
import * as d3 from 'd3';
import BorderCom from "../BorderCom/BorderCom.jsx";
import {useEffect} from "react";
/**
* 闭包函数创建tooltip
* @return {function(): *}
*/
const gen = () => {
let instance = void 0;
return () => {
if (!instance) {
instance = d3.select(self.document.body)
.append('div')
.classed("tooltip", true)
.style('position', 'absolute')
.style('z-index', '100000')
.style('color', '#ff7f0e')
.style('visibility', 'hidden') // 一开始设置为不可见
.style('text-anchor', 'middle')
.style('font-size', '20px')
.style('border', 'solid #acacac 1px')
.style('padding', '10px 20px')
.style('background', '#fff')
.style('border-radius', '10px')
.text('123213');
}
return instance;
}
}
const handle = gen()
/**
* 柱状图
* @return {JSX.Element}
* @constructor
*/
const BarGraph = () => {
// 全局变量
let data;
let svgWidth = 400, svgHeight = 380;
let intervalId = null; // 用于存储更新的定时器ID
let currentRectCount = 0;
let rectHeight = 14;
let rectMargin = 1;
/**
* 创建图表的函数
*/
function createChart() {
// 确定图表的宽度和高度
const xAxis = d3.axisLeft(d3.scaleBand(data.map(d => d.shortName), [0, svgHeight]))
const yAxis = d3.axisBottom(d3.scaleLinear([d3.min(data, d => d.openPrice), d3.max(data, d => d.openPrice)], [0, svgHeight]))
// 选择SVG元素并设置其宽度和高度
const chart = d3.select("#bar_chart")
.attr("width", svgWidth)
.attr("height", svgHeight)
.style('margin', 20)
chart.append('g')
.style('transform', 'translate(60px, -30px)')
.call(xAxis)
.attr('stroke', '#fff')
.attr('stroke-width', 0.4)
chart.append('g')
.style('transform', `translate(90px, ${svgHeight - 20}px)`)
.call(yAxis)
.attr('stroke', '#d3d8f0')
.select('path').remove();
// 更新矩形
updateData();
}
/**
* 更新数据的函数
*/
function updateData() {
// 计算下一组数据的起始索引和结束索引
const startIndex = currentRectCount;
const endIndex = startIndex + 26; // 每秒更新17个数据
const newData = data.slice(startIndex, endIndex);
d3.select('.bar_title').remove();
d3.select("#bar_chart")
.append('g')
.classed('bar_title', true)
.style('transform', `translate(0, ${svgHeight}px)`)
.append('text')
.classed("bar_title", true)
.text(newData[0].dateTime)
.attr('color', "#02a6b5")
.attr('stroke', "#02a6b5")
// 创建矩形并添加动画效果
const rectangles = d3.select("#bar_chart").selectAll("rect")
.data(newData)
// .enter()
.join("rect")
.attr("x", 80)
.attr("y", (d, i) => i * (rectHeight + rectMargin) - 50)
rectangles.transition(d3.transition(d3.easeLinear).duration(1000))
.attr("width", d => +d.maxPrice * 10) // 初始宽度为0
.attr("height", rectHeight)
.attr("fill", "steelblue")
rectangles.on("mousemove", (e, d) => {
// 鼠标覆盖时显
handle().style('visibility', 'visible')
.style('left', `${e.pageX + 10 + 'px'}`)
.style('top', `${e.pageY + 25 + 'px'}`).text("234345324")
.text(d.shortName + ' 开盘价 ' + d.openPrice + ' 最高价 ' + d.maxPrice);
})
.on("mouseout", function () {
// 鼠标移开时移除
d3.selectAll(".tooltip")
.style('visibility', 'hidden')
});
currentRectCount = endIndex;
if (currentRectCount >= data.length)
currentRectCount = 0;
}
useEffect(() => {
// 异步加载数据
d3.csv("./data/StockInformation.csv").then(function (csvData) {
data = csvData; // 将数据存储到全局变量中
data.sort(function (a, b) {
return d3.ascending(a.dateTime, b.dateTime);
});
// 在数据加载完成后调用创建图表的函数
clearInterval(intervalId);
createChart();
// 设置定时器,每秒更新数据
intervalId = setInterval(updateData, 3000);
});
}, [])
return (
)
}
export default BarGraph;
.attr("width", d => +d.maxPrice * 10) // 初始宽度为0
.attr("height", rectHeight)
.attr("fill", "steelblue")
rectangles.on("mousemove", (e, d) => {
// 鼠标覆盖时显
handle().style('visibility', 'visible')
.style('left', `${e.pageX + 10 + 'px'}`)
.style('top', `${e.pageY + 25 + 'px'}`).text("234345324")
.text(d.shortName + ' 开盘价 ' + d.openPrice + ' 最高价 ' + d.maxPrice);
})
.on("mouseout", function () {
// 鼠标移开时移除
d3.selectAll(".tooltip")
.style('visibility', 'hidden')
});
currentRectCount = endIndex;
if (currentRectCount >= data.length)
currentRectCount = 0;
}
useEffect(() => {
// 异步加载数据
d3.csv("./data/StockInformation.csv").then(function (csvData) {
data = csvData; // 将数据存储到全局变量中
data.sort(function (a, b) {
return d3.ascending(a.dateTime, b.dateTime);
});
// 在数据加载完成后调用创建图表的函数
clearInterval(intervalId);
createChart();
// 设置定时器,每秒更新数据
intervalId = setInterval(updateData, 3000);
});
}, [])
return (
)
}
export default BarGraph;import React, {useEffect, useState} from "react";
import ChinaGeo from "../components/Geo/Geo.jsx";
import {Button, Layout} from "tdesign-react";
import TicketCount from "../components/TicketCount/TicketCount.jsx";
import WordCloud from "../components/WordCloud/WordCloud.jsx";
import BGSvg from "../components/BGSvg/BGSvg.jsx";
import BarGraph from "../components/BarGraph/BarGraph.jsx";
import AreaChart from "../components/AreaChart/index.jsx";
import RotateCom from "../components/RotateCom/RotateCom.jsx";
import './index.css';
const {Header, Content, Footer} = Layout;
/**
* 主页
* @return {JSX.Element}
* @constructor
*/
const HomePage = () => {
const [dateNow, setDateNow] = useState(new Date());
const [provence, setProvence] = useState(null);
const handleProvienceClick = (pro) => setProvence(pro)
useEffect(() => {
setInterval(() => {
setDateNow(new Date())
}, 300)
}, [])
return (
<>
省代表公司股价动态分析{dateNow.toLocaleString()}
>
)
}
export default HomePage;import React, {useEffect, useState} from "react";
import ChinaGeo from "../components/Geo/Geo.jsx";
import {Button, Layout} from "tdesign-react";
import TicketCount from "../components/TicketCount/TicketCount.jsx";
import WordCloud from "../components/WordCloud/WordCloud.jsx";
import BGSvg from "../components/BGSvg/BGSvg.jsx";
import BarGraph from "../components/BarGraph/BarGraph.jsx";
import AreaChart from "../components/AreaChart/index.jsx";
import RotateCom from "../components/RotateCom/RotateCom.jsx";
import './index.css';
const {Header, Content, Footer} = Layout;
/**
* 主页
* @return {JSX.Element}
* @constructor
*/
const HomePage = () => {
const [dateNow, setDateNow] = useState(new Date());
const [provence, setProvence] = useState(null);
const handleProvienceClick = (pro) => setProvence(pro)
useEffect(() => {
setInterval(() => {
setDateNow(new Date())
}, 300)
}, [])
return (
<>
省代表公司股价动态分析{dateNow.toLocaleString()}
>
)
}
export default HomePage;# 省代表公司股价动态分析
## 项目介绍
(1)根据全国各地的代表公司股票数据,分析数据的独特性,并绘制多种不同类型的图表,包括条形图、区域图、词云图、K线图和全国地图,以展示数据的多样性和趋势。
(2)显示准确全地图,对于各省份的详细地图在点击对应省份实现。并且点击后在K线图和区域图上实现交互。
(3)K线图。在全地图上显示准确的地理信息,并提供详细的各省份地图,通过点击相应的省份实现交互功能。在与地图交互的同时,将相关数据呈现在K线图上,以便更好地理解和分析股票走势。
(4)区域图。利用区域图展示某个特定时间段内股价的变化情况,通过面积的大小来反映股价的涨跌幅度,从而更直观地观察和比较不同公司的股价走势。
(5)条形图。使用动态的条形图来展示每个公司随着时间推移的变化情况,特别是最高股价的变动情况,以便更清晰地了解不同公司的股价表现和潜在投资机会。
(6)词云图。获取数据信息,按数据的比重突出显示。
(7)最后根据这些图表信息分析得出股票价值与地区分布的关系。
## 项目运行
首先安装依赖项
```shell
npm install
# or
yarn install
```
然后运行即可
```shell
npm run dev
# or
yarn dev
```
本地访问
```
http://localhost:5173
```