Design your SVG floorplan or dashboard for HABPanel with Inkscape

Can you show the code you put in the template widget? Is there an error something showing in the developer tools console? (F12, Console tab, refresh the page)

Hereā€™s the code from the widget:

<div oc-lazy-load="'/static/Test.css'">
	<div ng-include="'/static/Test.svg'"></div>
</div>

In the console the only thing I get that is somewhat suspicious is this:

Service worker not registered 
SecurityError: Only secure origins are allowed

but thatā€™s all I see. Otherwise I have a default widget controlling a switch on the dashboard and it works just fine.

This is how I have the svg configured in Inkscape:

and this is the file it exports:

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

<svg:svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="500"
   height="500"
   viewBox="0 0 132.29166 132.29167"
   version="1.1"
   id="svg3741"
   inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
   sodipodi:docname="Test.svg">
  <svg:defs
     id="defs3735" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.35"
     inkscape:cx="155.08602"
     inkscape:cy="535.71429"
     inkscape:document-units="mm"
     inkscape:current-layer="svg3741"
     showgrid="false"
     inkscape:window-width="944"
     inkscape:window-height="1002"
     inkscape:window-x="960"
     inkscape:window-y="0"
     inkscape:window-maximized="0"
     units="px" />
  <svg:metadata
     id="metadata3738">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </svg:metadata>
  <svg:g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-164.70832)"
     ng-class="{&quot;light-on&quot;: itemState('KitchenCeilingLights') == 'ON' }"
     ng-click="sendCmd('KitchenCeilingLights', (itemState('KitchenCeilingLights') == 'ON') ? 'OFF' : 'ON')"
     cursor="pointer">
    <svg:rect
       id="rect3743"
       width="123.22024"
       height="127.75595"
       x="4.5357156"
       y="167.73215"
       style="stroke-width:0.26458332" />
  </svg:g>
  
</svg:svg>

I am using Inkscape 0.92 if that makes any difference, and OH 2.2 stable.

1 Like

Well, I donā€™t know what to say, I initially had the same problem as you with the SVG you provided.
So I loaded it in my Inkscape, removed the ā€œmetadataā€ node by clicking on it and pressing the image button in the XML editor, and it gave me this, which works:

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

<svg
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="500"
   height="500"
   viewBox="0 0 132.29166 132.29167"
   version="1.1"
   id="svg3741"
   inkscape:version="0.92.1 r15371"
   sodipodi:docname="Test.svg">
  <defs
     id="defs3735" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.35"
     inkscape:cx="-1312.0568"
     inkscape:cy="535.71429"
     inkscape:document-units="mm"
     inkscape:current-layer="svg3741"
     showgrid="false"
     inkscape:window-width="1920"
     inkscape:window-height="1017"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1"
     units="px" />
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0,-164.70832)"
     ng-class="{'light-on': itemState('KitchenCeilingLights') == 'ON' }"
     ng-click="sendCmd('KitchenCeilingLights', (itemState('KitchenCeilingLights') == 'ON') ? 'OFF' : 'ON')"
     cursor="pointer">
    <rect
       id="rect3743"
       width="123.22024"
       height="127.75595"
       x="4.5357156"
       y="167.73215"
       style="stroke-width:0.26458332" />
  </g>
</svg>

Note how it removed the svg: namespace prefixes in elements and added it as the default namespace (xmlns="http://www.w3.org/2000/svg"). I have an older Inkscape version than you but I donā€™t think it matters. Very odd.

Another thing: do not use double quotes in attribute values as it will apparently replace them by &quot; and that wonā€™t work. See &quot;light-on&quot; which I replaced by 'light-on'.

1 Like

I just followed the same steps you did and it fixed the issue here too. There may have been a change in the way the Inkscape application handles the SVG generation. I followed your steps above exactly and thatā€™s the file it generated for me. So my guess is thereā€™s something in the way the SVG is being generated by the program, maybe something in the way they handle the metadata.

I donā€™t know but deleting the metadata fixed the issue.

1 Like

Your floor plan looks stunning.

Did you create your floor plan with Inkscape ?

@ysc,

Why donā€™t we add support for Floor plan in Habpanel as they did for Home assistance ?

3 Likes

Thank you :blush:
No, I did any creative work like floorplan painting, text and font design etc. in Affinity Designer (I am a big fan of that tool!).
Exported as SVG. Any additional work and duplicating buttons and texts is done in Inkscape (which is not so funny at least on the Mac) :slight_smile:

1 Like

@ysc
A bit similar to what @shorty707 was asking:
How could I add a slider like that http://angular-slider.github.io/angularjs-slider/ to my floorplan controlling light percentage or blind control?

This is all awesome and Iā€™ve already created some genius stuff. Now, Iā€™m facing a problem and maybe you have an idea what is wrongā€¦
To indicate an open door Iā€™d like to change the color (which works) then adjust the X,Y position (which works), and then rotate it by 45 degreeā€¦ which doesnā€™t work.
I attached a ng-class attribute to the door object

{"tuer-balkon-offen": itemState('Fenster_EG_Kueche') == '0' }

This is my class:

.tuer-balkon-offen { 
        fill:#ff0000 !important;
        x:-105  !important; 
        y:225   !important;
        transform:rotate(-45.0) !important;         <---- what is wrong here?
}

Do you know why ā€œtransform:rotateā€ doesnā€™t work? ā€¦ all other attributes are fine. I tried different formats as well like this oneā€¦: transform=ā€œrotate(-45)ā€

Try to define the animation as a keyframe:

@-webkit-keyframes rotate {
100% { transform: rotate(-45deg); }
}

and use

.tuer-balkon-offen { 
   transform-origin: top right !important;
   animation: rotate 2s forwards !important;
}

I have follow this great tutorial to make my own floorplan. It works great on computer displaying fullscreen 1920x1080 size floorplan. But on android tablet and cell phone, the svg was displayed 2-3 times larger. (I am sure my tablet and phones were 1920x1080 screens). How can I make it adapt to android browsers? Is there something im missing?

Thank you very much.

@Simson,

it works in general! So many thanks for the first hint.
However, the challenge is now that the object does not rotate around ā€œtop rightā€, but around 0,0 point of the SVG canvas.
So ā€œtransform-originā€ seems not to work
Thanks
Pirx

@illxi
try this one: open the SVG file and change the width and height to:

   width="100%"
   height="100%"

It works! Thank you very much!

I read about this strange behavior in the linked HomeAssistant thread. It might help to just redraw your rectangles and try again.

ā€œtransform-originā€ should generally work - at least it does in my case.

I did many tests with ā€œtransform-originā€. It does work, but you need to specify the exact position within the SVG canvas.
In example. This is the object (let say it is a door) to be rotated

  <rect 
     ng-class="{&quot;tuer-balkon-offen&quot;: itemState('Door_status') == 'ON' }"
     style="fill:url(#linearGradient10225);fill-opacity:1;fill-rule:nonzero;stroke:#808080;stroke-width:0.23461722;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
     id="door"
     x="210"
     y="175"
     width="42"
     height="5" />

The rotation in CSS must be defined like this

@-webkit-keyframes rotate {  
100% { transform: rotate(-60deg)  !important}
}

@keyframes rotate {
100% { transform: rotate(-60deg) !important}
}

.tuer-balkon-offen {
   transform-origin: 210px 175px !important;
   animation: rotate 2s linear !important;
}

A ā€œtransform-origit: top leftā€ will point to the position in the canvas which results of a wired rotation of the door.
The downside of the px-notation is that I will need to define every single door in CSS and whenever I change the postion of a door in the SVG I need to update the CSS file. If someone knows how to avoid it, raise your hand please :slight_smile:

Thereā€™s a well written article about transform origins in SVG here, maybe itā€™ll help:

Thanks Yannick,

I found this article already yesterday. It is a very good peace of work but unfortunately there is no answer to my problem.

Regards
Pirx

This is just unbelievable. Hereā€™s my very rough progress so far.

One question I have: Is there any way to have multiple use cases in an ā€œng-classā€ attribute?

Letā€™s say I have a String item with three possible states, and Iā€™d like to define three different ng-class sets. Is it possible to define something like this (Iā€™ve tried this a few ways with no results):

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

I have a partial answer to my question for anyone who is curious. I havenā€™t been able to define multiple ng-class attributes for a single item, but if for example you wanted to hide several only on certain conditions, you can define them as either a layer or a group and add your ng-class definitions to the group itself, with different definitions for each member. I am creating a layer for each type of data I want to present (doors, motion, diagnostics, lights, etcā€¦) and will make a switch item on the SVG for each. Toggling it will toggle the display of each layer on and off. Additionally, I plan to make the button color responsive, so if the button turns red it could indicate a problem on the layer.

I created a separate SVG as a left vertical navigation bar that is displayed on each page of my HABPanel. My progress thus far:

2 Likes