![]() |
General Reading »
Book Chapters »
General
Intermediate
Learn SVG: The Web Graphics StandardBy Jon FrostLearn SVG: The Web Graphics Standard - Chapter 7 |
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
![]() |
|
Extract of SVG specifications :-
"There are several opacity properties within SVG:
- Fill opacity
- Stroke opacity
- Gradient stop opacity
- Object/group opacity (described here)
Except for object/group opacity, all other opacity properties are involved in intermediate rendering operations. Object/group opacity can be thought of conceptually as a post processing operation. Conceptually, after the object/group is rendered into an RGBA off-screen image, the object/group opacity setting specifies how to blend the off-screen image into the current background."
Any values outside the range 0.0 (fully transparent) to 1.0 (fully opaque) will be clamped to this range.
We can affect opacity for filling or stroking any element as shape, text ...
'fill-opacity'
Value: <opacity-value> | inherit
Initial: 1
Applies to: shapes and text content elements
Inherited: yes
Percentages: N/A
Media: visual
Animatable: yes'stroke-opacity'
Value: <opacity-value> | inherit
Initial: 1
Applies to: shapes and text content elements
Inherited: yes
Percentages: N/A
Media: visual
Animatable: yes
We can use
<rect x="0" y="0" width="200" height="200" fill-opacity="0.5" fill="red"/>
or
<rect x="0" y="0" width="200" height="200" style="fill-opacity:0.5;fill:red"/>
For opacity less than 1, result depends on background color. We create background with strips of color, we can see result of fill-opacity="0.5" for a rectangle in Figure 7-1.
Source of SVG file ( Example 7-1 ) :
<svg width="600" height="110" viewBox="-25 -30 600 110">
<rect x="0" y="0" width="50" height="50" style="fill:black;fill-opacity:1"/>
<rect x="50" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.9"/>
<rect x="100" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.8"/>
<rect x="150" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.7"/>
<rect x="200" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.6"/>
<rect x="250" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.5"/>
<rect x="300" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.4"/>
<rect x="350" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.3"/>
<rect x="400" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.2"/>
<rect x="450" y="0" width="50" height="50"
style="fill:black;fill-opacity:0.1"/>
<rect x="500" y="0" width="50" height="50"
style="fill:black;fill-opacity:0"/>
<rect x="20" y="10" width="510" height="30"
style="fill:yellow;fill-opacity:0.5"/>
</svg>
Figure 7-1. Rectangle with 0.5 as fill-opacity on strips
See below about gradients
'opacity'
Value: <alphavalue> | inherit
Initial: 1
Applies to: container elements and graphics elements
Inherited: no
Percentages: N/A
Media: visual
Animatable: yes
Figure 7-2 shows that if opacity of 0.5 apply to group, yellow circle covers red circle and then opacity of group apply to rendered raster. If opacity apply to each circle, we get common part of circles in orange.
Source for SVG file (Example 7-2 ) :
<svg width="450" height="250" viewBox="-25 -25 450 250">
<g opacity="0.5">
<circle cx="75" cy="100" r="50" fill="red" fill-opacity="1"/>
<circle cx="125" cy="100" r="50" fill="yellow" fill-opacity="1"/>
</g>
<g>
<circle cx="275" cy="100" r="50" fill="red" fill-opacity="0.5"/>
<circle cx="325" cy="100" r="50" fill="yellow" fill-opacity="0.5"/>
</g>
<text x="100" y="180" style="text-anchor:middle">opacity on group</text>
<text x="300" y="180" style="text-anchor:middle">opacity on elements</text>
</svg>
Figure 7-2. Opacity on group or on elements
Gradients are used to fill or stroke basic shapes, paths or text elements, using many colors with color transitions from one to other.
This is the syntax for the 'stop' element :
<stop id="name"
offset="NumberOrPercentage"
stop-color="Color"
stop-opacity="Opacity-value" />

Diagram 7-1. Chart for 'stop' syntax
Values for offset are from 0% to 100% or from 0 to 1. For each stop element, offset must be equal to or greater than the previous stop's offset value. Gradient offset values less than 0 (or less than 0%) are rounded up to 0%. Gradient offset values greater than 1 (or greater than 100%) are rounded down to 100%.
To begin, we create linear gradient with two colors only. Colors are defined in stop elements.
<defs>
<linearGradient id="MyGradient">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
</defs>
We create also radial gradient with same 'stop' elements :
<defs>
<radialGradient id="MyGradient">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
</defs>
For linear gradients, the offset attribute represents a location along the gradient vector. For radial gradients, it represents a percentage distance from (fx,fy) to the edge of the outermost/largest circle.
We can see result in Figure 7-3.
Figure 7-3. How work offset for stop element
In linear gradient, to fill shape, red is used from begin to 30% of total length, yellow is used from 70% to end. From 30% to 70%, color goes smoothly from red to yellow. We go from red ( rgb(255,0,0) ) to yellow ( rgb(255,255,0) ), so colors at x% of gradient vector is rgb(255,y,0) with y = 255 * (x � 30 ) / 40.
Figure 7-4 show some values for offset in linear gradient. For 0 and 100, all rectangle is filled with continuously smooth color transitions from red to yellow. For 50 and 50, we get only red for left part and yellow for right part.
Source of SVG file ( Example 7-4 ) :
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient2">
<stop offset="20%" stop-color="red"/>
<stop offset="80%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient3">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient4">
<stop offset="50%" stop-color="red"/>
<stop offset="50%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">Offset 0 and 100</text>
<text x="225" y="175" style="text-anchor:middle">Offset 20 and 80</text>
<text x="375" y="175" style="text-anchor:middle">Offset 30 and 70</text>
<text x="525" y="175" style="text-anchor:middle">Offset 50 and 50</text>
<g style="stroke-dasharray:2 2;stroke:black">
<path d="M180 0l0 150"/>
<path d="M270 0l0 150"/>
<path d="M0 0l0 150"/>
<path d="M150 0l0 150"/>
<path d="M345 0l0 150"/>
<path d="M405 0l0 150"/>
<path d="M525 0l0 150"/>
<path d="M525 0l0 150"/>
</g>
</svg>

Figure 7-4. Some values for offset in linearGradient element
For radial gradient 'offset' apply to radius of circles ( we can choose center of circles see after ) To fill shape, red is used for circle with radius of 30% of area's radius , yellow is used from 70% to end. From 30% to 70%, color goes smoothly from red to yellow.
We get this effects with radial gradient in Figure 7-5 for different values of offset attributes.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<radialGradient id="MyGradient1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</radialGradient>
<radialGradient id="MyGradient2">
<stop offset="20%" stop-color="red"/>
<stop offset="80%" stop-color="yellow"/>
</radialGradient>
<radialGradient id="MyGradient3">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</radialGradient>
<radialGradient id="MyGradient4">
<stop offset="50%" stop-color="red"/>
<stop offset="50%" stop-color="yellow"/>
</radialGradient>
</defs>
<rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">Offset 0 and 100</text>
<text x="225" y="175" style="text-anchor:middle">Offset 20 and 80</text>
<text x="375" y="175" style="text-anchor:middle">Offset 30 and 70</text>
<text x="525" y="175" style="text-anchor:middle">Offset 50 and 50</text>
<g style="stroke-dasharray:2 2;stroke:black;fill:none">
<circle cx="75" cy="75" r="0"/>
<circle cx="75" cy="75" r="75"/>
<circle cx="225" cy="75" r="15"/>
<circle cx="225" cy="75" r="60"/>
<circle cx="375" cy="75" r="22"/>
<circle cx="375" cy="75" r="52"/>
<circle cx="525" cy="75" r="37.5"/>
<circle cx="525" cy="75" r="37.5"/>
</g>
</svg>
Figure 7-5. Some values for offset in radialGradient element
With stop-color we choose color used ( name, RGB or hexadecimal value ). It's not possible to choose "none", but with any color and stop-opacity="0" we get same result. We can use this to get transparency effect or 3D lighting with filters on gradient.
Value: currentColor |<color> [icc-color(<name>
[,<icccolorvalue>]*)] |inherit
Initial: blackk
Applies to: 'stop' elements
Inherited: no
Percentages: N/A
Media: visual
Animatable: yes
WWith stop-opacity we choose opacity for color from 0 to 1.
Value: <alphavalue> | inherit
Initial: 1
Applies to: 'stop' elements
Inherited: no
Percentages: N/A
Media: visual
Animatable: yes
For gradients, one property is important : 'color-interpolation'. By default, 'color-interpolation' has value 'sRGB'
Value: auto | sRGB | linearRGB | inherit
Initial: sRGB
Applies to: container elements, graphics elements and 'animateColor'
Inherited: yes
Percentages: N/A
Media: visual
Animatable: yes
'auto' means that author doesn't require that color interpolation occur in a particular color space .
We can see on this example ( Figure 7-6 ) that to go from red to yellow, repartition of colors is not the same with 'sRGB' and 'linearRGB'.
Figure 7-6. 'color-interpolation' property value
gradientUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x1 y1 x2 y2 for linearGradient and cx cy r fx fy for radialGradient. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the gradient is applied. In this case, it's more easy to use percentages for attributes.
You can see after for linearGradient that this choice give different results on a square and a rectangle by example.
gradientTransform allow to add transform to coordinate system. We can use translate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a b c d e f).
Figure 7-7 show three transforms applied to linearGradient element.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient2" gradientTransform="rotate(45)">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient3" gradientTransform="scale(0.5)">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient4" gradientTransform="skewX(45)">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150"
style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150"
style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150"
style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150"
style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">identity</text>
<text x="225" y="175" style="text-anchor:middle">rotate(45)</text>
<text x="375" y="175" style="text-anchor:middle">scale(0.5)</text>
<text x="525" y="175" style="text-anchor:middle">skewX(45)</text>
</svg>
Figure 7-7. Three transforms applied to linearGradient element
spreadMethod attribute can be pad, reflect or repeat. This attribute indicates what happens if the gradient starts or ends inside the bounds of the target rectangle. With pad, default value, first or last color is used to complete before beginning or after end of gradient. With reflect, gradient is used start to end, then end to start , start to end ... to fill the rectangle. With repeat, gradient is used start to end, start to end ... to fill the rectangle. To see effect of this attribute, we define this linear gradient:
<defs>
<linearGradient id="MyGradient" x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
</defs>
With this values for x1 y1 x2 and y2, gradient start at 20% of shape and end at 50%. Figure 7-8 show effect of spreadMethod attribute, by default or with "pad" value, red is used from 0% to 20% and yellow from 50% to 100%. With reflect and repeat, we can see how gradient is used to fill the rectangle.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1" x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient2" spreadMethod="pad"
x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient3" spreadMethod="reflect"
x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient4" spreadMethod="repeat"
x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="30%" stop-color="red"/>
<stop offset="70%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150"
style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150"
style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150"
style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150"
style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">default</text>
<text x="225" y="175" style="text-anchor:middle">pad</text>
<text x="375" y="175" style="text-anchor:middle">reflect</text>
<text x="525" y="175" style="text-anchor:middle">repeat</text>
</svg>
Figure 7-8. Different values for spreadMethod attribute
We define gradient in <defs> section and give id, here "MyGradient" to linearGradient element.
<defs>
<linearGradient id="MyGradient" x1="20%" y1="0%" x2="50%" y2="0%">
<stop offset="10%" stop-color="red"/>
<stop offset="90%" stop-color="yellow"/>
</linearGradient>
</defs>
We can use this gradient to fill or stroke any element, as basic shape, path, text. This rectangle will be filled with linear gradient :
<rect x='0' y='0' width='200' height='200' fill='url(#MyGradient)'/>
We can also use style attribute :
<rect x='0' y='0' width='200' height='200'
style='stroke:black;fill:url(#MyGradient)'/>
Figure 7-9 show some examples for using linear gradient to fill or stroke SVG elements.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1" x2="5%" spreadMethod="reflect">
<stop offset="10%" stop-color="red"/>
<stop offset="90%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150"
style="stroke:black;fill:url(#MyGradient1)"/>
<circle cx="225" cy="75" r="60"
style="fill:none;stroke-width:10;stroke:url(#MyGradient1)"/>
<path d="M320 20l 70 0 0 60 20 50 -100 0z"
style="stroke:black;fill:url(#MyGradient1)"/>
<text x="525" y="100"
style="stroke:black;fill:url(#MyGradient1);font-family:Balloon;
text-anchor:middle;font-size:100">SVG</text>
<text x="75" y="175" style="text-anchor:middle">fill rectangle</text>
<text x="225" y="175" style="text-anchor:middle">stroke circle</text>
<text x="375" y="175" style="text-anchor:middle">fill path</text>
<text x="525" y="175" style="text-anchor:middle">fill text</text>
</svg>
Figure 7-9. Examples using gradient
This is the syntax for the 'linearGradient' element :
<linearGradient id="name"
gradientUnits="userSpaceOnUse|objectBoundingBox"
gradientTransform="transform-list"
spreadMethod="pad|repeat|reflect"
x1="NumberOrPercentage"
y1="NumberOrPercentage"
x2="NumberOrPercentage"
y2="NumberOrPercentage">
<!-- stop elements -->
</linearGradient>
Diagram 7-2. Chart for 'linearGradient' syntax
Figure 7-10 show results for three values of attribute "spreadMethod". In this example, x1="10%" and x2="40%".
Figure 7-10. Attributes for linearGradient
x1 y1 x2 y2 attributes define vector for linear gradient. This vector
provides starting and ending points onto which the gradient stops are mapped.
Colored strips are perpendicular to this vector. Default values are 0% 0%
100% 0%
Figure 7-11 show four examples :
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient2" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient3" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient4" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">0 0 100 0</text>
<text x="225" y="175" style="text-anchor:middle">0 0 100 100</text>
<text x="375" y="175" style="text-anchor:middle">0 100 100 0</text>
<text x="525" y="175" style="text-anchor:middle">0 0 0 100</text>
</svg>
Figure 7-11. Different values for x1 y1 x2 y2
Effect of x1, y1, x2 and y2 with gradientUnits="objectBoundingBox" depend of
filled object. Result is not the same on a square and a rectangle.
For a
rectangle, coordinate system is not orthogonal and strips of color are
perpendicular to gradient vector in calculus in this system, but not in common
sense.
Figure 7-12. gradientUnits and shapes
By example, in Figure 7-12, we use same gradient for gradientUnits =
"objectBoundingBox" with x1="0%" y1="0%" x2="100%" and y2="100%".
Stop
elements offset are 20% and 80%, we draw limits of colors. If we want same
orientation on the two shapes, we must use gradientUnits = "userSpaceOnUse" and
define a gradient for each shape with different values for x1, y1, x2 and
y2..
We have same problem using gradientTransform.
Figure 7-13 allow comparison using x1 y1 x2 y2 or gradientTransform :
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<linearGradient id="MyGradient1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient2" gradientTransform="rotate(45)">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient id="MyGradient3" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
<linearGradient gradientUnits="userSpaceOnUse" id="MyGradient4"
x1="450" y1="150" x2="600" y2="150"
gradientTransform="rotate(-45,450,150)">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">0 0 100 100</text>
<text x="225" y="175" style="text-anchor:middle">rotate(45)</text>
<text x="375" y="175" style="text-anchor:middle">0 100 100 0</text>
<text x="525" y="175" style="text-anchor:middle">rotate(-45)</text>
</svg>
We can see that gradientTransform="rotate(45)" give not same result that 0 100 100 0, reason come from length of gradient vector, in rotate, vector keep same length and cover only a part of rectangle. gradientTransform="rotate(-45,-450,150)" apply to 0 100 100 100 and 0 100 100 0 are different for same reason, and here we can not use percentages to give center of rotation. We cannot define such gradient for many objects.
Figure 7-13. Play with x1 y1 x2 y2 and gradientTransform
This is the syntax for the 'radialGradient' element :
<radialGradient id="name"
gradientUnits="userSpaceOnUse|objectBoundingBox"
gradientTransform="transform-list"
spreadMethod="pad|repeat|reflect"
cx="NumberOrPercentage"
cy="NumberOrPercentage"
r="NumberOrPercentage"
fx="NumberOrPercentage"
fy="NumberOrPercentage">
<!-- stop elements -->
</radialGradient>
Diagram 7-3. Chart for 'radialGradient' syntax
Figure 7-14. Attributes for radialGradient element
cx, cy, r define the largest circle for the radial gradient. Default values
are 50%. fx, fy define the focal point for the radial gradient.
The gradient
will be drawn such that the 0% gradient stop is mapped to (fx, fy). If values
are not specified for fx and fy, focal point is in cx,cy. Figure 7-14 show
example with cx="50%" cy="50%" r="50%" fx="20%" fy="20%" and offset="0%" for
black and offset="100%" for white.
We can play with focal point distinct from center and spreadMethod to fill rectangle. Figure 7-15 show two examples where focal point is in center with reflect and repeat values for spreadMethod. For two others, focal point is distinct from center.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<radialGradient id='MyGradient1' spreadMethod='reflect'
cx='50%' cy='50%' r='5%' fx='50%' fy='50%'>
<stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/>
<stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/>
</radialGradient>
<radialGradient id='MyGradient2' spreadMethod='repeat'
cx='50%' cy='50%' r='5%' fx='50%' fy='50%'>
<stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/>
<stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/>
</radialGradient>
<radialGradient id='MyGradient3' spreadMethod='reflect'
cx='50%' cy='50%' r='5%' fx='25%' fy='25%'>
<stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/>
<stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/>
</radialGradient>
<radialGradient id='MyGradient4' spreadMethod='repeat'
cx='50%' cy='50%' r='35%' fx='5%' fy='5%'>
<stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/>
<stop id='c2' offset='95%' stop-color='yellow' stop-opacity='1'/>
</radialGradient>
</defs>
<rect x="0" y="0" width="150" height="150" style="fill:url(#MyGradient1)"/>
<rect x="150" y="0" width="150" height="150" style="fill:url(#MyGradient2)"/>
<rect x="300" y="0" width="150" height="150" style="fill:url(#MyGradient3)"/>
<rect x="450" y="0" width="150" height="150" style="fill:url(#MyGradient4)"/>
<text x="75" y="175" style="text-anchor:middle">
reflect 50 50 5 50 50
</text>
<text x="225" y="175" style="text-anchor:middle">repeat 50 50 5 50 50</text>
<text x="375" y="175" style="text-anchor:middle">reflect 50 50 5 25 25</text>
<text x="525" y="175" style="text-anchor:middle">repeat 50 50 35 5 5</text>
</svg>
Figure 7-15. spreadMethod and focal point
We can apply filters to gradients. To get 3D lighting effect, we can use stop-opacity="0" for some stop elements. Figure 7-16 show radial gradient, lighting and composite of the two.
<svg width="660" height="300" viewBox="-30 -30 660 300">
<defs>
<radialGradient id='gradient' spreadMethod='repeat'
cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>
<stop id='c1' offset='5%' stop-color='red' stop-opacity='1'/>
<stop id='c2' offset='95%' stop-color='yellow' stop-opacity='0'/>
</radialGradient>
<filter id='Filter0' filterUnits='objectBoundingBox'
x='0%' y='0%' width='100%' height='100%'>
<feImage result="pict0" xlink:href="#Image2"/>
<feDiffuseLighting result='pict1' in='pict0'
lighting-color='white' diffuseConstant='1'
kernelUnitLength='1,1' surfaceScale='4.2'>
<feDistantLight azimuth='60' elevation='25'/>
</feDiffuseLighting>
<feComposite in2='pict1' in='pict0' operator='xor'/>
</filter>
<filter id='Filter1' filterUnits='objectBoundingBox'
x='0%' y='0%' width='100%' height='100%'>
<feImage result="pict0" xlink:href="#Image1"/>
<feDiffuseLighting result='pict1' in='pict0'
lighting-color='white' diffuseConstant='1'
kernelUnitLength='1,1' surfaceScale='4.2'>
<feDistantLight azimuth='60' elevation='25'/>
</feDiffuseLighting>
</filter>
<rect id="Image1" x="200" y="0" width='200' height='200'
fill='url(#gradient)'/>
<rect id="Image2" x="400" y="0" width='200' height='200'
fill='url(#gradient)'/>
</defs>
<rect x='0' y='0' width='200' height='200' fill='url(#gradient)'/>
<rect x="200" y="0" width='200' height='200' filter='url(#Filter1)'/>
<rect x="400" y="0" width='200' height='200' filter='url(#Filter0)'/>
<text x="100" y="225" style="text-anchor:middle">radial gradient</text>
<text x="300" y="225" style="text-anchor:middle">lighting gradient</text>
<text x="500" y="225" style="text-anchor:middle"> composite pictures</text>
</svg>
Figure 7-16. Composite radial gradient with lighting
In design tools, we can choose gradient, but you cannot try all parameters, so you can find online ( at pilat.free.fr ) or on companion cd a tool to create gradient, test all parameters and get code for gradient ( using PHP ) Figure 7-17 is screenshot of tool to create radial gradient. This tool exist also as reusable component that you can add at your application.
Figure 7-17. Tool to create radial gradient
"A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted."
This is syntax for "pattern" element :
<pattern id="name"
patternUnits=" userSpaceOnUse|objectBoundingBox"
patternContentUnits=" userSpaceOnUse|objectBoundingBox"
patternTransform="transform-list"
viewBox="min-x min-y width height"
x="NumberOrPercentage"
y="NumberOrPercentage"
width="NumberOrPercentage"
height="NumberOrPercentage">
<!-- some objects as pattern content -->
</pattern>
Diagram 7-4. Chart for 'pattern' syntax
In previous chapters, you see pictures with grid background using pattern :
<pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
We define pattern element, give attributes for rectangular tile, x ( 0 by default ), y ( 0 by default ), width ( 0 by default ) and height ( 0 by default ).
patternUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x y width and height for pattern tile. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the pattern is applied. In this case, it's more easy to use percentages for attributes.
patternContentUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for the contents of the 'pattern' element. Here, "userSpaceOnUse" is the default value.
viewBox attribute apply for pattern contents. If we define viewBox attribute, patternContentUnits attribute has no effect.
patternTransform attribute allow to add transform to coordinate system. We can use translate(tx,ty) rotate(angle,cx,cy) skewX(angle) skewY(angle) scale(sx,sy) or matrix(a b c d e f).
Figure 7-18 show effect of patternTransform attribute :
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<pattern id="Pat01" width="10" height="10" patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
<pattern id="Pat02" width="10" height="10"
patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
<pattern id="Pat03" width="10" height="10"
patternUnits="userSpaceOnUse" patternTransform="scale(2)">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
<pattern id="Pat04" width="10" height="10"
patternUnits="userSpaceOnUse" patternTransform="skewX(45)">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
</defs>
<rect x="0" y="0" width="150" height="150"
style="stroke:black;fill:url(#Pat01)"/>
<rect x="150" y="0" width="150" height="150"
style="stroke:black;fill:url(#Pat02)"/>
<rect x="300" y="0" width="150" height="150"
style="stroke:black;fill:url(#Pat03)"/>
<rect x="450" y="0" width="150" height="150"
style="stroke:black;fill:url(#Pat04)"/>
<text x="75" y="175" style="text-anchor:middle">identity</text>
<text x="225" y="175" style="text-anchor:middle">rotate(45)</text>
<text x="375" y="175" style="text-anchor:middle">scale(2)</text>
<text x="525" y="175" style="text-anchor:middle">skewX(45)</text>
</svg>
Figure 7-18. Some values for patternTransform attribute
Pattern contents are childs of pattern element, they can be any SVG object - basic shape, path, text, gradient, filter, mask, symbol, marker ....... For our example, one rectangle is the only content.
We define pattern in <defs> section and give id, here "MyPattern" to pattern element.
<pattern id="MyPattern" width="10" height="10"
patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
We can use this pattern to fill or stroke any element, as basic shape, path, text. This rectangle will be filled with pattern :
<rect x='0' y='0' width='200' height='200' fill='url(#MyPattern)'/>
We can also use style attribute :
<rect x='0' y='0' width='200' height='200'
style='stroke:black;fill:url(#MyPattern)'/>
Figure 7-19 show some examples of filling and stroking with pattern.
<svg width="640" height="220" viewBox="-20 -20 640 220">
<defs>
<pattern id="MyPattern" width="10" height="10"
patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="#FFFFFF" stroke="#000000"
stroke-width="0.1"/>
</pattern>
</defs>
<rect x="0" y="0" width="150" height="150"
style="stroke:black;fill:url(#MyPattern)"/>
<circle cx="225" cy="75" r="60"
style="fill:none;stroke-width:10;stroke:url(#MyPattern)"/>
<path d="M320 20l 70 0 0 60 20 50 -100 0z"
style="stroke:black;fill:url(#MyPattern)"/>
<text x="525" y="100" style="stroke:black;fill:url(#MyPattern);
font-family:Balloon;text-anchor:middle;font-size:100">SVG</text>
<text x="75" y="175" style="text-anchor:middle">fill rectangle</text>
<text x="225" y="175" style="text-anchor:middle">stroke circle</text>
<text x="375" y="175" style="text-anchor:middle">fill path</text>
<text x="525" y="175" style="text-anchor:middle">fill text</text>
</svg>
Figure 7-19. Fill and stroke with pattern
Figure 7-20 show classical examples of pattern used in statistical charts or maps.
Figure 7-20. Some classical examples of pattern
In design tools, we can choose pattern, but you cannot create our own pattern, so you can find online ( at pilat.free.fr ) a tool to create pattern content using rectangle, ellipse, polygon, line and path elements and get code for pattern ( using HTML form ).
Figure 7-21 is screenshot of this tool to create pattern content. To fill shapes, you can create your gradient with previous tool as reusable component.
Figure 7-21. Screenshot of tool to create pattern content
We can add filter to create effect on pattern
Figure 7-22 show two effects on very simple pattern. We use lighting filter on pattern and composite it with pattern.
<svg width="650" height="270" viewBox="-30 -30 650 270">
<defs>
<pattern id='motif' x='0' y='0' width='20' height='20'
patternUnits="userSpaceOnUse">
<circle cx='5' cy='5' r='5'
style='stroke:black;stroke-width:1;fill:red'/>
<circle cx='15' cy='15' r='5'
style='stroke:black;stroke-width:1;fill:red'/>
</pattern>
<filter id='Filter0' x="0%" y="0%" width="100%" height="100%">
<feImage result='pict0' xlink:href='#Image1'/>
<feDiffuseLighting result='pict1' in='pict0'
lighting-color='white' diffuseConstant='1'
kernelUnitLength='1,1' surfaceScale='1'>
<feDistantLight azimuth='45' elevation='45'/>
</feDiffuseLighting>
<feComposite result='pict2' in2='pict0' in='pict1' operator='over'/>
</filter>
<rect id='Image1' x="200" y="0" width='200' height='200'
fill="url(#motif)"/>
<rect id='Image2' x="400" y="0" width='200' height='200'
fill="url(#motif)"/>
<filter id='Filter1' x="0%" y="0%" width="100%" height="100%">
<feImage result='pict0' xlink:href='#Image2'/>
<feDiffuseLighting result='pict1' in='pict0'
lighting-color='white' diffuseConstant='1'
kernelUnitLength='1,1' surfaceScale='1'>
<feDistantLight azimuth='95' elevation='35'/>
</feDiffuseLighting>
<feComposite result='pict2' in2='pict0' in='pict1' operator='in'/>
</filter>
</defs>
<rect x="0" y="0" width="200" height="200" fill="url(#motif)"/>
<rect x='200' y='0' width='200' height='200' filter='url(#Filter0)'/>
<rect x='400' y='0' width='200' height='200' filter='url(#Filter1)'/>
<text x="100" y="225" style="text-anchor:middle">pattern</text>
<text x="300" y="225" style="text-anchor:middle">lighting</text>
<text x="500" y="225" style="text-anchor:middle">other composite</text>
</svg>
Figure 7-22. Example of effects on pattern with filters
With figure 7-23, we have Europa map as lego pieces using pattern with filters. Only color of lighting change for the two patterns.
Figure 7-23. Using pattern and filters for Europa map
Pattern create tile to fill shape or other element, but tiling use only translation of same tile. Why not try to create tilings of plane in the same way as M.C. Escher ? At same URL (pilat.free.fr), you can find tool to choose type of tiling and create your tile with basic shapes. Figure 7-24 show example of tiling of plane create with some Bezier curves and lighting effect
Figure 7-24. Example of tiling of plane and lighting effect
"The clipping path restricts the region to which paint can be applied. Conceptually, any parts of the drawing that lie outside of the region bounded by the currently active clipping path are not drawn."
We use "clipPath" element :
The syntax is
<clipPath id="name" clipPathUnits = "userSpaceOnUse | objectBoundingBox">
<!-- shapes paths text use ... elements as children -->
</clipPath>
Diagram 7-5. Chart for 'clipPath' syntax
clipPathUnits defines the coordinate system for the contents of the 'clipPath' element. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the clipping path is applied.
For complex shapes, to define which points are inside shape, we can choose value for clip-rule attribute, nonzero or evenodd.
'clip-rule'
Value: nonzero | evenodd | inherit
Initial: nonzero
Applies to: graphics elements within a 'clipPath' element
Inherited: yes
Percentages: N/A
Media: visual
Animatable: yes
This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a path segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside..
This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside.
We use clip-path property :
'clip-path'
Value: <ri> | none | inherit
Initial: nonee
Applies to: container elements and graphics elements
Inherited: no
Percentages: N/A
Media: visual
Animatable: yes
Figure 7-25 show a circle on a text, and text color change inside circle. For that we define in <defs> section :
We draw black rectangle, white text and use element with circle as clip-path and black text as xlink:href value.
We can animate the spot by moving circle, cx of circle going from 50 to 450 ...
<svg width="550" height="130" viewBox="-50 -30 550 130">
<defs>
<g id="new_text">
<rect x="0" y="0" width="500" height="100" fill="white"/>
<text x="250" y="60" style="text-anchor:middle;font-size:35;
font-family:Arial;fill:black">Scalable Vector Graphics</text>
</g>
<clipPath id="spot">
<circle cx="200" cy="50" r="50"/>
</clipPath>
</defs>
<rect x="0" y="0" width="500" height="100" fill="black"/>
<text x="250" y="60" style="text-anchor:middle;font-size:35;
font-family:Arial;fill:white;fill-opacity:1">
Scalable Vector Graphics
</text>
<use clip-path="url(#spot)" xlink:href="#new_text"/>
</svg>
Figure 7-25. ClipPath with circle on text
We can use clipPath element for drop-down list with scrolling :
Figure 7-26. Drop-down selection list with scrolling
Figure 7-26 is a screenshot of a drop-down selection list with scrolling. This reusable SVG component use a script file and a SVG file for design of window. Values of the list are passed as parameters and put in <defs> section:
<defs>
<g id="scroll_textes" transform="translate(0,90)"
style="text-anchor:left;font-size:12;font-family:Arial;fill:black">
<text x="10" y="15" startOffset="0">red</text>
<text x="10" y="35" startOffset="0">yellow</text>
<!-- other text elements -->
</g>
<clipPath id="txt_spot">
<rect id="txt_list" x="0" y="90" width="260" height="120"/>
</clipPath>
</defs>
ClipPath element define part of list to be show. When user click on scroll buttons or slide cursor, script change value of y in rectangle "txt_list" content of clipPath. We can use clipPath and animation to simulate one-armed bandit.
Figure 7-27 show animation to choose number between 0 and 999. Script is only used to change numbers for begining. We get random number ...
We use two animations :
<svg width='200' height='200'>
<script type="text/ecmascript">
<![CDATA[
function alea(evt)
{
svgdoc=evt.getTarget().ownerDocument();
for (i=1;i<=3;i++)
{
n=Math.floor(10*Math.random())-1;
node=svgdoc.getElementById("move_"+i.toString());
node.setAttribute("from",20+40*n);
node.setAttribute("to",40*n+380);
node=svgdoc.getElementById("number_"+i.toString());
node.setAttribute("from",20+50*(i-1)+","+(-40*n));
node.setAttribute("to",20+50*(i-1)+","+(-360-40*n));
}
}
]]>
</script>
<defs>
<style type="text/css">
<![CDATA[
.lettre {text-anchor:middle;font-family:Verdana;font-weight:bold;
font-size:30;stroke:black}
]]>
</style>
<text id="ico1" class="lettre" x="25" y="30">1</text>
<text id="ico2" class="lettre" x="25" y="30">2</text>
<text id="ico3" class="lettre" x="25" y="30">3</text>
<text id="ico4" class="lettre" x="25" y="30">4</text>
<text id="ico5" class="lettre" x="25" y="30">5</text>
<text id="ico6" class="lettre" x="25" y="30">6</text>
<text id="ico7" class="lettre" x="25" y="30">7</text>
<text id="ico8" class="lettre" x="25" y="30">8</text>
<text id="ico9" class="lettre" x="25" y="30">9</text>
<text id="ico0" class="lettre" x="25" y="30">0</text>
<g id="rolling_numbers">
<use x="0" y="0" xlink:href="#ico1"/>
<use x="0" y="40" xlink:href="#ico2"/>
<use x="0" y="80" xlink:href="#ico3"/>
<use x="0" y="120" xlink:href="#ico4"/>
<use x="0" y="160" xlink:href="#ico5"/>
<use x="0" y="200" xlink:href="#ico6"/>
<use x="0" y="240" xlink:href="#ico7"/>
<use x="0" y="280" xlink:href="#ico8"/>
<use x="0" y="320" xlink:href="#ico9"/>
<use x="0" y="360" xlink:href="#ico0"/>
<use x="0" y="400" xlink:href="#ico1"/>
<use x="0" y="440" xlink:href="#ico2"/>
<use x="0" y="480" xlink:href="#ico3"/>
<use x="0" y="520" xlink:href="#ico4"/>
<use x="0" y="560" xlink:href="#ico5"/>
<use x="0" y="600" xlink:href="#ico6"/>
<use x="0" y="640" xlink:href="#ico7"/>
<use x="0" y="680" xlink:href="#ico8"/>
<use x="0" y="720" xlink:href="#ico9"/>
<use x="0" y="760" xlink:href="#ico0"/>
<use x="0" y="800" xlink:href="#ico1"/>
<use x="0" y="840" xlink:href="#ico2"/>
<use x="0" y="880" xlink:href="#ico3"/>
</g>
</defs>
<rect x='0' y='0' width='200' height='200'
style='stroke:green;fill:yellow'/>
<rect x="20" y="20" width="150" height="80" fill="white"/>
<path d="M70 20l0 80 M120 20l0 80" stroke="black"/>
<clipPath id="spot1">
<rect x="0" y="20" width="50" height="80">
<animate id="move_1" attributeName="y" dur="4s" repeatCount="2"
fill="freeze" from="0" to="240" begin="go.click"/>
</rect>
</clipPath>
<clipPath id="spot2">
<rect x="0" y="60" width="50" height="80">
<animate id="move_2" attributeName="y" dur="3s" repeatCount="3"
fill="freeze" from="40" to="280" begin="go.click"/>
</rect>
</clipPath>
<clipPath id="spot3">
<rect x="0" y="100" width="50" height="80">
<animate id="move_3" attributeName="y" dur="2s" repeatCount="4"
fill="freeze" from="80" to="320" begin="go.click"/>
</rect>
</clipPath>
<g transform="translate(20,0)" clip-path="url(#spot1)">
<use xlink:href="#rolling_numbers"/>
<animateTransform id="number_1" attributeName="transform"
type="translate"
from="20,20" to="20,-220" fill="freeze" dur="4s"
repeatCount="2" begin="go.click"/>
</g>
<g transform="translate(70,-40)" clip-path="url(#spot2)">
<use xlink:href="#rolling_numbers"/>
<animateTransform id="number_2" attributeName="transform"
type="translate"
from="70,-20" to="70,-260" fill="freeze" dur="3s"
repeatCount="3" begin="go.click"/>
</g>
<g transform="translate(120,-80)" clip-path="url(#spot3)">
<use xlink:href="#rolling_numbers"/>
<animateTransform id="number_3" attributeName="transform"
type="translate"
from="120,-60" to="120,-300" fill="freeze" dur="2s"
repeatCount="4" begin="go.click"/>
</g>
<rect x="10" y="180" width="50" height="18" fill="black"/>
<text x="35" y="195"
style="text-anchor:middle;font-weight:bold;font-size:15;
font-family:Arial;fill:white;stroke:black">GO</text>
<rect id="go" x="10" y="180" width="50" height="18"
opacity="0.1" onclick="alea(evt)"/>
</svg>
Figure 7-27. Screenshot of one-armed bandit
We can create puzzle game with some scripts. In this example, user can change picture used for pieces, number of pieces, paths for clipping.
When SVG is loaded, clipPath elements are created in <defs> section in group "clips", paths used are defined in file "clip_paths.js". Init function create also pieces for puzzle in group "pieces".
<svg width="800" height="450" onload="init(evt)">
<defs>
<g id="picture">
<image id="source" x="0" y="0" width="400" height="400"
xlink:href="puzzle.jpg"/>
</g>
<g id="clips">
</g>
</defs>// Load paths for clipPath elements: <script type="text/ecmascript" xlink:href="clip_paths.js" /> <script type="text/ecmascript">
<![CDATA[
// Some variables used in script var svgdoc="",xd1,xd2,yd1,yd2,num;
var click_piece=false,cible="", nb_trials=0;
var played=new Array();// Variables which can be changed by user to get more or less pieces var size=5,nb_pieces=25,large=80, // Function init, on loading SVG, define svgdoc,
// values for large and nb_pieces.
// Call create_pieces to create pieces and distribution
// to arrange pieces before
// starting game
function init(evt)
{
svgdoc=evt.getTarget().ownerDocument();
large=Math.round(400/size);nb_pieces=size*size;
create_pieces(evt);
distribution(evt);
}// Function create pieces, first clipPath elements,
// then pieces as use elements function create_pieces(evt)
{
contents = svgdoc.getElementById ('clips');
contents2 = svgdoc.getElementById ('pieces');
k=-1;
for (i=0;i<size;i++)
{
for (j=0;j<size;j++)
{
k+=1;
node=svgdoc.createElement("clipPath");
name="clip_path"+(1+i+size*j).toString();
node.setAttribute("id",name);
contents.appendChild(node);
node2=svgdoc.createElement("path");
node2.setAttribute("d",chemin[k]);
node.appendChild(node2);
node=svgdoc.createElement("use");
node.setAttribute("id","tile"+(1+i+size*j).toString());
node.setAttribute("transform","translate(400,0)");
name="url(#clip_path"+(1+i+size*j).toString()+")";
node.setAttribute("clip-path",name);
node.setAttributeNS('http://www.w3.org/2000/xlink/namespace/',
"xlink:href","#picture");
contents2.appendChild(node);
}
}
}// Function put pieces in random order beside picture
// to complete and initialise
// values function distribution(evt)
{
var place_allowed=new Array();
for (i=0;i<size;i++)
{
for (j=0;j<size;j++)
{
place_allowed[i+size*j]=0
}
};
for (i=1;i<=nb_pieces;i++)
{
played[i]=0
};
for (i=0;i<size;i++)
{
for (j=0;j<size;j++)
{
while (place_allowed[i+size*j]==0)
{
k=1+Math.floor(nb_pieces*Math.random());
if (played[k]<1)
{
played[k]=played[k]+1;
place_allowed[i+size*j]=k
}
};
line=Math.floor((k-1)/size);
row=k-1-size*line;
dx=400-large*(line-i);
dy=large*(j-row);
transfo="translate("+dx.toString()+","+dy.toString()+")";
node = svgdoc.getElementById("tile"+k.toString());
node.setAttribute("transform",transfo);
}
}
for (i=1;i<=nb_pieces;i++)
{
played[i]=0
};
nb_trials=0;
node=svgdoc.getElementById("trials");
child=node.firstChild;
child.setData(nb_trials)
}
// Functions to move pieces
// On mouseup, piece is no more actived function mouse_up(evt)
{
click_piece=false
}// On click, piece is actived, nb_trials incremented, new value writed,
// We get position of piece on click (xd1,yd1) and pointer position (xd2,yd2)
function mouse_down(evt)
{
if (click_piece==false)
{
cible=evt.getTarget().getAttribute("id");
click_piece=true;
nb_trials+=1;
node=svgdoc.getElementById("trials");
child=node.firstChild;
child.setData(nb_trials);
xm=evt.getClientX();
ym=evt.getClientY();
num=parseInt(cible.substring(4,cible.length));
objet=svgdoc.getElementById("tile"+num.toString());
transfo=new String(objet.getAttribute("transform"));
posi2=transfo.lastIndexOf(",");
tranx=transfo.substring(10,posi2);
xd1=parseInt(tranx,10);
longueur=transfo.length-1;
trany=transfo.substring(posi2+1,longueur);
yd1=parseInt(trany,10);
xd2=xm;yd2=ym
}
}// On mousemove piece is moved of (x_pointer+xd1-xd2,y_pointer+yd1-yd2)
// If piece is nearest good position ( less than 5 pixels
// in x and y ), piece is
// in place and played[piece_number] get value of 1.
function mouse_move(evt)
{
xm=evt.getClientX();
ym=evt.getClientY();
if (click_piece==true)
{
depx=xm+xd1-xd2;
depy=ym+yd1-yd2;
if ((Math.abs(depx)<5)&&(Math.abs(depy)<5))
{
depx=0;
depy=0;
played[num]=1
}
else
{
played[num]=0
};
transfo="translate("+depx+","+depy+")";
node = svgdoc.getElementById("tile"+num.toString());
node.setAttribute("transform",transfo)
}
}
// Function to put pieces in place on user request function solution(evt)
{
for (i=1;i<=nb_pieces;i++)
{
node = svgdoc.getElementById("tile"+i.toString());
node.setAttribute("transform","translate(0,0)");
}
}// Function to give result of game function bilan(evt)
{
var win_game=true;
for (i=1;i<=nb_pieces;i++)
{
if (played[i]==0)
{
win_game=false
}
};
if (win_game==true)
{
alert("You win in "+nb_trials+" trials")
}
else
{
alert("It's not finished!")
}
} ]]> <rect x="0" y="0" width="800" height="450" fill="green" opacity="0.3"/>
<rect x="10" y="410" width="100" height="20" style="fill:white"/>
<text x="60" y="425" style="text-anchor:middle;font-size:15;
font-family:Arial;fill:red">Result</text>
<rect x="10" y="410" onclick="bilan(evt)" width="100" height="20"
style="fill:green;fill-opacity:0"/>
<rect x="120" y="410" width="120" height="20" style="fill:white"/>
<text x="180" y="425" style="text-anchor:middle;font-size:15;
font-family:Arial;fill:red">New game</text>
<rect x="120" y="410" onclick="distribution(evt)" width="120" height="20"
style="fill:green;fill-opacity:0"/>
<rect x="250" y="410" width="120" height="20" style="fill:white"/>
<text x="310" y="425" style="text-anchor:middle;font-size:15;
font-family:Arial;fill:red">Solution</text>
<rect x="250" y="410" onclick="solution(evt)" width="120" height="20"
style="fill:green;fill-opacity:0"/>
<text x="450" y="425" style="text-anchor:left;font-size:15;
font-family:Arial;fill:black">Trials: </text>
<text id="trials" x="580" y="425" style="text-anchor:right;font-size:15;
font-family:Arial;fill:black">0</text>
<g onmouseup="mouse_up(evt)">
<use opacity="0.3" xlink:href="#picture"/>
<g id="pieces" onmousemove="mouse_move(evt)"
onmousedown="mouse_down(evt)">
</g>
</g>
</svg>
When SVG is loaded, we get for SVG elements:
In <defs> section :
<g id="clips">
<clipPath id="clip_path1">
<path d="M0 0 l80 0 c-10,10 -10,25 0,40 c10,10 10,30 0,40 c-5,-10
-25,-10 -30,0 a10,10 0 1,1 -10,0 c-5,-5 -35,-5 -40,0 l0 -80z"/>
</clipPath>
<clipPath id="clip_path6">
<path d="M80 0 c-10,10 -10,25 0,40 c10,10 10,30 0,40 c5,10 25,
10 30,0 a10,10 0 1,1 10,0 c5,5 35,5 40,0 l-5 -35 a10,10 0 1,0
0,-10 l5 -35z"/>
</clipPath>
<!-- other clipPath elements -->
</g>
In group "pieces" :
<g id="pieces" onmousemove="mouse_move(evt)" onmousedown="mouse_down(evt)">
<use id="tile1" transform="translate(400,80)"
clip-path="url(#clip_path1)" xlink:href="#picture"/>
<use id="tile6" transform="translate(320,160)"
clip-path="url(#clip_path6)" xlink:href="#picture"/>
<!-- other pieces for puzzle -->
</g>
Using HTML form, user can choose local file for picture. We can add choice for clipping paths, number of pieces .....
Figure 7-28. Sceenshot of puzzle game
"A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted."
This is syntax for "mask" element :
<mask id="name"
maskUnits=" userSpaceOnUse|objectBoundingBox"
maskContentUnits=" userSpaceOnUse|objectBoundingBox"
x="NumberOrPercentage"
y="NumberOrPercentage"
width="NumberOrPercentage"
height="NumberOrPercentage">
<!-- some objects as mask content -->
</mask>
Diagram 7-6. Chart for 'mask' syntax
maskUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for attributes x y width and height for largest possible offscreen buffer. With "userSpaceOnUse", values are defined in current user coordinate system. With "objectBoundingBox", default value, values are defined in coordinate system using the bounding box of the element to which the pattern is applied. In this case, it's more easy to use percentages for attributes.
maskContentUnits attribute can be "userSpaceOnUse" or "objectBoundingBox", it defines the coordinate system for the contents of the 'pattern' element. Here, "userSpaceOnUse" is the default value.
To use mask for object, we use 'mask' property :
'mask'
Value: <uri> | none | inherit
Initial: none
Applies to: container elements and graphics elements
Inherited: no
Percentages: N/A
Media: visual
Animatable: yes
We can get same result as Figure 7-25 with this code ( Example 7-25 ) :
<svg width="550" height="130" viewBox="-50 -30 550 130">
<defs>
<g id="new_text">
<rect x="0" y="0" width="500" height="100" fill="white"/>
<text x="250" y="60" style="text-anchor:middle;font-size:35;
font-family:Arial;fill:black">Scalable Vector Graphics</text>
</g>
<mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0"
width="500" height="100">
<circle cx="200" cy="50" r="50" fill="white"/>
</mask>
</defs>
<rect x="0" y="0" width="500" height="100" fill="black" fill-opacity="1"/>
<text x="250" y="60"
style="text-anchor:middle;font-size:35;font-family:Arial;
fill:white;fill-opacity:1">
Scalable Vector Graphics
</text>
<use mask="url(#spot)" xlink:href="#new_text"/>
</svg>

"The clipping path restricts the region to which paint can be applied...." To get picture, only geometry of clipPath element modify drawing. If you choose filling or stroking for clipPath content, drawing keep the same.
"You can specify that any other graphics object or 'g' element can be used as an alpha mask for compositing the current object into the background ..." Here, geometry give boundaries of drawing and filling for mask content change drawing :
Figure 7-29 show result with
<mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0"
width="500" height="100">
<circle cx="200" cy="50" r="50" fill="white"/>
</mask>
for upper drawing and with
<mask id="spot" maskUnits="userSpaceOnUse" x="0" y="0"
width="500" height="100">
<circle cx="200" cy="50" r="50" fill="green"/>
</mask>
for other
Figure 7-29. Only filling color of mask content change ...
| You must Sign In to use this message board. | ||||||
|
||||||
|
||||||
|
||||||
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 14 Dec 2003 Editor: Nishant Sivakumar |
Copyright 2003 by Jon Frost Everything else Copyright © CodeProject, 1999-2010 Web19 | Advertise on the Code Project |