所以,让我们说我有一个看起来像这样的SVG:
<svg width="800" height="600" viewBox="0 0 800 600" style="border: 1px solid blue;">
<path fill="#f00" stroke="none" d="M720 394.5c-27.98 0-51.61-6.96-71.97-18.72-29.64-17.1-52.36-44.37-71.48-75.12-28-45.01-48.31-97.48-71.39-136.52-20.03-33.88-42.14-57.64-73.16-57.64-31.1 0-53.24 23.88-73.31 57.89-23.04 39.05-43.34 91.45-71.31 136.39-19.28 30.98-42.21 58.41-72.2 75.45C195 387.72 171.62 394.5 144 394.5Z"/>
</svg>
&#13;
如您所见,路径仅占用SVG(和viewBox区域)的一部分。
我想知道如何转换它们填充viewBox的路径中的值(基本上重新缩放和重新定位路径中的值,以便填充整个viewBox)。
[UPDATE]
我正在添加更多细节...
举一个例子 - 假设我开始使用带有这样的viewBox的SVG:0 0 1600 1600
。
在该SVG中,有一条路径占据了从1200,1200
到1500,1400
的区域。 (即,路径为300 x 200)。
我希望能够提取该路径,并将其添加到viewBox为0 0 300 200
的新SVG中。
为此,需要相应地修改d
属性中的值 - 基本上向上移动1200点。
显然,绝对坐标需要改变,但相对坐标不会改变。 (这应该很简单)。
但我也必须处理曲线及其控制点,这可能会有点棘手。
一个完美的解决方案是能够检查路径,识别可能包含它的最小边界框,然后调整所有点,使它们适合该边界框,锚定在0,0
。
我不想缩放或延伸路径。
我对这样做的数学过程或功能,或某种在线工具同样感到满意。
我意识到我可以使用SVG转换来实现这一目标,但我希望能够改变实际路径。
(即,我不希望我的网页包含&#34;错误的&#34;数据和转换为&#34;更正&#34;它;我只是希望我的代码包含& #34;纠正&#34;数据。)
有办法做到这一点吗?
答案 0 :(得分:1)
如果您不需要缩放新路径,那么您需要做的就是应用transform
将其移动到正确的位置。如果它从(1200,1200)开始,并且你希望它在(0,0),那么进行变换"translate(-1200, -1200)"
<svg width="800" height="600" viewBox="0 0 800 600" style="border: 1px solid blue;">
<path fill="#f00" stroke="none" transform="translate(-1200,-1200)"
d="M720 394.5c-27.98 0-51.61-6.96-71.97-18.72-29.64-17.1-52.36-44.37-71.48-75.12-28-45.01-48.31-97.48-71.39-136.52-20.03-33.88-42.14-57.64-73.16-57.64-31.1 0-53.24 23.88-73.31 57.89-23.04 39.05-43.34 91.45-71.31 136.39-19.28 30.98-42.21 58.41-72.2 75.45C195 387.72 171.62 394.5 144 394.5Z"/>
</svg>
答案 1 :(得分:1)
在您提供更新之前,我已经写了大部分答案。因此,我的回答是对我原本想要的回应:能够直接改变&#34; d&#34; SVG路径的属性,以便路径现在只填充SVG视口。因此,我的答案确实涉及您在原始答案中建议您确实需要的缩放,但您在更新中并不需要。在任何情况下,我希望我的代码能让您了解如何在不使用转换的情况下直接更改d属性。
下面的代码段显示了您以红色提供的原始路径,其中&#34;已转换为&#34;路径显示为蓝色。请注意,在svg代码中,两条路径的开头相同。您可以通过右键单击路径并选择&#34;检查元素&#34;来获取蓝色路径的d属性,至少在Firefox中是这样。
希望代码中的变量名称和注释提供了理解我的方法所需的指导。
(更新:修复了代码段中的代码,以便它现在也可以在Chrome和Safari中使用,而不仅仅是在Firefox中。看来有些ES6语言功能,例如&#34;让&# 34;,&#34; const&#34;,destructuring,Symbols,在Firefox中工作,但至少其中一些人不能在Chrome或Safari中工作。我还没有检查过Internet Explorer或Opera或其他任何内容浏览器)。
// Retrieve the "d" attribute of the SVG path you wish to transform.
var $svgRoot = $("svg");
var $path = $svgRoot.find("path#moved");
var oldPathDStr = $path.attr("d");
// Calculate the transformation required.
var obj = getTranslationAndScaling($svgRoot, $path);
var pathTranslX = obj.pathTranslX;
var pathTranslY = obj.pathTranslY;
var scale = obj.scale;
// The path could be transformed at this point with a simple
// "transform" attribute as shown here.
// $path.attr("transform", `translate(${pathTranslX}, ${pathTranslY}), scale(${scale})`);
// However, as described in your question you didn't want this.
// Therefore, the code following this line mutates the actual svg path.
// Calculate the path "d" attributes parameters.
var newPathDStr = getTransformedPathDStr(oldPathDStr, pathTranslX, pathTranslY, scale);
// Apply the new "d" attribute to the path, transforming it.
$path.attr("d", newPathDStr);
document.write("<p>Altered 'd' attribute of path:</p><p>" + newPathDStr + "</p>");
// This is the end of the main code. Below are the functions called.
// Calculate the transformation, i.e. the translation and scaling, required
// to get the path to fill the svg area. Note that this assumes uniform
// scaling, a path that has no other transforms applied to it, and no
// differences between the svg viewport and viewBox dimensions.
function getTranslationAndScaling($svgRoot, $path) {
var svgWdth = $svgRoot.attr("width" );
var svgHght = $svgRoot.attr("height");
var origPathBoundingBox = $path[0].getBBox();
var origPathWdth = origPathBoundingBox.width ;
var origPathHght = origPathBoundingBox.height;
var origPathX = origPathBoundingBox.x ;
var origPathY = origPathBoundingBox.y ;
// how much bigger is the svg root element
// relative to the path in each dimension?
var scaleBasedOnWdth = svgWdth / origPathWdth;
var scaleBasedOnHght = svgHght / origPathHght;
// of the scaling factors determined in each dimension,
// use the smaller one; otherwise portions of the path
// will lie outside the viewport (correct term?)
var scale = Math.min(scaleBasedOnWdth, scaleBasedOnHght);
// calculate the bounding box parameters
// after the path has been scaled relative to the origin
// but before any subsequent translations have been applied
var scaledPathX = origPathX * scale;
var scaledPathY = origPathY * scale;
var scaledPathWdth = origPathWdth * scale;
var scaledPathHght = origPathHght * scale;
// calculate the centre points of the scaled but untranslated path
// as well as of the svg root element
var scaledPathCentreX = scaledPathX + (scaledPathWdth / 2);
var scaledPathCentreY = scaledPathY + (scaledPathHght / 2);
var svgRootCentreX = 0 + (svgWdth / 2);
var svgRootCentreY = 0 + (svgHght / 2);
// calculate translation required to centre the path
// on the svg root element
var pathTranslX = svgRootCentreX - scaledPathCentreX;
var pathTranslY = svgRootCentreY - scaledPathCentreY;
return {pathTranslX, pathTranslY, scale};
}
function getTransformedPathDStr(oldPathDStr, pathTranslX, pathTranslY, scale) {
// constants to help keep track of the types of SVG commands in the path
var BOTH_X_AND_Y = 1;
var JUST_X = 2;
var JUST_Y = 3;
var NONE = 4;
var ELLIPTICAL_ARC = 5;
var ABSOLUTE = 6;
var RELATIVE = 7;
// two parallel arrays, with each element being one component of the
// "d" attribute of the SVG path, with one component being either
// an instruction (e.g. "M" for moveto, etc.) or numerical value
// for either an x or y coordinate
var oldPathDArr = getArrayOfPathDComponents(oldPathDStr);
var newPathDArr = [];
var commandParams, absOrRel, oldPathDComp, newPathDComp;
// element index
var idx = 0;
while (idx < oldPathDArr.length) {
var oldPathDComp = oldPathDArr[idx];
if (/^[A-Za-z]$/.test(oldPathDComp)) { // component is a single letter, i.e. an svg path command
newPathDArr[idx] = oldPathDArr[idx];
switch (oldPathDComp.toUpperCase()) {
case "A": // elliptical arc command...the most complicated one
commandParams = ELLIPTICAL_ARC;
break;
case "H": // horizontal line; requires only an x-coordinate
commandParams = JUST_X;
break;
case "V": // vertical line; requires only a y-coordinate
commandParams = JUST_Y;
break;
case "Z": // close the path
commandParams = NONE;
break;
default: // all other commands; all of them require both x and y coordinates
commandParams = BOTH_X_AND_Y;
}
absOrRel = ((oldPathDComp === oldPathDComp.toUpperCase()) ? ABSOLUTE : RELATIVE);
// lowercase commands are relative, uppercase are absolute
idx += 1;
} else { // if the component is not a letter, then it is a numeric value
var translX, translY;
if (absOrRel === ABSOLUTE) { // the translation is required for absolute commands...
translX = pathTranslX;
translY = pathTranslY;
} else if (absOrRel === RELATIVE) { // ...but not relative ones
translX = 0;
translY = 0;
}
switch (commandParams) {
// figure out which of the numeric values following an svg command
// are required, and then transform the numeric value(s) from the
// original path d-attribute and place it in the same location in the
// array that will eventually become the d-attribute for the new path
case BOTH_X_AND_Y:
newPathDArr[idx ] = Number(oldPathDArr[idx ]) * scale + translX;
newPathDArr[idx + 1] = Number(oldPathDArr[idx + 1]) * scale + translY;
idx += 2;
break;
case JUST_X:
newPathDArr[idx ] = Number(oldPathDArr[idx ]) * scale + translX;
idx += 1;
break;
case JUST_Y:
newPathDArr[idx ] = Number(oldPathDArr[idx ]) * scale + translY;
idx += 1;
break;
case ELLIPTICAL_ARC:
// the elliptical arc has x and y values in the first and second as well as
// the 6th and 7th positions following the command; the intervening values
// are not affected by the transformation and so can simply be copied
newPathDArr[idx ] = Number(oldPathDArr[idx ]) * scale + translX;
newPathDArr[idx + 1] = Number(oldPathDArr[idx + 1]) * scale + translY;
newPathDArr[idx + 2] = Number(oldPathDArr[idx + 2]) ;
newPathDArr[idx + 3] = Number(oldPathDArr[idx + 3]) ;
newPathDArr[idx + 4] = Number(oldPathDArr[idx + 4]) ;
newPathDArr[idx + 5] = Number(oldPathDArr[idx + 5]) * scale + translX;
newPathDArr[idx + 6] = Number(oldPathDArr[idx + 6]) * scale + translY;
idx += 7;
break;
case NONE:
throw new Error('numeric value should not follow the SVG Z/z command');
break;
}
}
}
return newPathDArr.join(" ");
}
function getArrayOfPathDComponents(str) {
// assuming the string from the d-attribute of the path has all components
// separated by a single space, then create an array of components by
// simply splitting the string at those spaces
str = standardizePathDStrFormat(str);
return str.split(" ");
}
function standardizePathDStrFormat(str) {
// The SVG standard is flexible with respect to how path d-strings are
// formatted but this makes parsing them more difficult. This function ensures
// that all SVG path d-string components (i.e. both commands and values) are
// separated by a single space.
return str
.replace(/,/g , " " ) // replace each comma with a space
.replace(/-/g , " -" ) // precede each minus sign with a space
.replace(/([A-Za-z])/g, " $1 ") // sandwich each letter between 2 spaces
.replace(/ /g , " " ) // collapse repeated spaces to a single space
.replace(/ ([Ee]) /g , "$1" ) // remove flanking spaces around exponent symbols
.replace(/^ /g , "" ) // trim any leading space
.replace(/ $/g , "" ); // trim any tailing space
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg width="800" height="600" viewBox="0 0 800 600" style="border: 1px solid blue;">
<path id="notmoved" fill="#f00" stroke="none" d="M720 394.5c-27.98 0-51.61-6.96-71.97-18.72-29.64-17.1-52.36-44.37-71.48-75.12-28-45.01-48.31-97.48-71.39-136.52-20.03-33.88-42.14-57.64-73.16-57.64-31.1 0-53.24 23.88-73.31 57.89-23.04 39.05-43.34 91.45-71.31 136.39-19.28 30.98-42.21 58.41-72.2 75.45C195 387.72 171.62 394.5 144 394.5Z" opacity="0.5" />
<path id="moved" fill="#00f" stroke="none" d="M720 394.5c-27.98 0-51.61-6.96-71.97-18.72-29.64-17.1-52.36-44.37-71.48-75.12-28-45.01-48.31-97.48-71.39-136.52-20.03-33.88-42.14-57.64-73.16-57.64-31.1 0-53.24 23.88-73.31 57.89-23.04 39.05-43.34 91.45-71.31 136.39-19.28 30.98-42.21 58.41-72.2 75.45C195 387.72 171.62 394.5 144 394.5Z" opacity="0.5" />
</svg>
&#13;