- From: Ken Stacey <ken@svgmaker.com>
- Date: Wed, 20 Jan 2010 19:32:07 +1000
- To: www-svg@w3.org
On 19/01/2010 7:08 AM, Erik Dahlstrom wrote: > update on the gradient issue (www-svg) > > AG: asv and inkscape do the same thing > ... same as firefox > > DS/CL: seems like the path of least resistence then > > CL: different from opera? > > ED: yes > > CL: can you get everything you want by one way or the other? > > AG: you can get the same result using any of these methods, by > specifying different values > ... mostly a question of what looks best when squished/transformed > ... technically both ways are correct > ... don't have a preference First, a quick description of the two methods when applied with userSpaceOnUse. A. Gradient normal is perpendicular to the gradient vector in current user space. B. Gradient normal is perpendicular to the gradient vector in viewport space. This is a case for method A. The spec does go some way towards defining the gradient normal. At least for objectBoundingBox: http://www.w3.org/TR/SVG11/pservers.html#LinearGradients """ When gradientUnits="objectBoundingBox" and gradientTransform is the identity matrix, the stripes of the linear gradient are perpendicular to the gradient vector in object bounding box space (i.e., the abstract coordinate system where (0,0) is at the top/left of the object bounding box and (1,1) is at the bottom/right of the object bounding box). When the object's bounding box is not square, the stripes that are conceptually perpendicular to the gradient vector within object bounding box space will render non-perpendicular relative to the gradient vector in user space due to application of the non-uniform scaling transformation from bounding box space to user space. """ Since the stripes are transformed by the the application of the non-uniform scaling transformation from bounding box space to user space, you would expect the CTM to further transform the stripes. A reasonable conclusion, or ambigious? Although unstated for userSpaceOnUse, I would expect the stripes of the linear gradient for these gradientUnits to be similarly defined - to be "perpendicular to the gradient vector in user space" and make the same conclusion that the CTM further transforms the stripes. Reasonable, or not? gradientTransform says: """ gradientTransform = "<transform-list>" Contains the definition of an optional additional transformation from the gradient coordinate system onto the target coordinate system (i.e., userSpaceOnUse or objectBoundingBox). This allows for things such as skewing the gradient. This additional transformation matrix is post-multiplied to (i.e., inserted to the right of) any previously defined transformations, including the implicit transformation necessary to convert from object bounding box units to user space. If attribute gradientTransform is not specified, then the effect is as if an identity transform were specified. """ What is the gradient coordinate system? Not defined anywhere. But whatever it is, it does appear to be in place prior to any transforms are applied (for both userSpaceOnUse and objectBoundingBox). I would think that the gradient coordinate system x axis is defined by the gradient vector, and the y axis is defined by the gradient normal at this time. That fits with method A thinking. I take the gradientTransform definition as saying: [viewport x y] = CTM . GTM . [gradientTransform] . [gradient x y] where, CTM accumulates all transformations on the referencing element and GTM is the gradient space to user space transformation. For an identity gradientTransform, [viewport x y] = CTM . GTM . [gradient x y] Consistent with how every graphic element behaves when transformed. How would you apply a gradientTransform with method B? There is only a one dimensional coordinate space defined at the time of application. Only after all transformations have been applied, a "y" axis appears. Not consistent in my view. > > ED: personally I prefer using objectBoundingBox units, since that's > more reusable > ... the issue only affects userspaceonuse gradients, right? I think that they should be conceptually the same. Differing only in the transformation from object bounding box space to user space. > > AG: will email the list with the results, completing my action Below is a test case for comparison between implementations and applies transformations to two simple linearGradients. A horizontal gradient vector and a diagonal gradient vector. The gradient vectors are shown by the magenta lines. The gradient normal* is shown by yellow lines. *For the objectBoundingBox case these lines follow the spec description quoted above - perpendicular in object bounding box space. For userSpaceOnUse I have assumed the gradient normal is perpendicular in user space. I hope this helps the discussion. Ken <?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 800" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="usou1" x1="0" y1="50" x2="200" y2="50" gradientUnits="userSpaceOnUse"> <stop offset="0" stop-color="red"/> <stop offset="0.5" stop-color="green"/> <stop offset="1.0" stop-color="blue"/> </linearGradient> <linearGradient id="usou2" x1="0" y1="0" x2="200" y2="100" gradientUnits="userSpaceOnUse"> <stop offset="0" stop-color="red"/> <stop offset="0.5" stop-color="green"/> <stop offset="1.0" stop-color="blue"/> </linearGradient> <linearGradient id="obb1" x1="0" y1="0.5" x2="1" y2="0.5" gradientUnits="objectBoundingBox"> <stop offset="0" stop-color="red"/> <stop offset="0.5" stop-color="green"/> <stop offset="1.0" stop-color="blue"/> </linearGradient> <linearGradient id="obb2" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox"> <stop offset="0" stop-color="red"/> <stop offset="0.5" stop-color="green"/> <stop offset="1.0" stop-color="blue"/> </linearGradient> <g id="r1"> <rect width="200" height="100" /> <line x1="0" y1="50" x2="200" y2="50" stroke="magenta" stroke-width="2"/> <line x1="100" y1="0" x2="100" y2="100" stroke="yellow" stroke-width="2"/> </g> <g id="r3"> <rect width="200" height="100" /> <line x1="0" y1="0" x2="200" y2="100" stroke="magenta" stroke-width="2"/> <line x1="-100" y1="-50" x2="100" y2="50" stroke="yellow" stroke-width="2" transform="matrix(0,-1,1,0,100,50)"/> </g> <g id="r4"> <rect width="200" height="100" /> <line x1="0" y1="0" x2="200" y2="100" stroke="magenta" stroke-width="2"/> <line x1="0" y1="100" x2="200" y2="0" stroke="yellow" stroke-width="2"/> </g> <text id="tusou" font-family="Arial" fill="black" font-size="20" x="750" y="50">userSpaceOnUse</text> <text id="tobb" font-family="Arial" fill="black" font-size="20" x="750" y="50">objectBoundingBox</text> </defs> <text font-family="Arial" fill="black" font-size="20" y="50"><tspan x="100">No transform</tspan><tspan x="350">scale(0.5,1)</tspan><tspan x="500">matrix(1,0.25,0.5,1,x,y)</tspan></text> <g transform="translate(100,100)" fill="url(#usou1)"> <use xlink:href="#r1" /> <use xlink:href="#r1" transform="matrix(0.5,0,0,1,250,0)"/> <use xlink:href="#r1" transform="matrix(1,0.25,0.5,1,400,0)"/> <use xlink:href="#tusou"/> </g> <g transform="translate(100,250)" fill="url(#obb1)"> <use xlink:href="#r1" /> <use xlink:href="#r1" transform="matrix(0.5,0,0,1,250,0)"/> <use xlink:href="#r1" transform="matrix(1,0.25,0.5,1,400,0)"/> <use xlink:href="#tobb"/> </g> <g transform="translate(100,450)" fill="url(#usou2)"> <use xlink:href="#r3" /> <use xlink:href="#r3" transform="matrix(0.5,0,0,1,250,0)"/> <use xlink:href="#r3" transform="matrix(1,0.25,0.5,1,400,0)"/> <use xlink:href="#tusou"/> </g> <g transform="translate(100,600)" fill="url(#obb2)"> <use xlink:href="#r4" /> <use xlink:href="#r4" transform="matrix(0.5,0,0,1,250,0)"/> <use xlink:href="#r4" transform="matrix(1,0.25,0.5,1,400,0)"/> <use xlink:href="#tobb"/> </g> </svg>
Received on Wednesday, 20 January 2010 09:32:40 UTC