I want to show dynamically svg but every time svg position is changing and sometimes overflowing from screen. I want to alignt this svg path center of screen.
function App() {
const [city, setCity] = useState("");
useEffect(() => {
setCity(cities[Math.floor(Math.random() * cities.length)]);
}, []);
return (
<div>
<div className="svg-div">
<svg height="100%" width="100%" className="svg" viewBox="0 0 600 600">
<g>
<path id="city" d={city?.d} />
</g>
</svg>
</div>
<Input cities={cities} />
</div>
);
}
export default App;
CodePudding user response:
Add this css . svg-div{ display: flex: justify-content: center; align-items: center; }
CodePudding user response:
Most likely your dynamically retrieved paths are parts of a complete map svg.
So the surrounding space or overflow ist caused by the paths' coordinates which are relative to the original map viewBox.
Example 1: extracted map region
.svgAssetHidden {
visibility: hidden;
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.map,
.svg-use
{
display: block;
width: 20em;
border: 1px solid #ccc;
fill:#ccc;
}
.map path{
stroke-width:2;
stroke:#fff;
}
<p>Complete map</p>
<svg id="svgMapComplete" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path id="region1" d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
<path id="region2" d="M100.1 30.2l-3.7 11.2l-9.5 15.1c0 0-26.1 1.3-27.4 1.3c-1.2 0-2.9 8.4-3.4 10.7l-19.1-2.2l-6.5-15.1l-3.3-12.9l-21.4-12.3l6.8-9.4l10.9-6.2l7-1l5.9 11.7l13 5.9l29-7.4l-1.4 2.7l9.6 3.7l10.8-5.4l2.7 9.6z" />
<path id="region3" d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
<p>Map fragment – display region</p>
<svg id="svgMapCompletePart" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" >
<path id="region3" d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
The southwestern region still has surrounding space since it's relative to the parent map's initial viewBox.
To circumvent this problem you could wrap all path elements in a <symbol>
element containing its own viewbox – you will need to get each region's boundary box via getBBox()
.
Example 2: show regions wrapped in symbol elements
/**
* select
*/
let svg = document.querySelector("#svgMap");
let regions = svg.querySelectorAll("path");
/**
* query elements to be wrapped in symbols
**/
function wrapSymbols(parent, els) {
els.forEach(function(el, i) {
let symbol = wrapSymbol(el, i);
parent.appendChild(symbol);
});
}
/**
* wrap path in symbol element
**/
function wrapSymbol(el, i = 0) {
let symbol = document.createElementNS("http://www.w3.org/2000/svg", "symbol");
symbol.id = el.id ? "symbol-" el.id : "symbol-" i;
let symbolBB = el.getBBox();
let symbolVBox = [symbolBB.x, symbolBB.y, symbolBB.width, symbolBB.height];
symbolVBox.forEach(function(el, i) {
symbolVBox[i] = symbolVBox[i].toFixed(2);
});
symbol.setAttribute("viewBox", symbolVBox.join(" "));
symbol.insertAdjacentElement("beforeend", el);
return symbol;
}
/**
* create example use html
**/
function getExampleUseHTML(el) {
let useHtml = "";
let symbols = document.querySelectorAll("symbol");
symbols.forEach(function(el, i) {
let vB = el.getAttribute("viewBox").split(" ");
useHtml =
'<svg viewBox="0 0 '
vB[2]
" "
vB[3]
'">\n'
'<use href="#'
el.id
'" />\n'
"</svg>\n";
});
return useHtml;
}
/**
* render example use html
*/
wrapSymbols(svg, regions);
let useHTML = getExampleUseHTML(svg);
document.body.insertAdjacentHTML(
"beforeend",
'<div >' useHTML "</div>"
);
.svgAssetHidden {
visibility: hidden;
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.map-cell-flex {
display: flex;
flex: 1;
}
.map,
.svg-use {
border: 1px solid #ccc;
fill: #ccc;
}
<p>Map fragment – display region by use element</p>
<svg id="svgMap" xmlns="http://www.w3.org/2000/svg">
<path d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
<path d="M100.1 30.2l-3.7 11.2l-9.5 15.1c0 0-26.1 1.3-27.4 1.3c-1.2 0-2.9 8.4-3.4 10.7l-19.1-2.2l-6.5-15.1l-3.3-12.9l-21.4-12.3l6.8-9.4l10.9-6.2l7-1l5.9 11.7l13 5.9l29-7.4l-1.4 2.7l9.6 3.7l10.8-5.4l2.7 9.6z" />
<path d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
Once you've wrapped your path elements in a symbol you can place your regions via <use>
Symbol definition:
<symbol id="symbol-0" viewBox="30.5 0.1 63.4 26.9">
<path d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
</symbol>
Use instance:
<svg viewBox="0 0 63.4 26.9">
<use href="#symbol-0" />
</svg>