Skip to content

Commit

Permalink
Adds lava flows
Browse files Browse the repository at this point in the history
Draws the lava flows occuring at an eruption on the map on a separate layer, #3
  • Loading branch information
gabrielhase committed Apr 28, 2013
1 parent 013f9f4 commit 2d7648e
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 221 deletions.
84 changes: 2 additions & 82 deletions coffee/d3layer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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])
Expand All @@ -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) ->
Expand All @@ -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: () ->
Expand Down
27 changes: 21 additions & 6 deletions coffee/eruptions.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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'
Expand All @@ -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'
Expand All @@ -139,16 +139,18 @@
# 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)
return elem
)
@interaction = mapbox.markers.interaction(@markerLayer)
@sanitizedData = []
@lavaFlows = []
for eruption of eruptionData
@sanitizedData.push
'date': parseDate(eruption)
Expand All @@ -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")
Expand Down Expand Up @@ -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();


Expand Down Expand Up @@ -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')
126 changes: 126 additions & 0 deletions coffee/lavaLayer.coffee
Original file line number Diff line number Diff line change
@@ -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])
)
20 changes: 16 additions & 4 deletions coffee/map.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 2d7648e

Please sign in to comment.