-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: initial implementation of activity racing bar(need to be modified) feat: initial implementation of activity racing bar(need to be modified v1) feat: initial implementation of activity racing bar(need to be modified v2) feat: implementation of activity racing bar feat: change the style of chart and button
- Loading branch information
1 parent
746d58b
commit 7aedbc3
Showing
8 changed files
with
330 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
src/pages/ContentScripts/features/repo-activity-racing-bar/RacingBar.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import React, { useState, useEffect, useRef } from 'react'; | ||
import * as echarts from 'echarts'; | ||
|
||
interface RacingBarProps { | ||
//theme: 'light' | 'dark'; | ||
width: number; | ||
height: number; | ||
repoName: string; | ||
data: any; | ||
} | ||
|
||
const RacingBar = (props: RacingBarProps): JSX.Element => { | ||
const [playing, setPlaying] = useState(0); | ||
const { width, height, data } = props; | ||
const divEL = useRef(null); | ||
const updateFrequency = 3000; | ||
const colorMap = new Map(); | ||
const option = { | ||
grid: { | ||
top: 10, | ||
bottom: 30, | ||
left: 150, | ||
right: 80, | ||
}, | ||
xAxis: { | ||
max: 'dataMax', | ||
}, | ||
yAxis: { | ||
type: 'category', | ||
inverse: true, | ||
max: 10, | ||
axisLabel: { | ||
show: true, | ||
fontSize: 14, | ||
formatter: function (value: string) { | ||
if (!value || value.endsWith('[bot]')) return value; | ||
return `${value} {avatar${value.replaceAll('-', '')}|}`; | ||
}, | ||
rich: null, | ||
}, | ||
animationDuration: 300, | ||
animationDurationUpdate: 300, | ||
}, | ||
series: [ | ||
{ | ||
realtimeSort: true, | ||
seriesLayoutBy: 'column', | ||
type: 'bar', | ||
itemStyle: { | ||
color: function (params: { value: any[] }) { | ||
const githubId = params.value[0]; | ||
if (colorMap.has(githubId)) { | ||
return colorMap.get(githubId); | ||
} else { | ||
const randomColor = | ||
'#' + Math.floor(Math.random() * 16777215).toString(16); | ||
colorMap.set(githubId, randomColor); | ||
return randomColor; | ||
} | ||
}, | ||
}, | ||
data: null, | ||
encode: { | ||
x: 1, | ||
y: 0, | ||
}, | ||
label: { | ||
show: true, | ||
precision: 1, | ||
position: 'right', | ||
valueAnimation: true, | ||
fontFamily: 'monospace', | ||
}, | ||
}, | ||
], | ||
// Disable init animation. | ||
animationDuration: 0, | ||
animationDurationUpdate: updateFrequency, | ||
animationEasing: 'linear', | ||
animationEasingUpdate: 'linear', | ||
graphic: { | ||
elements: [ | ||
{ | ||
type: 'text', | ||
right: 60, | ||
bottom: 60, | ||
style: { | ||
text: null, | ||
font: 'bolder 60px monospace', | ||
fill: 'rgba(100, 100, 100, 0.25)', | ||
}, | ||
z: 100, | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
useEffect(() => { | ||
// @ts-ignore | ||
let chartDOM = divEL.current; | ||
const instance = echarts.init(chartDOM as any); | ||
// 组件卸载时销毁图表 | ||
return () => { | ||
instance.dispose(); | ||
}; | ||
}, [playing]); | ||
|
||
useEffect(() => { | ||
let chartDOM = divEL.current; | ||
const instance = echarts.getInstanceByDom(chartDOM as any); | ||
const months = Object.keys(data); | ||
// 在数据变化时调用图表更新函数 | ||
// 根据传入的新数据进行图表的更新操作 | ||
let startIndex = 0; | ||
|
||
for (let i = startIndex; i < months.length - 1; ++i) { | ||
(function (i) { | ||
setTimeout(function () { | ||
updateMonth(months[i + 1]); | ||
if (i + 1 === months.length - 1) { | ||
} | ||
}, (i - startIndex) * updateFrequency); | ||
})(i); | ||
} | ||
|
||
// @ts-ignore | ||
function updateMonth(month: string | null) { | ||
const rich = {}; | ||
// @ts-ignore | ||
data[month].forEach((item: any[]) => { | ||
// rich name cannot contain special characters such as '-' | ||
// @ts-ignore | ||
rich[`avatar${item[0].replaceAll('-', '')}`] = { | ||
backgroundColor: { | ||
image: `https://avatars.githubusercontent.com/${item[0]}?s=48&v=4`, | ||
}, | ||
height: 20, | ||
}; | ||
}); | ||
// @ts-ignore | ||
option.yAxis.axisLabel.rich = rich; | ||
// @ts-ignore | ||
option.series[0].data = data[month]; | ||
// @ts-ignore | ||
option.graphic.elements[0].style.text = month; | ||
// @ts-ignore | ||
instance.setOption(option); | ||
} | ||
}, [playing]); | ||
|
||
const handleReplayClick = () => { | ||
let chartDOM = divEL.current; | ||
const instance = echarts.getInstanceByDom(chartDOM as any); | ||
// @ts-ignore | ||
instance.setOption(option); | ||
setPlaying(playing + 1); | ||
}; | ||
|
||
return ( | ||
<div className="hypertrons-crx-border"> | ||
<div ref={divEL} style={{ width, height }}></div> | ||
<div style={{ display: 'flex', justifyContent: 'center' }}> | ||
<button className="replay-button" onClick={handleReplayClick}> | ||
Replay | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RacingBar; |
59 changes: 59 additions & 0 deletions
59
src/pages/ContentScripts/features/repo-activity-racing-bar/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React from 'react'; | ||
import { render, Container } from 'react-dom'; | ||
import $ from 'jquery'; | ||
|
||
import features from '../../../../feature-manager'; | ||
import isPerceptor from '../../../../helpers/is-perceptor'; | ||
import { getRepoName } from '../../../../helpers/get-repo-info'; | ||
import { getActivityDetails } from '../../../../api/repo'; | ||
import View from './view'; | ||
import DataNotFound from '../repo-networks/DataNotFound'; | ||
import * as pageDetect from 'github-url-detection'; | ||
|
||
const featureId = features.getFeatureID(import.meta.url); | ||
let repoName: string; | ||
let repoActivityDetails: any; | ||
|
||
const getData = async () => { | ||
repoActivityDetails = await getActivityDetails(repoName); | ||
}; | ||
|
||
const renderTo = (container: Container) => { | ||
if (!repoActivityDetails) { | ||
render(<DataNotFound />, container); | ||
return; | ||
} | ||
render( | ||
<View currentRepo={repoName} repoActivityDetails={repoActivityDetails} />, | ||
container | ||
); | ||
}; | ||
|
||
const init = async (): Promise<void> => { | ||
repoName = getRepoName(); | ||
await getData(); | ||
const container = document.createElement('div'); | ||
container.id = featureId; | ||
renderTo(container); | ||
const parentElement = document.getElementById('hypercrx-perceptor-layout'); | ||
if (parentElement) { | ||
parentElement.append(container); | ||
} | ||
}; | ||
|
||
const restore = async () => { | ||
// Clicking another repo link in one repo will trigger a turbo:visit, | ||
// so in a restoration visit we should be careful of the current repo. | ||
if (repoName !== getRepoName()) { | ||
repoName = getRepoName(); | ||
} | ||
// rerender the chart or it will be empty | ||
renderTo($(`#${featureId}`)[0]); | ||
}; | ||
|
||
features.add(featureId, { | ||
asLongAs: [isPerceptor], | ||
awaitDomReady: false, | ||
init, | ||
restore, | ||
}); |
65 changes: 65 additions & 0 deletions
65
src/pages/ContentScripts/features/repo-activity-racing-bar/view.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
|
||
import getMessageByLocale from '../../../../helpers/get-message-by-locale'; | ||
import optionsStorage, { | ||
HypercrxOptions, | ||
defaults, | ||
} from '../../../../options-storage'; | ||
import RacingBar from './RacingBar'; | ||
|
||
interface Props { | ||
currentRepo: string; | ||
repoActivityDetails: any; | ||
} | ||
|
||
const View = ({ currentRepo, repoActivityDetails }: Props): JSX.Element => { | ||
const [options, setOptions] = useState<HypercrxOptions>(defaults); | ||
|
||
useEffect(() => { | ||
(async function () { | ||
setOptions(await optionsStorage.getAll()); | ||
})(); | ||
}, []); | ||
|
||
return ( | ||
<div> | ||
<div className="hypertrons-crx-border hypertrons-crx-container"> | ||
<div className="hypertrons-crx-title"> | ||
<span> | ||
{getMessageByLocale( | ||
'component_projectRacingBar_title', | ||
options.locale | ||
)} | ||
</span> | ||
</div> | ||
<div className="d-flex flex-wrap flex-items-center"> | ||
<div className="col-12 col-md-8"> | ||
<div style={{ margin: '10px 0 20px 20px' }}> | ||
<RacingBar | ||
repoName={currentRepo} | ||
height={300} | ||
width={700} | ||
data={repoActivityDetails} | ||
/> | ||
</div> | ||
</div> | ||
<div className="col-12 col-md-4"> | ||
<div | ||
className="color-text-secondary" | ||
style={{ marginLeft: '35px', marginRight: '35px' }} | ||
> | ||
<p> | ||
{getMessageByLocale( | ||
'component_projectRacingBar_description', | ||
options.locale | ||
)} | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default View; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters