Home > Software engineering >  How to programmatically duplicate (and then modify) an embedded svg image using javascript
How to programmatically duplicate (and then modify) an embedded svg image using javascript

Time:02-02

An ESP8266 is used to dynamically generate a webpage that includes images. The Javascript is embedded in c. The images will be dynamically modified such as rotated x degrees based on an externally measured value such as weight.

I have successfully referenced the embedded svg with the addition of the symbol id attribute and the "use href" tag as below

symbol id='toilet_paper'
<use href='#toilet_paper'/>

And the later in the html I reuse the svg and create duplicates by referencing as follows

<svg width='28pt' height='27pt' version='2.0'>
<use href='#toilet_paper' />
</svg>

However, I would like to know if it is possible to programmatically reference the embedded svg and duplicate.

In the code below, I have left in many of my unsuccessful attempts that are now commented out.

I have also left in some code that dynamically generates "input" elements to give some idea what I am trying to achieve. Sorry if it obscures the problem.

If all fails I can simply statically create the duplicates in html but this reduces the flexibility.

Code as follows. Hope it make sense. The goal is to create 15 copies of the toilet paper svg image and have one each sandwedged between the "input" elements.

<!DOCTYPE html>
<html>
<body>
<div align='center' id='outerdiv' style='line-height: 65%; width: 480px; border:5px solid #000000;margin: auto;'>
<h2>Duplicate embedded svg image </h2>

<p id='Duplicate svg test'></p>
<svg style='transform: rotate(90deg)' symbol id='toilet_paper' width='28.000000pt' height='27.000000pt' data-name='toilet paper'    xmlns='http://www.w3.org/2000/svg' viewBox='0 0 127.92 146.65'>
    <defs><style>.cls-1,.cls-3{fill:none;}.cls-1,.cls-2,.cls-3{stroke:#231f20;stroke-linecap:round;stroke-linejoin:round;}.cls-1{stroke-width:0.43px;}.cls-2{fill:#fff;stroke-width:0.85px;}.cls-3{stroke-width:1.42px;}</style></defs>
    <path class='cls-1' d='M250.58,221.7l-.27-84.27-119-.48.26,85.32c0,.33-.06.67-.06,1a6.85,6.85,0,0,0,.06,1v.59h.1c2.06,12.14,27.84,21.84,59.41,22,32.94.14,59.69-10.2,59.74-23.08A9,9,0,0,0,250.58,221.7Z' transform='translate(-126.01 -108.24)'/><ellipse class='cls-2' cx='190.98' cy='134.52' rx='23.32' ry='59.02' transform='matrix(0, -1, 1, 0, -70.32, 216.71)'/><ellipse class='cls-2' cx='190.89' cy='133.31' rx='6.8' ry='16.41' transform='translate(-69.21 215.42) rotate(-89.77)'/><path class='cls-2' d='M241.21,244.19c-8.78-24.15-9.92-57.79-6-83.48,0,0-30.77-.07-56.38-3.24-42.5-5.25-43.41-16.36-46.87-23.19s-3.45,84-.41,94.09C137.34,247.62,205.2,260,241.21,244.19Z' transform='translate(-126.01 -108.24)'/><path class='cls-3' d='M250.72,224a9.6,9.6,0,0,0-.24-2.07l-.26-84.26h-.72a9.3,9.3,0,0,0,.41-2.67c.05-12.88-26.33-23.43-58.93-23.56s-59.06,10.2-59.12,23.08c-3.46-6.84-3.44,84-.4,94.1,5.78,19.24,73.65,31.65,109.66,15.82-.77-2.14-1.49-4.35-2.15-6.61C246.33,234,250.7,229.21,250.72,224Z' transform='translate(-126.01 -108.24)'/>
    <use href='#toilet_paper'/>
</svg>

<svg width='28pt' height='27pt' version='2.0'>
<use href='#toilet_paper' />
</svg>

<svg  width='28pt' height='27pt' style='transform: rotate(45deg)'>
<use href='#toilet_paper'></use>
</svg>

<style>.b{white-space:normal;width: 70px;height: 40px;}</style>
       <div id='tpMagazine'></div>
</div>
<script charset='utf-8'>
  var element=document.getElementById('tpMagazine');
  function zeroPad(_text,_idx)
  {
   var zeropad = '';
   if(_idx<10){zeropad = '0';}
   return _text   zeropad   _idx;
  }
  for(var idx=0;idx<15;idx  )
  {
  tf=document.createElement('input');
  element.appendChild(tf);
  tf.value=zeroPad('TP #',idx)   ' ->';
  tf.title='Toilet Paper Role #'   idx;
  tf.disabled = true;
  tf.style.width='60px';
  tf.style.textAlign='center';
  
  tf=document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  
  tf.style.width='28';
  tf.style.height='28';
//  tf.setAttribute( 'href','#toilet_paper');
  //tf.setAttributeNS('http://www.w3.org/2000/svg' , 'use:href','#toilet_paper');
//  tf.setAttributeNS('http://www.w3.org/2000/svg' , 'image:href','https://i.imgur.com/LQIsf.jpg');
  //tf.style.href='#toilet_paper';
//  tf.setAttributeNS('#toilet_paper', 'spec:align', 'center');
//  tf.setAttributeNS(null, 'href','#toilet_paper');
//  tf.dhref='#'   'toilet_paper';
//  tf.setAttributeNS('http://www.w3.org/1999/xlink','href','http://i.imgur.com/LQIsf.jpg');
//  tf.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#toilet_paper');
//tf.setAttributeNS(null, 'image', '#toilet_paper');
  tf.setAttribute( 'href', '#toilet_paper');
  element.appendChild(tf);

  tf=document.createElement('input');
  element.appendChild(tf);
  tf.value='<- There should be an image in the space';
  tf.title='but I cant make it work';
  tf.disabled = true;
  tf.style.width='250px';
  tf.style.textAlign='center';
  
  tf=document.createElement('br');
  element.appendChild(tf);
  }

</script>

</body>
</html>

CodePudding user response:

Internet Explorer is dead, we live in modern Browser times.

Create your own HTML tag <toilet-paper> (and use some paper to clean up your SVG)

MDN: https://developer.mozilla.org/en-US/docs/Web/Web_Components

So

  <toilet-paper></toilet-paper>
  <toilet-paper rotate=0></toilet-paper>
  <toilet-paper rotate=45></toilet-paper>
  <toilet-paper rotate=180 stroke="green"></toilet-paper>

Displays:

Works in every modern Browser.

3 lines of JavaScript required to create the SVG:

customElements.define("toilet-paper", class extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<svg style='transform:rotate(${this.getAttribute("rotate") || 90}deg)' `  
      ` stroke='${this.getAttribute("stroke") || "#231f20"}' viewBox='0 0 146 146'>`  
      `<g fill='white'>`  
      `<ellipse cx='191' cy='135' rx='23' ry='59' transform='matrix(0, -1, 1, 0, -70, 217)'/>`  
      `<ellipse cx='191' cy='133' rx='7' ry='16' transform='translate(-69 215) rotate(-90)'/>`  
      `<path d='m115 136c-9-24-10-58-6-83 0 0-31 0-56-3-43-5-43-16-47-23s-3 84 0 94c5 19 73 31 109 15z'/>`  
      `</g>`  
      `<path fill='none' d='m125 116a10 10 0 000-2l0-84h-1a9 9 0 000-3c0-13-26-23-59-24s-59 10-59 23c-3-7-3 84 0 94 6 19 74 32 110 16-1-2-1-4-2-7 6-3 11-8 11-13z'/>`  
      `</svg>`
  }
});
<style>
  rolls { /* yes, an Unknown Element, who cares, the browser doesn't */
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap:1em;
  }
  
  toilet-paper { /* Web Component created with the standard customElements API */
    display: inline-block;
    background: beige;
  }
</style>
<rolls>
  <toilet-paper></toilet-paper>
  <toilet-paper rotate=0></toilet-paper>
  <toilet-paper rotate=45></toilet-paper>
  <toilet-paper rotate=180 stroke="green"></toilet-paper>
</rolls>

CodePudding user response:

Taking what Danny '36SCSI' Engleman provided and modifying to suit I came up with this to suit my needs.

<!DOCTYPE html>
<html>
<body>
<div id='tp'></div>
<script charset='utf-8'>

customElements.define("toilet-paper", class extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<svg style='transform:rotate(${this.getAttribute("rotate") || 90}deg)' `  
      ` stroke='${this.getAttribute("stroke") || "#231f20"}' viewBox='0 0 146 146' >`  

      `<g fill='white'>`  
      `<ellipse cx='191' cy='135' rx='23' ry='59' transform='matrix(0, -1, 1, 0, -70, 217)'/>`  
            
      `<ellipse cx='191' cy='133' rx='7' ry='16' transform='translate(-69 215) rotate(-90)'/>`  
      
      `<path d='m115 136c-9-24-10-58-6-83 0 0-31 0-56-3-43-5-43-16-47-23s-3 84 0 94c5 19 73 31 109 15z'/>`  
       `<text x="20" y="85" fill="red" transform="rotate(10 20,40 )" font-size="2em" >${this.getAttribute("weight") || "#231f20"}</text>`  
      `</g>`  
      
      `<path fill='none' d='m125 116a10 10 0 000-2l0-84h-1a9 9 0 000-3c0-13-26-23-59-24s-59 10-59 23c-3-7-3 84 0 94 6 19 74 32 110 16-1-2-1-4-2-7 6-3 11-8 11-13z'/>`  
      `</svg>`
  }
});
var element=document.getElementById('tp');

for(var idx=0;idx<15;idx  )
  {
  tf=document.createElement('toilet-paper');
    tf.style.width='80px';
  tf.setAttribute('rotate', idx * 15);
  tf.setAttribute('weight', 100   idx   'gr' );
  if(idx <7)
  {
    tf.setAttribute('stroke', 'green');
  }
  else
  {
    tf.setAttribute('stroke', 'red');
  }
  tf.style.background='beige';
  tf.style.display='inline-block';
  tf.text = 'black';
  element.appendChild(tf);
  
 tf=document.createElement('br');
 element.appendChild(tf);
  }

</script>
</body>
</html>

  •  Tags:  
  • Related