Home > Software engineering >  Centering a SVG path
Centering a SVG path

Time:02-22

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>

CodePudding user response:

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>

CodePudding user response:

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>.

Centering and scaling by recalculating path coordinates

Most likely a transform works perfectly fine.
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  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. To get all the path data I use Jarek Foksa's pathData polyfill

Centering paths
Involves some comparisons between the parent svg viewBox an the actual path's boundaries (retrieved vie 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 (using snap.svg's toRelative(d).
Now we only need to shift the M command x/y coordinates (see also Lea Verous post Convert SVG path to all-relative or all-absolute commands)

Disclaimer: not intended for live usuage
This approach should only be used as for custom svg optimizing. So run the script - resave your optimized svg asset.

  • Related