1

I need a piece of advice. We have an existing system based on .Net core/MVC. And we're moving all frontend parts to Blazor. For now we have one part where we're not sure how to better solve the task.

We have a module, which controls rooms. It's a web page which loads an SVG scheme of a floor from the database. Each room in SVG is an < G > element with ID. Like < G room-id="15" >...

In the existing app, we have a javascript code, which runs after the page is loaded and this script appends to each element an "onclick" event with "room-id" parameter. Also this script changes fill color of the element if there is no "room-id" to show inactive rooms.

Now, we have to move these functions to Blazor. But Blazor can't manipulate DOM directly. We can keep Javascript, of course. But it would be the worst solution.

We're ready to update backend as well. For example, one of our ideas is to use HtmlAgility package, parse SVG (which is XML by fact), and insert CSS class to inactive rooms. By this way we can solve our second problem (Maybe). With OnClick events the only idea is again to parse SVG inside the Blazor component, and then rebuild the picture with code and add needed events.

But maybe somebody could find a better way to do these tasks.

Thanks a lot!

Dmitry

Dmitry T
  • 41
  • 1
  • 3
  • Never use HtmlAgitlity package on XML!!! Use an XML library in Net like Xml Linq. SVG files can be huge and you may need to use XmlReader instead of Xml Linq. Are the pictures embedded in the SVG or are they URL links? – jdweng Sep 05 '22 at 14:51
  • Yes, there are background pictures. And the whole SVG can be very large. – Dmitry T Sep 05 '22 at 15:12
  • See my anwser are following posting : https://stackoverflow.com/questions/61607180/parse-big-xml-file-using-xmlreader. I used a combination of XMLReader and XML Linq. – jdweng Sep 05 '22 at 15:20
  • Thanks, I looked through your solution and tried to implement it. But there is still a problem. There is a part of SVG file: < svg version="1.1" ... > < style .. > .. < / style > < path class="..>< / path > < rect ..">< /rect > < /g > I can get the descendants and filter them by the attribute. I can even change the attribute. Its's fine. The problem is that I can't get the header and so on. I can show either descendent elements (which shows nothing) or the whole SVG which doesn't allow me to add events – Dmitry T Sep 05 '22 at 16:23
  • Do it in two steps. Get header and read into XElement. Then using XML Linq get the properties you need which will have both the header name and the picture. – jdweng Sep 05 '22 at 18:03
  • I can't find how to get a header. If i take a child element and read a "parent node" property from it, I get a full SVG. – Dmitry T Sep 05 '22 at 19:38
  • You need use my code in the link and loop on a parent tag that contains both the header and the picture. The parent could be the tag that contains the header. – jdweng Sep 05 '22 at 21:38
  • As I already mentioned, I tried your code. Each child G element contains full SVG as parent. Also in your code you explicitely define the header. But my svg files are different. And contains different headers. I can't define them directly incide my code. – Dmitry T Sep 06 '22 at 04:45
  • I need more info like sample xml. – jdweng Sep 06 '22 at 09:02

1 Answers1

0

Finally, how I solved the task. SVG elemens have options like "onMouseOver", "onClick" and so on. So, couldn't completely avoid Javascript. But it's now minimal and easy to maintain.

 xScheme = XDocument.Parse(roomScheme);
    elements = xScheme.Descendants("{http://www.w3.org/2000/svg}g");

    foreach (var el in elements)
    {
        var roomId= el.Attribute("data-room-id")?.Value;
        if (roomId!= null)
        {
            Guid.TryParse(roomId, out var roomGuid);
            var room = allRooms.FirstOrDefault(s => s.Id == roomGuid);
            if (room != null)
            {
                el.SetAttributeValue("class", "thover");                   
                el.SetAttributeValue("title", $" ...Hint details ...");
                el.SetAttributeValue("data-placement", "top");
                el.SetAttributeValue("data-html", "true");
                var attr = new XAttribute("onClick", $"window.location.href = '/RoomDetails/{roomGuid}'");
                el.Add(attr);
                attr = new XAttribute("onMouseover", " $(function() {$('.thover').tooltip();});");
                el.Add(attr);
            }
            else
            {
                el.SetAttributeValue("class", "inactive");
            }
        }
    }

And then inside Razor part:

@((MarkupString)xScheme.ToString())
Dmitry T
  • 41
  • 1
  • 3