Add ability to toggle the inclusion of device images when rendering a rack elevation SVG

This commit is contained in:
Jeremy Stretch 2020-02-20 13:09:43 -05:00
parent adf9221bab
commit ba6562a5db
4 changed files with 30 additions and 13 deletions

View File

@ -186,6 +186,9 @@ class RackElevationDetailFilterSerializer(serializers.Serializer):
unit_height = serializers.IntegerField( unit_height = serializers.IntegerField(
default=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT default=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT
) )
legend_width = serializers.IntegerField(
default=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT
)
exclude = serializers.IntegerField( exclude = serializers.IntegerField(
required=False, required=False,
default=None default=None
@ -194,6 +197,10 @@ class RackElevationDetailFilterSerializer(serializers.Serializer):
required=False, required=False,
default=True default=True
) )
include_images = serializers.BooleanField(
required=False,
default=True
)
# #

View File

@ -220,7 +220,13 @@ class RackViewSet(CustomFieldModelViewSet):
if data['render'] == 'svg': if data['render'] == 'svg':
# Render and return the elevation as an SVG drawing with the correct content type # Render and return the elevation as an SVG drawing with the correct content type
drawing = rack.get_elevation_svg(data['face'], data['unit_width'], data['unit_height']) drawing = rack.get_elevation_svg(
face=data['face'],
unit_width=data['unit_width'],
unit_height=data['unit_height'],
legend_width=data['legend_width'],
include_images=data['include_images']
)
return HttpResponse(drawing.tostring(), content_type='image/svg+xml') return HttpResponse(drawing.tostring(), content_type='image/svg+xml')
else: else:

View File

@ -11,9 +11,13 @@ from .choices import DeviceFaceChoices
class RackElevationSVG: class RackElevationSVG:
""" """
Use this class to render a rack elevation as an SVG image. Use this class to render a rack elevation as an SVG image.
:param rack: A NetBox Rack instance
:param include_images: If true, the SVG document will embed front/rear device face images, where available
""" """
def __init__(self, rack): def __init__(self, rack, include_images=True):
self.rack = rack self.rack = rack
self.include_images = include_images
@staticmethod @staticmethod
def _add_gradient(drawing, id_, color): def _add_gradient(drawing, id_, color):
@ -46,8 +50,7 @@ class RackElevationSVG:
return drawing return drawing
@staticmethod def _draw_device_front(self, drawing, device, start, end, text):
def _draw_device_front(drawing, device, start, end, text):
name = str(device) name = str(device)
if device.devicebay_count: if device.devicebay_count:
name += ' ({}/{})'.format(device.get_children().count(), device.devicebay_count) name += ' ({}/{})'.format(device.get_children().count(), device.devicebay_count)
@ -69,14 +72,13 @@ class RackElevationSVG:
link.add(drawing.text(str(name), insert=text, fill=hex_color)) link.add(drawing.text(str(name), insert=text, fill=hex_color))
# Embed front device type image if one exists # Embed front device type image if one exists
if device.device_type.front_image: if self.include_images and device.device_type.front_image:
url = device.device_type.front_image.url url = device.device_type.front_image.url
image = drawing.image(href=url, insert=start, size=end, class_='device-image') image = drawing.image(href=url, insert=start, size=end, class_='device-image')
image.stretch() image.stretch()
link.add(image) link.add(image)
@staticmethod def _draw_device_rear(self, drawing, device, start, end, text):
def _draw_device_rear(drawing, device, start, end, text):
rect = drawing.rect(start, end, class_="slot blocked") rect = drawing.rect(start, end, class_="slot blocked")
rect.set_desc('{}{} ({}U) {} {}'.format( rect.set_desc('{}{} ({}U) {} {}'.format(
device.device_role, device.device_type.display_name, device.device_role, device.device_type.display_name,
@ -86,7 +88,7 @@ class RackElevationSVG:
drawing.add(drawing.text(str(device), insert=text)) drawing.add(drawing.text(str(device), insert=text))
# Embed rear device type image if one exists # Embed rear device type image if one exists
if device.device_type.front_image: if self.include_images and device.device_type.front_image:
url = device.device_type.rear_image.url url = device.device_type.rear_image.url
image = drawing.image(href=url, insert=start, size=end, class_='device-image') image = drawing.image(href=url, insert=start, size=end, class_='device-image')
image.stretch() image.stretch()
@ -128,11 +130,12 @@ class RackElevationSVG:
return elevation return elevation
def render(self, reserved_units, face, unit_width, unit_height, legend_width): def render(self, face, unit_width, unit_height, legend_width):
""" """
Return an SVG document representing a rack elevation. Return an SVG document representing a rack elevation.
""" """
drawing = self._setup_drawing(unit_width + legend_width, unit_height * self.rack.u_height) drawing = self._setup_drawing(unit_width + legend_width, unit_height * self.rack.u_height)
reserved_units = self.rack.get_reserved_units()
unit_cursor = 0 unit_cursor = 0
for ru in range(0, self.rack.u_height): for ru in range(0, self.rack.u_height):

View File

@ -666,7 +666,8 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
face=DeviceFaceChoices.FACE_FRONT, face=DeviceFaceChoices.FACE_FRONT,
unit_width=RACK_ELEVATION_UNIT_WIDTH_DEFAULT, unit_width=RACK_ELEVATION_UNIT_WIDTH_DEFAULT,
unit_height=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT, unit_height=RACK_ELEVATION_UNIT_HEIGHT_DEFAULT,
legend_width=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT legend_width=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT,
include_images=True
): ):
""" """
Return an SVG of the rack elevation Return an SVG of the rack elevation
@ -676,11 +677,11 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
:param unit_height: Height of each rack unit for the rendered drawing. Note this is not the total :param unit_height: Height of each rack unit for the rendered drawing. Note this is not the total
height of the elevation height of the elevation
:param legend_width: Width of the unit legend, in pixels :param legend_width: Width of the unit legend, in pixels
:param include_images: Embed front/rear device images where available
""" """
elevation = RackElevationSVG(self) elevation = RackElevationSVG(self, include_images=include_images)
reserved_units = self.get_reserved_units()
return elevation.render(reserved_units, face, unit_width, unit_height, legend_width) return elevation.render(face, unit_width, unit_height, legend_width)
def get_0u_devices(self): def get_0u_devices(self):
return self.devices.filter(position=0) return self.devices.filter(position=0)