From 2d7648e50b7aeacb68efe54ed0883ca93eae140a Mon Sep 17 00:00:00 2001 From: Gabriel Date: Sun, 28 Apr 2013 18:31:28 +0200 Subject: [PATCH] Adds lava flows Draws the lava flows occuring at an eruption on the map on a separate layer, #3 --- coffee/d3layer.coffee | 84 +------------------ coffee/eruptions.coffee | 27 +++++-- coffee/lavaLayer.coffee | 126 +++++++++++++++++++++++++++++ coffee/map.coffee | 20 ++++- css/barchart.css | 23 ++---- css/story.css | 2 +- data/etna-history-with-events.json | 124 ++++++++++++++++------------ img/lavaflow-icon.png | Bin 0 -> 47658 bytes index.html | 2 + js/d3layer.js | 54 +------------ js/eruptions.js | 42 ++++++++-- js/lavaLayer.js | 102 +++++++++++++++++++++++ js/map.js | 17 +++- 13 files changed, 402 insertions(+), 221 deletions(-) create mode 100644 coffee/lavaLayer.coffee create mode 100644 img/lavaflow-icon.png create mode 100644 js/lavaLayer.js diff --git a/coffee/d3layer.coffee b/coffee/d3layer.coffee index 8eba50e..9a23a92 100644 --- a/coffee/d3layer.coffee +++ b/coffee/d3layer.coffee @@ -2,7 +2,7 @@ # provides a layer of circles corresponding to the area of influence of an eruption # uses d3 to draw on a mapbox layer. -@etna.d3layer = (map, mapDrawSvg, mapDrawGroup, lavaDrawGroup) -> +@etna.d3layer = (map, mapDrawSvg, mapDrawGroup) -> etnaLocation = [15.004, 37.734] # official plume area for different VEI values (from Wikipedia) plumes = { @@ -40,30 +40,6 @@ firstDraw = false pixelLocation = project(etnaLocation) - # mapDrawGroup.selectAll('rect') - # .attr('x', pixelLocation[0]) - # .attr('y', pixelLocation[1]) - # .attr('width', 5) - # .attr('height', (d, i) -> - # h = 0 - # if d.lavaflows - # for direction, length of d.lavaflows - # #h = 1 - # switch direction - # when "South" then h = length - - # h - # #dist = d.lava / 111 - # ) - - # lineFunction = d3.svg.line - # .x( (d) -> - # d.x - # ) - # .y( (d) -> - # d.y - # ) - # .interpolate("linear") d3.selectAll('circle') .attr('cx', pixelLocation[0]) @@ -75,59 +51,6 @@ pixelLocation[1] - distPoint[1] ) - d3.selectAll('path') - .attr('d', (d, i) -> - #lineFunction(d) - path = "M 0 0 L 0 0" - if d.lavaflows && d.lavaflows - for direction, length of d.lavaflows - switch direction - when "South" - dist = length / 111 - distPointLat = etnaLocation[1] - dist - distPoint = project([etnaLocation[0], distPointLat]) - path = "M #{pixelLocation[0]} #{pixelLocation[1]} L #{distPoint[0]} #{distPoint[1]}" - when "North" - dist = length / 111 - distPointLat = etnaLocation[1] + dist - distPoint = project([etnaLocation[0], distPointLat]) - path = "M #{pixelLocation[0]} #{pixelLocation[1]} L #{distPoint[0]} #{distPoint[1]}" - when "East" - dist = length / (111 * Math.cos(pixelLocation[1])) - distPointLon = etnaLocation[0] + dist - distPoint = project([distPointLon, etnaLocation[1]]) - path = "M #{pixelLocation[0]} #{pixelLocation[1]} L #{distPoint[0]} #{distPoint[1]}" - when "West" - dist = length / (111 * Math.cos(pixelLocation[1])) - distPointLon = etnaLocation[0] - dist - distPoint = project([distPointLon, etnaLocation[1]]) - path = "M #{pixelLocation[0]} #{pixelLocation[1]} L #{distPoint[0]} #{distPoint[1]}" - else - path = "M 0 0 L 0 0" - - path - ) - .attr("stroke", "red") - .attr("stroke-width", 10) - .attr("fill", "red") - .selectAll('title') - .text((d, i) -> - text = "lavaflow in #{d.date.getFullYear()}" - # if d.lavaflows && d.lavaflows - # for direction, length of d.lavaflows - # text = "#{text} #{length} in direction #{direction}" - text - ) - - # .attr('x1', pixelLocation[0]) - # .attr('x2', pixelLocation[0] + 1) - # .attr('y1', pixelLocation[1]) - # .attr('y2', (d, i) -> - # if d.lavaflows - # console.log d - # pixelLocation[1] + 1 - # ) - # binds the bounding box and eruptions data to the svg data: (boundingBox, eruptions) -> @@ -136,10 +59,7 @@ .data(eruptions) feature.exit().remove() feature.enter().append('circle') - lava = lavaDrawGroup.selectAll('path') - .data(eruptions) - lava.exit().remove() - lava.enter().append('path').append('title') + # sets the visible map extension extent: () -> diff --git a/coffee/eruptions.coffee b/coffee/eruptions.coffee index b91f76b..2561611 100644 --- a/coffee/eruptions.coffee +++ b/coffee/eruptions.coffee @@ -78,7 +78,7 @@ if location markerLayer.add_feature geometry: - coordinates: [location.lon-0.01, location.lat-0.01] # sightly offset for overlaying pins + coordinates: [location.lon-0.005, location.lat-0.005] # sightly offset for overlaying pins properties: 'marker-color': '#777' 'marker-size': 'small' @@ -110,7 +110,7 @@ if location markerLayer.add_feature geometry: - coordinates: [location.lon+0.01, location.lat+0.01] # slightly offset for overlaying pins + coordinates: [location.lon+0.005, location.lat+0.005] # slightly offset for overlaying pins properties: 'marker-color': '#000' 'marker-size': 'small' @@ -127,7 +127,7 @@ if location markerLayer.add_feature geometry: - coordinates: [location.lon-0.01, location.lat+0.01] # slightly offset for overlaying pins + coordinates: [location.lon-0.005, location.lat+0.005] # slightly offset for overlaying pins properties: 'marker-color': '#5C461F' 'marker-size': 'small' @@ -139,9 +139,10 @@ # Module Singleton # ================================ # init the non-changing data for this singleton - init: (eruptionData, map, circleLayer, markerLayer) => + init: (eruptionData, map, circleLayer, markerLayer, lavaLayer) => @map = map @circleLayer = circleLayer + @lavaLayer = lavaLayer @markerLayer = markerLayer @markerLayer.factory((f) -> elem = mapbox.markers.simplestyle_factory(f) @@ -149,6 +150,7 @@ ) @interaction = mapbox.markers.interaction(@markerLayer) @sanitizedData = [] + @lavaFlows = [] for eruption of eruptionData @sanitizedData.push 'date': parseDate(eruption) @@ -160,6 +162,15 @@ 'earthquake': eruptionData[eruption].earthquake 'lavaflows': eruptionData[eruption].lavaflows + for lavaStream in eruptionData[eruption].lavaflows + @lavaFlows.push + 'direction': lavaStream.flow.direction + 'length': lavaStream.flow.length + 'crater': lavaStream.crater + 'date': parseDate(eruption) + 'reachedHere': 1 + 'yearsReached': [parseDate(eruption).getFullYear()] + drawBarchart: (eruptionData) => svg_container = d3.select("#map-legend").append("svg") @@ -230,8 +241,13 @@ dataFiltered = @sanitizedData.filter( (d, i) -> true if (d.date >= focusScale.domain()[0]) && (d.date <= focusScale.domain()[1]) ) - @circleLayer.data(boundingBox, dataFiltered); + lavaFiltered = @lavaFlows.filter( (d, i) -> + true if (d.date >= focusScale.domain()[0]) && (d.date <= focusScale.domain()[1]) + ) + @circleLayer.data(boundingBox, dataFiltered) @circleLayer.draw(); + @lavaLayer.data(boundingBox, lavaFiltered) + @lavaLayer.draw() @map.refresh(); @@ -277,5 +293,4 @@ focusScale.domain()[1].getFullYear()]) # make sure z-index of markers is good - #$(".simplestyle-marker:not('.town-marker')").parent('div').addClass('markers') $(".simplestyle-marker").parent('div').addClass('markers') \ No newline at end of file diff --git a/coffee/lavaLayer.coffee b/coffee/lavaLayer.coffee new file mode 100644 index 0000000..7fb68ab --- /dev/null +++ b/coffee/lavaLayer.coffee @@ -0,0 +1,126 @@ +@etna = @etna || {} + +@etna.lavaLayer = (map, mapDrawSvg, mapDrawGroup) -> + + etnaLocation = [15.004, 37.734] + # TODO: these should be shared with the eruptions layer + craterLocations = { + "NorthEast": [15.0636, 37.7516], + "SouthEast": [15.0742, 37.7098], + "Voragine": [15.0677, 37.7305], + "Bocca Nuova": [15.0197, 37.7256] + } + + firstDraw = true + + + # projects a location in geographical data to pixel-space. + project = (location) -> + point = map.locationPoint + lat: location[1] + lon: location[0] + [point.x, point.y] + + + # calculates the distance in lat points with the hack 111km = 1 lat point + getLatDistance = (distance) -> + distance / 111; + + + getLonDistance = (distance, latitude) -> + distance / (111 * Math.cos(latitude)) + + + getPath = (length, craterLocation, craterLocationMapped, angle, horizDir, vertDir) -> + distLon = getLonDistance(length * Math.sin(angle), craterLocation[1]) + distLat = getLatDistance(length * Math.cos(angle)) + distPointLon = craterLocation[0] + (horizDir * distLon) + distPointLat = craterLocation[1] + (vertDir * distLat) + + distPoint = project([distPointLon, distPointLat]) + path = "M #{craterLocationMapped[0]} #{craterLocationMapped[1]} L #{distPoint[0]} #{distPoint[1]}" + + + draw: () -> + if firstDraw + mapDrawSvg + .attr('width', map.dimensions.x) + .attr('height', map.dimensions.y) + .style('margin-left', '0px') + .style('margin-top', '0px') + firstDraw = false + + pixelLocation = project(etnaLocation) + + mapDrawGroup.selectAll('path') + .attr('d', (d, i) -> + # TODO how is this possible? + if d == 0 + return "M 0 0 L 0 0" + craterLocation = craterLocations[d.crater] + if !craterLocation # TODO: should not be possible + return "M 0 0 L 0 0" + craterLocationMapped = project(craterLocation) + + # ANGLES: + # South, North: 0 + # -> steered over vert direction + # East, West: PI / 2 + # -> steered over horiz direction + + switch d.direction + when "South" + getPath(d.length, craterLocation, craterLocationMapped, 0, 1, -1) + when "North" + getPath(d.length, craterLocation, craterLocationMapped, 0, -1, 1) + when "East" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 2, 1, 1) + when "West" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 2, -1, 1) + when "SouthEast" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, 1, -1) + when "SouthWest" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, -1, -1) + when "NorthWest" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, -1, 1) + when "NorthEast" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, 1, 1) + when "NNorthWest" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, -1, 1) + when "WNorthWest" + getPath(d.length, craterLocation, craterLocationMapped, 3 * (Math.PI / 8), -1, 1) + when "NNorthEast" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, 1, 1) + when "WSouthWest" + getPath(d.length, craterLocation, craterLocationMapped, 3 * (Math.PI / 8), -1, -1) + when "SSouthEast" + getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, 1, -1) + when "ESouthEast" + getPath(d.length, craterLocation, craterLocationMapped, 3*(Math.PI / 8), 1, -1) + else + "M 0 0 L 0 0" + + ) + .attr("stroke", "red") + .attr("stroke-width", 10) + .attr("fill", "red") + .selectAll('title') + .text((d, i) -> + "lavaflow in #{d.date.getFullYear()}" + ) + + + data: (boundingBox, flows) -> + bounds = d3.geo.bounds(boundingBox) + lava = mapDrawGroup.selectAll('path') + .data(flows) + lava.exit().remove().remove() + lava.enter().append('path').append('title') + + + # sets the visible map extension + extent: () -> + new MM.Extent( + new MM.Location(bounds[0][1], bounds[0][0]), + new MM.Location(bounds[1][1], bounds[1][0]) + ) diff --git a/coffee/map.coffee b/coffee/map.coffee index b5418d3..347ca9d 100644 --- a/coffee/map.coffee +++ b/coffee/map.coffee @@ -54,25 +54,37 @@ # init the layer on which the eruption circles will be drawn @initD3Layer() + # init the layer on which the lava flows will be drawn + @initLavaLayer() + # init and draw the barchart - etna.eruptionsChart.init(etna.eruptions, @map, @circleLayer, @markerLayer) + etna.eruptionsChart.init(etna.eruptions, @map, @circleLayer, @markerLayer, @lavaLayer) etna.eruptionsChart.drawBarchart(etna.eruptions) + initLavaLayer: () -> + lavaDrawDiv = d3.select(document.body) + .append('div') + .attr('class', 'lava-vec') + lavaDrawSvg = lavaDrawDiv.append('svg') + lavaDrawGroup = lavaDrawSvg.append('g') + @lavaLayer = etna.lavaLayer(@map, lavaDrawSvg, lavaDrawGroup) + @lavaLayer.parent = lavaDrawDiv.node() + @map.addLayer(@lavaLayer) + + initD3Layer: () -> mapDrawDiv = d3.select(document.body) .append('div') .attr('class', 'd3-vec') mapDrawSvg = mapDrawDiv.append('svg') mapDrawGroup = mapDrawSvg.append('g') - lavaDrawGroup = mapDrawSvg.append('g') - @circleLayer = etna.d3layer(@map, mapDrawSvg, mapDrawGroup, lavaDrawGroup) + @circleLayer = etna.d3layer(@map, mapDrawSvg, mapDrawGroup) @circleLayer.parent = mapDrawDiv.node() @map.addLayer(@circleLayer) initEvents: () -> - # hide legend and tooltips if users clicks somewhere on the map $("#map").click (event) => @hideLegend() diff --git a/css/barchart.css b/css/barchart.css index 0a4aea4..f1a1ccb 100644 --- a/css/barchart.css +++ b/css/barchart.css @@ -3,24 +3,14 @@ z-index: 100; } -/* make sure markers layer is always on top for tooltips */ - -/* -div.markers div.marker-tooltip { - z-index: 1000 !important; -} - This doesn't help since the z-index of the parent element overrules - => the parents z-index is set by mapbox so I changed the mapbox API code -*/ -/* -.markers { - z-index: 99 !important; -} -*/ .d3-vec { z-index: 1; } +.lava-vec { + z-index: 1; +} + .axis path, .axis line { fill: none; @@ -50,11 +40,12 @@ div.markers div.marker-tooltip { circle { /*fill: #993341;*/ fill: #ccc; - fill-opacity: .2; + fill-opacity: .1; stroke: #fff; stroke-width: 1.5px; } -path { +.lava-vec { position: absolute; } +.lava-vec path { opacity: 0.2; } diff --git a/css/story.css b/css/story.css index be449ab..38f3464 100644 --- a/css/story.css +++ b/css/story.css @@ -58,7 +58,7 @@ div.section-title.introduction .intro-title p { } .section-title.cs171 { - background-color: #000; + background-color: #bbb; } .section-title h2 { diff --git a/data/etna-history-with-events.json b/data/etna-history-with-events.json index da53a12..e4044e2 100644 --- a/data/etna-history-with-events.json +++ b/data/etna-history-with-events.json @@ -4,7 +4,7 @@ "craters": [], "sideeffects": [], "airportShutdown": ["catania"], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": [] }, @@ -12,7 +12,7 @@ "vei": 2, "craters": ["SouthEast", "Bocca Nuova", "NorthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": [] }, @@ -21,9 +21,9 @@ "craters": ["Voragine"], "sideeffects": ["earthquakes"], "earthquake": ["Voragine"], - "lavaflows": { - "?": 6.5 - }, + "lavaflows": [ + {"crater": "Voragine", "flow": {"direction": "SSouthEast", "length": 6.5}} + ], "ash": [], "destroyed": [] }, @@ -32,10 +32,10 @@ "craters": ["SouthEast"], "sideeffects": ["airportShutdown"], "airportShutdown": ["catania"], - "lavaflows": { - "Valle del Bove": 4.5, - "Valle del Bove": 6.2 - }, + "lavaflows": [ + {"crater": "SouthEast", "flow": {"direction": "SSouthEast", "length": 4.5}}, + {"crater": "SouthEast", "flow": {"direction": "SSouthEast", "length": 6.2}} + ], "ash": ["EastFlank, NorthFlank"], "destroyed": [] }, @@ -44,7 +44,9 @@ "craters": ["SouthEast"], "sideeffects": [], "airportShutdown": ["catania"], - "lavaflows": {}, + "lavaflows": [ + {"crater": "SouthEast", "flow": {"direction": "ESouthEast", "length": 1.3}} + ], "ash": [], "destroyed": [] }, @@ -52,9 +54,9 @@ "vei": 1, "craters": ["SouthEast"], "sideeffects": [], - "lavaflows": { - "Valle del Bove": 3 - }, + "lavaflows": [ + {"crater": "SouthEast", "flow": {"direction": "SSouthEast", "length": 3}} + ], "ash": [], "destroyed": [] }, @@ -62,7 +64,7 @@ "vei": 1, "craters": ["SouthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": [] }, @@ -70,7 +72,7 @@ "vei": 1, "craters": ["SouthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": [] }, @@ -80,7 +82,9 @@ "sideeffects": ["deformation", "touristStationDestroyed"], "airportShutdown": ["catania"], "earthquake": ["zafferana"], - "lavaflows": {}, + "lavaflows": [ + {"crater": "Voragine", "flow": {"direction": "South", "length": 10.5}} + ], "ash": ["catania", "belpasso"], "destroyed": [] }, @@ -88,9 +92,9 @@ "vei": 1, "craters": ["Voragine"], "sideeffects": [], - "lavaflows": { - "South": 0.5 - }, + "lavaflows": [ + {"crater": "Voragine", "flow": {"direction": "South", "length": 0.5}} + ], "ash": ["giarre"], "destroyed": [] }, @@ -98,7 +102,7 @@ "vei": 1, "craters": ["Voragine"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": ["catania", "siracusa", "zafferana"], "destroyed": [] }, @@ -107,7 +111,7 @@ "craters": ["NorthEast"], "sideeffects": ["airportShutdown"], "airportShutdown": ["catania"], - "lavaflows": {}, + "lavaflows": [], "ash": ["giarre"], "destroyed": [] }, @@ -116,9 +120,9 @@ "craters": ["SouthEast"], "sideeffects": ["airportShutdown"], "airportShutdown": ["catania"], - "lavaflows": { - "SSouthEast": "upToZafferana" - }, + "lavaflows": [ + {"crater": "SouthEast", "flow": {"direction": "ESouthEast", "length": 5}} + ], "ash": [], "destroyed": [] }, @@ -126,7 +130,7 @@ "vei": 2, "craters": ["SouthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": [] }, @@ -134,7 +138,7 @@ "vei": 1, "craters": ["SouthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": ["NorthWestFlank", "Barcellona Pozzo di Grotto"], "destroyed": [] }, @@ -143,9 +147,9 @@ "craters": ["NorthEast"], "sideeffects": ["airportShutdown"], "airportShutdown": ["catania"], - "lavaflows": { - "SouthEast": 1.5 - }, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "SouthEast", "length": 1.5}} + ], "ash": ["SouthEastFlank", "siracusa"], "destroyed": [] }, @@ -153,9 +157,9 @@ "vei": 1, "craters": ["Bocca Nuova"], "sideeffects": [], - "lavaflows": { - "South": 6.5 - }, + "lavaflows": [ + {"crater": "Bocca Nuova", "flow": {"direction": "South", "length": 6.5}} + ], "ash": [], "destroyed": [] }, @@ -163,9 +167,9 @@ "vei": 2, "craters": ["NorthEast"], "sideeffects": [], - "lavaflows": { - "North": 6 - }, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "NNorthWest", "length": 18}} + ], "ash": [], "destroyed": [] }, @@ -174,15 +178,20 @@ "craters": ["SouthEast"], "sideeffects": ["airportShutdown"], "airportShutdown": ["catania"], - "lavaflows": {}, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "NNorthEast", "length": 7}} + ], "ash": ["catania", "siracusa"], "destroyed": [] }, "1971": { "vei": 2, - "craters": [], + "craters": ["NorthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "ESouthEast", "length": 6.5}}, + {"crater": "Bocca Nuova", "flow": {"direction": "South", "length": 2.4}} + ], "ash": [], "destroyed": [] }, @@ -190,15 +199,17 @@ "vei": 1, "craters": ["Voragine"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": ["taormina", "messina"], "destroyed": [] }, "1949": { "vei": 2, - "craters": [], + "craters": ["Voragine"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [ + {"crater": "Voragine", "flow": {"direction": "WNorthWest", "length": 7.2}} + ], "ash": [], "destroyed": [] }, @@ -206,7 +217,9 @@ "vei": 3, "craters": ["NorthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "North", "length": 11.4}} + ], "ash": ["EastFlank", "giarre"], "destroyed": [] }, @@ -214,7 +227,7 @@ "vei": 2, "craters": ["NorthEast"], "sideeffects": [], - "lavaflows": {}, + "lavaflows": [], "ash": ["EastFlank", "messina"], "destroyed": [] }, @@ -222,19 +235,30 @@ "vei": 1, "craters": ["NorthEast"], "sideeffects": [], - "lavaflows": { - "East": 17 - }, + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "East", "length": 17}} + ], "ash": ["EastFlank", "messina"], "destroyed": ["mascali"] }, + "1923": { + "vei": 1, + "craters": ["NorthEast"], + "sideeffects": [], + "lavaflows": [ + {"crater": "NorthEast", "flow": {"direction": "NNorthEast", "length": 15}}, + {"crater": "NorthEast", "flow": {"direction": "North", "length": 10}} + ], + "ash": [], + "destroyed": [] + }, "1910": { "vei": 1, "craters": ["Voragine", "SouthEast", "Bocca Nuova", "NorthEast"], "sideeffects": [], - "lavaflows": { - "South": 15.6 - }, + "lavaflows": [ + {"crater": "Voragine", "flow": {"direction": "South", "length": 15.6}} + ], "ash": [], "destroyed": ["cavaliere"] }, @@ -243,7 +267,7 @@ "craters": ["SouthEast"], "sideeffects": ["earthquakes"], "earthquake": ["messina"], - "lavaflows": {}, + "lavaflows": [], "ash": [], "destroyed": ["messina"] } diff --git a/img/lavaflow-icon.png b/img/lavaflow-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..048b07a86fad65cf69b7d2fb2a34419b56bbf03b GIT binary patch literal 47658 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html index 931dce9..ee13c3b 100644 --- a/index.html +++ b/index.html @@ -20,6 +20,7 @@ + @@ -318,6 +319,7 @@

Explore the volcano and towns

  • Shrinking Town
  • VEI
  • +
  • Lava Flow
  • Explosion
  • Ashfall
  • Airport Shutdown
  • diff --git a/js/d3layer.js b/js/d3layer.js index 10f050d..48dd774 100644 --- a/js/d3layer.js +++ b/js/d3layer.js @@ -1,7 +1,7 @@ this.etna = this.etna || {}; -this.etna.d3layer = function(map, mapDrawSvg, mapDrawGroup, lavaDrawGroup) { +this.etna.d3layer = function(map, mapDrawSvg, mapDrawGroup) { var bounds, etnaLocation, firstDraw, getDistance, plumes, project; etnaLocation = [15.004, 37.734]; plumes = { @@ -33,66 +33,20 @@ this.etna.d3layer = function(map, mapDrawSvg, mapDrawGroup, lavaDrawGroup) { firstDraw = false; } pixelLocation = project(etnaLocation); - d3.selectAll('circle').attr('cx', pixelLocation[0]).attr('cy', pixelLocation[1]).attr('r', function(d, i) { + return d3.selectAll('circle').attr('cx', pixelLocation[0]).attr('cy', pixelLocation[1]).attr('r', function(d, i) { var dist, distPoint, distPointLat; dist = getDistance(d.vei); distPointLat = etnaLocation[1] + dist; distPoint = project([etnaLocation[0], distPointLat]); return pixelLocation[1] - distPoint[1]; }); - return d3.selectAll('path').attr('d', function(d, i) { - var direction, dist, distPoint, distPointLat, distPointLon, length, path, _ref; - path = "M 0 0 L 0 0"; - if (d.lavaflows && d.lavaflows) { - _ref = d.lavaflows; - for (direction in _ref) { - length = _ref[direction]; - switch (direction) { - case "South": - dist = length / 111; - distPointLat = etnaLocation[1] - dist; - distPoint = project([etnaLocation[0], distPointLat]); - path = "M " + pixelLocation[0] + " " + pixelLocation[1] + " L " + distPoint[0] + " " + distPoint[1]; - break; - case "North": - dist = length / 111; - distPointLat = etnaLocation[1] + dist; - distPoint = project([etnaLocation[0], distPointLat]); - path = "M " + pixelLocation[0] + " " + pixelLocation[1] + " L " + distPoint[0] + " " + distPoint[1]; - break; - case "East": - dist = length / (111 * Math.cos(pixelLocation[1])); - distPointLon = etnaLocation[0] + dist; - distPoint = project([distPointLon, etnaLocation[1]]); - path = "M " + pixelLocation[0] + " " + pixelLocation[1] + " L " + distPoint[0] + " " + distPoint[1]; - break; - case "West": - dist = length / (111 * Math.cos(pixelLocation[1])); - distPointLon = etnaLocation[0] - dist; - distPoint = project([distPointLon, etnaLocation[1]]); - path = "M " + pixelLocation[0] + " " + pixelLocation[1] + " L " + distPoint[0] + " " + distPoint[1]; - break; - default: - path = "M 0 0 L 0 0"; - } - } - } - return path; - }).attr("stroke", "red").attr("stroke-width", 10).attr("fill", "red").selectAll('title').text(function(d, i) { - var text; - text = "lavaflow in " + (d.date.getFullYear()); - return text; - }); }, data: function(boundingBox, eruptions) { - var feature, lava; + var feature; bounds = d3.geo.bounds(boundingBox); feature = mapDrawGroup.selectAll('circle').data(eruptions); feature.exit().remove(); - feature.enter().append('circle'); - lava = lavaDrawGroup.selectAll('path').data(eruptions); - lava.exit().remove(); - return lava.enter().append('path').append('title'); + return feature.enter().append('circle'); }, extent: function() { return new MM.Extent(new MM.Location(bounds[0][1], bounds[0][0]), new MM.Location(bounds[1][1], bounds[1][0])); diff --git a/js/eruptions.js b/js/eruptions.js index 7cd72c8..fe55054 100644 --- a/js/eruptions.js +++ b/js/eruptions.js @@ -88,7 +88,7 @@ this.etna.eruptionsChart = (function() { if (location) { _results.push(markerLayer.add_feature({ geometry: { - coordinates: [location.lon - 0.01, location.lat - 0.01] + coordinates: [location.lon - 0.005, location.lat - 0.005] }, properties: { 'marker-color': '#777', @@ -138,7 +138,7 @@ this.etna.eruptionsChart = (function() { if (location) { _results.push(markerLayer.add_feature({ geometry: { - coordinates: [location.lon + 0.01, location.lat + 0.01] + coordinates: [location.lon + 0.005, location.lat + 0.005] }, properties: { 'marker-color': '#000', @@ -164,7 +164,7 @@ this.etna.eruptionsChart = (function() { if (location) { _results.push(markerLayer.add_feature({ geometry: { - coordinates: [location.lon - 0.01, location.lat + 0.01] + coordinates: [location.lon - 0.005, location.lat + 0.005] }, properties: { 'marker-color': '#5C461F', @@ -180,10 +180,11 @@ this.etna.eruptionsChart = (function() { return _results; }; return { - init: function(eruptionData, map, circleLayer, markerLayer) { - var eruption, _results; + init: function(eruptionData, map, circleLayer, markerLayer, lavaLayer) { + var eruption, lavaStream, _results; _this.map = map; _this.circleLayer = circleLayer; + _this.lavaLayer = lavaLayer; _this.markerLayer = markerLayer; _this.markerLayer.factory(function(f) { var elem; @@ -192,9 +193,10 @@ this.etna.eruptionsChart = (function() { }); _this.interaction = mapbox.markers.interaction(_this.markerLayer); _this.sanitizedData = []; + _this.lavaFlows = []; _results = []; for (eruption in eruptionData) { - _results.push(_this.sanitizedData.push({ + _this.sanitizedData.push({ 'date': parseDate(eruption), 'vei': +eruptionData[eruption].vei, 'craters': eruptionData[eruption].craters, @@ -203,7 +205,24 @@ this.etna.eruptionsChart = (function() { 'destroyed': eruptionData[eruption].destroyed, 'earthquake': eruptionData[eruption].earthquake, 'lavaflows': eruptionData[eruption].lavaflows - })); + }); + _results.push((function() { + var _i, _len, _ref, _results1; + _ref = eruptionData[eruption].lavaflows; + _results1 = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + lavaStream = _ref[_i]; + _results1.push(this.lavaFlows.push({ + 'direction': lavaStream.flow.direction, + 'length': lavaStream.flow.length, + 'crater': lavaStream.crater, + 'date': parseDate(eruption), + 'reachedHere': 1, + 'yearsReached': [parseDate(eruption).getFullYear()] + })); + } + return _results1; + }).call(_this)); } return _results; }, @@ -235,7 +254,7 @@ this.etna.eruptionsChart = (function() { } }, eruptionsBrush: function() { - var dataFiltered; + var dataFiltered, lavaFiltered; lastExtent = _this.brush.extent(); focusScale.domain(_this.brush.extent()); dataFiltered = _this.sanitizedData.filter(function(d, i) { @@ -243,8 +262,15 @@ this.etna.eruptionsChart = (function() { return true; } }); + lavaFiltered = _this.lavaFlows.filter(function(d, i) { + if ((d.date >= focusScale.domain()[0]) && (d.date <= focusScale.domain()[1])) { + return true; + } + }); _this.circleLayer.data(boundingBox, dataFiltered); _this.circleLayer.draw(); + _this.lavaLayer.data(boundingBox, lavaFiltered); + _this.lavaLayer.draw(); return _this.map.refresh(); }, eruptionsBrushEnd: function() { diff --git a/js/lavaLayer.js b/js/lavaLayer.js new file mode 100644 index 0000000..6e595c6 --- /dev/null +++ b/js/lavaLayer.js @@ -0,0 +1,102 @@ + +this.etna = this.etna || {}; + +this.etna.lavaLayer = function(map, mapDrawSvg, mapDrawGroup) { + var craterLocations, etnaLocation, firstDraw, getLatDistance, getLonDistance, getPath, project; + etnaLocation = [15.004, 37.734]; + craterLocations = { + "NorthEast": [15.0636, 37.7516], + "SouthEast": [15.0742, 37.7098], + "Voragine": [15.0677, 37.7305], + "Bocca Nuova": [15.0197, 37.7256] + }; + firstDraw = true; + project = function(location) { + var point; + point = map.locationPoint({ + lat: location[1], + lon: location[0] + }); + return [point.x, point.y]; + }; + getLatDistance = function(distance) { + return distance / 111; + }; + getLonDistance = function(distance, latitude) { + return distance / (111 * Math.cos(latitude)); + }; + getPath = function(length, craterLocation, craterLocationMapped, angle, horizDir, vertDir) { + var distLat, distLon, distPoint, distPointLat, distPointLon, path; + distLon = getLonDistance(length * Math.sin(angle), craterLocation[1]); + distLat = getLatDistance(length * Math.cos(angle)); + distPointLon = craterLocation[0] + (horizDir * distLon); + distPointLat = craterLocation[1] + (vertDir * distLat); + distPoint = project([distPointLon, distPointLat]); + return path = "M " + craterLocationMapped[0] + " " + craterLocationMapped[1] + " L " + distPoint[0] + " " + distPoint[1]; + }; + return { + draw: function() { + var pixelLocation; + if (firstDraw) { + mapDrawSvg.attr('width', map.dimensions.x).attr('height', map.dimensions.y).style('margin-left', '0px').style('margin-top', '0px'); + firstDraw = false; + } + pixelLocation = project(etnaLocation); + return mapDrawGroup.selectAll('path').attr('d', function(d, i) { + var craterLocation, craterLocationMapped; + if (d === 0) { + return "M 0 0 L 0 0"; + } + craterLocation = craterLocations[d.crater]; + if (!craterLocation) { + return "M 0 0 L 0 0"; + } + craterLocationMapped = project(craterLocation); + switch (d.direction) { + case "South": + return getPath(d.length, craterLocation, craterLocationMapped, 0, 1, -1); + case "North": + return getPath(d.length, craterLocation, craterLocationMapped, 0, -1, 1); + case "East": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 2, 1, 1); + case "West": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 2, -1, 1); + case "SouthEast": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, 1, -1); + case "SouthWest": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, -1, -1); + case "NorthWest": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, -1, 1); + case "NorthEast": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 4, 1, 1); + case "NNorthWest": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, -1, 1); + case "WNorthWest": + return getPath(d.length, craterLocation, craterLocationMapped, 3 * (Math.PI / 8), -1, 1); + case "NNorthEast": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, 1, 1); + case "WSouthWest": + return getPath(d.length, craterLocation, craterLocationMapped, 3 * (Math.PI / 8), -1, -1); + case "SSouthEast": + return getPath(d.length, craterLocation, craterLocationMapped, Math.PI / 8, 1, -1); + case "ESouthEast": + return getPath(d.length, craterLocation, craterLocationMapped, 3 * (Math.PI / 8), 1, -1); + default: + return "M 0 0 L 0 0"; + } + }).attr("stroke", "red").attr("stroke-width", 10).attr("fill", "red").selectAll('title').text(function(d, i) { + return "lavaflow in " + (d.date.getFullYear()); + }); + }, + data: function(boundingBox, flows) { + var bounds, lava; + bounds = d3.geo.bounds(boundingBox); + lava = mapDrawGroup.selectAll('path').data(flows); + lava.exit().remove().remove(); + return lava.enter().append('path').append('title'); + }, + extent: function() { + return new MM.Extent(new MM.Location(bounds[0][1], bounds[0][0]), new MM.Location(bounds[1][1], bounds[1][0])); + } + }; +}; diff --git a/js/map.js b/js/map.js index ec4d767..2565b28 100644 --- a/js/map.js +++ b/js/map.js @@ -47,16 +47,25 @@ this.etna.map = (function() { this.markerLayer = mapbox.markers.layer(); this.map.addLayer(this.markerLayer); this.initD3Layer(); - etna.eruptionsChart.init(etna.eruptions, this.map, this.circleLayer, this.markerLayer); + this.initLavaLayer(); + etna.eruptionsChart.init(etna.eruptions, this.map, this.circleLayer, this.markerLayer, this.lavaLayer); return etna.eruptionsChart.drawBarchart(etna.eruptions); }, + initLavaLayer: function() { + var lavaDrawDiv, lavaDrawGroup, lavaDrawSvg; + lavaDrawDiv = d3.select(document.body).append('div').attr('class', 'lava-vec'); + lavaDrawSvg = lavaDrawDiv.append('svg'); + lavaDrawGroup = lavaDrawSvg.append('g'); + this.lavaLayer = etna.lavaLayer(this.map, lavaDrawSvg, lavaDrawGroup); + this.lavaLayer.parent = lavaDrawDiv.node(); + return this.map.addLayer(this.lavaLayer); + }, initD3Layer: function() { - var lavaDrawGroup, mapDrawDiv, mapDrawGroup, mapDrawSvg; + var mapDrawDiv, mapDrawGroup, mapDrawSvg; mapDrawDiv = d3.select(document.body).append('div').attr('class', 'd3-vec'); mapDrawSvg = mapDrawDiv.append('svg'); mapDrawGroup = mapDrawSvg.append('g'); - lavaDrawGroup = mapDrawSvg.append('g'); - this.circleLayer = etna.d3layer(this.map, mapDrawSvg, mapDrawGroup, lavaDrawGroup); + this.circleLayer = etna.d3layer(this.map, mapDrawSvg, mapDrawGroup); this.circleLayer.parent = mapDrawDiv.node(); return this.map.addLayer(this.circleLayer); },