Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

popup: Simplify HTML tree to fix spacing #527

Merged
merged 4 commits into from
Oct 10, 2023
Merged

Conversation

mstefarov
Copy link
Collaborator

@mstefarov mstefarov commented Oct 10, 2023

This is a result of a little background project I've been working on since July. This PR teaches our HTML parser to simplify the document structure and remove most spacing-related quirks that plague HTML. It also implements support for display:none attribute and unbreakable spaces ( ), seen in a number of Living Atlas maps.

New code walks the node tree, skips empty/useless nodes, and merges as many single-child nodes as possible. It then finds groups of inline nodes that flow together, and adjusts trailing/leading whitespace among and around these nodes.

Although this adds some complexity to our HTML parser, it benefits all supported platforms in terms of fidelity (more accurate rendering) and performance (much fewer UI element needed to render a popup). Here are some concrete examples:

Example 1: Social Vulnerability Index

https://www.arcgis.com/apps/mapviewer/index.html?webmap=2c8fdc6267e4439e968837020e7618f3
This popup has a number of empty paragraphs, which were getting collapsed by browsers, but wasted a lot of space in PopupViewer.

Before:After:
Popup HTML
<div>
  <p>
    <span><font size="3">2018 Overall SVI Score:</font></span>
  </p>
  <p>
    <span style="font-weight:bold;"><font size="5">0.82</font></span>
  </p>
  <p>
    <font size="3"><span></span></font>
  </p>
  <p>
    <font size="3"><span>Possible scores range from </span><span style="font-weight:bold;">0 </span><span>(lowest vulnerability) to </span><span style="font-weight:bold;">1</span><span> (highest vulnerability).</span></font>
  </p>
  <p>
    <font size="3"><span></span></font>
  </p>
  <p>
    <font size="3"><span>A score of </span><span style="font-weight:bold;">0.82 </span><span>indicates </span><span style="font-weight:bold;">high </span><span>vulnerability.</span></font>
  </p>
  <p>
    <font size="3"><span></span></font>
  </p>
  <p>
    <a href="https://svi.cdc.gov/Documents/Data/2018_SVI_Data/SVI2018Documentation.pdf" rel="nofollow ugc" style="color:#6D6D6D;text-decoration:underline;">
      <span><font size="3">Data Dictionary </font></span>
    </a>
  </p>
  <p><span></span></p>
</div>
Original document tree
Document { children=1 }
  Block { children=9 }
    Block { children=1 }
      Span { children=1 }
        Span { size=1 children=1 }
          Text { text="2018 Overall SVI Score:" }
    Block { children=1 }
      Span { bold=True children=1 }
        Span { size=1.5 children=1 }
          Text { text="0.82" }
    Block { children=1 }
      Span { size=1 children=1 }
        Span { }
    Block { children=1 }
      Span { size=1 children=5 }
        Span { children=1 }
          Text { text="Possible scores range from " }
        Span { bold=True children=1 }
          Text { text="0 " }
        Span { children=1 }
          Text { text="(lowest vulnerability) to " }
        Span { bold=True children=1 }
          Text { text="1" }
        Span { children=1 }
          Text { text=" (highest vulnerability)." }
    Block { children=1 }
      Span { size=1 children=1 }
        Span { }
    Block { children=1 }
      Span { size=1 children=5 }
        Span { children=1 }
          Text { text="A score of " }
        Span { bold=True children=1 }
          Text { text="0.82 " }
        Span { children=1 }
          Text { text="indicates " }
        Span { bold=True children=1 }
          Text { text="high " }
        Span { children=1 }
          Text { text="vulnerability." }
    Block { children=1 }
      Span { size=1 children=1 }
        Span { }
    Block { children=1 }
      Link { color=Color [A=255, R=109, G=109, B=109] text="https://svi.cdc.gov/Documents/Data/2018_SVI_Data/SVI2018Documentation.pdf" children=1 }
        Span { children=1 }
          Span { size=1 children=1 }
            Text { text="Data Dictionary " }
    Block { children=1 }
      Span { }
Simplified document tree
Document { children=1 }
  Block { children=5 }
    Block { children=1 }
      Text { size=1 text="2018 Overall SVI Score:" }
    Block { children=1 }
      Text { bold=True size=1.5 text="0.82" }
    Block { size=1 children=5 }
      Text { text="Possible scores range from " }
      Text { bold=True text="0 " }
      Text { text="(lowest vulnerability) to " }
      Text { bold=True text="1" }
      Text { text=" (highest vulnerability)." }
    Block { size=1 children=5 }
      Text { text="A score of " }
      Text { bold=True text="0.82 " }
      Text { text="indicates " }
      Text { bold=True text="high " }
      Text { text="vulnerability." }
    Block { children=1 }
      Link { color=Color [A=255, R=109, G=109, B=109] text="https://svi.cdc.gov/Documents/Data/2018_SVI_Data/SVI2018Documentation.pdf" children=1 }
        Text { size=1 text="Data Dictionary" }

Example 2: NWS Wind Speed forecast

https://www.arcgis.com/apps/mapviewer/index.html?webmap=a7b007939f02406ca2b8559a821c08ab
These popups have many ignorable line break and extra spaces/newlines between paragraphs, which caused bad spacing and bloated the visual tree.

Before:After:
Popup HTML
<p align='center' style='margin-bottom: 0.0001pt; text-align: center;'><b><span style='font-size: 18pt; font-family: Verdana, sans-serif;'>Wind Speed Forecast</span></b><span style='font-size: 9pt; font-family: Verdana, sans-serif;'><br />
</span><span style='font-size: 10pt; font-family: Verdana, sans-serif;'> </span><span style='font-size: 9pt; font-family: Verdana, sans-serif;'></span></p>

<p align='center' style='margin-bottom: 0.0001pt; text-align: center;'><b><span style='font-size: 13.5pt; font-family: Verdana, sans-serif;'><font color='#0000ff'>Fresh Breeze (18-24mph, 29-38km/h)</font></span></b><span style='font-size: 9pt; font-family: Verdana, sans-serif;'></span></p>

<p style='margin-bottom: 0.0001pt;'><span style='font-size:12.0pt;font-family:&quot;Times New Roman&quot;,&quot;serif&quot;;
mso-fareast-font-family:&quot;Times New Roman&quot;'> </span></p>

<p align='center' style='margin-bottom: 0.0001pt; text-align: center;'><span style='font-size: 13.5pt; font-family: Verdana, sans-serif;'>From</span><span style='font-size: 9pt; font-family: Verdana, sans-serif;'></span></p>

<p align='center' style='margin-bottom: 0.0001pt; text-align: center;'><b><span style='font-size: 9pt; font-family: Verdana, sans-serif;'>10/12/2023 02:00 PM<br />
 </span></b><span style='font-size: 9pt; font-family: Verdana, sans-serif;'></span></p>

<p align='center' style='margin-bottom: 0.0001pt; text-align: center;'><span style='font-size: 13.5pt; font-family: Verdana, sans-serif;'>Until</span><span style='font-size: 9pt; font-family: Verdana, sans-serif;'></span></p>

<p align='center' style='margin-bottom: 12pt; text-align: center;'><b><span style='font-size: 9pt; font-family: Verdana, sans-serif;'>10/12/2023 04:58 PM</span></b><i><span style='font-size:9.0pt;font-family:
&quot;Verdana&quot;,&quot;sans-serif&quot;;mso-fareast-font-family:&quot;Times New Roman&quot;;mso-bidi-font-family:
&quot;Times New Roman&quot;;color:dimgray'></span></i></p>

<p style='margin-bottom: 0.0001pt;'><i><span style='font-size:9.0pt;font-family:&quot;Verdana&quot;,&quot;sans-serif&quot;;
mso-fareast-font-family:&quot;Times New Roman&quot;;mso-bidi-font-family:&quot;Times New Roman&quot;;
color:dimgray'>Source: The National Digital Forecast Database produced by
the National Weather Service<br />
 </span></i></p>

<p><i><span style='font-size:9.0pt;line-height:115%;font-family:
&quot;Verdana&quot;,&quot;sans-serif&quot;;mso-fareast-font-family:&quot;Times New Roman&quot;;mso-bidi-font-family:
&quot;Times New Roman&quot;;color:dimgray'>Data updated every 3 hours</span></i></p>
Original document tree
Document { children=17 }
  Block { align=Center children=4 }
    Span { bold=True children=1 }
      Span { size=1.5 children=1 }
        Text { text="Wind Speed Forecast" }
    Span { size=0.75 children=2 }
      Break { }
      Text { text=" " }
    Span { size=0.8333333333333334 children=1 }
      Text { text=" " }
    Span { size=0.75 }
  Text { text=" " }
  Block { align=Center children=2 }
    Span { bold=True children=1 }
      Span { size=1.125 children=1 }
        Span { color=Color [A=255, R=0, G=0, B=255] children=1 }
          Text { text="Fresh Breeze (18-24mph, 29-38km/h)" }
    Span { size=0.75 }
  Text { text=" " }
  Block { children=1 }
    Span { size=1 children=1 }
      Text { text=" " }
  Text { text=" " }
  Block { align=Center children=2 }
    Span { size=1.125 children=1 }
      Text { text="From" }
    Span { size=0.75 }
  Text { text=" " }
  Block { align=Center children=2 }
    Span { bold=True children=1 }
      Span { size=0.75 children=3 }
        Text { text="10/12/2023 02:00 PM" }
        Break { }
        Text { text=" " }
    Span { size=0.75 }
  Text { text=" " }
  Block { align=Center children=2 }
    Span { size=1.125 children=1 }
      Text { text="Until" }
    Span { size=0.75 }
  Text { text=" " }
  Block { align=Center children=2 }
    Span { bold=True children=1 }
      Span { size=0.75 children=1 }
        Text { text="10/12/2023 04:58 PM" }
    Span { italic=True children=1 }
      Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] }
  Text { text=" " }
  Block { children=1 }
    Span { italic=True children=1 }
      Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] children=3 }
        Text { text="Source: The National Digital Forecast Database produced by the National Weather Service" }
        Break { }
        Text { text=" " }
  Text { text=" " }
  Block { children=1 }
    Span { italic=True children=1 }
      Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] children=1 }
        Text { text="Data updated every 3 hours" }
Simplified document tree
Document { children=8 }
  Block { align=Center children=1 }
    Text { bold=True size=1.5 text="Wind Speed Forecast" }
  Block { align=Center children=1 }
    Text { bold=True size=1.125 color=Color [A=255, R=0, G=0, B=255] text="Fresh Breeze (18-24mph, 29-38km/h)" }
  Block { align=Center children=1 }
    Text { size=1.125 text="From" }
  Block { bold=True size=0.75 align=Center children=1 }
    Text { text="10/12/2023 02:00 PM" }
  Block { align=Center children=1 }
    Text { size=1.125 text="Until" }
  Block { align=Center children=1 }
    Text { bold=True size=0.75 text="10/12/2023 04:58 PM" }
  Block { italic=True size=0.75 color=Color [A=255, R=105, G=105, B=105] children=1 }
    Text { text="Source: The National Digital Forecast Database produced by the National Weather Service" }
  Block { children=1 }
    Text { italic=True size=0.75 color=Color [A=255, R=105, G=105, B=105] text="Data updated every 3 hours" }

Example 3: Energielabels (Netherlands Enterprise Agency)

https://www.arcgis.com/apps/mapviewer/index.html?webmap=22f951f0951f4922b800021b0ba98539
These popups have many collapsible table rows/cells and hidden elements, which caused Runtime to render completely differently from the browser.

Before:After:
Popup HTML
Er is 1 energielabel geregistreerd in dit pand met bouwjaar  1888<br /><br />
<table>
<tbody><tr style='display: none' valign='middle'>
<td>
<img alt='' src='https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data' style='width:80px;height:40px;' /> </td><td>  <div></div></td>
</tr>
<tr style='display: none' valign='middle'>
<td>
<img alt='' src='https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data' style='width:80px;height:40px;' /></td><td> Meest zuinig <div></div></td>
</tr>
<tr valign='middle'>
</tr>
<tr style='display: none' valign='middle'>
<td>
<img alt='' src='https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data' style='width:80px;height:40px;' /></td><td> Minst zuinig</td>
</tr>
<tr style='' valign='middle'>
<td>
<img alt='' src='https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data' style='width:80px;height:40px;' /></td>
<td>  <div></div></td>
</tr>
</tbody></table><br />Dit pand bevat in totaal <b>9</b> verblijfsobject(en), met de volgende gebruiksfunctie(s):<br /> <br />
<table>
<tbody><tr style='display: none'><td>• Winkelfunctie: 0<br /></td></tr>
<tr style=''><td>• Woonfunctie: 8<br /></td></tr>
<tr style='display: none'><td>• Kantoorfunctie: 0<br /></td></tr>
<tr style=''><td>• Bijeenkomstfunctie: 1<br /></td></tr>
<tr style='display: none'><td>• Gezondheidszorgfunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Industriefunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Logiesfunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Celfunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Onderwijsfunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Sportfunctie: 0<br /></td></tr>
<tr style='display: none'><td>• Overige gebruiksfuncties: 0</td></tr>
</tbody></table>
Original document tree
Document { children=14 }
  Text { text="Er is 1 energielabel geregistreerd in dit pand met bouwjaar 1888" }
  Break { }
  Break { }
  Text { text=" " }
  Table { children=5 }
    TableRow { children=2 }
      TableCell { children=3 }
        Text { text=" " }
        Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" }
        Text { text=" " }
      TableCell { children=2 }
        Text { text=" " }
        Block { }
    TableRow { children=2 }
      TableCell { children=2 }
        Text { text=" " }
        Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" }
      TableCell { children=2 }
        Text { text=" Meest zuinig " }
        Block { }
    TableRow { }
    TableRow { children=2 }
      TableCell { children=2 }
        Text { text=" " }
        Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" }
      TableCell { children=1 }
        Text { text=" Minst zuinig" }
    TableRow { children=2 }
      TableCell { children=2 }
        Text { text=" " }
        Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" }
      TableCell { children=2 }
        Text { text=" " }
        Block { }
  Break { }
  Text { text="Dit pand bevat in totaal " }
  Span { bold=True children=1 }
    Text { text="9" }
  Text { text=" verblijfsobject(en), met de volgende gebruiksfunctie(s):" }
  Break { }
  Text { text=" " }
  Break { }
  Text { text=" " }
  Table { children=11 }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Winkelfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Woonfunctie: 8" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Kantoorfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Bijeenkomstfunctie: 1" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Gezondheidszorgfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Industriefunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Logiesfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Celfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Onderwijsfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=2 }
        Text { text="• Sportfunctie: 0" }
        Break { }
    TableRow { children=1 }
      TableCell { children=1 }
        Text { text="• Overige gebruiksfuncties: 0" }
Simplified document tree
Document { children=10 }
  Text { text="Er is 1 energielabel geregistreerd in dit pand met bouwjaar 1888" }
  Break { }
  Table { children=2 }
    TableRow { }
    TableRow { children=2 }
      TableCell { children=1 }
        Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" }
      TableCell { }
  Break { }
  Text { text="Dit pand bevat in totaal " }
  Text { bold=True text="9" }
  Text { text=" verblijfsobject(en), met de volgende gebruiksfunctie(s):" }
  Break { }
  Text { text=" " }
  Table { children=2 }
    TableRow { children=1 }
      TableCell { children=1 }
        Text { text="• Woonfunctie: 8" }
    TableRow { children=1 }
      TableCell { children=1 }
        Text { text="• Bijeenkomstfunctie: 1" }

@mstefarov mstefarov self-assigned this Oct 10, 2023
@mstefarov mstefarov merged commit 4b28627 into main Oct 10, 2023
1 check passed
@mstefarov mstefarov deleted the matvei/popup-tree-simpl branch October 10, 2023 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants