|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>Demonstration fo ArcGeometries 3</title> |
|
<meta charset="utf-8" /> |
|
<script src="http://cdn.leafletjs.com/leaflet-0.6.1/leaflet.js"></script> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="http://d3js.org/topojson.v1.min.js"></script> |
|
<script src="http://mourner.github.io/simplify-js/simplify.js"></script> |
|
|
|
<script src="http://bl.ocks.org/milkbread/raw/5779939/RKMapping_0.4.5.js"></script> |
|
<script src="http://bl.ocks.org/milkbread/raw/5829814/RKAggregation_1.0.js"></script> <!--this function needs RKMapping.js additionally--> |
|
<script src="http://bl.ocks.org/milkbread/raw/5947143/crossfilter.min.js"></script> <!--NOT WRITTEN BY ME!!!--> |
|
<script src="loadAdditionalData.js"></script> |
|
<script src="animationSelektor.js"></script> |
|
|
|
<style> |
|
@import url(http://cdn.leafletjs.com/leaflet-0.6.1/leaflet.css); |
|
@import url(simplyArcDemoStyles.css); |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<h1>Animated Demonstration of Data-Driven<br> Polygon Simplification with the help of TopoJSON</h1> |
|
<div id="selectAnimation" style="width: 960px; height: 30px"></div> |
|
<div id="info"style="width: 960px;"></div> |
|
<div id="map" style="width: 960px; height: 500px"></div> |
|
<script> |
|
//0. DEFINE SOME INITIAL VARIABLES |
|
var strokeColors = ['rgb(255,0,0)','rgb(0,150,0)'], |
|
geometryFinal = [], |
|
geometryGlobal = []; |
|
topologyGlobal = []; |
|
|
|
//0.1 READ THE HASH OF THE URL |
|
var hashValue = window.location.hash; |
|
if(hashValue.indexOf('#') == -1)hashValue = [0.1]; |
|
else hashValue = hashValue.replace('#','').split(':'); |
|
|
|
//0.2 Leaflet Map |
|
var map = L.map('map').setView([51, 11], 5); |
|
var data_attrib = " | Data: <a href='http://www.geodatenzentrum.de/geodaten/gdz_rahmen.gdz_div?gdz_spr=eng&gdz_akt_zeile=5&gdz_anz_zeile=1&gdz_unt_zeile=18&gdz_user_id=0' target='_blank'>© GeoBasis-DE / BKG 2013</a> | <a href='http://d3js.org/'>D3.js</a> | <a href='https://github.com/mbostock/topojson/wiki'>TopoJSON</a> | <a href='http://mourner.github.io/simplify-js/'>Simplify</a>" |
|
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: "Map: <a href='http://www.openstreetmap.org/'>© OpenStreetMap </a>contributers" + data_attrib}); |
|
var esri = L.tileLayer('http://services.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}.png', {attribution: "Map: <a href='http://www.arcgis.com/home/item.html?id=c4ec722a1cd34cf0a23904aadf8923a0'>ArcGIS - World Physical Map</a>" + data_attrib}); |
|
var stamen = L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png', {attribution: "Map: <a href='http://maps.stamen.com/#toner/12/37.7706/-122.3782'>Stamen Design</a>" + data_attrib}).addTo(map); |
|
var baseLayers = {"stamen": stamen, "OpenStreetMap":osm, "World Physical Map":esri}; |
|
var control = L.control.layers(baseLayers).addTo(map); |
|
|
|
//0.3 Map overlay - BASICS |
|
var clickCounter = 0; |
|
var svgContainer= d3.select(map.getPanes().overlayPane).append("svg") |
|
var group= svgContainer.append("g").attr("class", "leaflet-zoom-hide"); |
|
var path2 = d3.geo.path().projection(project); |
|
|
|
|
|
//0.4.1 INFO-VISUALISATION && |
|
//5.1 SLIDER FOR MANUAL SIMPLIFCATION |
|
var tableRow = d3.select('#info').append('table').attr('border',0).append('tr') |
|
var heading = tableRow.append('td').attr('width',960/2).append('text').attr('id','head').text('Load data...') |
|
var countInfo = tableRow.append('td').attr('width',960/2-80).append('text') |
|
var selectMan = tableRow.append('td').attr('width',80).attr('align','center').datum('off') |
|
var selectManText = selectMan.append('text_').text('Simplify manually') |
|
var sliderContainer = d3.select('#info').append('svg').attr('width',960).attr('height',0); |
|
var slider = sliderContainer.append('rect') |
|
.attr("x", 0).attr("y", 0) |
|
.attr("width", 960).attr("height", 25) |
|
.style('fill','#a00').style('opacity',0.4); |
|
var indicator = sliderContainer.append('rect') |
|
.attr("x", 0).attr("y", 0) |
|
.attr("width", 8).attr("height", 25) |
|
.style('fill','#000').style('opacity',0.4); |
|
var sliderScale = d3.scale.linear().domain([0,1]).range([0,960]); |
|
|
|
//1. OPEN BASIC DATA |
|
var selMaxVal = 0, counter, position; |
|
d3.json("vg250_states_topo.json", function(error, topology) { |
|
|
|
//1.1 DEFINE BASIC DATA |
|
var pure_features = topology.objects.vg250_bld; |
|
var featureStorage = new featureObjStorage(); |
|
pure_features.geometries.forEach(function(d){ featureStorage.addFeatObj(d); }) |
|
var featuresObjects = featureStorage.featureObjects; |
|
|
|
//1.2 BASIC POLYGONS |
|
var basicObjects = topojson.feature(topology, pure_features).features; |
|
|
|
//1.3 INITIAL SIMPLIFICATION OF BASIC POLYGONS |
|
basicObjects = basicObjects.map(function(data){ |
|
data.geometry.coordinates = polygonSimplification2(data, parseFloat(hashValue[0])) |
|
return data; |
|
}) |
|
|
|
//1.4 GET BOUNDS OF DATA - NEEDED FOR THE SIZE OF THE SVG-CONTAINER |
|
var overlayBounds = d3.geo.bounds(topojson.feature(topology, pure_features)); |
|
|
|
//2. GET THE ARCS OF THE BASIC POLYGONS |
|
var arcCollection = getArcs(topology, featuresObjects); |
|
|
|
//2.1 SIMPLIFY EACH ARC && 2.2 PUSH THEM TO AN ARRAY ... because, we need an array of objects not an object |
|
var arcCollectionArray_ = [], maxLength = 0, i=0; |
|
for (arc in arcCollection){ |
|
var cache = arcCollection[arc]; |
|
//simplify LineStrings of the arcs |
|
cache.geometry.coordinates = pointsConversion(simplify(pointsConversion(cache.geometry.coordinates, 'toObject'),parseFloat(hashValue[0]),false), 'toArray') |
|
cache.id=i; |
|
//push simplified version to an array |
|
arcCollectionArray_.push(cache) |
|
//directly get the maximum value (needed for the slider) |
|
if(maxLength<cache.length)maxLength=cache.length; |
|
i++; |
|
} |
|
|
|
//2.3 SETUP BASIC ARCS AS CROSSFILTER |
|
var arcCollectionCF = crossfilter(arcCollectionArray_); |
|
var arcsLenDim = arcCollectionCF.dimension(function(d){return d.length;}) |
|
filter(); |
|
|
|
//3. LOAD A 2nd DATASET WITH A HIGHER DENSITY |
|
var globalData_bld2 = []; |
|
loadAdditionalData("vg250_bld_krs_topo.json", 'bld', globalData_bld2); |
|
var globalData_krs2 = []; |
|
loadAdditionalData("vg250_bld_krs_topo.json", 'krs', globalData_krs2); |
|
|
|
//TELL THE USER THAT DATA WAS LOADED ... not 100% exactly, as it is not sure, that the 2nd dataset in already loaded |
|
heading.transition().duration(1000).text('Data was completely loaded...start an animation!') |
|
|
|
map.on("viewreset", reset); |
|
|
|
reset(); |
|
|
|
//0.4.2 CLICK ON THE MAIN SVG-CONTAINER AND START EACH ANIMATION |
|
/*svgContainer.on('mouseup',mainClick); |
|
function mainClick(){ |
|
console.log(clickCounter); |
|
if(clickCounter==0)selectBlock('basics') |
|
else if(clickCounter==1)selectBlock('consistency') |
|
else if(clickCounter==2)selectBlock('data_driven') |
|
else if(clickCounter==3)selectBlock('final_geom') |
|
else window.location.reload() |
|
clickCounter++; |
|
}*/ |
|
|
|
//5.2 DEFINE THE INTERACTIONS FOR THE MANUAL SIMPLIFICATION |
|
selectMan.on('mousedown',function(d){ |
|
var status, trans, text; |
|
if(d=='on'){status='off'; trans = 0; text = 'Simplify manually'} |
|
else {status='on'; trans = 20; text = 'Hide slider'} |
|
selectMan.datum(status); |
|
sliderContainer.transition().duration(1500).attr('height',trans) |
|
selectManText.text(text); |
|
if(d=='off') showFeatures(10000 * 0, [0, globalData_bld2[1].length], 'arcs2', 'These are the more detailled arcs of the german states ... use the slider to simplify!') |
|
else showFeatures(10000 * 0, [globalData_bld2[1].length, 0], 'arcs2', 'Remove the Arcs of the german states') |
|
}) |
|
slider.on('mousemove',sliderAction); |
|
function sliderAction(){ |
|
var value = (d3.mouse(this)[0]); |
|
indicator.attr("x", value-4) |
|
countInfo.text('Number of geometries: ' + globalData_bld2[1].length + ' | Tolerance: ' + sliderScale.invert(value).toFixed(5)) |
|
group.selectAll("path").attr("d", setPath_); |
|
function setPath_(d){ |
|
var cache = pointsConversion(simplify(pointsConversion(d.geometry.coordinates, 'toObject'),sliderScale.invert(value),false), 'toArray') |
|
return path2({type: d.geometry.type, coordinates: cache}) |
|
} |
|
} |
|
|
|
//0.5.1 INITIALIZE THE VARIABLES TO SETUP THE ANIMATION-SELECTION |
|
var all = {'a1':0,'a2':1,'a3':2,'a4':3,'b1':4,'b2':5,'b3':6,'b4':7,'b5':8, 'c1':9, 'c2':10, 'c3':11, 'c4':12, 'c5':13, 'c6':14, 'c7':15, 'd1':16, 'd2':17}; |
|
var animateWhat = 'final_geom'; //'all' | 'basics' | 'consistency' | 'data_driven' | 'final_geom' |
|
var endless = true; |
|
var delays = getDelays(animateWhat); |
|
//0.5.2 SETUP THE SELECTION FOR THE ANIMATIONS |
|
var tags = []; |
|
for (key in all)tags.push(key) |
|
var animSel = new animationSelektor(d3.select('#selectAnimation'), tags, 960, 30) |
|
animSel.defineSupDownAction(selectBlock) |
|
//0.5.3 FUNTION THAT LISTENS FOR THE SELECTED ANIMATION |
|
function selectBlock(d){ |
|
animateWhat = d; //what animation was chosen ...GLOBAL |
|
delays = getDelays(animateWhat); //which delays are needed for this animation ...GLOBAL |
|
animation(); //apply the chosen animation |
|
//show the progress of each |
|
var partSize = animSel.partSize; |
|
if(d=='basics')animSel.defineProgressor(0,partSize*4, 10000*4) |
|
else if(d=='consistency')animSel.defineProgressor(partSize*4,partSize*5, 10000*5) |
|
else if(d=='data_driven')animSel.defineProgressor(partSize*(4+5),partSize*7, 10000*7) |
|
else if(d=='final_geom')animSel.defineProgressor(partSize*(4+5+7),partSize*2, 10000*2) |
|
else if(d=='all')animSel.moveProgressor(partSize*(4+5+7+2), 10000*(4+5+7+2)) |
|
} |
|
|
|
//Can be started automatically, but needs a timeout, because the 2nd dataset has to be fully loaded! |
|
//setTimeout(animation,3000) |
|
|
|
//MAIN FUNCTION ... EXECUTES ALL THE AUTOMATIC ANIMATIONS |
|
function animation() { |
|
console.log(animateWhat, delays) |
|
if(animateWhat=='all' || animateWhat=='basics'){ |
|
//1. BASIC SITUATION |
|
showFeatures(10000 * delays.a1, [0, 16], 'polygon', 'German States as Polygons (GeoJSON)') |
|
simplifyCurrentGeometries(10000 * delays.a2, [0, 1], 'poly', 'Simplify Polygons to high Tolerance ... failures on topology'); |
|
simplifyCurrentGeometries(10000 * delays.a3, [1, 0.1], 'poly', 'Simplify Polygons to adequate Tolerance ... failures on topology'); |
|
removeFeatures(10000 * delays.a4, [0,16], basicObjects); |
|
} |
|
if(animateWhat=='all' || animateWhat=='consistency'){ |
|
//2. Demonstrating the Arcs and how we can keep the topology |
|
showFeatures(10000 * delays.b1, [0, arcCollectionCF.groupAll().reduceCount().value()], 'arcs', 'Arcs of the German States as LineStrings (TopoJSON)') |
|
showFeatures(10000 * delays.b2, [0, arcCollectionCF.groupAll().reduceCount().value()], 'label', 'Start- & End-points of the Arcs') |
|
simplifyCurrentGeometries(10000 * delays.b3, [0, 1], 'arc', 'Simplify the Arcs to high Tolerance ... preserve topology'); |
|
simplifyCurrentGeometries(10000 * delays.b4, [1, 0.1], 'arc', 'Simplify the Arcs to adequate Tolerance ... preserve topology'); |
|
removeFeatures(10000 * delays.b5, [0,215]); |
|
} |
|
if(animateWhat=='all' || animateWhat=='data_driven'){ |
|
//3. Demonstrating the data-driven degree of simplification |
|
showFeatures(10000 * delays.c1, [0, globalData_krs2[1].length], 'arcs2', 'Arcs of the German States as LineStrings (TopoJSON ... including German Counties)') |
|
showFeatures(10000 * delays.c2, [globalData_krs2[1].length, globalData_bld2[1].length], 'arcs2', 'Remove the Arcs of the German Counties') |
|
showFeatures(10000 * delays.c3, [0, globalData_bld2[1].length], 'label2', 'Show the labels of the Arcs') |
|
showFeatures(10000 * delays.c4, [globalData_bld2[1].length, 0], 'label2', 'Remove the labels of the Arcs') |
|
simplifyCurrentGeometries(10000 * delays.c5, [0, 1], 'arc', 'Simplify the Arcs to high Tolerance ... data-driven degree of simplification'); |
|
simplifyCurrentGeometries(10000 * delays.c6, [1, 0.1], 'arc', 'Simplify the Arcs to adequate Tolerance ... data-driven degree of simplification'); |
|
showFeatures(10000 * delays.c7, [globalData_bld2[1].length, 0], 'arcs2', 'Clean up the SVG-Visualisation Area!') |
|
} |
|
//4. Finally, show the resulting polygons |
|
if(animateWhat=='all' || animateWhat=='final_geom'){ |
|
showFinalGeometries(10000 * delays.d1); |
|
removeFeatures(10000 * delays.d2, [0,16], geometryFinal); |
|
} |
|
//5. Let it never stop... |
|
if(endless == true) { |
|
var counter = 0; |
|
for(del in delays){counter++;} |
|
svgContainer.transition() |
|
.delay(10000*counter) |
|
.duration(1000) |
|
.each("end", animation); |
|
} |
|
} |
|
|
|
//SUPPORTING FUNCTIONS OF THE MAIN FUNCTION |
|
//show final features ... needed 1 time |
|
function showFinalGeometries(delay){ |
|
//simplify arcs before converting them |
|
for (arc in globalData_bld2[2]){ |
|
globalData_bld2[2][arc].coordinates = pointsConversion(simplify(pointsConversion(globalData_bld2[2][arc].coordinates, 'toObject'),parseFloat(hashValue[0]),false), 'toArray'); |
|
} |
|
geometryFinal = getGeometries(globalData_bld2[0], globalData_bld2[2]) |
|
showFeatures(delay, [0, 16], 'cons_geometry', 'Simplified Polygons of German States with preserved Topology and data-driven degree') |
|
} |
|
//show features ... needed 9 times |
|
function showFeatures(delay, range, type, head){ |
|
svgContainer.transition() |
|
.delay(delay) |
|
.duration(5000) |
|
.tween("precision", function() { |
|
heading.text(head); |
|
var pos = d3.interpolateRound(range[0], range[1]); |
|
return function(t) { |
|
position = pos(t); |
|
if(type=='arcs' || type=='label')geometryGlobal = arcsLenDim.top(position); |
|
if(type=='arcs2'){ |
|
geometryGlobal = globalData_krs2[1].slice(0,position); |
|
} |
|
else if(type=='label'){ |
|
topologyGlobal = topology; |
|
addPoints(); |
|
} |
|
else if(type=='label2'){ |
|
geometryGlobal = globalData_krs2[1].slice(0,position); |
|
addLabels(); |
|
} |
|
else if(type=='polygon'){ |
|
geometryGlobal = basicObjects.slice(0,position); |
|
} |
|
else if(type=='cons_geometry'){ |
|
geometryGlobal = geometryFinal.slice(0,position); |
|
} |
|
if(type=='arcs' || type=='arcs2' || type=='polygon' || type=='cons_geometry') countInfo.text('Number of geometries: ' + geometryGlobal.length); |
|
if(type=='arcs' || type=='arcs2') render3('line'); |
|
if(type=='polygon' || type=='cons_geometry') render3('polygon'); |
|
}; |
|
}) |
|
} |
|
//remove the features ... needed 3 times |
|
function removeFeatures(delay, range, data){ |
|
svgContainer.transition() |
|
.delay(delay) |
|
.duration(5000) |
|
.tween("precision", function() { |
|
var pos = d3.interpolateRound(range[1], range[0]); |
|
return function(t) { |
|
position = pos(t); |
|
if (data!=undefined) geometryGlobal = data.slice(0,position); |
|
else{ |
|
geometryGlobal = geometryGlobal.slice(0,position); |
|
} |
|
heading.text('Clean up the SVG-Visualisation Area!'); |
|
countInfo.text('Number of geometries: ' + geometryGlobal.length) |
|
group.selectAll("path").data(geometryGlobal, function(d){return d.geometry.coordinates}) |
|
.transition().duration(5000) |
|
.attr("transform","translate(0,0) scale(-1,1)") |
|
.remove() |
|
group.selectAll("circle").remove(); |
|
}; |
|
}) |
|
} |
|
//simplify the geometries that lie currently in the svg-container ... 6 times, each animated simplification |
|
function simplifyCurrentGeometries(delay, range, type, value){ |
|
svgContainer.transition() |
|
.delay(delay) |
|
.duration(5000) |
|
.tween("precision", function() { |
|
var sim = d3.interpolate(range[0], range[1]); |
|
return function(t) { |
|
simpleVal = sim(t); |
|
group.selectAll("path").attr("d", setPath_) |
|
heading.text(value); |
|
if(type!='arc')countInfo.text('Number of geometries: ' + geometryGlobal.length + ' | Tolerance: ' + simpleVal.toFixed(5)) |
|
else countInfo.text('Number of geometries: ' + globalData_bld2[1].length + ' | Tolerance: ' + simpleVal.toFixed(5)) |
|
function setPath_(d){ |
|
if(type=='poly') var cache = polygonSimplification2(d, simpleVal) |
|
else if(type=='arc') var cache = pointsConversion(simplify(pointsConversion(d.geometry.coordinates, 'toObject'),simpleVal,false), 'toArray') |
|
return path2({type: d.geometry.type, coordinates: cache}) |
|
} |
|
}; |
|
}) |
|
} |
|
|
|
//THIS IS THE ANIMATION OF GEOMETRIES ... CALLED WITHIN THE TRANSITION-TWEEN |
|
function render3(style){ |
|
//1. JOIN |
|
var feature = group.selectAll("path").data(geometryGlobal, function(d){return d.geometry.coordinates}) |
|
//3. ENTER |
|
feature.enter() |
|
.append("path") |
|
.attr("class",style) |
|
.attr('id',function(d){return "arc"+d.id}) |
|
.on('mouseover', function(d){d3.select(this).style('stroke',strokeColors[0])}) |
|
.on('mouseout', function(d){d3.select(this).style('stroke',strokeColors[1])}) |
|
.style('stroke',strokeColors[0]) |
|
.attr("d", path2) |
|
.attr("transform","translate(0,0) scale(-1,1)") |
|
.transition().duration(4000) |
|
.attr("transform","translate(0,0) scale(1,1)") |
|
.transition().duration(1000) |
|
.style('stroke',strokeColors[1]); |
|
//5. EXIT |
|
feature.exit().remove(); |
|
|
|
function setPath(d){ return path2(d.geometry)} |
|
} |
|
//THIS IS THE ANIMATION OF LABELS ... CALLED WITHIN THE TRANSITION-TWEEN |
|
function addLabels(){ |
|
//1. JOING |
|
var labels = group.selectAll("text").data(geometryGlobal, function(d){return d.geometry.coordinates}); |
|
//3. ENTER |
|
labels.enter() |
|
.append('text') |
|
.attr('font-size',12) |
|
.text(function(d){if(d.members.length == 2) return d.id}) |
|
.attr("fill",'#00f') |
|
.attr('x',function(d){return path2.centroid({'type':'Feature','geometry':d.geometry})[0]}) |
|
.attr('y',function(d){return path2.centroid({'type':'Feature','geometry':d.geometry})[1]}) |
|
.attr("opacity",0) |
|
.transition().duration(3000) |
|
.attr("opacity",0.7) |
|
//5. EXIT |
|
labels.exit().transition().duration(3000).attr("opacity","0").remove(); |
|
|
|
} |
|
function addPoints(){ |
|
var tf = topologyGlobal.transform, |
|
kx = tf.scale[0], |
|
ky = tf.scale[1], |
|
dx = tf.translate[0], |
|
dy = tf.translate[1]; |
|
|
|
group.selectAll("circle") |
|
.data(topologyGlobal.arcs) |
|
.enter().append("circle") |
|
.attr("cx", function(d) { return project([d[0][0] * kx + dx, d[0][1] * ky + dy])[0] }) |
|
.attr("cy", function(d) { return project([d[0][0] * kx + dx, d[0][1] * ky + dy])[1] }) |
|
.attr("r", 0) |
|
.attr("fill", '#f00') |
|
.attr("opacity", 0) |
|
.transition().duration(2000) |
|
.attr("opacity", 0.7) |
|
.attr("r", 20) |
|
.transition().delay(2200).duration(2000) |
|
.attr("r", 2) |
|
//.transition().delay(3500+3000).duration(3000).attr("opacity", 0.3).remove(); |
|
|
|
} |
|
|
|
//RESET THE SVG-OVERLAY AND THE GROUPS WHEN THE ZOOMLEVEL OF THE MAP HAS CHANGED |
|
function reset() { |
|
var bottomLeft = project(overlayBounds[0]), |
|
topRight = project(overlayBounds[1]); |
|
|
|
svgContainer.attr("width", topRight[0] - bottomLeft[0]) |
|
.attr("height", bottomLeft[1] - topRight[1]) |
|
.style("margin-left", bottomLeft[0] + "px") |
|
.style("margin-top", topRight[1] + "px"); |
|
|
|
group.attr("transform", "translate(" + -bottomLeft[0] + "," + -topRight[1] + ")"); |
|
|
|
group.selectAll("path").attr("d", path2) |
|
|
|
group.selectAll('text') |
|
.attr('x',function(d){return path2.centroid({'type':'Feature','geometry':d.geometry})[0]}) |
|
.attr('y',function(d){return path2.centroid({'type':'Feature','geometry':d.geometry})[1]}) |
|
|
|
} |
|
|
|
//GET THE CORRESPONDING DELAYS FOR EACH POSSIBLE ANIMATION |
|
function getDelays(animateWhat_){ |
|
switch(animateWhat_) |
|
{ |
|
case 'all': |
|
var delays = all; |
|
break; |
|
case 'basics': |
|
var delays = {'a1':0,'a2':1,'a3':2,'a4':3}; |
|
break; |
|
case 'consistency': |
|
var delays = {'b1':0,'b2':1,'b3':2,'b4':3,'b5':4}; |
|
break; |
|
case 'data_driven': |
|
var delays = {'c1':0, 'c2':1, 'c3':2, 'c4':3, 'c5':4, 'c6':5, 'c7':6}; |
|
break; |
|
case 'final_geom': |
|
var delays = {'d1':0, 'd2':1}; |
|
break; |
|
} |
|
return delays; |
|
} |
|
|
|
//DOES THE FILTERING ON A CROSSFILTER-OBJECT ... not really needed! |
|
function filter(){ |
|
//Filtering |
|
arcsLenDim.filterAll(); //reset filter |
|
var origCount = arcCollectionCF.groupAll().reduceCount().value(); //count elements initially |
|
//arcsLenDim.filter(function(d){return (d < selMaxVal)}) //filter the dataset |
|
counter = arcCollectionCF.groupAll().reduceCount().value(); //count elements after filtering |
|
} |
|
}); |
|
|
|
//PROJECT POINT OF OVERLAY TO LEAFLET-SVG-COORDINATES (LayerPoint) |
|
function project(point) { |
|
var latlng = new L.LatLng(point[1], point[0]); |
|
var layerPoint = map.latLngToLayerPoint(latlng); |
|
return [layerPoint.x, layerPoint.y]; |
|
} |
|
//CONVERT POINTS 'toARRAY' || 'toOBJECT' - NEEDED FOR THE SIMPLIFICATION LIBRARY simplify.js |
|
function pointsConversion(points, direction){ |
|
var cache; |
|
if(direction=='toObject'){ |
|
cache = points.map(function(point){return {'y':point[0],'x':point[1]}}); |
|
} |
|
else if(direction=='toArray'){ |
|
cache = points.map(function(point){return [point.y,point.x]}); |
|
} |
|
return cache; |
|
} |
|
//SIMPLE POLYGON SIMPLIFICATION - WITHOUT ANY ADHERANCE OF TOPOLOGY |
|
function polygonSimplification2(feature, maxVal_){ |
|
if (feature.geometry.type=='Polygon')var cache_ = readPoly(feature.geometry.coordinates.slice(0)); |
|
else if (feature.geometry.type=='MultiPolygon'){ |
|
var cache_ = feature.geometry.coordinates.slice(0); |
|
cache_ = cache_.map(function(single_poly){return readPoly(single_poly); }) |
|
} |
|
return cache_; |
|
function readPoly(polygon){ |
|
return polygon.map(function(poly_part){ |
|
return pointsConversion(simplify(pointsConversion(poly_part, 'toObject'),maxVal_,false), 'toArray') |
|
}) |
|
} |
|
} |
|
</script> |
|
</body> |
|
</html> |