Skip to content

Commit d571cb4

Browse files
authored
Closes #19902: add clip path to avoid overflow of device name, truncate text to improve centering (#19913)
1 parent 2129355 commit d571cb4

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

netbox/dcim/svg/racks.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from svgwrite.container import Hyperlink
44
from svgwrite.image import Image
55
from svgwrite.gradients import LinearGradient
6+
from svgwrite.masking import ClipPath
67
from svgwrite.shapes import Rect
78
from svgwrite.text import Text
89

@@ -67,6 +68,20 @@ def get_device_description(device):
6768
return description
6869

6970

71+
def truncate_text(text, width, font_size=15):
72+
"""
73+
Truncate text to fit within the width of a rectangle.
74+
75+
:param text: The text to truncate
76+
:param width: Width of rectangle
77+
:param font_size: Font size (default is 15, ~0.875rem)
78+
"""
79+
char_width = font_size * 0.6 # 0.6 is an approximation of the average character width in pixels
80+
max_char = int(width / char_width)
81+
82+
return text if len(text) <= max_char else text[:max_char] + '...'
83+
84+
7085
class RackElevationSVG:
7186
"""
7287
Use this class to render a rack elevation as an SVG image.
@@ -177,12 +192,26 @@ def _draw_device(self, device, coords, size, color=None, image=None):
177192
link = Hyperlink(href=f'{self.base_url}{device.get_absolute_url()}', target="_parent")
178193
link.set_desc(description)
179194

195+
# Create clipPath element
196+
# This is necessary as fallback because the truncate_text method is an approximation
197+
clip_id = f"clip-{device.id}"
198+
clip_path = ClipPath(id=clip_id)
199+
clip_path.add(Rect(coords, size))
200+
201+
self.drawing.defs.add(clip_path)
202+
203+
# Name to display
204+
display_name = truncate_text(name, size[0])
205+
180206
# Add rect element to hyperlink
181207
if color:
182208
link.add(Rect(coords, size, style=f'fill: #{color}', class_=f'slot{css_extra}'))
183209
else:
184210
link.add(Rect(coords, size, class_=f'slot blocked{css_extra}'))
185-
link.add(Text(name, insert=text_coords, fill=text_color, class_=f'label{css_extra}'))
211+
link.add(
212+
Text(display_name, insert=text_coords, fill=text_color, clip_path=f"url(#{clip_id})",
213+
class_=f'label{css_extra}')
214+
)
186215

187216
# Embed device type image if provided
188217
if self.include_images and image:

0 commit comments

Comments
 (0)