skip to Main Content

I work as an ambulance officer for a community that has random house numbers that don’t conform to any recognizable pattern. It can take valuable time to scan a map for an unfamiliar house number. I have made an SVG map of the houses and house numbers and I would like to highlight the appropriate house by entering the house number in a text field to use as a variable in a getElementById JS function, to change the SVG ‘fill’ property for that element, to highlight the right house. My knowledge of JS is rudimentary, and I have not found any examples of how to achieve this on my searches. My example below is a complete kludge, but illustrates what I am trying to do, except with a text input instead of a button for every house.

<!DOCTYPE html>
<html lang="en">
    
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test SVG</title>
    <style>

        .default {
            fill: #008000;
            stroke: #000000;
            stroke-width: 3px;
            width: 150px;
            height: 50px;
        }

        .selected {
            fill: #ff0000;
            stroke: #000000;
            stroke-width: 3px;
            width: 150px;
            height: 50px;
        }

        text {
            font-family: Arial, Helvetica, sans-serif;
            font-size: 24px;
        }

        div {
            padding-left: 30px;
        }

    </style>

</head>

<body>

    <svg width="500" height="500">
        
        <g>
            <circle class="default" id="01" cx="380" cy="400" r="40" />
            <text x="373" y="408">1</text>
        </g>
        
        <g>
            <circle class="default" id="02" cx="380" cy="60" r="40" />
            <text x="373" y="68">2</text>
        </g>

        <g>
            <circle class="default" id="03" cx="80" cy="240" r="40" />
            <text x="74" y="248">3</text>
        </g>

        <g>
            <circle class="default" id="04" cx="430" cy="210" r="40" />
            <text x="423" y="218">4</text>
        </g>

        <g>
            <circle class="default" id="05" cx="110" cy="60" r="40" />
            <text x="103" y="68">5</text>
        </g>

        <g>
            <circle class="default" id="06" cx="230" cy="130" r="40" />
            <text x="224" y="138">6</text>
        </g>

        <g>
            <circle class="default" id="07" cx="130" cy="370" r="40" />
            <text x="124" y="378">7</text>
        </g>

        <g>
            <circle class="default" id="08" cx="280" cy="280" r="40" />
            <text x="273" y="288">8</text>
        </g>

    </svg>

    <div>
    <button type="button" onclick="select01()">House 1</button>
    <button type="button" onclick="select02()">House 2</button>
    <button type="button" onclick="select03()">House 3</button>
    <button type="button" onclick="select04()">House 4</button>
    <button type="button" onclick="select05()">House 5</button>
    <button type="button" onclick="select06()">House 6</button>
    <button type="button" onclick="select07()">House 7</button>
    <button type="button" onclick="select08()">House 8</button>    
    </div>

    <script>
        function select01() {
            const element = document.getElementById("01");
            element.classList.toggle("selected")
        }
        function select02() {
            const element = document.getElementById("02");
            element.classList.toggle("selected")
        }
        function select03() {
            const element = document.getElementById("03");
            element.classList.toggle("selected")
        }
        function select04() {
            const element = document.getElementById("04");
            element.classList.toggle("selected")
        }
        function select05() {
            const element = document.getElementById("05");
            element.classList.toggle("selected")
        }
        function select06() {
            const element = document.getElementById("06");
            element.classList.toggle("selected")
        }
        function select07() {
            const element = document.getElementById("07");
            element.classList.toggle("selected")
        }
        function select08() {
            const element = document.getElementById("08");
            element.classList.toggle("selected")
        }
    </script>

</body>
</html>

2

Answers


  1. You can use a text input where you can enter the house number. When you click the Select House button, it retrieves the value from the input element and uses it as the ID to find the corresponding SVG element. If the element is found, it toggles the selected class, else it shows an alert.

    Demo:

    <style>
        .default {
            fill: #008000;
            stroke: #000000;
            stroke-width: 3px;
            width: 150px;
            height: 50px;
        }
    
        .selected {
            fill: #ff0000;
            stroke: #000000;
            stroke-width: 3px;
            width: 150px;
            height: 50px;
        }
    
        text {
            font-family: Arial, Helvetica, sans-serif;
            font-size: 24px;
        }
    
        div {
            padding-left: 30px;
        }
    </style>
    
    <svg width="500" height="500">
        <g>
            <circle class="default" id="01" cx="380" cy="400" r="40" />
            <text x="373" y="408">1</text>
        </g>
    
        <g>
            <circle class="default" id="02" cx="380" cy="60" r="40" />
            <text x="373" y="68">2</text>
        </g>
    
        <g>
            <circle class="default" id="03" cx="80" cy="240" r="40" />
            <text x="74" y="248">3</text>
        </g>
    
        <g>
            <circle class="default" id="04" cx="430" cy="210" r="40" />
            <text x="423" y="218">4</text>
        </g>
    
        <g>
            <circle class="default" id="05" cx="110" cy="60" r="40" />
            <text x="103" y="68">5</text>
        </g>
    
        <g>
            <circle class="default" id="06" cx="230" cy="130" r="40" />
            <text x="224" y="138">6</text>
        </g>
    
        <g>
            <circle class="default" id="07" cx="130" cy="370" r="40" />
            <text x="124" y="378">7</text>
        </g>
    
        <g>
            <circle class="default" id="08" cx="280" cy="280" r="40" />
            <text x="273" y="288">8</text>
        </g>
    </svg>
    <div>
        <!-- Add a text input for entering the house number -->
        <input type="text" id="houseNumber" placeholder="Enter house number">
        <!-- Use a button to trigger the selection -->
        <button type="button" onclick="selectHouse()">Select House</button>
        <!-- Add buttons for other houses as needed -->
    </div>
    
    
    <script>
    function selectHouse() {
      const houseNumber = document.getElementById("houseNumber").value;
      const element = document.getElementById(houseNumber);
    
      if (element) {
        element.classList.toggle("selected");
      } else {
        alert("House not found");
      }
    }
    </script>
    Login or Signup to reply.
  2. A tat more JavaScript knowledge will save you time.

    You can create your own <svg-house-map> Native JavaScript Web Component (JSWC)

    <svg-house-map>
      <svg>
        <house>1a,30,20</house> 
        <house>2,100,15</house>  
        <house>32,150,25</house>
      </svg>
    </svg-house-map>
    

    It will read all defined <house>NR,CX,CY></house> elements and inserts them into the <svg>

    This gives you full control on how houses are displayed; you only have to change the HTML once inside the Web Component definition

    To selected and unselected houses it is easier to alter/swap your <input> logic to:

    • Every house listens to the input,
      and checks if input.value matches to its own house number

    All code required:

    <svg-house-map>
      <input type="text" placeholder="house number?"><br>
      <svg viewBox="0 0 0 0" style="background:pink">
        <style>.selected { fill: green }</style>
        <house>1a,30,20</house> <house>2,100,15</house>  <house>32,150,25</house>
        <house>11,25,55</house> <house>22a,80,50</house> <house>222b,180,46</house>
      </svg>
    </svg-house-map>
    <script>
      customElements.define("svg-house-map", class extends HTMLElement {
        connectedCallback() {
          setTimeout(() => { // wait till innerHTML <svg> is parsed
            let vbx = [], vby = []; // calc viewBox dimensions with padding
            let svg    = this.querySelector("svg");
            Array.from(  svg.querySelectorAll("house")  ).forEach(house => {
              let [nr, cx, cy, r=10, pad=5 ] = house.innerHTML.split(",");
              vbx.push(Number(cx) + r + pad); vby.push(Number(cy) + r + pad);
              house.innerHTML = `<circle cx="${cx}" cy="${cy}" r="${r}"
                                  fill="lightgrey" stroke="black" stroke-width="1"/>` +
                // align the text label:
                `<path id="NR${nr}" d="M${cx-r} ${cy}h${r*2}" stroke="yellow"/>` +
                `<text><textPath href="#NR${nr}" startoffset="50%" text-anchor="middle" dominant-baseline="middle"
                        fill="darkred" font-size="${r*.9}px">${nr}</textPath></text>`; 
              // now in the DOM, then grab this! <circle> reference:
              let circle = house.querySelector("circle");
              this.querySelector("input").addEventListener("keyup", (evt) => {
                   let match = evt.target.value && nr.includes(evt.target.value);
                   circle.classList.toggle("selected", match );
              });
              house.replaceWith(...house.children); // replace <house> with created SVG tags
            })// Array.from
            svg.setAttribute("viewBox", "0 0 " + Math.max(...vbx) + " " + Math.max(...vby));
          })
        }
      })
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search