How to use setMatrix in svg

Viewed 50

I am working with the following element where I am trying to see if I can use setMatrix. But I am not sure why it is not working.

I am trying set up transform through setMatrix which fails, as a POC I have tried setTranslate and setRotate which is doing the job correctly. If setMatrix works correctly, it would place the green circle at exactly same place as the red

const svgns = 'http://www.w3.org/2000/svg'
const svg = d3.select('svg');

height = 400;
width = 720;

svg
    .attr('xmlns', svgns)
    .attr('viewBox', `0 0 ${width} ${height}`)

svg.append('rect')
    .attr('class', 'vBoxRect')
    .style("overflow", "visible")
    .attr('width', `${width}`)
    .attr('height', `${height}`)
    .attr('stroke', 'black')
    .attr('fill', 'transparent');

const red = document.querySelector('.red').transform.baseVal;
console.log(red);

const green = document.querySelector('.green');
const additionalTransform = green.ownerSVGElement.createSVGTransform();

//works

// additionalTransform.setTranslate(50, 90); //equivalent matrix = (1, 0, 0, 1, 50, 90)
// green.transform.baseVal.appendItem(additionalTransform);
// green.transform.baseVal.consolidate();
// additionalTransform.setRotate(-45, 0, 0); //equivalent matrix = (0.7071067811865476, -0.7071067811865476, 0.7071067811865476, 0.7071067811865476, 0, 0)
// green.transform.baseVal.appendItem(additionalTransform);
// green.transform.baseVal.consolidate();
// additionalTransform.setTranslate(30, 160); //equivalent matrix = (1, 0, 0, 1, 30,160)
// green.transform.baseVal.appendItem(additionalTransform);
// green.transform.baseVal.consolidate();

//does not work

additionalTransform.setMatrix[1, 0, 0, 1, 50, 90]
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
additionalTransform.setMatrix[0.7071067811865476, -0.7071067811865476, 0.7071067811865476, 0.7071067811865476, 0, 0];
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
additionalTransform.setMatrix1, [0, 0, 1, 30, 160];
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
    <svg>
        <circle class="red" cx="10" cy="10" r="50" fill="red" transform="translate(50,90) rotate(-45) translate(30,160)"/>
        <circle class="green" cx="10" cy="10" r="50" fill="green"/>
  </svg>
</body>
<script type="text/javascript">

</script>

</html>

1 Answers

On UAs that have implemented SVG 2 such as Firefox you can use a dictionary because the interface takes a DOMMatrix2DInit.

const svgns = 'http://www.w3.org/2000/svg'
const svg = d3.select('svg');

height = 400;
width = 720;

svg
    .attr('viewBox', `0 0 ${width} ${height}`)

svg.append('rect')
    .attr('class', 'vBoxRect')
    .style("overflow", "visible")
    .attr('width', `${width}`)
    .attr('height', `${height}`)
    .attr('stroke', 'black')
    .attr('fill', 'none');

const red = document.querySelector('.red').transform.baseVal;

const green = document.querySelector('.green');
const additionalTransform = green.ownerSVGElement.createSVGTransform();

additionalTransform.setMatrix({a:1, b:0, c:0, d:1, e:50, f:90});
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
additionalTransform.setMatrix({a:0.7071067811865476, b:-0.7071067811865476, c:0.7071067811865476, d:0.7071067811865476, e:0, f:0});
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
additionalTransform.setMatrix({a:1, b:0, c:0, d:1, e:30, f:160});
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
    <svg>
        <circle class="red" cx="10" cy="10" r="50" fill="red" transform="translate(50,90) rotate(-45) translate(30,160)"/>
        <circle class="green" cx="10" cy="10" r="50" fill="green"/>
  </svg>
</body>
<script type="text/javascript">

</script>

</html>

If you need backwards compatibility with SVG 1.1 then you'd have to create an SVGMatrix object...

const svgns = 'http://www.w3.org/2000/svg'
const svg = d3.select('svg');

height = 400;
width = 720;

svg
    .attr('viewBox', `0 0 ${width} ${height}`)

svg.append('rect')
    .attr('class', 'vBoxRect')
    .style("overflow", "visible")
    .attr('width', `${width}`)
    .attr('height', `${height}`)
    .attr('stroke', 'black')
    .attr('fill', 'none');

const red = document.querySelector('.red').transform.baseVal;

const green = document.querySelector('.green');
const additionalTransform = green.ownerSVGElement.createSVGTransform();
const svgMatrix = green.ownerSVGElement.createSVGMatrix();

svgMatrix.e = 50;
svgMatrix.f = 90;
additionalTransform.setMatrix(svgMatrix);
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
svgMatrix.a = 0.7071067811865476;
svgMatrix.b = -0.7071067811865476;
svgMatrix.c = 0.7071067811865476;
svgMatrix.d = 0.7071067811865476;
svgMatrix.e = 0;
svgMatrix.f = 0;

additionalTransform.setMatrix(svgMatrix);
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
svgMatrix.a = 1;
svgMatrix.b = 0;
svgMatrix.c = 0;
svgMatrix.d = 1;
svgMatrix.e = 30;
svgMatrix.f = 160;

additionalTransform.setMatrix(svgMatrix);
green.transform.baseVal.appendItem(additionalTransform);
green.transform.baseVal.consolidate();
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>
    <svg>
        <circle class="red" cx="10" cy="10" r="50" fill="red" transform="translate(50,90) rotate(-45) translate(30,160)"/>
        <circle class="green" cx="10" cy="10" r="50" fill="green"/>
  </svg>
</body>
<script type="text/javascript">

</script>

</html>

Related