math
math

Reputation: 187

Strange diagonal viewBox SVG Behaviour

Trying to figure out how this svg viewBox thing works but sadly the code below is breaking all logic we know lol. Please someone explain if this is a bug or it's the correct svg behaviour. I can't see what I'm getting wrong...

<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>

This my svg symbol here and I'm trying to stack more of them (both horizzontally and vertically)

//vertical stack ->viewBox = 0, 0, 10*1, 7*2
<svg viewBox="0 0 10 14">
      <use href="#Atom"/>
      <use href="#Atom" y="7"/> 
</svg>

//horizontal stack ->viewBox = 0, 0, 10*2, 7*1
<svg viewBox="0 0 20 7">
      <use href="#Atom"/>
      <use href="#Atom" x="10"/>    
</svg>

//"diagonal" stack ->viewBox = 0, 0, 10*2, 7*2
<svg viewBox="0 0 20 14">
      <use href="#Atom"/>
      <use href="#Atom" x="10"/>
      <use href="#Atom" y="7"/>
</svg>

First one is 2 symbols in vertical so I kept the same viewBox as the symbol but doubling the height from 7 to 14. Works perfectly.

Second one is 2 symbols in horizontal so I kept the same viewBox as the symbol but doubled the width from 10 to 20. Works as well.

Third one is 2 symbols in horizontal and 2 symbols in vertical making both viewBox's width and height twice as the original. This doesn't work. strange behaviour screenshot

As you can see from the image the symbols get all messed up togheter (seems like I have a wrong viewBox)

This is kinda what I'm looking for (though as you can see I'm using overflow: visible and the symbols goes out of the viewbox)

kinda expected result

Can somebody explain me what I'm getting wrong here? Any help is really appreciated.

Here's a codepen for playing with this stuff

Upvotes: 0

Views: 148

Answers (2)

math
math

Reputation: 187

So I ended up replying to myself but I really want to thanks @ciekals11 for its input.

The solution to get the result I wanted was to specify width and height attributes in my symbol. This makes everything works perfectly. Not sure why it does need this, but anyway I'll share my symbol again so you can see the difference.

<svg class="symbol"><symbol width="10" height="7" id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"/></symbol></svg>

Upvotes: 1

ciekals11
ciekals11

Reputation: 2155

your symbol want to take full width or height when you stretch only one dimension of viewport then it fit nicely because it take full width or height and stops from stretching in other direction because it want to preserve aspect ratio.

But in this svg viewport is 2x bigger than symbol so it take it all

here is simple solution

.svg {
  max-width: 200px;
  border: 1px solid red;
}
<svg class="svg" viewBox="0 0 20 14">
    <use href="#Atom" x="0" y="0"  width="50%" />
    <use href="#Atom" x="0" y="7"  width="50%" />
    <use href="#Atom" x="10" y="0" width="50%" />
    <use href="#Atom" x="10" y="7" width="50%" />
</svg>
<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>


UPDATE:

if you doesn't want to manually add width to use tag AND you are creating them programmatically then (I assumed that you use javascript but you could use same logic for other language) you just want to calc rows and columns in your viewport and calculate width and height of every use

here is an example

const config = {
    svg: {
        width: 20,
        height: 14,
        rows: 2,
        cols: 2,
        symbol: '#Atom'
    }
}
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 '+config.svg.width+' '+config.svg.height);

for (let i = 0; i < config.svg.rows; i++) {
    for (let j = 0; j < config.svg.cols; j++) {
        const xPosition = (config.svg.width / config.svg.rows) * i;
        const yPosition = (config.svg.height / config.svg.cols) * j;

        const width = (100 / config.svg.rows);
        const height = (100 / config.svg.cols);

        const svgUse = document.createElementNS('http://www.w3.org/2000/svg', 'use');
        svgUse.setAttribute('href', config.svg.symbol);
        svgUse.setAttribute('x', xPosition);
        svgUse.setAttribute('y', yPosition);
        svgUse.setAttribute('width', width + '%');
        svgUse.setAttribute('height', height + '%');

        svg.append(svgUse);
    }
}

document.body.prepend(svg)
<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>
    </body>
</html>

Upvotes: 2

Related Questions