Skip to content

Commit

Permalink
Merge pull request #1832 from nervosnetwork/develop
Browse files Browse the repository at this point in the history
Merge develop into testnet
  • Loading branch information
Keith-CY authored Jan 4, 2025
2 parents 17f3cf7 + 3d3d8c7 commit b193379
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 46 deletions.
31 changes: 30 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
"circulating_supply": "Circulating Supply",
"burnt": "Burnt",
"locked": "Unvested",
"week": "Time (week)",
"year": "Time (year)",
"nominal_apc": "Nominal DAO Compensation Rate",
"inflation_rate": "Inflation Rate",
Expand Down Expand Up @@ -326,6 +327,9 @@
"ckb_amount": "CKB Amount",
"contract_resource_distributed": "Contract Resource Distribution",
"contract_resource_distributed_description": "The x axis represents contract's unique address count, the y axis represents the contract's CKB amount, the symbol size represents the contract's transaction count.",
"active_addresses": "Active Addresses",
"active_addresses_description": "The number of unique addresses that have participated in the network as a sender or receiver.",
"active_address_count": "Active Addresses Count",
"country": "Country/Region",
"node_country_distribution": "Nodes distribution by Country/Region",
"top_50_holders": "Top 50 Holders",
Expand All @@ -340,7 +344,32 @@
"over_three_years": "> 3y",
"ckb_hodl_wave": "CKB HODL Wave",
"h24_transaction_count": "24hr Transaction Count",
"holder_count": "Holder Count"
"holder_count": "Holder Count",
"address_label": {
"anyoneCanPayLock": "Anyone Can Pay",
"btcTimeLock": "BTC Time",
"cheque": "Cheque",
"flashSigner": "Flash Signer",
"godwokenCustodianLock": "Godwoken Custodian",
"godwokenDepositLock": "Godwoken Deposit",
"godwokenStakeLock": "Godwoken Stake",
"godwokenWithdrawalLock": "Godwoken Withdrawal",
"iCkbLogic": "iCKB Logic",
"joyId": "Joy ID",
"nostr": "Nostr",
"omniLockV1": "Omni Lock V1",
"omniLockV2": "Omni Lock V2",
"pwLock": "Portal Wallet",
"rgb++": "RGB++",
"secp256K1/blake160": "Secp256k1/Blake160",
"secp256K1/multisig": "Secp256k1/Multisig",
"singleUseLock": "Single Use",
"udtLimitOrderr": "UDT Limit Order",
"unipassV2": "Unipass V2",
"unipassV3": "Unipass V3",
"wrOwnedOwner": "WR Owned Owner",
"others": "Others"
}
},
"home": {
"height": "Height",
Expand Down
4 changes: 4 additions & 0 deletions src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@
"circulating_supply": "总流通量",
"burnt": "销毁量",
"locked": "未解锁数量",
"week": "时间 (周)",
"year": "时间 (年)",
"nominal_apc": "基准补偿率",
"inflation_rate": "通胀率",
Expand Down Expand Up @@ -340,6 +341,9 @@
"ckb_amount": "CKB 数量",
"contract_resource_distributed": "合约资源分布图",
"contract_resource_distributed_description": "横轴表示合约的唯一地址数量, 纵轴是合约的 CKB 数量, 图标大小代表合约的交易数量",
"active_addresses": "活跃地址",
"active_addresses_description": "活跃地址是指在特定时间段内有交易记录的地址",
"active_address_count": "活跃地址数量",
"country": "国家(地区)",
"node_country_distribution": "节点国家(地区)分布图",
"top_50_holders": "前 50 持有地址",
Expand Down
151 changes: 151 additions & 0 deletions src/pages/StatisticsChart/activities/ActiveAddressesChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { useTranslation } from 'react-i18next'
import type { ChartColorConfig } from '../../../constants/common'
import { SmartChartPage } from '../common'
import { DATA_ZOOM_CONFIG, handleAxis, variantColors } from '../../../utils/chart'
import { explorerService } from '../../../services/ExplorerService'

// Helper function to get ISO week number and year
function getWeekNumber(timestamp: string) {
const date = new Date(+timestamp * 1000)
const firstDayOfYear = new Date(date.getFullYear(), 0, 1)
const days = Math.floor((date.getTime() - firstDayOfYear.getTime()) / (24 * 60 * 60 * 1000))
const weekNumber = Math.ceil((days + firstDayOfYear.getDay() + 1) / 7)
return `${date.getFullYear()}-W${weekNumber}`
}

const useOption = (
activeAddresses: {
createdAtUnixtimestamp: string
distribution: Record<string, number>
}[],
_: ChartColorConfig,
isMobile: boolean,
isThumbnail = false,
): echarts.EChartOption => {
const { t } = useTranslation()
const gridThumbnail = {
left: '4%',
right: '10%',
top: '8%',
bottom: '6%',
containLabel: true,
}
const grid = {
left: '4%',
right: '8%',
top: '12%',
bottom: '5%',
containLabel: true,
}

const aggregatedByWeek = activeAddresses.reduce((acc, item) => {
const week = getWeekNumber(item.createdAtUnixtimestamp)

if (!acc[week]) {
acc[week] = {
createdAtWeek: week,
distribution: {},
}
}

Object.entries(item.distribution).forEach(([key, value]) => {
acc[week].distribution[key] = (acc[week].distribution[key] || 0) + value
})

return acc
}, {} as Record<string, { createdAtWeek: string; distribution: Record<string, number> }>)

const aggregatedDdata = Object.values(aggregatedByWeek)
const dataset = aggregatedDdata.slice(0, aggregatedDdata.length - 1) // Remove the last week data because it's not complete
const xAxisData = dataset.map(item => item.createdAtWeek)
const allKeys = Array.from(new Set(dataset.flatMap(item => Object.keys(item.distribution)))).sort((a, b) => {
if (a === 'others') return 1
if (b === 'others') return -1
return a.localeCompare(b)
})
const series = allKeys.map(key => ({
name: t(`statistic.address_label.${key}`),
type: 'line',
stack: 'total',
areaStyle: {},
lineStyle: {
width: 0,
},
symbol: 'none',
emphasis: {
focus: 'series',
},
data: dataset.map(item => item.distribution[key] || 0),
}))
const colors = variantColors(allKeys.length)

return {
color: colors,
tooltip: !isThumbnail
? {
trigger: 'axis',
axisPointer: { type: 'cross' },
formatter: params => {
// Filter out fields with value 0
if (!Array.isArray(params)) return ''
const filteredParams = params.filter(item => item.value !== 0)

// Construct the tooltip content
if (filteredParams.length === 0) return '' // No fields to display

const header = `${filteredParams[0].axisValue}<br/>` // Show week
const sum = `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:white;"></span>
${t('statistic.active_address_count')}: ${filteredParams.reduce(
(acc, item) => acc + Number(item.value),
0,
)}<br/><hr style="margin: 4px 0" />`
const body = filteredParams
.map(
item =>
`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${item.color};"></span>
${item.seriesName}: ${item.value}`,
)
.join('<br/>')

return header + sum + body
},
}
: undefined,
grid: isThumbnail ? gridThumbnail : grid,
dataZoom: isThumbnail ? [] : DATA_ZOOM_CONFIG,
legend: { data: isThumbnail ? [] : allKeys.map(key => t(`statistic.address_label.${key}`) as string) },
xAxis: {
type: 'category',
boundaryGap: false,
data: xAxisData,
axisLabel: {
formatter: (value: string) => value, // Display week labels
},
name: isMobile || isThumbnail ? '' : t('statistic.week'),
},
yAxis: {
type: 'value',
name: isMobile || isThumbnail ? '' : `${t('statistic.active_address_count')}`,
axisLabel: {
formatter: (value: string) => handleAxis(+value),
},
},
series,
}
}

export const ActiveAddressesChart = ({ isThumbnail = false }: { isThumbnail?: boolean }) => {
const [t] = useTranslation()
return (
<SmartChartPage
title={t('statistic.active_addresses')}
description={t('statistic.active_addresses_description')}
isThumbnail={isThumbnail}
fetchData={explorerService.api.fetchStatisticActiveAddresses}
getEChartOption={useOption}
queryKey="fetchStatisticActiveAddresses"
/>
)
}

export default ActiveAddressesChart
Loading

0 comments on commit b193379

Please sign in to comment.