After hours of looking for a solution here and there, I come here to ask for help.
I'm developing a customization module using <svg> element and Javascript.
In the end, I convert and download the SVG element in a .svg file but the problem is that some elements like the <text> ones are not in the right place when opening the file with Illustrator, it doesn't seem to care about the x and y attributes.
When I open the file in a browser, everything is in the right place.
Here is the HTML of the downloaded .svg file I get, all at the right place (the browser read the HTML attributes well I guess) : https://codepen.io/florianeychenne/pen/vYRgMWx
Here is the rendering in Illustrator :
The browser contains it to the first SVG element, which is width="833" height="396". Thats why you don't see the 'Exemple', it is contained to that first SVG tag. Illustrator does not contain anything, as it is not a browser viewport. I think that if you use only 1 SVG tag, it will solve your issue. It should then render the same in both software.
Some ideas for a workaround
convert/combine all transformations to matrix():
this way we circumvent problems with transform-origin (Illustrator
apparently can't use it - rotations will have a wrong pivot point)
convert nested svg elements to <g> group elements
some attributes like textLength won't work at all in AI - you might use a condensed font instead.
Working example
// getTransformToElement polyfill
SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(
toElement) {
return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM());
};
function fixNestedSvgs() {
let svgs = document.querySelectorAll('svg');
let nested = document.querySelectorAll('svg svg');
// all transformations to matrix()
svgs.forEach(function(svg) {
let children = [...svg.children];
children.forEach(function(child) {
transFormToMatrix(child);
styleToAttribute(child, ['fill', 'stroke', 'stroke-width']);
});
})
// nested to groups
nested.forEach(function(svg) {
let parent = svg.parentNode.closest('svg');
nestedSvgToGroup(svg);
svgMarkup.value = parent.outerHTML;
})
}
// all transformations to matrix()
function transFormToMatrix(el) {
let type = el.nodeName.toLowerCase();
let matrixString = '';
let types = ["path", "polygon", "polyline", "rect", "ellipse", "circle", "line", "text", "g", "svg"];
if (types.indexOf(type) !== -1) {
// get el matrix
let matrix = el.getTransformToElement(el.parentNode.closest("svg"));
let [a, b, c, d, e, f] = [
matrix.a,
matrix.b,
matrix.c,
matrix.d,
matrix.e,
matrix.f
];
matrixString = [a, b, c, d, e, f].join(" ");
//exclude non transformed elements
if (matrixString != "1 0 0 1 0 0") {
el.setAttribute("transform", `matrix(${matrixString})`);
el.removeAttribute("transform-origin");
}
}
return matrixString;
}
// convert fill styles to attributes
function styleToAttribute(el, attributes = ['fill', 'stroke', 'stroke-width']) {
let types = ["path", "polygon", "polyline", "rect", "ellipse", "circle", "line", "text", "g", "svg"];
let type = el.nodeName.toLowerCase();
if (types.indexOf(type) !== -1) {
let style = window.getComputedStyle(el);
attributes.forEach(function(attName) {
let value = style.getPropertyValue(attName);
if (value !== 'rgb(0, 0, 0)') {
el.setAttribute(attName, value);
}
})
}
}
//convert nested svgs to groups
function nestedSvgToGroup(svg) {
let svgSub = svg;
if (svg.parentNode) {
let parent = svg.parentNode.closest('svg');
let svgSubChildren = [...svgSub.children];
let groupMatrix = transFormToMatrix(svgSub);
//replace nested svg with group - apply matrix
let group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
group.classList.add('svgNest');
group.setAttribute('transform', `matrix( ${groupMatrix} )`);
//copy children to group
svgSubChildren.forEach(function(child, i) {
group.appendChild(child);
})
//remove nested svg
svgSub.replaceWith(group);
}
}
svg {
width: 80%
}
<svg class="center" viewBox="0 0 833 396" xmlns="http://www.w3.org/2000/svg">
<style>
#import url("https://fonts.googleapis.com/css2?family=Audiowide&family=Black+Ops+One&family=Faster+One&family=Fugaz+One&family=Racing+Sans+One&display=swap");
.fillColor {
fill: currentColor;
}
.strokeColor {
stroke: currentColor;
fill: none;
stroke-width: 5px;
}
.fillStrokeColor {
stroke: currentColor;
fill: currentColor;
stroke-width: 1px;
}
text {
font-family: 'Fugaz One', cursive;
}
</style>
<rect id="allCarpet" x="0" y="0" width="833" height="396"></rect>
<rect class="fillColor" id="foamCarpet" x="10" y="10" width="813" height="376" style="color:#ffd100"></rect>
<!-- <rect class="fillColor" id="leftLogo" x="22" y="105" width="84" height="187" style="color:white" /> -->
<text class="svg" x="580" y="345" font-size="15" id="topNickname" fill="black" textLength="70"
lengthAdjust="spacingAndGlyphs">FLORIAN</text>
<text class="svg" x="590" y="368" font-size="30" id="topNickname" fill="black" textLength="80"
lengthAdjust="spacingAndGlyphs">FLORIAN</text>
<text class="svg" x="-25" y="55" font-size="60" id="topNumber" fill="black" textLength="80"
lengthAdjust="spacingAndGlyphs" transform="rotate(180)" transform-origin="42px 42px">00</text>
<text class="svg" x="725" y="366" font-size="60" id="botNumber" fill="black" textLength="80"
lengthAdjust="spacingAndGlyphs">00</text>
<svg version="1.1" class="nested" id="Calque_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="1px" y="0px" viewBox="0 0 197 100"
style="enable-background:new 0 0 197 100;" xml:space="preserve" width="150px">
<style type="text/css">
.st0 {
fill: #CA0D25;
}
.st1 {
fill: none;
}
.st2 {
fill: #FF0000;
}
.st3 {
fill: #FEFEFE;
}
</style>
<path class="st1" d="M7.2,3.8v92.5h182.7V3.8H7.2z M186.8,93.2H10.2V6.8h176.5L186.8,93.2L186.8,93.2z"
transform="rotate(90)" transform-origin="center"></path>
<path class="st2" fill="red" d="M66.9,62.1v0.3c-0.1-0.1-0.2-0.2-0.2-0.3H66.9z M73.7,41.5c-5.6,0-6.9,5-6.9,9.6c0,4.6,1.3,9.5,6.9,9.5
c5.2-0.1,6.9-4.7,6.9-9.5C80.5,46.4,78.7,41.6,73.7,41.5z M43.4,53.1c-0.2,0.1-0.5,0.1-0.7,0.1c-2.5,0.5-5.1,1.6-5.1,4.6
c0,3.1,2.1,3.4,4.7,3.4c0.4,0,0.7,0,1.1,0c5.2-0.5,5.7-4.4,5.7-6.1L49,51.5C47.8,52.6,45.7,52.8,43.4,53.1z M186.8,6.8v86.3H10.2
V6.8H186.8z M57.5,66.4c-1.3-1.7-0.9-3.9-0.9-6.6V44.3c0-7.6-7.8-8.4-13.3-8.4c-6.2,0.1-11.9,2.3-12.3,9.5l7.3,0.1
c0.3-2.7,2.1-4,5.1-4.1c2.7,0,5.8,0.3,5.8,4c0,2.4-2.6,2.6-5.8,2.7c-1.4,0-2.8,0.1-4.3,0.3c-4.9,0.7-9.2,2.6-9.2,9.3
c0,5.3,4.1,9.2,9.9,9.2c1.2,0,2.1,0,3.3-0.2l0.3,0c2.2-0.4,4.3-1.3,6-3.1c0,0.9,0.6,1.9,0.9,2.8L57.5,66.4L57.5,66.4z M88.7,51.3
c0-8.5-4.2-16-13.5-16c-0.5,0-1,0-1.5,0.1c-3.1,0.4-5.7,1.8-7.4,4.5h-0.1v-3.1h-6.9v37.8h7.6V62.4c1.6,2.2,4.1,3.6,6.8,4.1
c0.6,0.1,1.3,0.1,2,0.1C84.3,66.7,88.7,59.2,88.7,51.3z M106.1,35.9c-4.3,0-7.1,1.8-8.8,5.5l0-4.8h-7.1v29.8h7.6V53
c0-6.8,3.8-9.5,8.2-9.5L106.1,35.9L106.1,35.9z M116.5,36.7h-7.6v29.7h7.6V36.7z M116.5,25.4h-7.6v6.8h7.6V25.4z M126.5,25.4h-7.6
v41.1h7.6V25.4z M136.7,36.7H129v29.7h7.6V36.7z M136.7,25.4H129v6.8h7.6V25.4z M166.7,66.3c-1.3-1.7-0.9-3.9-0.9-6.6V44.2
c0-7.6-7.8-8.4-13.3-8.4c-6.2,0.1-11.9,2.3-12.3,9.5l7.3,0.1c0.3-2.7,2.1-4,5.1-4.1c2.7,0,5.8,0.3,5.8,4c0,2.4-2.6,2.6-5.8,2.7
c-1.4,0-2.8,0.1-4.3,0.3c-4.9,0.7-9.2,2.6-9.2,9.3c0,5.3,4.1,9.2,9.9,9.2c1.2,0,2.1,0,3.3-0.2l0.3,0c2.2-0.4,4.3-1.3,6-3.1
c0,0.9,0.6,1.9,0.9,2.8L166.7,66.3L166.7,66.3z M152.5,53c-0.2,0.1-0.5,0.1-0.7,0.1c-2.5,0.5-5.1,1.6-5.1,4.6c0,3.1,2.1,3.4,4.7,3.4
c0.4,0,0.7,0,1.1,0c5.2-0.5,5.7-4.4,5.7-6.1l-0.1-3.7C156.9,52.5,154.8,52.7,152.5,53z" transform="rotate(90)"
transform-origin="center"></path>
<path class="st3"
d="M129.2,25.4h7.6v6.8h-7.6V25.4z M57.7,66.4h-7.3c-0.3-0.9-0.8-1.9-0.9-2.8c-1.6,1.8-3.7,2.7-6,3.1l-0.3,0
c-1.2,0.2-2.1,0.2-3.3,0.2c-5.8,0-9.9-4-9.9-9.2c0-6.7,4.3-8.6,9.2-9.3c1.5-0.2,2.9-0.3,4.3-0.3c3.2-0.2,5.8-0.4,5.8-2.7
c0-3.7-3-4-5.8-4c-2.9,0-4.8,1.3-5.1,4.1l-7.3-0.1c0.5-7.1,6.1-9.4,12.3-9.5c5.4,0,13.3,0.8,13.3,8.4v15.5
C56.9,62.4,56.5,64.7,57.7,66.4z M49.3,55.1l-0.1-3.7c-1.2,1.1-3.3,1.3-5.6,1.6c-0.2,0.1-0.5,0.1-0.7,0.1c-2.5,0.5-5.1,1.6-5.1,4.6
c0,3.1,2.1,3.4,4.7,3.4c0.4,0,0.7,0,1.1,0C48.8,60.7,49.3,56.8,49.3,55.1z M166.9,66.3h-7.3c-0.3-0.9-0.8-1.9-0.9-2.8
c-1.6,1.8-3.7,2.7-6,3.1l-0.3,0c-1.2,0.2-2.1,0.2-3.3,0.2c-5.8,0-9.9-4-9.9-9.2c0-6.7,4.3-8.6,9.2-9.3c1.5-0.2,2.9-0.3,4.3-0.3
c3.2-0.2,5.8-0.4,5.8-2.7c0-3.7-3-4-5.8-4c-2.9,0-4.8,1.3-5.1,4.1l-7.3-0.1c0.5-7.1,6.1-9.4,12.3-9.5c5.4,0,13.3,0.8,13.3,8.4v15.5
C166,62.3,165.6,64.6,166.9,66.3z M158.4,55l-0.1-3.7c-1.2,1.1-3.3,1.3-5.6,1.6c-0.2,0.1-0.5,0.1-0.7,0.1c-2.5,0.5-5.1,1.6-5.1,4.6
c0,3.1,2.1,3.4,4.7,3.4c0.4,0,0.7,0,1.1,0C157.9,60.7,158.4,56.7,158.4,55z M88.9,51.2c0,8-4.4,15.4-13.1,15.4c-0.6,0-1.3,0-2-0.1
c-2.7-0.4-5.2-1.9-6.8-4.1v-0.3h-0.2c0.1,0.1,0.2,0.2,0.2,0.3v12.2h-7.6V36.8h6.9v3.1h0.1c1.7-2.7,4.3-4.2,7.4-4.5
c0.5,0,1-0.1,1.5-0.1C84.8,35.2,88.9,42.8,88.9,51.2z M80.7,51c0-4.6-1.8-9.4-6.9-9.6c-5.6,0-6.9,5-6.9,9.6c0,4.6,1.3,9.5,6.9,9.5
C79.1,60.4,80.7,55.8,80.7,51z M129.2,66.4h7.6V36.7h-7.6V66.4z M119.1,66.5h7.6V25.4h-7.6V66.5z M109.1,66.4h7.6V36.7h-7.6V66.4z
M97.5,41.4l0-4.8h-7.1v29.8h7.6V53c0-6.8,3.8-9.5,8.2-9.5v-7.6C102,35.9,99.2,37.7,97.5,41.4z M109.1,32.2h7.6v-6.8h-7.6V32.2z"
transform="rotate(90)" transform-origin="center"></path>
</svg>
<text class="svg" x="323" y="586" font-size="100" id="rightText" fill="black" transform="rotate(-90)" transform-origin="center" textLength="187" lengthAdjust="spacingAndGlyphs">EXEMPLE</text>
<polyline class="strokeColor" id="centerPolygon" points="144,103 642,103 689,153 689,294 192,294 144,246 144,100.5" style="color:#010101;"></polyline>
<polyline class="fillStrokeColor" id="bottomPolygon" points="10,374 525,374 547,347 10,347" style="color:#009afb"></polyline>
<polyline class="fillStrokeColor" id="topPolygon" points="823,22 308,22 286,49 823,49" style="color:#009afb">
</polyline>
<polyline class="fillStrokeColor" id="littleBottomPolygon" points="10,340 553,340 560,332 10,332" style="color:#fefefe"></polyline>
<polyline class="fillStrokeColor" id="littleTopPolygon" points="823,57 280,57 273,65 823,65" style="color:#fefefe"></polyline>
</svg>
<p><button type="button" onclick="fixNestedSvgs()"> Fix nested svg</button></p>
<textarea id="svgMarkup" style="width:100%; min-height:20em"></textarea>
Drawbacks
This conversions might fail in browsers struggling with transform-origin (like some safari/webkit versions).
Some graphic applications might also have issues parsing inherited fill attributes like fill:currentColor.
The above example includes a helper styleToAttribute() to inline some attributes.
I'm using Snap.svg in order to animate an SVG image on hover. In this case, I'm trying to make the image a little bit bigger (1.1x) and then change the fill color. On hover, the image scales correctly, but the fill color is unchanged. I have a suspicion it's because the image consists of three child elements which is where the fill colors reside, but I'm unable to figure out how to access them.
Here's the html:
<svg id="mySvg" width="200" height="200"
viewBox="0 0 2000 2000" preserveAspectRatio="none"></svg>
And here's the javascript:
var s = Snap("#mySvg");
var g = s.group();
var tux = Snap.load("3d_glasses.svg", function (loadedFragment) {
g.append(loadedFragment);
g.hover(hoverover, hoverout);
});
var hoverover = function () {
g.animate({
transform: 'scale(1.1)',
fill: '#FF0000'
}, 1000, mina.bounce);
};
var hoverout = function () {
g.animate({
transform: 'scale(1)',
fill: '#252525'
}, 1000, mina.bounce);
};
My SVG image file (3d_glasses.svg) looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1024px" height="1024px" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="nonzero" clip-rule="evenodd" viewBox="0 0 10240 10240" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>3D_glasses icon</title>
<path id="curve2" fill="#252525" d="M6669 6080c-89,-175 -174,-356 -261,-531 -39,-78 -85,-152 -137,-222 -131,-175 -191,-356 -191,-575l0 -592 2560 0 0 1920 -1971 0z"/>
<path id="curve1" fill="#252525" d="M3571 6080c89,-175 174,-356 261,-531 39,-78 85,-152 137,-222 131,-175 191,-356 191,-575l0 -592 -2560 0 0 1920 1971 0z"/>
<path id="curve0" fill="#252525" d="M960 3200l8320 0c176,0 320,144 320,320l0 3200c0,176 -144,320 -320,320l-2804 0c-249,0 -462,-132 -573,-354l-354 -707c-83,-167 -243,-266 -429,-266 -186,0 -346,99 -429,266l-354 707c-111,222 -324,354 -573,354l-2804 0c-176,0 -320,-144 -320,-320l0 -3200c0,-176 144,-320 320,-320zm5162 2492c120,240 249,708 547,708l1971 0c176,0 320,-144 320,-320l0 -1920c0,-176 -144,-320 -320,-320l-2560 0c-176,0 -320,144 -320,320l0 592c0,288 83,536 255,767 41,54 76,113 107,173zm-2551 708c123,0 229,-65 285,-175 90,-177 174,-356 262,-533 31,-60 67,-119 107,-173 172,-231 255,-479 255,-767l0 -592c0,-176 -144,-320 -320,-320l-2560 0c-176,0 -320,144 -320,320l0 1920c0,176 144,320 320,320l1971 0z"/>
</svg>
defghi is correct in that the fill value of the elements is causing the issue.
I'm going to give an alternative answer though, and I guess its down to personal preference in terms of one may work better with the rest of your code and solution.
Rather than remove the fill, I would probably use a css transition, that way the original fills are left intact. So it would work something like...
s.select("g").hover( hoverFunc, hoverOut );
function hoverFunc() {
this.selectAll('path').forEach( function( el ){
el.attr({ class: 'redfadein' }) } );
this.animate({ transform: 's1.1,1.1' }, 1000);
};
function hoverOut() {
this.selectAll('path').forEach( function( el ){
el.attr({ class: 'redfadeout' }) } );
this.animate({ transform: 's1,1' }, 1000);
};
and css
redfadein {
transition: fill 1s ease;
fill:red;
}
.redfadeout {
transition: fill 1s ease;
}
jsfiddle
You may also just want to put a white filled background (or small opacity) on the space in the middle of the path so it doesn't hover out when over the white space. You could also move the scale to css as well to keep it all in one place.
You should remove fill attributes from path elements in source SVG file.
When path elements have fill attribute, the fill value of g element contains these path is ignored for rendering.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1024px" height="1024px" fill-rule="nonzero" viewBox="0 0 10240 10240" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>3D_glasses icon</title>
<path id="curve2" d="M6669 6080c-89,..."/>
<path id="curve1" d="M3571 6080c89,-175 174..."/>
<path id="curve0" d="M960 3200..."/>
</svg>
If you can't edit SVG file, you can remove fill attributes by calling removeAttribute method of SVGDOM.
I'm developing a map, in Javascript using SVG to draw the lines.
I would like to add a feature where you can search for a road, and if the road is found, a circle appears on the map.
I know i can draw a circle in SVG, but my problem is that, the size of the circle should not change depending on the zoom-level. In other words the circle must have the same size at all times.
The roads on my map have this feature, all i had to do was add
vector-effect="non-scaling-stroke"
to the line attributes..
A line looks like this.
<line vector-effect="non-scaling-stroke" stroke-width="3" id = 'line1' x1 = '0' y1 = '0' x2 = '0' y2 = '0' style = 'stroke:rgb(255,215,0);'/>
The circle looks like this.
<circle id = "pointCircle" cx="0" cy="0" r="10" stroke="red" stroke-width="1" fill = "red"/>
Is it possible to define the circle as "non-scaling" somehow?
It took me a while, but I finally got the math clean. This solution requires three things:
Include this script in your page (along with the SVGPan.js script), e.g.
<script xlink:href="SVGPanUnscale.js"></script>
Identify the items you want not to scale (e.g. place them in a group with a special class or ID, or put a particular class on each element) and then tell the script how to find those items, e.g.
unscaleEach("g.non-scaling > *, circle.non-scaling");
Use transform="translate(…,…)" to place each element on the diagram, not cx="…" cy="…".
With just those steps, zooming and panning using SVGPan will not affect the scale (or rotation, or skew) of marked elements.
Demo: http://phrogz.net/svg/scale-independent-elements.svg
Library
// Copyright 2012 © Gavin Kistner, !#phrogz.net
// License: http://phrogz.net/JS/_ReuseLicense.txt
// Undo the scaling to selected elements inside an SVGPan viewport
function unscaleEach(selector){
if (!selector) selector = "g.non-scaling > *";
window.addEventListener('mousewheel', unzoom, false);
window.addEventListener('DOMMouseScroll', unzoom, false);
function unzoom(evt){
// getRoot is a global function exposed by SVGPan
var r = getRoot(evt.target.ownerDocument);
[].forEach.call(r.querySelectorAll(selector), unscale);
}
}
// Counteract all transforms applied above an element.
// Apply a translation to the element to have it remain at a local position
function unscale(el){
var svg = el.ownerSVGElement;
var xf = el.scaleIndependentXForm;
if (!xf){
// Keep a single transform matrix in the stack for fighting transformations
// Be sure to apply this transform after existing transforms (translate)
xf = el.scaleIndependentXForm = svg.createSVGTransform();
el.transform.baseVal.appendItem(xf);
}
var m = svg.getTransformToElement(el.parentNode);
m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
xf.setMatrix(m);
}
Demo Code
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Scale-Independent Elements</title>
<style>
polyline { fill:none; stroke:#000; vector-effect:non-scaling-stroke; }
circle, polygon { fill:#ff9; stroke:#f00; opacity:0.5 }
</style>
<g id="viewport" transform="translate(500,300)">
<polyline points="-100,-50 50,75 100,50" />
<g class="non-scaling">
<circle transform="translate(-100,-50)" r="10" />
<polygon transform="translate(100,50)" points="0,-10 10,0 0,10 -10,0" />
</g>
<circle class="non-scaling" transform="translate(50,75)" r="10" />
</g>
<script xlink:href="SVGPan.js"></script>
<script xlink:href="SVGPanUnscale.js"></script>
<script>
unscaleEach("g.non-scaling > *, circle.non-scaling");
</script>
</svg>
If you are looking for a fully static way of doing this, you might be able to combine non-scaling-stroke with markers to get this, since the markers can be relative to the stroke-width.
In other words, you could wrap the circles in a <marker> element and then use those markers where you need them.
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
<marker id="Triangle"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth"
markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<path d="M 100 100 l 200 0" vector-effect="non-scaling-stroke"
fill="none" stroke="black" stroke-width="10"
marker-end="url(#Triangle)" />
<path d="M 100 200 l 200 0"
fill="none" stroke="black" stroke-width="10"
marker-end="url(#Triangle)" />
</svg>
The same can also be viewed and tweaked here. The svg spec isn't fully explicit about what should happen in this case (since markers are not in SVG Tiny 1.2, and vector-effect isn't in SVG 1.1). My current line of thinking was that it should probably affect the size of the marker, but it seems no viewers do that at the moment (try in a viewer that supports vector-effect, e.g Opera or Chrome).
Looks like some work was done in webkit (maybe related to this bug: 320635) and the new transform doesn't stick around when simply appended like that
transform.baseVal.appendItem
This seems to work better. Even works in IE 10.
EDIT: Fixed the code for more general case of multiple translate transformations in the front and possible other transformations after. First matrix transformation after all translates must be reserved for unscale though.
translate(1718.07 839.711) translate(0 0) matrix(0.287175 0 0 0.287175 0 0) rotate(45 100 100)
function unscale()
{
var xf = this.ownerSVGElement.createSVGTransform();
var m = this.ownerSVGElement.getTransformToElement(this.parentNode);
m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
xf.setMatrix(m);
// Keep a single transform matrix in the stack for fighting transformations
// Be sure to apply this transform after existing transforms (translate)
var SVG_TRANSFORM_MATRIX = 1;
var SVG_TRANSFORM_TRANSLATE = 2;
var baseVal = this.transform.baseVal;
if(baseVal.numberOfItems == 0)
baseVal.appendItem(xf);
else
{
for(var i = 0; i < baseVal.numberOfItems; ++i)
{
if(baseVal.getItem(i).type == SVG_TRANSFORM_TRANSLATE && i == baseVal.numberOfItems - 1)
{
baseVal.appendItem(xf);
}
if(baseVal.getItem(i).type != SVG_TRANSFORM_TRANSLATE)
{
if(baseVal.getItem(i).type == SVG_TRANSFORM_MATRIX)
baseVal.replaceItem(xf, i);
else
baseVal.insertItemBefore(xf, i);
break;
}
}
}
}
EDIT2:
Chrome killed getTransformToElement for some reason, so the matrix needs to be retrieved manually:
var m = this.parentNode.getScreenCTM().inverse().multiply(this.ownerSVGElement.getScreenCTM());
It's discussed here and here
It looks like current browsers don't do the expected thing, so one needs to apply the inverse transform of the zoom (scale) on the contents of the <marker>, eg. transorm: scaleX(5) on the user of the <marker> etc. will need to be accompanied by a transform: translate(...) scaleX(0.2) inside the <pattern>, also factoring in possible x/y/width/height/transform-origin values inside the pattern if needed