wide?
The stylesheet just allows you to use other properties that do not appear on the style configuration GUI. There are MANY CSS properties that are not available in the GUI.
There are 2 main ways I could use the stylesheet (or a combination of both).
- Use it to replace the built-in style creation GUI entirely
- Use it to extend/replace properties on existing styles
For instance (1), you can define a style called "Alarm" using the GUI.
The same style could be defined manually in the stylesheet as .psc-Alarm
. ".psc-" is simply a prefix for the style that Ignition uses to avoid collisions with the built-in styles. Or, the style could be extended in the same way as shown below with a built-in IA style.
Also (2), you can change existing styles by simply overwriting or adding properties. For instance, I wanted to change the look and feel of my popup headers, which is defined in the IA styles, so I do it like so:
/*popup header font and color*/
.ia_popup__header {
background-color: var(--neutral-40);
color: var(--neutral-100);
border-bottom: var(--containerBorder);
font-size: 0.875rem;
font-family: Consolas;
}
The applied style depends on which property was "called" last. The stylesheet is always last. So, it'll use these properties, in addition to any of the properties that I didn't overwrite.
I found looking at the built-in CSS style files very helpful in understanding CSS.
C:\Program Files\Inductive Automation\Ignition\data\modules\com.inductiveautomation.perspective\themes
Just a quick reply to the original question... Gauge and Simple Gauge, and some of the other amCharts based components, simply have performance problems - especially on iOS platforms (one of my pages took 1m30s to load, another was over 4 minutes!).
After escalating a support ticket to our partner manager, Inductive scrambled together a 'quick fix' for us by way of crafting a new set views that encapsulate svg based gauges that we now reference as embedded views where we used to reference the native amCharts components. We now get page loads within 2-3 seconds on an iPhoneXR.
What we have is kind of a one-off and stripped down (ie does not support all amCharts gauge capabilities), but our partner manager has indicated that Inductive plans to review their use of the amCharts components and perhaps create 'alternative' implementations (ie like the svg gauges they made for us) and post them to the Exchange for community use. They have specifically said the svg gauges they made for us will be cleaned up, additional features added to replicate most if not all of the amCharts gauge functionalities, and made available. Which other components they take on as well will depend on their internal reviews.
Best to design your pages for the smallest screen resolution your clients will be. However I would generally use different Views for mobile and PC displays, unless they're forms. I've also just been stung by operators using their phones with text scaling on (being "not old" and not needing glasses myself, I didn't even consider this was a thing on a phone, but it certainly plays havoc with screens designed for 100% scaling on a phone!!)
The mobile option was restricted here as a technique to limit where the pages can be accessed.
I have tried most my pages with ctrl+scroll scaling for the web versions.
@nminchin you have used embedded views as cards that had flex containers.
Did those pages load fast?
I am on 8.1.19.
I think one of the benefits about Perspective is you don't have to.
You can create a truly responsive design that scales no matter the size.
If you do, it would be best to breakpoints, but then you have to use multiple designs for various screen sizes.
Not everyone is using the same screen size, so it might be hard to get a definitive. Only you know what size screens your users will be using.
I hoped to gain insight from Victor on the way he sets the width of the majority of his screens.
I thought maybe he either always customized them or he always made them to some format standard that he then later would modify if required.
I can't really estimate when 4k monitors will become standard. I recall that one company tried to make me take a giant tv size monitor, but I declined in favor of keeping some 22" screens. It is a redundant conversation though. I just wondered how he would respond with his widths and then to extract information from that to synthesize into my own permutations.
I agree that I will know my requirements best. Mostly cubicle monitor usages, some monitors at the machines, and a few overhead TVs are used.
It is kind of tangent to speeding up my pages though. I kind of hope that cpu tech just leaps far soon and I won't have to worry about it haha.
Don't want to put words in @victordcq's mouth, but I'm guessing his response should tell you that, he rarely if ever considers width for his screens. I would say that the vast majority of perspective developers use flex containers, and thus, don't really consider width at all. The most you might get is rough resolution size's in order to set break points.
@nader.chinichian is the only one I know for certain uses co-ordinate containers primarily in his designs perhaps he can give you some insight.
When it comes to Video wall remember they are like normal LCD as the video card upscale pixel for you or if you set the scale mode to something like 250% in Windows for example.
If this is not the case for you you should consider using media query for your fonts as they are suffer a lot in huge screen.
Usually when I deal with video wall client ask to show 4 screen at same time. So you need to use embedded views side by side as a grid. As all of you know you cant get runtime width of embedded view which make everything harder.(the page width height is accessible only not embedded view)
One way to fix this problem is use map component in xy coordinate container and hide it and make it 100% width and height.
This way you get access runtime height and width of view which is part of bigger view.
I think I read it twice, and I don't know what video wall is.
I don't have a ton of experience with Perspective, but I'll provide what insight I have from the projects I've done.
I think in most situations you have 3 basic devices to design for.
- Mobile
- Tablet (iPad)
- Desktop
Coming from a traditional SCADA system (i.e. Vision), we're used to only having to consider widescreen desktop formats where 1920x1080 is the smallest resolution these days and Ignition can easily scale up from there. Having entirely different views for desktop and mobile access provides somewhat of a disjointed experience, IMO.
That said, I typically design all of my views to take full advantage of the tablet landscape area. Design the screen in percent mode and fix the aspect ratio. You can then embed that "root" view in a couple of breakpoint containers that the mobile and desktop will use. At the end of the day, this approach may take some extra screens for larger processes, because you're not taking advantage of the full area of your widescreen displays, but it saves a lot of development and maintenance time.
Here are the results:
Desktop:
iPad (native):
Mobile portrait (320x658):
Mobile landscape (658x320):
In big company control center they have a number set of LCDs that put together to create large display for you and fill a wall with data like cinema.
This is the forth kind of display you will face and need to adjust many thing base on the width of screen.
Believe me there are challenging
Edit: Oh I see this is what you meant and were advising on earlier, thanks
@nader.chinichian instead of media queries to set font sizes, have you tried css clamp with vmin and vmax?
Eg
clamp(4pt, 0.8*(vmin + vmax), 50pt)
Edit: the middle might need to be wrapped in a calc()
I still haven't worked out exactly how the vmin+vmax part works... But it does work to resize font based on viewport size, and far simpler than multiple media queries
Okay, I had a bit of free time today, so here is a complete SVG solution. You could do the Label as SVG text as well, or a gauge needle if you wanted, I haven't gone that far. Just a little example of the power of using the Ignition Designer to add SVG elements. I didn't include the label for the example.
Note: All of this (outside of the calculations needed to find the points for the shape) was done inside of the designer (yes I can be somewhat of a masochist at times. ).
First a simple example:
I keep a blank svg file handy, for simple shapes and such. I started this by embedding that file into the view.
File XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="50mm"
height="50mm"
viewBox="0 0 50 50"
version="1.1">
</svg>
I then modified the viewBox to something a bit more reasonable for this application, in this case 0 0 300 300
I then added elements to the elements array as needed.
For the simple example, you will need 2 elements for the Clip-Paths, 2 elements for the rectangles that will be clipped, and 1 element for the border.
I created two clipPath elements, one for the meter, and one for the background. The background looks like this:
The clipPath elements need to have an id, this is important because it's how the rectangle elements reference the path they need to be clipped by.
Full Path
M0.7963 165.436 A150 150 0 1 1 299.2037 165.436
A10 10 0 1 1 279.2567 164.4069 A130 130 0 1 0 20.7433 164.4039
A10 10 0 1 1 0.7963 165.436
Use your favorite SVG reference for help decoding that to understand what really going on.
The clipPath for the meter is where the "magic" happens, so to speak. Everything is pretty much the same for it as for the last path, the exception is there is a binding on the path (d value).
For the binding I added a custom prop to the SVG, that I called value. I am treating it like a percentage, but it could be whatever you want it to be. The binding is a property binding on the value custom prop with a script transform. The script transform looks at the value and makes decisions about the best way to draw the gauge. At, 0 and 100% it short circuits to already known paths. Otherwise it calculates the new path.
Script Transform
def transform(self, value, quality, timestamp):
import math
### full path: M0.7963 165.436 A150 150 0 1 1 299.2037 165.436 A10 10 0 1 1 279.2567 164.4069 A130 130 0 1 0 20.7433 164.4039 A10 10 0 1 1 0.7963 165.436
if value == 100:
return "M0.7963 165.436 A150 150 0 1 1 299.2037 165.436 A10 10 0 1 1 279.2567 164.4069 A130 130 0 1 0 20.7433 164.4039 A10 10 0 1 1 0.7963 165.436"
if value == 0:
return "M0.7963 165.436 A10 10 0 1 1 20.7433 164.4039 A10 10 0 1 1 0.7963 165.436"
calPath = "M0.7963 165.436 A150 150 0 "
calPath += "1 1 " if value >= 94 else "0 1"
outsideStopX = 150 - 150 * math.cos(math.radians((200 * value / 100) - 15))
outsideStopY = 150 -150 * math.sin(math.radians((200 * value/100) - 15 ))
insideStopX = 150 - 130 * math.cos(math.radians((200 * value/100)-15))
insideStopY = 150 - 130 * math.sin(math.radians((200 * value/100) - 15))
calPath += str(outsideStopX) + " " + str(outsideStopY) + " A10 10 0 1 1 " + str(insideStopX) + " " + str(insideStopY) + " A130 130 0 "
calPath += "1 0 " if value >= 95 else "0 0"
calPath += "20.7433 164.4039 A10 10 0 1 1 0.7963 165.436"
return calPath
It is important that the clipPath elements be defined prior to any elements that will reference them.
Finally I have two rectangle elements, one which is clipped by the meterPath and one that is clipped by the bgPath. They look like this:
Notice the order, the order of elements determines the "z-index" so to speak. Basically, the elements are added to the DOM in the order they appear in the array, and later elements in the DOM are rendered on top of those that come before.
Also, notice that I have set the clipPath for the rectangles to the clipPaths that we defined earlier, using the url()
function with the selector for that id.
Finally, I have added a border element because I think it looks better. This is just a path with the fill set to none, and the stroke defined. The path is the same one used for the background clip path.
Simple gauge example images
0%
25%
50%
75%
100%
If you want to get fancy, then you can fill the meter rectangle with a gradient. To add a gradient, add a defs
element to top to the elements array, and give it an id, x1,y1,x2, y2
the these two points define the line along which the gradient is drawn, in this case it is just a horizontal line across the full width. Also add an elements array, add an element for each stop that you want defined in your gradient. I have used 4 stops.
Then, set the fill paint for the meter rectangle to the gradient, using the url function, the result is a meter with gradient fill.
Gradient Fill Gauge Examples
0%
50%
100%
I do not really consider width. However some screen are disigned different when they are intented for tablet/phone use or not. But also there no specific size is in mind, as tablet/phones come in many sizes
(i dont always use flex though, sometimes i use fixed containers with calc(%) width/height which are also dynamic but require to be configured a bit more)
How fast/efficient is it?
You were curious about it too?
In my testing it is instantaneous. I would be willing to bet you would see a significant performance boost over having multiple stacked components on a view.
Maybe I’ll throw together a couple of views as a test.
Just an interesting exercise to flex my SVG muscles, been a while since I’ve need to use them.
Only way to get better at something is to do it.
Don't do it on my behalf.
I think it is probably a ton faster.
But if you are curious, I am interested in the results for sure. Probably a bit of work though.
I didn't know the SVG would be so complicated to make, but that is just if you make it in Ignition?
There is another way?
You can make an SVG in several ways, from typing them straight into a text editor, to a third party software like Inksacpe. If you wan't to have bindings on the elements though you will need to embed the SVG.
I wouldn't say that this is complicated, in reality, that shape is just a move and 4 arcs, its just that SVG paths look cryptic when you don't know what you're looking at.
The only complicated part, IMO, is knowing how to construct the paths to maintain the correct shape through the arc, when the angle changes. This has to do with how Arcs in SVG work, and even that isn't extremely complicated its just something you have to know to watch out for.