SVG or Overlapping Views?

Hi all,

Been at this Perspective 8.1 for about 4 months now. I have an interesting client request and I'm reaching out to all the experts here for some ideas.

The component on the left has 4 boxes (which needs borders too so it looks like the component on the right). The bottom 2 yellow boxes do not have a label in them but they can be "active" as well.

In the middle you see a red circle with a white arrow. That arrow is pointing to the "active" box. That arrow can point towards any of the 4 boxes at any given time based on which box is "active". The arrow only needs to be shown once and will be pointing to the active box. Only 1 box can be active at one time.

I cut the red circle image into 8 images.4 without the white pointer in it and 4 with the white pointer in it. I swap out the image in each box based on an expression in order to display the image with the white pointer or to display the image without the white pointer in it. That works fine.

However, my dilemma is:

I can not add borders to the 4 boxes (like you see in the component on the right) because the borders display between the 4 red circle images.

I do not think I can create a circle component or an SVG and place it on TOP of the 4 flex containers (the 4 boxes)

Any recommendations on how I can achieve this component with the red circle, white pointer, AND have borders around the boxes?

Does the entire component need to be an SVG? Would that even work?

Thank you very much.

An SVG is definitely the way to go on this. It can achieve this easily. I am away from my computer so cannot provide an example, I will check back in tomorrow and if no one else has provided help, I’ll work something up.

For an example of what is possible see this post:

2 Likes

Hi, thank you very much for the quick reply. You help out a lot on here. It is greatly appreciated.

Are you suggesting that the entire component-flex view contain 1 SVG that contains the 4 boxes, red circle and white indicator?

Thank you again...

I would make this as one complete SVG:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="210mm"
   height="297mm"
   viewBox="0 0 210 297"
   version="1.1"
   id="svg1"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <g
     id="layer1">
    <g
       id="TopLeft">
      <rect
         style="fill:none;stroke:#000000;stroke-width:0.793999;stroke-linecap:square"
         id="rect1"
         width="35.096569"
         height="38.870396"
         x="59.626427"
         y="78.872932" />
      <text
         xml:space="preserve"
         style="font-size:9.87778px;font-family:Arial;-inkscape-font-specification:Arial;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square"
         x="69.060989"
         y="101.51588"
         id="text4"><tspan
           id="tspan4"
           style="font-size:9.87778px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.794"
           x="69.060989"
           y="101.51588">Off</tspan></text>
    </g>
    <g
       id="TopRight"
       transform="translate(35.248354)">
      <rect
         style="fill:none;stroke:#000000;stroke-width:0.793999;stroke-linecap:square"
         id="rect4"
         width="35.096569"
         height="38.870396"
         x="59.626427"
         y="78.872932" />
      <text
         xml:space="preserve"
         style="font-size:9.87778px;font-family:Arial;-inkscape-font-specification:Arial;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square"
         x="69.060989"
         y="101.51588"
         id="text5"><tspan
           id="tspan5"
           style="font-size:9.87778px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.794"
           x="69.060989"
           y="101.51588">On</tspan></text>
    </g>
    <g
       id="BotRight"
       transform="translate(35.248354,38.629185)">
      <rect
         style="fill:none;stroke:#000000;stroke-width:0.793999;stroke-linecap:square"
         id="rect6"
         width="35.096569"
         height="38.870396"
         x="59.626427"
         y="78.872932" />
      <text
         xml:space="preserve"
         style="font-size:9.87778px;font-family:Arial;-inkscape-font-specification:Arial;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square"
         x="69.060989"
         y="101.51588"
         id="text6"><tspan
           id="tspan6"
           style="font-size:9.87778px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.794"
           x="69.060989"
           y="101.51588">Off</tspan></text>
    </g>
    <g
       id="BotLeft">
      <rect
         style="fill:none;stroke:#000000;stroke-width:0.793999;stroke-linecap:square"
         id="rect5"
         width="35.096569"
         height="38.870396"
         x="59.626427"
         y="117.50212" />
      <text
         xml:space="preserve"
         style="font-size:9.87778px;font-family:Arial;-inkscape-font-specification:Arial;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square"
         x="69.590157"
         y="140.67404"
         id="text7"><tspan
           id="tspan7"
           style="font-size:9.87778px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.794"
           x="69.590157"
           y="140.67404">Off</tspan></text>
    </g>
    <g
       id="Dial">
      <circle
         style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square"
         id="path7"
         cx="94.998489"
         cy="117.43198"
         r="10.140288" />
      <g
         id="Face">
        <circle
           style="fill:#ff0909;fill-opacity:1;stroke:#fa0000;stroke-width:0.793999;stroke-linecap:square;stroke-opacity:1"
           id="circle7"
           cx="94.998489"
           cy="117.43198"
           r="8.140288" />
        <path
           style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.793999;stroke-linecap:square;stroke-opacity:1"
           d="m 100.76112,111.28065 -6.273986,0.5189 5.354113,5.35412 z"
           id="Pointer" />
      </g>
    </g>
  </g>
</svg>

Chuck a transform: rotate() on the dial face. Add a transform anchor on the styling too.

2 Likes

Yes, a single SVG is the best, most performant approach IMHO

Thank you very much.

Thank you very much. Really appreciate it. I assume I can modify it and remove the extra whitespace around the box in inkscape as well or do you recommend a different online tool to modify what you provided? Canva, Illustrator etc.

Just for a difference of solution... You could use pure CSS to do this as well.

The example below uses position: absolute with top and left with calcs to position the circle on top and in the centre of the flex container.

I'd like to think that using this method would be simpler to modify if you ever needed to change it. It's also horrible to style text in SVGs, and word wrapping is simply not a thing

You'd probably replace the circle which is a label in my example, with an SVG.

View JSON
{
  "custom": {},
  "params": {},
  "props": {
    "defaultSize": {
      "height": 766,
      "width": 209
    }
  },
  "root": {
    "children": [
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": 1,
              "grow": 1
            },
            "props": {
              "style": {
                "backgroundColor": "#EE7272",
                "textAlign": "center"
              },
              "text": "A"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "Label_0"
            },
            "position": {
              "basis": 1,
              "grow": 1
            },
            "props": {
              "style": {
                "backgroundColor": "#72CAEE",
                "textAlign": "center"
              },
              "text": "B"
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "FlexContainer"
        },
        "position": {
          "basis": 1,
          "grow": 1
        },
        "props": {
          "style": {
            "gap": "5px"
          }
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Label"
            },
            "position": {
              "basis": 1,
              "grow": 1
            },
            "props": {
              "style": {
                "backgroundColor": "#EEDC72",
                "textAlign": "center"
              },
              "text": "C"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "Label_0"
            },
            "position": {
              "basis": 1,
              "grow": 1
            },
            "props": {
              "style": {
                "backgroundColor": "#C0EE72",
                "textAlign": "center"
              },
              "text": "D"
            },
            "type": "ia.display.label"
          }
        ],
        "meta": {
          "name": "FlexContainer_0"
        },
        "position": {
          "basis": 1,
          "grow": 1
        },
        "props": {
          "style": {
            "gap": "5px"
          }
        },
        "type": "ia.container.flex"
      },
      {
        "meta": {
          "name": "Label_0"
        },
        "position": {
          "basis": 1,
          "grow": 1
        },
        "props": {
          "style": {
            "backgroundColor": "#FFFFFF",
            "borderColor": "#000000",
            "borderRadius": "50%",
            "borderStyle": "solid",
            "borderWidth": "2px",
            "height": "50px",
            "left": "calc(50% - 25px)",
            "position": "absolute",
            "textAlign": "center",
            "top": "calc(50% - 25px)",
            "transform": "rotate(45deg)",
            "width": "50px"
          },
          "text": "|"
        },
        "type": "ia.display.label"
      }
    ],
    "meta": {
      "name": "root"
    },
    "props": {
      "direction": "column",
      "style": {
        "backgroundColor": "#000",
        "gap": "5px",
        "padding": "5px",
        "position": "relative"
      }
    },
    "type": "ia.container.flex"
  }
}
4 Likes

I would fully modify all the elements to the size you want.
I normally edit them when embedded in Ignition with the text editor, you can set up all the <rect> items width and height manually and play around in there. Also you can set up all the bindings to modify the svg live.

Thank you very much. I am going to think this through on the 2 ideas that were proposed on this post. You all know better than I do. I just want to proof of concept both ideas for educational purposes.

Thank you very much. Great job. I really appreciate it. I realize the white circle is a label. My dilemma (if it is possible) is to have the label shrink as the view shrinks. I realize the label is not in a flex container. Is that a solution I should explore? Is it possible? Thank you again.


Thank you very much. I am going to think this through on the 2 ideas that were proposed on this post. You all know better than I do. I just want to proof of concept both ideas for educational purposes.

Thank you very much. I am going to think this through on the 2 ideas that were proposed on this post. I really appreciate the help.

Hello. I duplicated your CSS on a flex container and I set the display and visible = false on the label (from your original post). It functions the same as I displayed above. So, now that I have the flex container positioned as I want...thanks to you, I assume I could just drop the SVG in there and remove all of the CSS styling that we set to show the red button with the black border?

If you think adding the SVG to the new flex container would work, lets see if the SVG resizes now that it is in a flex container.

What are your thoughts?

The size of the circle is set statically at the moment to 50px I think. You could use relative units like % but you'd also need to change the calculation of the top and left to replace the 25px (half of 50) with half of the new percent size value eg. calc(50% - 5%) if you set it to 10%.or just get rid of the calc and set to 45%....

If course, then it won't be a circle unless it's square... This is where an svg does help as it all scales together

1 Like

Hi David. I am getting there. I used the code from your circle to create my own SVG with just the circle. Now I am trying to figure out how:

  1. Get the white arrow to be much larger (like your original SVG) and slightly overlay the black border
  2. Create 6 total arrows in the SVG: northeast, northwest, southeast, southwest, north, and west

Ideal end result:

And I need to be able to switch the arrow position but you covered that in your 1st response.

Just a comment on design and user interface:
Why is the knob or pointer red? I read it as an error or fault.
What is the user supposed to think?

Use color sensibly and consistently. Use of the Perspective Built-In Themes | Ignition User Manual makes this much easier.

I think you need to stop thinking like 1990's F@ctoryTalk. You only need one arrow, you only ever see one arrow, we don't layer hidden objects on screens anymore, its appalling to maintain and wastes memory. Software now lets us access all the attributes of items on screens, so we can do direct actions to objects as we want. Want to rotate an arrow? Apply a rotation to the arrow. None of this round about hack fix stacks of invisible objects stuff you were forced to do by legacy systems.

Import the attached into your project, and have a look at the structure of the elements and the place and method I have used to rotate the arrow.

knobSVG.zip (10.1 KB)

What we have done is just rotate the element inside the SVG using the binding on transform: rotate(10) around a point specified by transform-origin: 12 12 in the same SVG, and simply change the amount of degrees it is rotated by in a binding that rebuilds the transform string.

What I haven't covered here, and I'm not great at it, is that you can also apply animations to make the knob change state smoothly etc. There are some much better CSS people on this forum that are into this stuff.

To understand what we are able to do with the SVG, your Google search terms are "css style on svg" and you will see lots more possibilities that pretty much all work in Perspective.

Thank you. I will work on this once I can get the white arrow in the center of the red circle working as desired.

Hi. I appreciate your concern and agree. However this is what the client requested long ago for our Vision 7.9 project and we are upgrading-creating the same project in Perspective 8.1.