@@ -117,36 +117,6 @@ function sigmaBuildColorMap(array $items, string $groupBy, ?string $propTerm, ar
117117 return $ map ;
118118}
119119
120- /**
121- * Build icon map for current groupBy, with a default icon for gaps.
122- * @return array<string,string> key => icon class (Font Awesome)
123- */
124- function sigmaBuildIconMap (array $ items , string $ groupBy , ?string $ propTerm , array $ nodeIcons , string $ defaultIcon = 'fas fa-circle ' ): array
125- {
126- $ rows = sigmaNormalizeRows ($ nodeIcons );
127- $ map = [];
128-
129- foreach ($ rows as $ row ) {
130- $ key = '' ;
131- if ($ groupBy === 'resource_class ' ) $ key = (string ) ($ row ['resource_class ' ] ?? '' );
132- elseif ($ groupBy === 'resource_template ' ) $ key = (string ) ($ row ['resource_template ' ] ?? '' );
133- elseif ($ groupBy === 'property_value ' ) $ key = (string ) ($ row ['property_value ' ] ?? '' );
134- if ($ key === '' ) continue ;
135-
136- $ icon = trim ((string ) ($ row ['icon ' ] ?? '' ));
137- $ map [$ key ] = $ icon !== '' ? $ icon : $ defaultIcon ;
138- }
139-
140- // Ensure every observed group has an icon
141- foreach ($ items as $ item ) {
142- if (!$ item instanceof ItemRepresentation) continue ;
143- $ key = sigmaGetItemGroupKey ($ item , $ groupBy , $ propTerm );
144- if ($ key === '' ) continue ;
145- if (!isset ($ map [$ key ])) $ map [$ key ] = $ defaultIcon ;
146- }
147-
148- return $ map ;
149- }
150120
151121/**
152122 * Safe thumbnail URL (best-effort).
@@ -181,148 +151,25 @@ function sigmaBuildPopUpContent(ItemRepresentation $item, array $popupConfig)
181151 return htmlspecialchars ((string ) $ s , ENT_QUOTES | ENT_SUBSTITUTE , 'UTF-8 ' );
182152 };
183153
154+ $ itemUrl = (string ) $ item ->siteUrl ();
155+ // Title
184156 if (in_array ('title ' , $ popupConfig , true )) {
185- $ popupContent .= '<p style="font-size:10px"> ' . $ e ($ item ->displayTitle ()) . '</p> ' ;
157+ $ title = $ e ($ item ->displayTitle ());
158+ $ popupContent .= $ itemUrl
159+ ? '<p style="font-size:10px"><a href=" ' . $ e ($ itemUrl ) . '" target="_blank" rel="noopener"> ' . $ title . '</a></p> '
160+ : '<p style="font-size:10px"> ' . $ title . '</p> ' ;
186161 }
187162
188163 // Thumbnail
189164 if (in_array ('thumbnail ' , $ popupConfig , true )) {
190165 $ thumbnail = sigmaGetItemThumbnailUrl ($ item );
191166 if ($ thumbnail ) {
192167 $ popupContent .= '<div> '
193- . '<img src=" ' . $ e ($ thumbnail ) . '" alt="" style="max- width:100px;max- height:100px " /> '
168+ . '<img src=" ' . $ e ($ thumbnail ) . '" alt="" style="width:100%; height:auto;display:block " /> '
194169 . '</div> ' ;
195170 }
196171 }
197172
198- // Metadata: all non-resource values (literal, uri), each in its own <p>
199- if (in_array ('metadata ' , $ popupConfig , true )) {
200- $ bundle = $ item ->values (); // keyed by term
201-
202- foreach ($ bundle as $ term => $ propData ) {
203- // Normalize to: $prop (PropertyRepresentation|null), $vals (ValueRepresentation[])
204- $ prop = null ;
205- $ vals = [];
206-
207- if (is_array ($ propData ) && array_key_exists ('values ' , $ propData )) {
208- // Shape #1: ['property' => PropertyRepresentation|array, 'values' => ValueRepresentation[]]
209- $ vals = is_array ($ propData ['values ' ]) ? $ propData ['values ' ] : [];
210- if (isset ($ propData ['property ' ]) && $ propData ['property ' ] instanceof PropertyRepresentation) {
211- $ prop = $ propData ['property ' ];
212- }
213- } elseif (is_array ($ propData ) && isset ($ propData [0 ]) && $ propData [0 ] instanceof ValueRepresentation) {
214- // Shape #2: ValueRepresentation[] directly
215- $ vals = $ propData ;
216- } else {
217- // Unknown shape — skip
218- continue ;
219- }
220-
221- // Label: prefer PropertyRepresentation->label(), else fall back to a friendly term
222- $ label = $ prop instanceof PropertyRepresentation ? $ prop ->label () : preg_replace ('~^.+:~ ' , '' , (string ) $ term );
223-
224- foreach ($ vals as $ v ) {
225- if (!$ v instanceof ValueRepresentation) {
226- // Very old shapes could be arrays; keep a defensive fallback:
227- $ type = is_array ($ v ) ? ($ v ['type ' ] ?? '' ) : '' ;
228- if ($ type === 'resource ' || $ type === 'resource:item ' || $ type === 'resource:media ' ) {
229- continue ;
230- }
231- $ text = '' ;
232- if (is_array ($ v )) {
233- $ text = isset ($ v ['@value ' ]) ? (string ) $ v ['@value ' ]
234- : (isset ($ v ['@id ' ]) ? (string ) $ v ['@id ' ] : (string ) ($ v ['value ' ] ?? '' ));
235- }
236- if ($ text !== '' ) {
237- $ popupContent .= '<p style="font-size:10px"><strong> ' . $ e ($ label ) . ':</strong> ' . $ e ($ text ) . '</p> ' ;
238- }
239- continue ;
240- }
241-
242- // Skip resource links; we only want non-resource objects
243- $ type = $ v ->type ();
244- if ($ type === 'resource ' || $ type === 'resource:item ' || $ type === 'resource:media ' ) {
245- continue ;
246- }
247-
248- // Literal and URI
249- $ text = (string ) $ v ->value ();
250- if ($ text === '' ) {
251- continue ;
252- }
253-
254- $ popupContent .= '<p style="font-size:10px"><strong> '
255- . $ e (sigmaUcfirst ($ label )) . ':</strong> ' . $ e ($ text ) . '</p> ' ;
256- }
257- }
258- }
259-
260- // Relationships: only resource-valued links to *items*
261- if (in_array ('relationships ' , $ popupConfig , true )) {
262- $ bundle = $ item ->values (); // keyed by term
263-
264- foreach ($ bundle as $ term => $ propData ) {
265- // Normalize shapes -> $prop, $vals
266- $ prop = null ;
267- $ vals = [];
268-
269- if (is_array ($ propData ) && array_key_exists ('values ' , $ propData )) {
270- $ vals = is_array ($ propData ['values ' ]) ? $ propData ['values ' ] : [];
271- if (isset ($ propData ['property ' ]) && $ propData ['property ' ] instanceof PropertyRepresentation) {
272- $ prop = $ propData ['property ' ];
273- }
274- } elseif (is_array ($ propData ) && isset ($ propData [0 ]) && $ propData [0 ] instanceof ValueRepresentation) {
275- $ vals = $ propData ;
276- } else {
277- continue ;
278- }
279-
280- $ label = $ prop instanceof PropertyRepresentation
281- ? $ prop ->label ()
282- : preg_replace ('~^.+:~ ' , '' , (string ) $ term );
283-
284- $ links = [];
285- foreach ($ vals as $ v ) {
286- if (!$ v instanceof ValueRepresentation) {
287- // Legacy array fallback
288- $ type = is_array ($ v ) ? ($ v ['type ' ] ?? '' ) : '' ;
289- if ($ type !== 'resource ' && $ type !== 'resource:item ' ) {
290- continue ;
291- }
292- // No reliable way to resolve resource from legacy array; skip
293- continue ;
294- }
295-
296- // Accept both 'resource:item' and generic 'resource' (check valueResource)
297- $ type = $ v ->type ();
298- if (($ type !== 'resource ' && $ type !== 'resource:item ' ) || !$ v ->valueResource ()) {
299- continue ;
300- }
301-
302- $ vr = $ v ->valueResource ();
303- if (!$ vr instanceof ItemRepresentation) {
304- continue ; // only link to items
305- }
306-
307- $ title = $ vr ->displayTitle ();
308- $ url = method_exists ($ vr , 'siteUrl ' ) ? $ vr ->siteUrl () : '' ;
309-
310- if ($ url ) {
311- $ links [] = '<a href=" ' . $ e ($ url ) . '" target="_blank" rel="noopener"> ' . $ e ($ title ) . '</a> ' ;
312- } else {
313- $ links [] = $ e ($ title );
314- }
315- }
316-
317- if ($ links ) {
318- $ popupContent .= '<p style="font-size:10px"><strong> '
319- . $ e (sigmaUcfirst ($ label )) . ':</strong> '
320- . implode (', ' , $ links )
321- . '</p> ' ;
322- }
323- }
324- }
325-
326173 return $ popupContent ;
327174}
328175
@@ -331,7 +178,6 @@ function sigmaGenerateGraph(array $items, array $opts = []): array
331178 $ groupBy = $ opts ['groupBy ' ] ?? 'resource_class ' ;
332179 $ propTerm = $ opts ['propTerm ' ] ?? null ;
333180 $ colorsRaw = $ opts ['nodeColors ' ] ?? [];
334- $ iconsRaw = $ opts ['nodeIcons ' ] ?? [];
335181 $ relProps = array_values (array_filter ($ opts ['relationshipProperties ' ] ?? []));
336182 $ excludeIsolated = !empty ($ opts ['excludeWithoutRelationships ' ]);
337183 $ sizeMin = isset ($ opts ['sizeMin ' ]) ? (int ) $ opts ['sizeMin ' ] : 3 ;
@@ -341,7 +187,6 @@ function sigmaGenerateGraph(array $items, array $opts = []): array
341187
342188 // Build maps
343189 $ colorMap = sigmaBuildColorMap ($ items , $ groupBy , $ propTerm , $ colorsRaw );
344- $ iconMap = sigmaBuildIconMap ($ items , $ groupBy , $ propTerm , $ iconsRaw );
345190
346191 // Pre-index items by id for quick lookups
347192 $ itemById = [];
@@ -359,7 +204,6 @@ function sigmaGenerateGraph(array $items, array $opts = []): array
359204 $ short = (mb_strlen ($ label , 'UTF-8 ' ) > 25 ) ? (mb_substr ($ label , 0 , 22 , 'UTF-8 ' ) . '… ' ) : $ label ;
360205
361206 $ color = $ key !== '' && isset ($ colorMap [$ key ]) ? $ colorMap [$ key ] : sigmaColorFromKey ((string ) $ id );
362- $ icon = $ key !== '' && isset ($ iconMap [$ key ]) ? $ iconMap [$ key ] : 'fas fa-circle ' ;
363207
364208 if ($ key !== '' && !isset ($ groupLabels [$ key ])) {
365209 $ groupLabels [$ key ] = sigmaResolveGroupLabelFromItem ($ item , $ groupBy , $ propTerm );
@@ -380,12 +224,9 @@ function sigmaGenerateGraph(array $items, array $opts = []): array
380224 'size ' => $ sizeMin ,
381225 'color ' => $ color ,
382226 'originalColor ' => $ color ,
383- 'icon ' => $ icon ,
384227 'groupKey ' => $ key ,
385228 'popupContent ' => sigmaBuildPopUpContent ($ item , $ popupConfig ),
386229 'link ' => method_exists ($ item , 'siteUrl ' ) ? $ item ->siteUrl () : null ,
387- 'type ' => 'image ' ,
388- "image " => 'https://cdn0.iconfinder.com/data/icons/30-hardware-line-icons/64/Server-128.png ' ,
389230 ];
390231 }
391232
@@ -528,7 +369,6 @@ function sigmaGenerateGraph(array $items, array $opts = []): array
528369
529370 $ legendMap [$ groupLabels [$ key ] ?? (string ) $ key ] = [
530371 'color ' => $ colorMap [$ key ] ?? sigmaColorFromKey ($ key ),
531- 'icon ' => $ iconMap [$ key ] ?? 'fas fa-circle ' ,
532372 ];
533373 }
534374
0 commit comments