Im trying to tile a plane in SVG, but unfortunatley i cant use css3 perspective as its buggy in safari. I tried skewX with a fixed perspective tile. It kind of works, but i think the maths is wrong? Has anyone experience with maths of tiling a plane in CSS?
I was hoping the mirror tiles would stay aligned but they don't seem to line up after 5 columns.
:root {
--baseWidth: 97;
--baseFactor: calc(5/8);
}
#sRows use:nth-child(even) {
--f1: #ff0;
--f2: #000;
--col: var(--f1);
}
#sRows use:nth-child(odd) {
--f1: #000;
--f2: #ff0;
--col: var(--f1);
}
#mCol use:nth-child(even) {
--f: var(--f1);
}
#mCol use:nth-child(odd) {
--f: var(--f2);
}
#mCol use {
--x: calc(var(--baseWidth) * var(--i));
--s: calc(89 - calc(30 / var(--i)));
}
#mCol use:first-child {
--s: calc(91 - calc(30 / var(--i)));
}
#mirrorLeft {
transform: skewX(calc( var(--s) * -1deg)) translate(calc(var(--x) * -1px));
}
#mirrorRight {
transform: skewX(calc( var(--s) * 1deg)) translate(calc(var(--x) * 1px));
}
#sRows use {
--rx: calc(240 - calc(204 * pow(var(--baseFactor), calc( var(--ri) + 1))));
--ry: calc(88 + calc( 90 * pow( var(--baseFactor), var(--ri))));
--rz: calc( var(--baseWidth) * pow(var(--baseFactor), var(--ri)));
transform: translate(calc(var(--rx)*1px), calc( var(--ry) * 1px)) scale(calc(var(--rz)*1.66%));
}
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="180">
<defs>
<symbol id="tileTemplate" overflow="hidden" >
<path style="fill:var(--f)" d="M 31.5 0 H 127.5 L 160 35 H 0 Z" opacity=".5" />
<?ignore
<g >
<path style="fill:var(--f)" d="M 31.5 0 H 128.5 L 160 35 H 0 Z" opacity=".25"/>
<g opacity=".5" >
<path d="m 79 23.3471 l -0.208 11.433 m 30.182 -20.888 l 3.75 8.6 m -64.112 -8.6 l -4.063 8.6 m 100.9347 1.3838 l 9.1319 9.852 M 130 6.5311 l 6.003 7.031 M 79 6.5311 L 78.873 13.5621 m 24.23 -13.135 l 2.435 5.585 M 54.971 0.4271 L 52.333 6.0121" style="stroke:#fff;stroke-width:2"/>
<path d="m 147.571,22.984 10.177,11 M 81,22.984 81.208,34.417 m 30.18,-20.888 4.063,8.6 m -64.425,-8.6 -3.75,8.6 m 85.327,-15.961 6.003,7.031 M 81,6.168 l 0.127,7.031 m 23.902,-13.135 2.638,5.585 M 56.897,0.064 54.462,5.649" style="stroke:#000000;stroke-width:2" />
<path d="m 0.665,33.984 h 158.67 M 11.44,22.554 H 148.56 M 20.063,13.2 H 140.189 M 26.6,5.907 h 106.88" style="stroke:#000000;stroke-width:2"/>
</g>
</g>
?>
</symbol>
<symbol id="tRow" overflow="visible">
<use href="#tileTemplate" style="--f:var(--col)" />
<use href="#mCol" />
</symbol>
<symbol id="mSkew" overflow="visible" >
<use id="mirrorRight" href="#tileTemplate" />
<use id="mirrorLeft" href="#tileTemplate" />
</symbol>
<symbol id="mCol" overflow="visible" >
<use href="#mSkew" style="--i:1" />
<use href="#mSkew" style="--i:2 " />
<use href="#mSkew" style="--i:3 " />
<use href="#mSkew" style="--i:4 " />
<use href="#mSkew" style="--i:5 " />
<use href="#mSkew" style="--i:6 " />
<use href="#mSkew" style="--i:7 " />
<use href="#mSkew" style="--i:8 " />
<use href="#mSkew" style="--i:9 " />
<use href="#mSkew" style="--i:10" />
<use href="#mSkew" style="--i:11" />
<use href="#mSkew" style="--i:12" />
<use href="#mSkew" style="--i:13" />
<use href="#mSkew" style="--i:14" />
<use href="#mSkew" style="--i:15" />
<use href="#mSkew" style="--i:16" />
<use href="#mSkew" style="--i:17" />
<use href="#mSkew" style="--i:18" />
<use href="#mSkew" style="--i:19" />
<use href="#mSkew" style="--i:20" />
<use href="#mSkew" style="--i:21" />
<use href="#mSkew" style="--i:22" />
<use href="#mSkew" style="--i:23" />
<use href="#mSkew" style="--i:24" />
<use href="#mSkew" style="--i:25" />
<use href="#mSkew" style="--i:26" />
<use href="#mSkew" style="--i:27" />
<use href="#mSkew" style="--i:28" />
<use href="#mSkew" style="--i:29" />
<use href="#mSkew" style="--i:30" />
<use href="#mSkew" style="--i:31" />
<use href="#mSkew" style="--i:32" />
</symbol>
</defs>
<g id="sRows" class="scaleRows" >
<use href="#tRow" style="--ri:1;"/>
<use href="#tRow" style="--ri:2;" />
<use href="#tRow" style="--ri:3;" />
<use href="#tRow" style="--ri:4;" />
<use href="#tRow" style="--ri:5;" />
<use href="#tRow" style="--ri:6;" />
<use href="#tRow" style="--ri:7;" />
<use href="#tRow" style="--ri:8;" />
</g>
<g transform="translate(240)" display="inline" opacity=".5" >
<path d="M 0,0 -80,180 M 0,0 80,180" style="stroke:#888;stroke-width:0.5"/>
<path d="M -240,145 H 240" style="stroke:#0f0;stroke-width:.5;stroke-dasharray:1, 1" />
<path d="M 0,90 -80,180 M 0,90 80,180" style="stroke:#00f;stroke-width:.5;stroke-dasharray:1, 1" />
</g>
</svg>
To make your computations as easy as possible, your focal point should be at [0, 0]
of the user coordinate system. Then, after you draw a base tile, two characteristic numbers are needed:
--width: x distance between the two lower corners / y value of the lower corners
--height: y value of the upper corners / y value of the lower corners
For my example, I've choosen them to be 0.2
and 0.9
, respectively.
Then, the skewed tiles of each row can be computed as
transform: skewX(atan(var(--width) * [0, 1, 2,...]));
and the scaling of each row as
transform: scale(pow(var(--height), [0, 1, 2,...]));
Instead of explicite mirroring, you can just add negative numbers to continue in the opposite direction from the base tile. This is both true for horizontal and vertical tiling.
:root {
--width: 0.2;
--height: 0.9;
}
use[href="#tile"] {
fill: none;
transform: skewX(atan(var(--width, 0) * var(--x)));
}
use[href="#row"] {
transform: scale(pow(var(--height), var(--y)));
}
use[href="#row"]:nth-child(even) {
--even: red;
--odd: darkgreen;
}
use[href="#row"]:nth-child(odd) {
--even: darkgreen;
--odd: red;
}
use[href="#tile"]:nth-child(even) {
stroke: var(--even);
}
use[href="#tile"]:nth-child(odd) {
stroke: var(--odd);
}
use#base {
stroke: black;
}
<svg viewBox="-100 50 200 100">
<defs>
<path id="tile" d="M -9.4,90 H 8.6 M -9.25,92.4 H 8.75 L 9,94.8 M -9.5,94.8 H 9.5 M -9.75,97.4 H 9.25 L 9.5,100 M -4.5,90 -4.625,92.4 M -4.75,94.8 -4.875,97.4 M 4.5,90 4.625,92.5 M 4.75,94.8 4.875,97.4 M 0,92.5 V 94.8 M 0,97.4 V 99.5"/>
<g id="row">
<use href="#tile" style="--x:-10"/>
<use href="#tile" style="--x:-9"/>
<use href="#tile" style="--x:-8"/>
<use href="#tile" style="--x:-7"/>
<use href="#tile" style="--x:-6"/>
<use href="#tile" style="--x:-5"/>
<use href="#tile" style="--x:-4"/>
<use href="#tile" style="--x:-3"/>
<use href="#tile" style="--x:-2"/>
<use href="#tile" style="--x:-1"/>
<use href="#tile" style="--x:0"/>
<use href="#tile" style="--x:1"/>
<use href="#tile" style="--x:2"/>
<use href="#tile" style="--x:3"/>
<use href="#tile" style="--x:4"/>
<use href="#tile" style="--x:5"/>
<use href="#tile" style="--x:6"/>
<use href="#tile" style="--x:7"/>
<use href="#tile" style="--x:8"/>
<use href="#tile" style="--x:9"/>
<use href="#tile" style="--x:10"/>
</g>
</defs>
<use href="#row" style="--y:-4"/>
<use href="#row" style="--y:-3"/>
<use href="#row" style="--y:-2"/>
<use href="#row" style="--y:-1"/>
<use href="#row" style="--y:0"/>
<use href="#row" style="--y:1"/>
<use href="#row" style="--y:2"/>
<use href="#row" style="--y:3"/>
<use href="#row" style="--y:4"/>
<use href="#row" style="--y:5"/>
<use href="#row" style="--y:6"/>
<use href="#row" style="--y:7"/>
<use href="#row" style="--y:8"/>
<!-- repeat the base tile just to mark its position -->
<use id="base" href="#tile"/>
</svg>