居中 SVG 路径
Centering a SVG path
有没有办法将我的 <path>
置于 SVG
文件的中心?
这是我的 SVG:
xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z" fill="#6441A4" />
</svg>
添加合适的变换。这似乎相当接近:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path fill="#6441A4"
transform="translate(3.95 3.95)"
d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z"/>
</svg>
另一个快速修复可以设置 negative viewBox x/y values 像这样:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3.95 -3.95 72 72" >
<rect x="-3.95" y="-3.95" width="100%" height="100%" fill="#444444" />
<path fill="#6441A4"
d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z"/>
</svg>
有点hacky,特别是如果你需要像<rect>
这样的背景元素。
通过重新计算路径坐标来居中和缩放
很可能,转换工作得很好,应该是您的第一选择。
如果您需要对转换进行“硬编码”——这并不太复杂:
let svg = document.querySelector(".svg");
let path = svg.querySelector("path");
let bBox = svg.getBBox();
let vBox = svg.getAttribute("viewBox");
let vBoxArr = vBox ? vBox.split(" ") : [0, 0, bBox.width, bBox.height];
scalePathProportional(path, 0.75);
centerPath(path, true, true);
function centerPath(path, centerX= true, centerY=true, precision=3, render=true){
let svg = path.closest('svg');
let viewBox = svg.getAttribute('viewBox');
let bBox = svg.getBBox();
viewBox = viewBox ? viewBox.split(' ') : ([bBox.x, bBox.y, bBox.width, bBox.height]);
let offXnorm = viewBox[0] * (-1);
let offYnorm = viewBox[1] * (-1);
// convert to relative to move only M
let dRel = snapPathToRelative(path, 1);
let pathBB = path.getBBox();
let pX = pathBB["x"];
let pY = pathBB["y"];
// get x/y offsets to center path
let shiftX = (viewBox[2] - pathBB.width) / 2 - pX ;
let shiftY = (viewBox[3] - pathBB.height) / 2 - pY;
// save them to pathData
dRel[0][1] = (dRel[0][1] + shiftX).toFixed(precision) * 1;
dRel[0][2] = (dRel[0][2] + shiftY).toFixed(precision) * 1;
// apply change
if(render){
path.setAttribute('d',dRel.toString());
}
return dRel;
}
//scale to path to width and height by units or percentages
function scalePathProportional(path, scale=1) {
let svg = path.closest("svg");
let pathData = path.getPathData();
pathData.forEach(function (command, p) {
let coords = command.values;
//scale coordinates if viewBox < 1000 units
if (scale!==1) {
coords.forEach(function (el, i) {
coords[i] = coords[i] * scale;
});
}
});
path.setPathData(pathData);
return pathData;
}
function snapPathToRelative(path, precicion=null, render=false){
let d = path.getAttribute('d');
let pathRel = Snap.path.toRelative(d);
if(precicion){
roundCoords(pathRel)
}
if(render){
path.setAttribute('d', pathRel.toString());
}
return pathRel;
}
function roundCoords(commands, decimals=1){
commands.forEach(function (coordinates, i) {
let coordRelative = [];
coordinates.forEach(function (coordinate, v) {
if (typeof coordinate === 'number') {
coordinate = (coordinate).toFixed(decimals) * 1
}
coordRelative.push(coordinate);
});
commands[i] = coordRelative;
});
//console.log(commands)
return commands;
}
svg {
display: inline-block;
height: 5em;
font-size: 1em;
border: 1px solid #ccc;
background-color:#444;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.3/path-data-polyfill.min.js"></script>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z" fill="#6441A4" />
</svg>
按比例缩放 d 坐标
需要遍历所有路径命令并将所有坐标乘以比例因子(如 0.75)。
要获取路径数据,我使用 Jarek Foksa's pathData polyfill
居中路径
涉及父 svg 的 viewBox 和实际路径边界之间的一些比较(通过 path.getBBox()
检索)。
要实际水平和垂直移动路径 x/y 偏移量,我们可以通过将路径命令转换为相对坐标(使用 snap.svg's toRelative(d)
.
来简化任务
现在我们只需要更改 M 命令的 x/y 坐标(另见 Lea Verou 的 post Convert SVG path to all-relative or all-absolute commands)
**免责声明:不适用于现场使用**
这种方法应该用于自定义 svg pre-optimizing。所以 运行 脚本 - re-save 你的 svg 资源。
有没有办法将我的 <path>
置于 SVG
文件的中心?
这是我的 SVG: xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z" fill="#6441A4" />
</svg>
添加合适的变换。这似乎相当接近:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path fill="#6441A4"
transform="translate(3.95 3.95)"
d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z"/>
</svg>
另一个快速修复可以设置 negative viewBox x/y values 像这样:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3.95 -3.95 72 72" >
<rect x="-3.95" y="-3.95" width="100%" height="100%" fill="#444444" />
<path fill="#6441A4"
d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z"/>
</svg>
有点hacky,特别是如果你需要像<rect>
这样的背景元素。
通过重新计算路径坐标来居中和缩放
很可能,转换工作得很好,应该是您的第一选择。
如果您需要对转换进行“硬编码”——这并不太复杂:
let svg = document.querySelector(".svg");
let path = svg.querySelector("path");
let bBox = svg.getBBox();
let vBox = svg.getAttribute("viewBox");
let vBoxArr = vBox ? vBox.split(" ") : [0, 0, bBox.width, bBox.height];
scalePathProportional(path, 0.75);
centerPath(path, true, true);
function centerPath(path, centerX= true, centerY=true, precision=3, render=true){
let svg = path.closest('svg');
let viewBox = svg.getAttribute('viewBox');
let bBox = svg.getBBox();
viewBox = viewBox ? viewBox.split(' ') : ([bBox.x, bBox.y, bBox.width, bBox.height]);
let offXnorm = viewBox[0] * (-1);
let offYnorm = viewBox[1] * (-1);
// convert to relative to move only M
let dRel = snapPathToRelative(path, 1);
let pathBB = path.getBBox();
let pX = pathBB["x"];
let pY = pathBB["y"];
// get x/y offsets to center path
let shiftX = (viewBox[2] - pathBB.width) / 2 - pX ;
let shiftY = (viewBox[3] - pathBB.height) / 2 - pY;
// save them to pathData
dRel[0][1] = (dRel[0][1] + shiftX).toFixed(precision) * 1;
dRel[0][2] = (dRel[0][2] + shiftY).toFixed(precision) * 1;
// apply change
if(render){
path.setAttribute('d',dRel.toString());
}
return dRel;
}
//scale to path to width and height by units or percentages
function scalePathProportional(path, scale=1) {
let svg = path.closest("svg");
let pathData = path.getPathData();
pathData.forEach(function (command, p) {
let coords = command.values;
//scale coordinates if viewBox < 1000 units
if (scale!==1) {
coords.forEach(function (el, i) {
coords[i] = coords[i] * scale;
});
}
});
path.setPathData(pathData);
return pathData;
}
function snapPathToRelative(path, precicion=null, render=false){
let d = path.getAttribute('d');
let pathRel = Snap.path.toRelative(d);
if(precicion){
roundCoords(pathRel)
}
if(render){
path.setAttribute('d', pathRel.toString());
}
return pathRel;
}
function roundCoords(commands, decimals=1){
commands.forEach(function (coordinates, i) {
let coordRelative = [];
coordinates.forEach(function (coordinate, v) {
if (typeof coordinate === 'number') {
coordinate = (coordinate).toFixed(decimals) * 1
}
coordRelative.push(coordinate);
});
commands[i] = coordRelative;
});
//console.log(commands)
return commands;
}
svg {
display: inline-block;
height: 5em;
font-size: 1em;
border: 1px solid #ccc;
background-color:#444;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.3/path-data-polyfill.min.js"></script>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<rect width="100%" height="100%" fill="#444444" />
<path d="M5.7 0L1.4 10.985V55.88h15.284V64h8.597l8.12-8.12h12.418l16.716-16.716V0H5.7zm51.104 36.3L47.25 45.85H31.967l-8.12 8.12v-8.12H10.952V5.73h45.85V36.3zM47.25 16.716v16.716h-5.73V16.716h5.73zm-15.284 0v16.716h-5.73V16.716h5.73z" fill="#6441A4" />
</svg>
按比例缩放 d 坐标
需要遍历所有路径命令并将所有坐标乘以比例因子(如 0.75)。
要获取路径数据,我使用 Jarek Foksa's pathData polyfill
居中路径
涉及父 svg 的 viewBox 和实际路径边界之间的一些比较(通过 path.getBBox()
检索)。
要实际水平和垂直移动路径 x/y 偏移量,我们可以通过将路径命令转换为相对坐标(使用 snap.svg's toRelative(d)
.
来简化任务
现在我们只需要更改 M 命令的 x/y 坐标(另见 Lea Verou 的 post Convert SVG path to all-relative or all-absolute commands)
**免责声明:不适用于现场使用**
这种方法应该用于自定义 svg pre-optimizing。所以 运行 脚本 - re-save 你的 svg 资源。