micro =require("micromodal@0.4.10")micro.init({awaitOpenAnimation:true,awaitCloseAnimation:true,// hide the area controls when a modal is openonShow: () =>document.getElementById("area-search-controls").classList.add("hide"),onClose: () =>document.getElementById("area-search-controls").classList.remove("hide")});
James Goldie, 360info
& Dean Marchiori,
Wave Data Labs
GET THIS MAP
Click to copy this into your story
allStates = ["NSW","VIC","QLD","SA","WA","TAS","NT","ACT"]selectedState = {const pageURL =newURL(window.location.href)const stateChoice = pageURL.searchParams.get("state")?.toUpperCase()return allStates.includes(stateChoice) ? stateChoice :"NSW"}selectedStateCode = allStates.indexOf(selectedState) +1titles = ({"NSW":"Bushfire Prone Areas: NSW","VIC":"Bushfire Prone Areas: VIC","QLD":"Bushfire Prone Areas: QLD","SA":"Bushfire Protection Areas: SA","WA":"Bushfire Prone Areas: WA","TAS":"Bushfire Prone Areas: TAS","NT":"Fire Protection Zones: NT","ACT":"Bushfire Prone Areas: ACT"})subtitles = ({"NSW":"This map shows the percentage of your suburb with vegetation that could potentially support a bushfire.","VIC":"This map shows the percentage of your suburb subject to โ or likely to be subject to โ bushfire.","QLD":"This map shows the percentage of your suburb identified as potentially being subject to at least a medium potential bushfire intensity.","SA":"This map shows the percentage of your suburb classified as at least general risk.","WA":"This map shows the percentage of your suburb subject to โ or likely to be subject to โ bushfire attack.","TAS":"This map shows the percentage of your suburb either designated as bushfire-prone by planning laws or, if there are none, near bushfire-prone vegetation.","NT":"This map shows the percentage of your suburb designated a Fire Protection Zone. These are generally limited to the fringes of urban areas.","ACT":"This map shows the percentage of your suburb assessed as being at high risk to life and property due to bushfires."})// display a customised title and subtitle based on selected statemapTitle =md`# ${titles[selectedState]}`mapSubtitle =md`${subtitles[selectedState]}`// initial boundsinitBounds = ({"NSW": [[146.0,-38.0], [154.0,-28.0]],"VIC": [[140.0,-39.0], [150.0,-33.0]],"QLD": [[142.0,-35.0], [159.0,-15.0]],"SA": [[131.0,-40.0], [144.0,-27.0]],"WA": [[108.5,-42.0], [125.5,-20.0]],"TAS": [[143.0,-43.0], [149.0,-38.0]],"NT": [[128.0,-22.0], [138.0,-6.0]],"ACT": [[148.7,-35.9], [149.3,-35.0]],})
r = require.alias({maplibregl:"maplibre-gl@2.1.9/dist/maplibre-gl.js",});maplibregl =r("maplibregl").catch(() =>window["maplibregl"]);
/* this is a bit different to regular mapbox/maplibre instantiation it lets have the map react to other values in the document, like a button or a timer, without reinstantiating! (based on https://observablehq.com/@tmcw/using-mapbox-gl-js) */viewof map = {let container =html`<div style="position: absolute; left: 0; top: 0; height: 100vh; width: 100%;" />`;// Give the container dimensions.yield container;// Create the \`map\` object with the mapboxgl.Map constructor, referencing// the container divlet map =new maplibregl.Map({ container,// bounds: [[111, -46], [155, -9]],bounds: initBounds[selectedState],fitBoundsOptions: {padding: {top:100,bottom:5,left:5,right:5} },minZoom:5,maxZoom:14,antialias:true,style:"style.json",attributionControl:false,// very loose to accomodate all of aus on portrait screensmaxBounds: [[95,-70], [170,15]], });// on map load:// - dispatch its value back to ojs// - add a prop to the layer that adds/removes a popup from the map// (we can't do this on initial layer def because the map isn't ready yet) map.on("load", () => { container.value= map; container.dispatchEvent(newCustomEvent("input")); map.addSource("suburbs-source", {"url":"/data/suburb-tiles/tiles.json","type":"vector","promoteId":"SAL_NAME21" });// coastline bg map.addLayer({id:"coastline",source:"suburbs-source","source-layer":"auscoast",type:"fill",paint: {"fill-color":"#56e8ae" } });// this layer shades all suburbs map.addLayer({id:"suburbs-colors",source:"suburbs-source","source-layer":"suburbs",type:"fill",filter: ["==","STE_CODE21", selectedStateCode.toString()] });// duplicate layer for selected suburb map.addLayer({id:"selected-suburb",source:"suburbs-source","source-layer":"suburbs",filter: ["==","SAL_NAME21",""],type:"line",paint: {"line-width":3,"line-color":"black","line-dasharray": [3,2], },"layout": {"line-cap":"round","line-join":"round" } });/* popup */const popup =new maplibregl.Popup({closeButton:true,closeOnClick:false,className:"map-popup" }); map.on("click","suburbs-colors",function(e) {// change the cursor style as a ui indicator. map.getCanvas().style.cursor="pointer";// display a warning if stats aren't available, or show them for// this layer if they areconst suburbName = e.features[0].properties.SAL_NAME21const bfArea = (e.features[0].state.bf_area||0).toFixed(1)const bfPercent = e.features[0].state.bf_area_pct.toLocaleString(undefined, {style:"percent"})const noDataMessage ="We don't have data for "+ suburbName +", but try another suburb nearby.";var dataMessage ="<h3>"+ e.features[0].properties.SAL_NAME21+"</h3>"+"<p><strong>"+ bfPercent +"</strong> "+"(about "+ bfArea +" sq. km) "+"is classified as "+ terms[selectedState] +"</p>"// populate popup; locate based on mouse's back-projected position popup.setLngLat(e.lngLat).setHTML(dataMessage).addTo(map); }); });}
viewof areaSearch = Inputs.search(stateStats, {placeholder:"Enter your suburb",// don't show the number of resultsformat: () =>``});// display a menu of results and a search button when we're down to 100 resultsviewof selectedSuburb = areaSearch.length>0&& areaSearch.length<100? Inputs.select(areaSearch, {format: d => d.SAL_NAME21 }) :md``viewof goBtn = areaSearch.length>0&& areaSearch.length<100? Inputs.button(`๐ Find`, {reduce: () =>zoomToSuburb(selectedSuburb.SAL_NAME21) }) :md``// need a switch for when our tile search fails due to a postcode being too// small (bit of a workaround for not having the time to re-do the tiles!)mutable tileSearchFailed =false;areaWarn = tileSearchFailed ?md`๐ This suburb's either very small or not in view โ zoom in or out a bit and search again.`: areaSearch.length==0?md`โ No areas matched this search`:md``
yellowRedFill = [0.0,"#ffffd4",0.2,"#fed98e",0.4,"#fe9929",0.6,"#d95f0e",0.8,"#993404"]yellowRedStroke = [0.0,"#ffff76",0.2,"#fdbe3f",0.4,"#ea7c01",0.6,"#ad4c0b",0.8,"#7a2903"]// when the filtered data changes, rejoin it to the map tiles and update the// colour schemeupdateMapData = { stateStats.forEach(row => { map.setFeatureState( {source:"suburbs-source",sourceLayer:"suburbs",id: row.SAL_NAME21, }, {bf_area:row.bf_area,bf_area_pct: row.bf_area_pct,cent_lat: row.cent_lat,cent_lon: row.cent_lon } ); }); map.setPaintProperty("suburbs-colors","fill-color", ["case", ["==", ["feature-state","bf_area_pct"],null],"#666666", ["interpolate", ["linear"], ["feature-state","bf_area_pct"],...yellowRedFill] ]) map.setPaintProperty("suburbs-colors","fill-outline-color", ["case", ["==", ["feature-state","bf_area_pct"],null],"#666666", ["interpolate", ["linear"], ["feature-state","bf_area_pct"],...yellowRedStroke] ]);}
functionzoomToSuburb(suburb) {// zoom to the suburb based on its centroidconst targetSuburb = stateStats.filter(d => d.SAL_NAME21== suburb)if (targetSuburb.length!=1) {console.error("Can only zoom to 1 suburb at a time, not ", targetSuburb.length); mutable tileSearchFailed =true; } else { map.flyTo({center: [targetSuburb[0].cent_lon, targetSuburb[0].cent_lat],zoom: targetSuburb[0].SHAPE_Area>0.1?4: targetSuburb[0].SHAPE_Area>0.05?6: targetSuburb[0].SHAPE_Area>0.005?7: targetSuburb[0].SHAPE_Area>0.0025?9:10 }) }// highlight suburb? map.setFeatureState( {source:"suburbs-source",sourceLayer:"suburbs",id: suburb, }, { isFocused:true } );// display info panel// (hide the area controls when a modal is open)setTimeout( micro.show("modal-focused-suburb", {onShow: () =>document.getElementById("area-search-controls").classList.add("hide"),onClose: () =>document.getElementById("area-search-controls").classList.remove("hide") }),1000);}
Each Australian state and territory maps out bushfire risk differently. Some mark out all areas with vegetation that can support a bushfire, while others choose to focus on the protection of populated areas.
Regardless of their name, on this map, suburbs in brown have a high percentage of areas marked for bushfire planning.
These areas are also used by firefighters and planning authorities to consider where the greatest risk may lie.
Although rules vary, many states and territories legally require people building in bushfire prone areas (or similarly named areas) to meet a bushfire resilience standard.
Some also impose obligations on landholders even if they arenโt building.