11import { compose , scale , translate } from "transformation-matrix"
22import { GraphicsObject } from "../../../lib"
3- import { useMemo , useState , useEffect } from "react"
3+ import { useMemo , useState } from "react"
44import useMouseMatrixTransform from "use-mouse-matrix-transform"
55import { InteractiveState } from "./InteractiveState"
66import { SuperGrid } from "react-supergrid"
@@ -146,62 +146,94 @@ export const InteractiveGraphics = ({
146146 size ,
147147 )
148148
149- const [ visibleObjectCount , setVisibleObjectCount ] = useState ( 0 )
150- const [ limitReached , setLimitReached ] = useState ( false )
151-
152- const filteredLines = useMemo ( ( ) => {
153- if ( ! graphics . lines ) return [ ]
154- return graphics . lines . filter ( filterLines )
155- } , [ graphics . lines , filterLines ] )
156-
157- const filteredPoints = useMemo ( ( ) => {
158- if ( ! graphics . points ) return [ ]
159- return graphics . points . filter ( filterPoints )
160- } , [ graphics . points , filterPoints ] )
161-
162- const filteredRects = useMemo ( ( ) => {
163- if ( ! graphics . rects ) return [ ]
164- return graphics . rects . filter ( filterRects )
165- } , [ graphics . rects , filterRects ] )
166-
167- const filteredCircles = useMemo ( ( ) => {
168- if ( ! graphics . circles ) return [ ]
169- return graphics . circles . filter ( filterCircles )
170- } , [ graphics . circles , filterCircles ] )
171-
172- useEffect ( ( ) => {
173- const totalObjects =
174- filteredLines . length +
175- filteredPoints . length +
176- filteredRects . length +
177- filteredCircles . length
178-
179- setVisibleObjectCount ( totalObjects )
180- setLimitReached ( ! ! objectLimit && totalObjects > objectLimit )
181- } , [ filteredLines , filteredPoints , filteredRects , filteredCircles , objectLimit ] )
182-
183- const limitObjects = < T , > ( objects : T [ ] , currentCount : number ) : T [ ] => {
184- if ( ! objectLimit || currentCount >= objectLimit ) return [ ]
185- const remaining = objectLimit - currentCount
186- return objects . slice ( 0 , remaining )
187- }
188-
189- const limitedLines = useMemo ( ( ) =>
190- objectLimit ? filteredLines . slice ( 0 , objectLimit ) : filteredLines
191- , [ filteredLines , objectLimit ] )
192-
193- const limitedPoints = useMemo ( ( ) =>
194- limitObjects ( filteredPoints , limitedLines . length )
195- , [ filteredPoints , limitedLines . length , objectLimit ] )
196-
197- const limitedRects = useMemo ( ( ) =>
198- limitObjects ( filteredRects , limitedLines . length + limitedPoints . length )
199- , [ filteredRects , limitedLines . length , limitedPoints . length , objectLimit ] )
200-
201- const limitedCircles = useMemo ( ( ) =>
202- limitObjects ( filteredCircles , limitedLines . length + limitedPoints . length + limitedRects . length )
203- , [ filteredCircles , limitedLines . length , limitedPoints . length , limitedRects . length , objectLimit ] )
149+ const filteredLines = useMemo (
150+ ( ) => graphics . lines ?. filter ( filterLines ) || [ ] ,
151+ [ graphics . lines , filterLines ] ,
152+ )
153+
154+ const filteredPoints = useMemo (
155+ ( ) => graphics . points ?. filter ( filterPoints ) || [ ] ,
156+ [ graphics . points , filterPoints ] ,
157+ )
158+
159+ const filteredRects = useMemo (
160+ ( ) => graphics . rects ?. filter ( filterRects ) || [ ] ,
161+ [ graphics . rects , filterRects ] ,
162+ )
163+
164+ const filteredCircles = useMemo (
165+ ( ) => graphics . circles ?. filter ( filterCircles ) || [ ] ,
166+ [ graphics . circles , filterCircles ] ,
167+ )
168+
169+ const visibleObjectCount = useMemo (
170+ ( ) =>
171+ filteredLines . length +
172+ filteredPoints . length +
173+ filteredRects . length +
174+ filteredCircles . length ,
175+ [ filteredLines , filteredPoints , filteredRects , filteredCircles ] ,
176+ )
177+
178+ const limitReached = useMemo (
179+ ( ) => ! ! objectLimit && visibleObjectCount > objectLimit ,
180+ [ objectLimit , visibleObjectCount ] ,
181+ )
182+
183+ const { displayedLines, displayedPoints, displayedRects, displayedCircles } =
184+ useMemo ( ( ) => {
185+ if ( ! objectLimit ) {
186+ return {
187+ displayedLines : filteredLines ,
188+ displayedPoints : filteredPoints ,
189+ displayedRects : filteredRects ,
190+ displayedCircles : filteredCircles ,
191+ }
192+ }
193+
194+ let remaining = objectLimit
195+ const total = visibleObjectCount
196+
197+ const lineCount = Math . min (
198+ filteredLines . length ,
199+ Math . floor ( ( remaining * filteredLines . length ) / total ) ,
200+ )
201+ remaining -= lineCount
202+
203+ const pointCount = Math . min (
204+ filteredPoints . length ,
205+ Math . floor (
206+ ( remaining * filteredPoints . length ) / ( total - filteredLines . length ) ,
207+ ) ,
208+ )
209+ remaining -= pointCount
210+
211+ const rectCount = Math . min (
212+ filteredRects . length ,
213+ Math . floor (
214+ ( remaining * filteredRects . length ) /
215+ ( total - filteredLines . length - filteredPoints . length ) ,
216+ ) ,
217+ )
218+ remaining -= rectCount
219+
220+ // Use any remaining slots for circles
221+ const circleCount = Math . min ( filteredCircles . length , remaining )
204222
223+ return {
224+ displayedLines : filteredLines . slice ( 0 , lineCount ) ,
225+ displayedPoints : filteredPoints . slice ( 0 , pointCount ) ,
226+ displayedRects : filteredRects . slice ( 0 , rectCount ) ,
227+ displayedCircles : filteredCircles . slice ( 0 , circleCount ) ,
228+ }
229+ } , [
230+ filteredLines ,
231+ filteredPoints ,
232+ filteredRects ,
233+ filteredCircles ,
234+ objectLimit ,
235+ visibleObjectCount ,
236+ ] )
205237
206238 return (
207239 < div >
@@ -253,7 +285,7 @@ export const InteractiveGraphics = ({
253285 Filter by step
254286 </ label >
255287 { limitReached && (
256- < span style = { { color : ' red' , marginLeft : 8 } } >
288+ < span style = { { color : " red" , marginLeft : 8 } } >
257289 Showing { objectLimit } of { visibleObjectCount } objects
258290 </ span >
259291 ) }
@@ -271,35 +303,35 @@ export const InteractiveGraphics = ({
271303 } }
272304 >
273305 < DimensionOverlay transform = { realToScreen } >
274- { limitedLines . map ( ( l , originalIndex ) => (
306+ { displayedLines . map ( ( line ) => (
275307 < Line
276- key = { originalIndex }
277- line = { l }
278- index = { graphics . lines ! . indexOf ( l ) }
308+ key = { `line- ${ graphics . lines ! . indexOf ( line ) } ` }
309+ line = { line }
310+ index = { graphics . lines ! . indexOf ( line ) }
279311 interactiveState = { interactiveState }
280312 />
281313 ) ) }
282- { limitedRects . map ( ( r , originalIndex ) => (
314+ { displayedRects . map ( ( rect ) => (
283315 < Rect
284- key = { originalIndex }
285- rect = { r }
286- index = { graphics . rects ! . indexOf ( r ) }
316+ key = { `rect- ${ graphics . rects ! . indexOf ( rect ) } ` }
317+ rect = { rect }
318+ index = { graphics . rects ! . indexOf ( rect ) }
287319 interactiveState = { interactiveState }
288320 />
289321 ) ) }
290- { limitedPoints . map ( ( p , originalIndex ) => (
322+ { displayedPoints . map ( ( point ) => (
291323 < Point
292- key = { originalIndex }
293- point = { p }
294- index = { graphics . points ! . indexOf ( p ) }
324+ key = { `point- ${ graphics . points ! . indexOf ( point ) } ` }
325+ point = { point }
326+ index = { graphics . points ! . indexOf ( point ) }
295327 interactiveState = { interactiveState }
296328 />
297329 ) ) }
298- { limitedCircles . map ( ( c , originalIndex ) => (
330+ { displayedCircles . map ( ( circle ) => (
299331 < Circle
300- key = { originalIndex }
301- circle = { c }
302- index = { graphics . circles ! . indexOf ( c ) }
332+ key = { `circle- ${ graphics . circles ! . indexOf ( circle ) } ` }
333+ circle = { circle }
334+ index = { graphics . circles ! . indexOf ( circle ) }
303335 interactiveState = { interactiveState }
304336 />
305337 ) ) }
0 commit comments