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 0000000..048b07a Binary files /dev/null and b/img/lavaflow-icon.png differ 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); },