Reputation: 74
is there a way to center my <path>
in an SVG
-File?
This is my 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>
Upvotes: 0
Views: 290
Reputation: 17354
Another quick fix could be setting negative viewBox x/y values like so:
<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>
Slightly hacky, especially if you need a background element like a <rect>
.
Most likely, a transform works perfectly fine and should be your first choice.
If you need your transformations to be "hard coded" – it's not too complicated:
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/[email protected]/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>
Scaling d coordinates proportionally
Requires to loop through all path commands and multiply all coordinates by a scaling factor (like 0.75).
To get the path data, I use Jarek Foksa's pathData polyfill
Centering paths
Involves some comparisons between the parent svg's viewBox and the actual path's boundaries (retrieved via path.getBBox()
).
To actually shift the path horizontally and vertically by x/y offsets we can simplify the task by converting the path commands to relative coordinates (using snap.svg's toRelative(d)
.
Now we only need to change the M command's x/y coordinates (see also Lea Verou's post Convert SVG path to all-relative or all-absolute commands)
**Disclaimer: not intended for live usage **
This approach should be used for custom svg pre-optimizing. So run the script - re-save your svg asset.
Upvotes: 0
Reputation: 31805
Add a suitable transform. This seems fairly close:
<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>
Upvotes: 1