|
3 | 3 | from svgwrite.container import Hyperlink |
4 | 4 | from svgwrite.image import Image |
5 | 5 | from svgwrite.gradients import LinearGradient |
| 6 | +from svgwrite.masking import ClipPath |
6 | 7 | from svgwrite.shapes import Rect |
7 | 8 | from svgwrite.text import Text |
8 | 9 |
|
@@ -67,6 +68,20 @@ def get_device_description(device): |
67 | 68 | return description |
68 | 69 |
|
69 | 70 |
|
| 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 | + |
70 | 85 | class RackElevationSVG: |
71 | 86 | """ |
72 | 87 | 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): |
177 | 192 | link = Hyperlink(href=f'{self.base_url}{device.get_absolute_url()}', target="_parent") |
178 | 193 | link.set_desc(description) |
179 | 194 |
|
| 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 | + |
180 | 206 | # Add rect element to hyperlink |
181 | 207 | if color: |
182 | 208 | link.add(Rect(coords, size, style=f'fill: #{color}', class_=f'slot{css_extra}')) |
183 | 209 | else: |
184 | 210 | 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 | + ) |
186 | 215 |
|
187 | 216 | # Embed device type image if provided |
188 | 217 | if self.include_images and image: |
|
0 commit comments