{"id":2335,"date":"2019-08-24T13:00:31","date_gmt":"2019-08-24T12:00:31","guid":{"rendered":"https:\/\/chewett.co.uk\/blog\/?p=2335"},"modified":"2019-08-26T21:08:20","modified_gmt":"2019-08-26T20:08:20","slug":"d3-js-version-5-lazily-loading-dom-elements","status":"publish","type":"post","link":"https:\/\/chewett.co.uk\/blog\/2335\/d3-js-version-5-lazily-loading-dom-elements\/","title":{"rendered":"D3.js version 5 Lazily loading DOM elements"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"678\" height=\"254\" data-attachment-id=\"2336\" data-permalink=\"https:\/\/chewett.co.uk\/blog\/2335\/d3-js-version-5-lazily-loading-dom-elements\/d3_lazily_loading_dom\/\" data-orig-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?fit=800%2C300&amp;ssl=1\" data-orig-size=\"800,300\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"d3_lazily_loading_dom\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?fit=300%2C113&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?fit=678%2C254&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?resize=678%2C254&#038;ssl=1\" alt=\"\" class=\"wp-image-2336\" srcset=\"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?w=800&amp;ssl=1 800w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?resize=300%2C113&amp;ssl=1 300w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?resize=768%2C288&amp;ssl=1 768w, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom.jpg?resize=50%2C19&amp;ssl=1 50w\" sizes=\"auto, (max-width: 678px) 100vw, 678px\" \/><\/figure>\n\n\n\n<p>In this example I demonstrate how you can lazily load DOM elements as you scroll through a page using D3.js. The full code for this is <a href=\"https:\/\/chewett.co.uk\/d3\/d3_v5_lazily_loading_dom_elements\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"available on my website (opens in a new tab)\">available on my website<\/a>.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Why you might want to lazily load DOM elements<\/h2>\n\n\n\n<p>As page size increases the browser will slow down rendering it. This can have detrimental effects when someone is using the page.<\/p>\n\n\n\n<p>One way to reduce the amount of DOM elements on the page is to only draw those that a viewer can see. By doing this once the person has scrolled past elements they can be cleaned up and removed.<\/p>\n\n\n\n<p>This should improve the redraw speed and memory usage of the page, as it needs to store less elements in the DOM.<\/p>\n\n\n\n<p>This will however increase the complexity of the page, and may overall cause it to run slower cumulatively as it will spend more time performing calculations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Working out where each element will be placed<\/h2>\n\n\n\n<p>The big disadvantage of this method is that you need to keep track of where all the elements are on the page. Once you know this you can work out which ones you conditionally want to not display.<\/p>\n\n\n\n<p>In my example I am going focus on y axis scrolling (standard scrolling). As elements get scrolled offscreen they will be removed from the page.<\/p>\n\n\n\n<p>For my example I am creating rectangles and when created, storing the maxium and minimum y positions. Here this is done in a loop that creates my data.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nfor(var i = 0; i &lt; ROWS; i++) {\n    rawData.push({&quot;index&quot;: i, &quot;color&quot;: colorScale(i), &quot;startY&quot;: i * ROW_HEIGHT, &quot;endY&quot;: (i+1) * ROW_HEIGHT});\n}\n<\/pre><\/div>\n\n\n<p>Calculating these values is trivial in this case as my SVG is placed at <code>(0,0)<\/code> on the page. However if your SVG is not placed here you will also need to calculate the position of the SVG and add this to your Y values.<\/p>\n\n\n\n<p>These values are stored as the position of these elements never change. This is then later used to decide whether it should be rendered or not.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Only rendering those elements currently shown<\/h2>\n\n\n\n<p>Once I have calculated the Y positions of the elements I can create my filter function to decide what is within the bounds of my user scroll.<\/p>\n\n\n\n<p>Here before I pass my data array to D3 I call <code>filter()<\/code> on it to remove the elements I dont want to render.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n\/\/This will be called for each element, if this returns true it will keep the element in the array\n\/\/Otherwise it will remove it from the newly returned array\nfunction filterVisibleElements(d) {\n    return (d.startY &gt;= minYWithPreloading &amp;&amp; d.endY &lt;= maxYWithPreloading)\n        || (d.startY &lt;= minYWithPreloading &amp;&amp;  d.endY &gt;= minYWithPreloading)\n        || (d.startY &lt;= maxYWithPreloading &amp;&amp; d.endY &gt;= maxYWithPreloading)\n    ;\n}\n<\/pre><\/div>\n\n\n<p>Each element will be tested with the above function to decide whether it should be drawn or not.<\/p>\n\n\n\n<p>For this I have defined two variables, <code>minYWithPreloading<\/code> and <code>maxYWithPreloading<\/code>. These define the minimum and maximum Y that I want all elements to sit in.<\/p>\n\n\n\n<p>These have been created by taking the current Y positions of the screen and padding it by 1.5 times the viewpoint. This renders the elements before the user scrolls to it, meaning that if they scroll fast the elements should always be rendered.<\/p>\n\n\n\n<p>The three tests used to decide whether an element should be rendered are:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Does the element sit entirely between the two bounds<\/li><li>Does the element sit at the top of one of the bounds, with part of it inside the bound<\/li><li>Does the element sit at the bottom of one of the bounds, with part of it inside the bound<\/li><\/ul>\n\n\n\n<p>If the elements match these criteria, they are returned into the data array that is passed to D3.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nvar filteredData = rawData.filter(filterVisibleElements);\n\nvar rowRectSelection = dynamicSvg.selectAll(&quot;.rowsMain&quot;).data(filteredData);\nvar rowRectScrollSelection = scrollSvg.selectAll(&quot;.rowsScroll&quot;).data(filteredData);\n<\/pre><\/div>\n\n\n<p>Every time the user scrolls the update function is called and the elements visible are updated.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary of lazily loading DOM elements<\/h2>\n\n\n\n<p>First when the elements are created their Y positions are calculated. These are stored as they will be constant throughout the lifetime of the page.<\/p>\n\n\n\n<p>Once this is calculated the update function is called for the first time. This draws the first set of elements. Once this has been done any further scroll events will trigger an update, refreshing what elements are displayed.<\/p>\n\n\n\n<p>The right SVG is used to demonstrate what elements have been loaded on the page. Here the red box is used to show the range of elements that are loaded for the page. The blue box is demonstrating the current view of the page.<\/p>\n\n\n\n<p>This relatively simple example allows expansion to more complex methods of drawing a page. It is important to note that if the update method is quite expensive you may need to buffer DOM updates. This may require writing a small buffer function to delay updates if multiple scroll events are received at the same time.<\/p>\n\n\n\n<p>The <a rel=\"noreferrer noopener\" aria-label=\"full code is available on my website (opens in a new tab)\" href=\"https:\/\/chewett.co.uk\/d3\/d3_v5_lazily_loading_dom_elements\/\" target=\"_blank\">full code is available on my website<\/a> and if you have any questions ask below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this example I demonstrate how you can lazily load DOM elements as you scroll through a page using D3.js. The full code for this is available on my website.<\/p>\n","protected":false},"author":1,"featured_media":2337,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Over this weekend I have written how you can lazily load DOM elements with #D3js and the problems associated with this.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[98],"tags":[229,291,219,72],"class_list":["post-2335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software","tag-d3-js","tag-d3-js-version-5","tag-data-visualisation","tag-javascript"],"wppr_data":{"cwp_meta_box_check":"No"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/08\/d3_lazily_loading_dom_elements.jpg?fit=800%2C800&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p2toWX-BF","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1030,"url":"https:\/\/chewett.co.uk\/blog\/1030\/overlaying-geo-data-leaflet-version-1-3-d3-js-version-4\/","url_meta":{"origin":2335,"position":0},"title":"Overlaying geo data with Leaflet Version 1.3 and D3.js Version 4","author":"Chewett","date":"February 24, 2018","format":false,"excerpt":"In this post I describe how you can overlay Geo Data onto a leaflet map with D3.js. Combining Leaflet and D3 and objectives There are a number of tutorials online on how to overlay Geodata with D3.js. However, I couldn't find any of these that worked for the most recent\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/02\/d3_leaftlet_intro.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/02\/d3_leaftlet_intro.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/02\/d3_leaftlet_intro.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/02\/d3_leaftlet_intro.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":2021,"url":"https:\/\/chewett.co.uk\/blog\/2021\/how-to-load-multiple-d3-versions-at-once\/","url_meta":{"origin":2335,"position":1},"title":"How to load multiple D3 versions at once","author":"Chewett","date":"March 2, 2019","format":false,"excerpt":"Today I am writing a short tutorial on how you can load multiple D3.js versions at once. Why you might want to load multiple D3 versions? Most of the time you will be using the same version of D3 for all visualisations on the page. However there may be cases\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/02\/loading_multiple_d3_versions-1.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/02\/loading_multiple_d3_versions-1.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/02\/loading_multiple_d3_versions-1.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2019\/02\/loading_multiple_d3_versions-1.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1485,"url":"https:\/\/chewett.co.uk\/blog\/1485\/drawing-shapes-in-d3-js-version-5\/","url_meta":{"origin":2335,"position":2},"title":"Drawing shapes in D3.js Version 5","author":"Chewett","date":"September 5, 2018","format":false,"excerpt":"This post goes over the various D3.js symbols typically used for scatter plots. D3.js built-in symbols D3.js has a number of built-in symbols which can be used for any data visualisation needs. The most common use of these are\u00a0for points on scatter plots and similar graphs. It is important to\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_v5_drawing_shapes.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_v5_drawing_shapes.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_v5_drawing_shapes.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_v5_drawing_shapes.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1431,"url":"https:\/\/chewett.co.uk\/blog\/1431\/simple-d3-js-version-5-data-binding-and-updating-example-and-code\/","url_meta":{"origin":2335,"position":3},"title":"Simple D3.js version 5 data binding and updating example and code","author":"Chewett","date":"August 11, 2018","format":false,"excerpt":"This post goes through the process of binding data to elements and creating a simple updatable SVG graphic using D3.js version 5. Data binding and updating in D3.js version 5 In D3.js version 4 there was quite a big update to how data is bound to elements and updated. This\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_simple_data_binding.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_simple_data_binding.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_simple_data_binding.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_simple_data_binding.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1463,"url":"https:\/\/chewett.co.uk\/blog\/1463\/summary-of-mike-bostock-on-d3-selections\/","url_meta":{"origin":2335,"position":4},"title":"Summary of Mike Bostock on D3 selections","author":"Chewett","date":"August 25, 2018","format":false,"excerpt":"Today I talk about and link to Mike Bostock's post on D3 selections, in this he talks about the basic unit of d3, the selection. Who is Mike Bostock? Mike Bostock is one of the key developers of d3.js and worked for a number of years creating visualizations with this\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_mike_post_selections.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_mike_post_selections.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_mike_post_selections.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/08\/d3_mike_post_selections.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":1700,"url":"https:\/\/chewett.co.uk\/blog\/1700\/colour-scales-in-d3-version-5\/","url_meta":{"origin":2335,"position":5},"title":"Colour scales in D3 Version 5","author":"Chewett","date":"November 3, 2018","format":false,"excerpt":"Over the past versions in D3.js there have been a number of changes to how you can get a colour scale to use with your charting. This blog post explores what is available and how to use it. This blog post applies to D3.js version 5. Colour scales in D3.js\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/chewett.co.uk\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/11\/d3_colour_scales-1.jpg?fit=800%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/11\/d3_colour_scales-1.jpg?fit=800%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/11\/d3_colour_scales-1.jpg?fit=800%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/chewett.co.uk\/blog\/wp-content\/uploads\/2018\/11\/d3_colour_scales-1.jpg?fit=800%2C800&ssl=1&resize=700%2C400 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=2335"}],"version-history":[{"count":3,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2335\/revisions"}],"predecessor-version":[{"id":2340,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2335\/revisions\/2340"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/media\/2337"}],"wp:attachment":[{"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=2335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=2335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chewett.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=2335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}