1
- import { useCallback , useEffect } from "react" ;
1
+ import { useCallback , useEffect , useMemo } from "react" ;
2
2
3
3
import type { DiffRowOrCollapsed } from "../types" ;
4
4
@@ -13,6 +13,7 @@ const MINIMAP_SCROLL_COLOR = "#7B7B7B80";
13
13
14
14
type Props = {
15
15
canvasRef : React . RefObject < HTMLCanvasElement | null > ;
16
+ containerRef : React . RefObject < HTMLDivElement | null > ;
16
17
height : number ;
17
18
miniMapWidth : number ;
18
19
leftDiff : DiffRowOrCollapsed [ ] ;
@@ -28,6 +29,7 @@ type Props = {
28
29
29
30
export function useMinimapDraw ( {
30
31
canvasRef,
32
+ containerRef,
31
33
height,
32
34
miniMapWidth,
33
35
leftDiff,
@@ -64,45 +66,67 @@ export function useMinimapDraw({
64
66
ctx . fillRect ( x , y , width , ROW_HEIGHT ) ;
65
67
} , [ ROW_HEIGHT ] ) ;
66
68
67
- // Draw the differences -> This will be called in drawScrollBox method
68
- const drawDifferencesInMinimap = useCallback ( ( ctx : CanvasRenderingContext2D ) => {
69
- const scale = height / totalLines ;
69
+ const diffCanvas = useMemo ( ( ) => {
70
+ const offscreen = document . createElement ( "canvas" ) ;
71
+ offscreen . width = miniMapWidth ;
72
+ offscreen . height = height ;
73
+ const ctx = offscreen . getContext ( "2d" ) ;
74
+ if ( ! ctx )
75
+ return null ;
70
76
71
- if ( currentMatchIndex >= 0 && searchResults [ currentMatchIndex ] !== undefined ) {
72
- const y = searchResults [ currentMatchIndex ] * scale ;
73
- const lineHeight = Math . max ( 1 , scale ) ;
74
- ctx . fillStyle = CURRENT_MATCH_COLOR ;
75
- ctx . fillRect ( 0 , y , miniMapWidth , lineHeight ) ;
76
- }
77
+ const scale = height / totalLines ;
77
78
79
+ // left diff
78
80
leftDiff . forEach ( ( line , index ) => {
79
81
const y = index * scale ;
80
82
drawLine ( ctx , line , y , 0 , miniMapWidth / 2 ) ;
81
83
} ) ;
82
84
85
+ // right diff
83
86
rightDiff . forEach ( ( line , index ) => {
84
87
const y = index * scale ;
85
88
drawLine ( ctx , line , y , miniMapWidth / 2 , miniMapWidth / 2 ) ;
86
89
} ) ;
87
90
91
+ // search highlights
88
92
searchResults . forEach ( ( index ) => {
89
93
const y = index * scale ;
90
94
const lineHeight = Math . max ( 1 , scale ) ;
91
95
ctx . fillStyle = SEARCH_HIGHLIGHT_COLOR ;
92
96
ctx . fillRect ( 0 , y , miniMapWidth , lineHeight ) ;
93
97
} ) ;
94
- } , [ height , totalLines , currentMatchIndex , searchResults , leftDiff , rightDiff , miniMapWidth , drawLine ] ) ;
95
98
96
- // Draw the scroll box and also differences in minimapo
97
- const drawScrollBox = useCallback ( ( ctx : CanvasRenderingContext2D , color : string ) => {
98
- const totalContentHeight = totalLines * ROW_HEIGHT ;
99
- const viewportTop = ( currentScrollTop / totalContentHeight ) * height ;
100
-
101
- drawDifferencesInMinimap ( ctx ) ;
99
+ return offscreen ;
100
+ } , [ leftDiff , rightDiff , searchResults , height , totalLines , miniMapWidth , drawLine ] ) ;
102
101
103
- ctx . fillStyle = color ;
104
- ctx . fillRect ( 0 , viewportTop , miniMapWidth , viewportHeight ) ;
105
- } , [ totalLines , ROW_HEIGHT , currentScrollTop , height , drawDifferencesInMinimap , miniMapWidth , viewportHeight ] ) ;
102
+ // Draw the scroll box and also differences in minimapo
103
+ const drawScrollBox = useCallback (
104
+ ( ctx : CanvasRenderingContext2D , color : string ) => {
105
+ if ( ! diffCanvas )
106
+ return ;
107
+
108
+ // Copy pre-rendered diff
109
+ ctx . clearRect ( 0 , 0 , miniMapWidth , height ) ;
110
+ ctx . drawImage ( diffCanvas , 0 , 0 ) ;
111
+
112
+ // Draw scroll box
113
+ const totalContentHeight = totalLines * ROW_HEIGHT ;
114
+ const viewportTop = ( currentScrollTop / totalContentHeight ) * height ;
115
+
116
+ ctx . fillStyle = color ;
117
+ ctx . fillRect ( 0 , viewportTop , miniMapWidth , viewportHeight ) ;
118
+
119
+ // Draw current match highlight (optional)
120
+ if ( currentMatchIndex >= 0 && searchResults [ currentMatchIndex ] !== undefined ) {
121
+ const scale = height / totalLines ;
122
+ const y = searchResults [ currentMatchIndex ] * scale ;
123
+ const lineHeight = Math . max ( 1 , scale ) ;
124
+ ctx . fillStyle = CURRENT_MATCH_COLOR ;
125
+ ctx . fillRect ( 0 , y , miniMapWidth , lineHeight ) ;
126
+ }
127
+ } ,
128
+ [ diffCanvas , currentScrollTop , totalLines , ROW_HEIGHT , height , miniMapWidth , viewportHeight , currentMatchIndex , searchResults ] ,
129
+ ) ;
106
130
107
131
const drawMinimap = useCallback ( ( ) => {
108
132
const canvas = canvasRef . current ;
@@ -116,12 +140,18 @@ export function useMinimapDraw({
116
140
ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
117
141
118
142
if ( ! isDragging . current ) {
143
+ if ( containerRef . current ) {
144
+ containerRef . current . style . opacity = "0.65" ;
145
+ }
119
146
drawScrollBox ( ctx , MINIMAP_SCROLL_COLOR ) ;
120
147
}
121
148
else {
149
+ if ( containerRef . current ) {
150
+ containerRef . current . style . opacity = "0.85" ;
151
+ }
122
152
drawScrollBox ( ctx , MINIMAP_HOVER_SCROLL_COLOR ) ;
123
153
}
124
- } , [ leftDiff , rightDiff , height , currentScrollTop , searchResults , currentMatchIndex , drawLine , viewportHeight ] ) ;
154
+ } , [ drawScrollBox ] ) ;
125
155
126
156
useEffect ( ( ) => {
127
157
drawMinimap ( ) ;
0 commit comments