Design your SVG floorplan or dashboard for HABPanel with Inkscape

That would be something like:

{ "fill-red": itemState('Item_Name') == 'State1', "fill-blue": itemState('Item_Name') == 'State2', "fill-green": itemState('Item_Name') == 'State3' }

Tutorial here: https://appendto.com/2016/03/ng-class-use-cases-action/

3 Likes

I donā€™t know if you solved it but try putting your rectangle in a group and zero itā€¦ then move your group where you want itā€¦

<g
       id="g935"
       transform="translate(23,358)">
      <rect
         ng-class="{&quot;open_door&quot;: itemState('DoorStatus') == 'ON' }"
         y="0"
         x="0"
         height="23.823421"
         width="200.11674"
         id="door"
         style="opacity:1;fill:#ff37ff;fill-opacity:0.8738739;fill-rule:nonzero;stroke:#a0a0a0;stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
    </g>
1 Like

just wanted to show what Iā€™ve done so farā€¦
In particular the dynamic sensor info, floating in from the leftā€¦
This is stil under testingā€¦ so the code is very uglyā€¦
and alot of the code isnā€™t relevantā€¦
if you have any pointers please let me know :slight_smile:
And a questionā€¦ is this the right way to manipulate variables in svg?? (it doesnā€™t look right to me, but it works)

// in HABPanel

<div oc-lazy-load="['/static/js/jquery-3.2.1.min.js','/static/pressableTest.js']">
  <div oc-lazy-load="'/static/floorplan.css'">
    <div ng-include="'/static/floorplan.svg'" ng-controller="MainCtrl"></div>
  </div>
</div>

// pressableTest.js ā€¦I made a long press actionā€¦
// This is stil in testing ā€¦ alot of code is just test code
// $scope.testing is the part where the control off css animations isā€¦
"use strict";var cancelled = false;angular.module('app',[]).directive( - Pastebin.com

// floorplan.css (just the relevant stuff)
.test_out{ animation: animationFrames ease-in-out 6s; animation-iteration- - Pastebin.com

// in inkscapeā€¦ ng-click on the sensors

move=true;
move2=true;
move3=true;
testing('Temperature_Xiaomi_13');
varitem=(itemState('Temperature_Xiaomi_13') | number:1) + 'Ā°C';
varitem2=(itemState('Humidity_Xiaomi_14') | number:1) + '%';
varitem3=(itemState('Pressure_Xiaomi_15') | number:1) + 'kPa';

// in inkscapeā€¦ ng-class on the different ā€˜bubblesā€™ floating out
// first bubble

{test_out : move}

//second bubble

{test_out2 : move2}

ā€¦ and so on
let me know what you thinkā€¦ :crazy_face:

3 Likes

Is it possible to utilize dynamic SVGs without the use of HABpanel? I think thereā€™s a use case for an html file with the svg embedded as a low overhead alternative if none of the other features of HABpanel are needed, but Iā€™m not sure if this is even possible.

It certainly is! I am working on something like this to be used as a dynamic floor plan of my house (i.e. e floor plan with dynamic information elements like temperature in rooms, status on doors, etc.).

Using Inkscape (or some other editor) you can draw whatever you like, and then add identifiers to the elements that you would like to be dynamic in some sense.

Including the SVG as an object in your HTML file, you can use JavaScript (possibly with the help of JQuery) to manipulate the SVG DOM (by referencing the dynamic elements of your SVG by the aforementioned identifiers).

I am more or less doing this as a project to teach myself some HTML5, so it is far from usable, but I have come far enough to understand that it is possible to do fairly complex stuff without too much hassle, so it looks promising.

1 Like

Awesome! Iā€™d love to see some of your code if/when youā€™re willing to share!

Nisse,

That is awesome, I am just getting started with this and I have a question for youā€¦ Is it possible to have one of those slide outs with an image linked from a web address? Iā€™d like to incorporate an ng-click/ng-class for my security cameras and have a slide out when you click on the camera icon to show the current static image?

Yes, it is. I have it set up just as you described. There may be a faster or easier way to do it but this is how I did it.

First, go to File > Import, and import a placeholder file in the same format as your camera or software (I use Shinobi) outputs stills (probably jpg). Open the XML editor for the picture. Change the height and width to the values youā€™d like while trying to preserve your aspect ratio. Change ā€œxlink:hrefā€ to the path to your camera feed. Then, add a new ā€œng-clickā€ attribute with the following text:

sendCmd('Dashboard', 'Security Video')

For this to work properly, youā€™ll need an Item named Dashboard, to configure HABpanel to switch to dashboards based on the Dashboard item, and a panel called ā€œSecurity Video.ā€ Feel free to change names to suit your needs.

It wonā€™t show up properly in Inkscape, just showing a ā€œLinked Image Not Foundā€ error. However, it should display a snapshot of the video wherever you put the image, and clicking it will open the linked dashboard where you can create a full page web frame.

I put all of the video feeds in a ā€œvideoā€ layer which I can then show or hide as desired.

Hi everyone!

First of all, thanks to everyone involved here. It is very nice to be able to draw your own visualization.
However I am stuck at something right now. What Iā€™m trying to do is letting an arrow change from red to green and the other way around depending on a value stored in an item in OH. That works perfect but I would like to rotate the arrow 180 degrees when the arrow is in the red state. I managed to get that working as well but here comes the problem:

As you can see, the arrow is way too big after the transformation.

This is the css code I used.

.negativePower {
    fill: #ff0000 !important;
    transform-origin: center !important;
    -webkit-transform: rotateY(180deg) !important; /* Safari */
    transform: rotateY(180deg) !important;
}
.positivePower {
    fill: #00d400 !important;
}

Has somebody the ultimate answer? Thanks!

I donā€™t have a perfect answer, but one solution is to make two arrows, one red and one green, and change their opacity depending on the openHAB value.

I did it like that for now.
In fact I would have liked to go a step further and use gifā€™s for the arrows but unfortunately that is not possible with Inkscape.

So with that said, next question. Iā€™m trying to show numbers but would like them to be formatted in the European way. Like so: 10.000,45 . Now it is shown like this: 10,000.45 . I used (itemState(ā€˜Luxā€™) | number:1) + ā€™ Luxā€™ to limit the numbers but then the formatting goes ā€œwrongā€.

Is there an easy solution?

Thanks again

Hi Dome,

Thanks for the pointers. I tried it the way you describe, but I am using MotionEye to manage all of my cameras and my HabPanel actually shows the live feed from the camera. I also tried with the current image (.jpg), but I have to refresh the page every time I want an updated image.
I am now researching a way to show/hide with an ng-clickā€¦ this should do what Iā€™d like to with HabPanel if I can figure it out!

This is how I did it: I made a habpanel.itmems file with a dummy Switch item for each layer. Then, I made a ā€œtransparentā€ class in my CSS file with opacity:0. Set each layer to use that class when the corresponding switch is off. Finally, set your switch item to toggle when you click a rectangle or whatever shape. Configure this with ng-click as described above. I am on my phone so let me know if code is examples would help.

Dome, any code you could supply would be helpful!

~John

Hereā€™s my relevant items:

// HABPanel SVG Items

Switch SVGDisplayMotion
Switch SVGDisplayDoors
Switch SVGDisplayVideo
Switch SVGDisplayDiagnostics
Switch SVGDisplayLights
String SVGDisplayPanel

In my CSS file, I made these attributes:

.transparent {
opacity: 0 !important;
}
.button-selected {
fill: #0000FF !important;
}

Then in Inkscape I grouped all the similar elements by layer. Make a layer, name it, and adjust it so itā€™s above the background (I made a background layer as well), and then open the layer itself in the XML editor. Then add an SVG attribute to the layer itself. In my example, I added the following ng-class attribute:

{'transparent': itemState('SVGDisplayVideo') == 'OFF' }

If viewing my video layer in code, it looks like this (URL API keys redacted):

<g
     inkscape:groupmode="layer"
     id="layer11"
     inkscape:label="Video"
     style="display:inline"
     ng-class="{'transparent': itemState('SVGDisplayVideo') == 'OFF' }">
    <image
       y="1240"
       x="1640"
       id="image10029"
       xlink:href="http://192.168.1.180:8082/camera1url.jpg"
       height="220"
       width="280"
       ng-click="sendCmd('Dashboard', 'Security Video')" />
    <image
       width="220"
       height="140"
       xlink:href="http://192.168.1.180:8082/camera2url.jpg"
       id="image10153"
       x="1380"
       y="1060"
       inkscape:transform-center-x="2.7436242"
       inkscape:transform-center-y="-74.077853" />
  </g>

Then make a button using the rectangle tool. I added text over it and used added the following ng-click attributes to both the text and the rectangle:

sendCmd('SVGDisplayVideo', (itemState('SVGDisplayVideo') == 'ON') ? 'OFF' : 'ON')

I also added this ng-classattribute to the rectangle:

{"button-selected": itemState('SVGDisplayVideo') == 'ON' }

Hopefully this is helpful.

I need to do some more work with the cameras but itā€™s not at the top of my priority list right now. Iā€™m thinking Iā€™ll use a proxy item that will both change to the live view dashboard and change the source for a web frame to show the proper camera.

I did note that limitation - in my use case the picture is little more than a thumbnail so it didnā€™t really matter, but I can see where that would be frustrating if youā€™re looking to use it to view a live feed.

1 Like

@Dome,

Thanks for all the help! This worked out very well for me. I ended up putting each camera on itā€™s own layer, I only wanted the selected camera to show up when activated.
One thing that took me a while to figure out was that even though the camera image was hidden, I could not tap/click on the item under it (even though it is visible when the image is hidden).
Here is what I have so far:
1st%20Floor%20Cameras

~John

2 Likes

Yes, I noticed that too. Itā€™s a bit of work, but you can always add a transparent rectangle over the video if you want a region to be clickable.

@Dome,
I got the items sorted. by lowering the layer for the images. I still need to do some more work on this, one thing that took me a few weeks to notice is that no matter what time of day I click on the link for a camera, it does not refresh the image when clicked later in the day. So, if I look at a camera at 8 am, then check it again at 3 pm, it is still the same image from 8 am, that is, until I refresh the page. I have to re-think how I list the images because the camera stream does not work with the existing codeā€¦ I think it would be better to have these images as the live camera feed. I may to have to borrow some code from the security camera carousel widgetā€¦

1 Like

hey guys and @ysc
How to make the svg ā€œpan-ableā€(or should I say ā€œdrag-ableā€)?
I found the github python lib for svg pan and zoom, but I have no idea how to use in habpanel, currently I make the svg responsive but in habpanel it looks too small and hard to touch the lights. Could someone please take a look at it and make this happen? Thanks!

Hi,

could it be that there is a character limitation in the ng-class?
Everytime when my ng-class string is larger than 60 character the class asignment doesnā€™t work.

This string (60 chars) works:
{ā€˜presence-onā€™: itemState(ā€˜abcdefghijklmnopqrstuvā€™) == ā€˜ONā€™}

This string (61 chars) doesnā€™t work:
{ā€˜presence-onā€™: itemState(ā€˜abcdefghijklmnopqrstuvwā€™) == ā€˜ONā€™}

Did anyone of you have a similar issue?