Newer
Older
return cls.to_geometry(commands)
##############################################
@classmethod
def to_xml(cls, value):
path_data = ''
for command in value:
if path_data:
path_data += ' '
path_data += ' '.join(list(command[0]) + [str(x) for x in command[1]])
return path_data
##############################################
@classmethod
def as_vector(cls, args):
number_of_args = len(args)
number_of_vectors = number_of_args // 2
if number_of_args != number_of_vectors * 2:
raise ValueError('len(args) is not // 2: {}'.format(number_of_args))
return [Vector2D(args[i:i+2]) for i in range(0, number_of_args, 2)]
##############################################
@classmethod
def to_geometry(cls, commands):
# cls._logger.info('Path:\n' + str(commands).replace('), ', '),\n '))
path = None
for command, args in commands:
command_lower = command.lower()
absolute = command_lower != command # Upper case means absolute
# if is_lower:
# cls._logger.warning('incremental command')
# raise NotImplementedError
if path is None:
if command_lower != 'm':
raise NameError('Path must start with m')
path = Path2D(args) # Vector2D()
else:
if command_lower == 'l':
path.line_to(args, absolute=absolute)
elif command == 'h':
path.horizontal_to(*args, absolute=False)
elif command == 'H':
path.absolute_horizontal_to(*args)
path.vertical_to(*args, absolute=absolute)
elif command == 'V':
path.absolute_vertical_to(*args)
path.cubic_to(*cls.as_vector(args), absolute=absolute)
path.stringed_quadratic_to(*cls.as_vector(args), absolute=absolute)
path.quadratic_to(*cls.as_vector(args), absolute=absolute)
path.stringed_cubic_to(*cls.as_vector(args), absolute=absolute)
radius_x, radius_y, angle, large_arc, sweep, x, y = args
point = Vector2D(x, y)
path.arc_to(point, radius_x, radius_y, angle, bool(large_arc), bool(sweep), absolute=absolute)
elif command_lower == 'z':
path.close()
return path
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
####################################################################################################
class Path(PathMixin, SvgElementMixin, XmlObjectAdaptator):
"""Defines a path"""
__tag__ = 'path'
__attributes__ = (
PathDataAttribute('path_data', 'd'), # a set of commands which define the path
FloatAttribute('path_length', 'pathLength'),
# If present, the path will be scaled so that the computed path length of the points equals
# this value
)
####################################################################################################
class Pattern(IdMixin, PositionMixin, SizeMixin, XmlObjectAdaptator):
"""Defines the coordinates you want the view to show and the size of the view. Then you add shapes
into your pattern. The pattern repeats when an edge of the view box (viewing area) is hit
"""
__tag__ = 'pattern'
# id="the unique id used to reference this pattern." Required.
# patternUnits="'userSpaceOnUse' or 'objectBoundingBox'. The second value makes units of x, y, width, height a fraction (or %) of the object bounding box which uses the pattern."
# patternContentUnits="'userSpaceOnUse' or 'objectBoundingBox'"
# patternTransform="allows the whole pattern to be transformed"
# x="pattern's offset from the top-left corner (default 0)"
# y="pattern's offset from the top-left corner. (default 0)"
# width="the width of the pattern tile (default 100%)"
# height="the height of the pattern tile (default 100%)"
# viewBox="the points "seen" in this SVG drawing area. 4 values separated by white space or commas. (min x, min y, width, height)"
# xlink:href="reference to another pattern whose attribute values are used as defaults and any children are inherited. Recursive"
####################################################################################################
class Polyline(PointsMixin, PathMixin, SvgElementMixin, XmlObjectAdaptator):
"""Defines a graphic that contains at least three sides"""
__tag__ = 'polyline'
####################################################################################################
class Polygon(Polyline, XmlObjectAdaptator):
"""Defines any shape that consists of only straight lines"""
__tag__ = 'polyline'
# fill-rule="part of the FillStroke presentation attributes"
####################################################################################################
class RadialGradient(XmlObjectAdaptator):
"""Defines a radial gradient. Radial gradients are created by taking a circle and smoothly changing
values between gradient stops from the focus point to the outside radius.
"""
__tag__ = 'radialGradient'
# gradientUnits="'userSpaceOnUse' or 'objectBoundingBox'. Use the view box or object to determine relative position of vector points. (Default 'objectBoundingBox')"
# gradientTransform="the transformation to apply to the gradient"
# cx="the center point of the gradient (number or % - 50% is default)"
# cy="the center point of the gradient. (50% default)"
# r="the radius of the gradient. (50% default)"
# fx="the focus point of the gradient. (0% default)"
# fy="The focus point of the gradient. (0% default)"
# spreadMethod="'pad' or 'reflect' or 'repeat'"
# xlink:href="Reference to another gradient whose attribute values are used as defaults and stops included. Recursive"
####################################################################################################
class Rect(PositionMixin, RadiusMixin, SizeMixin, PathMixin, SvgElementMixin, XmlObjectAdaptator):
"""Defines a rectangle"""
__tag__ = 'rect'
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
##############################################
@property
def geometry(self):
# Fixme: width is str
width = float(self.width)
height = float(self.height)
# Fixme: which one ???
radius_x = self.rx
radius_y = self.ry
if radius_y == 0:
radius = None
else:
radius = radius_y
point = Vector2D(self.x, self.y)
path = Path2D(point)
path.horizontal_to(width)
path.vertical_to(height, radius=radius)
path.horizontal_to(-width, radius=radius)
return path
####################################################################################################
class Stop(XmlObjectAdaptator):
"""The stops for a gradient"""
__tag__ = 'stop'
# offset="the offset for this stop (0 to 1/0% to 100%)". Required.
# stop-color="the color of this stop"
# stop-opacity="the opacity of this stop (0 to 1)"
####################################################################################################
class Style(TextXmlObjectAdaptator):
"""Defines style"""
__tag__ = 'style'
####################################################################################################
class Text(PositionMixin, DeltaMixin, FontMixin, ColorMixin, SvgElementMixin, TextXmlObjectAdaptator):
"""Defines a text"""
__tag__ = 'text'
# x="a list of x-axis positions. The nth x-axis position is given to the nth character in the text. If there are additional characters after the positions run out they are placed after the last character. 0 is default"
# y="a list of y-axis positions. (see x). 0 is default"
# dx="a list of lengths which moves the characters relative to the absolute position of the last glyph drawn. (see x)"
# dy="a list of lengths which moves the characters relative to the absolute position of the last glyph drawn. (see x)"
# rotate="a list of rotations. The nth rotation is performed on the nth character. Additional characters are NOT given the last rotation value"
# textLength="a target length for the text that the SVG viewer will attempt to display the text between by adjusting the spacing and/or the glyphs. (default: The text's normal length)"
# lengthAdjust="tells the viewer what to adjust to try to accomplish rendering the text if the length is specified. The two values are 'spacing' and 'spacingAndGlyphs'"
__attributes__ = (
# Fixme: common ???
StringAttribute('_class', 'class', None),
StringAttribute('style'),
)
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
####################################################################################################
class TextRef(XmlObjectAdaptator):
"""References any <text> element in the SVG document and reuse it"""
__tag__ = 'tref'
####################################################################################################
class TextSpan(Text, XmlObjectAdaptator):
"""Identical to the <text> element but can be nested inside text tags and inside itself"""
__tag__ = 'textspan'
####################################################################################################
class Use(PositionMixin, SizeMixin, XmlObjectAdaptator):
"""Uses a URI to reference a <g>, <svg> or other graphical element with a unique id attribute and
replicate it. The copy is only a reference to the original so only the original exists in the
document. Any change to the original affects all copies.
"""
__tag__ = 'use'
# x="the x-axis top-left corner of the cloned element"
# y="the y-axis top-left corner of the cloned element"
# width="the width of the cloned element"
# height="the height of the cloned element"
# xlink:href="a URI reference to the cloned element"