From ca712fb2572757be6d0462bab9bd339629e6e5de Mon Sep 17 00:00:00 2001 From: Stein Runar Bergheim Date: Fri, 15 Jul 2016 10:40:32 +0300 Subject: [PATCH 1/2] Modifications to map helper, routing test --- dist/s4a.js | 10 ++++++---- dist/s4a.min.js | 6 +++--- src/map/MapHelper.js | 2 +- src/mobile/File.js | 6 ++++-- test/analytics/Routing.test.html | 12 +++++++++--- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/dist/s4a.js b/dist/s4a.js index c752ee3..ecf06f4 100644 --- a/dist/s4a.js +++ b/dist/s4a.js @@ -1,4 +1,4 @@ -/*! s4a - v1.0.0 - 2016-05-06 +/*! s4a - v1.0.0 - 2016-06-21 * https://github.com/SDI4Apps/s4a.js * Copyright (c) 2016 SDI4Apps Partnership; Licensed */ 'use strict'; @@ -1135,7 +1135,7 @@ s4a.map.MapHelper = function(nodeSelector, config) { var _map = new ol.Map({ layers: [ - _config.baseMaps.OFFLINE + _config.baseMaps.MAPQUEST ], target: nodeSelector, view: new ol.View({ @@ -1621,7 +1621,8 @@ s4a.mobile.File = (function() { }; fileWriter.onerror = function(e) { - promise.resolve(s4a.mobile.FileResponse.createError(e.toString())); + promise.resolve(s4a.mobile.FileResponse + .createError('Error writing file: ' + e.toString())); }; var blob = new Blob([JSON.stringify(contents, null, '\t')], {type: 'text/plain'}); @@ -1629,7 +1630,8 @@ s4a.mobile.File = (function() { }); } else { - promise.resolve(s4a.mobile.FileResponse.createError(fileResponse.messages)); + promise.resolve(s4a.mobile.FileResponse + .createError('Error getting file entry: ' + fileResponse.messages)); } }); diff --git a/dist/s4a.min.js b/dist/s4a.min.js index 963adc3..ad11f28 100644 --- a/dist/s4a.min.js +++ b/dist/s4a.min.js @@ -1,5 +1,5 @@ -/*! s4a - v1.0.0 - 2016-05-06 +/*! s4a - v1.0.0 - 2016-06-21 * https://github.com/SDI4Apps/s4a.js * Copyright (c) 2016 SDI4Apps Partnership; Licensed */ -"use strict";var s4a=function(){var a={},b="http://portal.sdi4apps.eu/openapi",c=null;return a.version="1.0",a.proxy=function(a){return void 0!==a&&(c=a),c},a.openApiUrl=function(a){return void 0!==a&&(b=a),b},a.extend=function(a){var b,c,d=a.split("."),e=s4a;for(b=d.length,c=0;b>c;c++)"undefined"==typeof e[d[c]]&&(e[d[c]]={}),e=e[d[c]];return e},a.doPost=function(a,b,c){void 0===c&&(c="json");var d=s4a.openApiUrl()+a;return jQuery.post(d,b,null,c)},a.doGet=function(a,b,c){void 0===c&&(c="json");var d=s4a.openApiUrl()+a;return jQuery.get(d,b,null,c)},a}();s4a.extend("config"),s4a.config=function(){var a={};return a.loadConfig=function(a){a=a||{};var b={center:{x:6.45996,y:49.92294,epsg:"EPSG:4326",zoom:4},baselayers:[new ol.layer.Tile({source:new ol.source.TileWMS({url:"http://opencache.statkart.no/gatekeeper/gk/gk.open?",params:{LAYERS:"norges_grunnkart",VERSION:"1.1.1"}})})],layers:[]};return jQuery.extend(b,a)},a}(),s4a.extend("analytics"),s4a.analytics.Routing=function(){var a={},b="/routing";return a.getShortestRoute=function(a,c){var d={action:"GetShortestPath",from:a,to:c};return s4a.doPost(b,d)},a.getNearestNode=function(a,c,d){void 0===d&&(d=100);var e={action:"GetNearestNode",lon:a,lat:c,radius:d};return s4a.doPost(b,e)},a.getOptimalRoute=function(a,c,d){var e={action:"GetOptimalRoute",nodeIds:a.concat([d,c]),start:c,finish:d};return s4a.doPost(b,e)},a.getReachableArea=function(a,c){var d={action:"GetReachableArea",fromNode:a,distance:c};return s4a.doPost(b,d)},a}(),s4a.extend("data"),s4a.data.SensLog=function(){var a={},b="/../SensLog/ControllerServlet",c="/../SensLog/FeederServlet",d="/../SensLog/DataService",e="/../SensLog/SensorService",f=function(a){var b=a.getFullYear(),c=(a.getMonth()+1).toString();1===c.length&&(c="0"+c);var d=a.getDate().toString();1===d.length&&(d="0"+d);var e=a.getHours().toString();1===e.length&&(e="0"+e);var f=a.getMinutes().toString();1===f.length&&(f="0"+f);var g=a.getSeconds().toString();return 1===g.length&&(g="0"+g),b+"-"+c+"-"+d+"T"+e+":"+f+":"+g};a.toSensLogDate=f;var g=function(a){var b=a.split(" "),c=b[0].split("-"),d=b[1].split("+"),e=d[0].split(":"),f=new Date(+c[0],+c[1]-1,+c[2],+e[0],+e[1],+e[2]);return f};a.toJsDate=g;var h=function(a){var b=a.getFullYear(),c=(a.getMonth()+1).toString();1===c.length&&(c="0"+c);var d=a.getDate().toString();1===d.length&&(d="0"+d);var e=a.getHours().toString();1===e.length&&(e="0"+e);var f=a.getMinutes().toString();1===f.length&&(f="0"+f);var g=a.getSeconds().toString();return 1===g.length&&(g="0"+g),b+"-"+c+"-"+d+" "+e+":"+f+":"+g};return a.toIsoDate=h,a.login=function(a,c){return s4a.doPost(b,{username:a,password:c})},a.insertPosition=function(a,b,d,e){return s4a.doGet(c,{Operation:"InsertPosition",lat:a,lon:b,unit_id:d,date:f(e)},"text")},a.insertObservation=function(a,b,d,e){return s4a.doGet(c,{Operation:"InsertObservation",value:a,unit_id:b,sensor_id:d,date:f(e)},"text")},a.getLastPositions=function(a){return s4a.doGet(d,{Operation:"GetLastPositions",user:a})},a.getLastPosition=function(b,c){return a.getLastPositions(c).then(function(a){for(var c=0;ca.maxx)&&(a.maxx=b),(null===a.miny||ca.maxy)&&(a.maxy=c)},this.extendByCoordinate=function(a){return this.extendByXY(a[0],a[1])},this.extent=a},s4a.extend("map"),s4a.map.GeometryType={point:"point",line:"line",polygon:"polygon",none:"none"},s4a.map.ITool={label:"Button",toolType:null,geomType:s4a.map.GeometryType.none,icon:"button.png",onClick:function(a){console.log("Must be overridden by derived class")},onDoubleClick:function(a){console.log("Must be overridden by derived class")},onActivate:function(){console.log("Must be overridden by derived class")},onDeactivate:function(){console.log("Must be overridden by derived class")}},s4a.map.LayerSwitcher=function(){this.test=1},s4a.extend("map"),s4a.map.Map=function(a,b){var c,d=this,e=[];b=b||s4a.config.loadConfig();var f=[b.center.x,b.center.y],g="EPSG:3857";b.center.epsg!==g&&(f=ol.proj.transform(f,b.center.epsg,g));var h=new ol.Map({layers:[new ol.layer.Group({title:"Base layer",layers:b.baselayers}),new ol.layer.Group({title:"Overlays",layers:b.layers})],renderer:"canvas",target:a,view:new ol.View({center:f,zoom:b.center.zoom})});return h.on("postcompose",function(a){d.redraw()}),d.add=function(a){a.setMap(d),e.push(a)},d.addKey=function(a){c=a},d.createMapLayer=function(a,b){var d={key:c,LAYERS:a};return new ol.layer.Image({source:new ol.source.ImageWMS({url:"http://localhost/a_a3_mapserver/mapserv.ashx",params:$.extend(d,b)})})},d.getDomElement=function(){return $(h.getViewport())},d.getOlMap=function(){return h},d.projectPoint=function(a,b){var c=ol.proj.transform([a,b],"EPSG:4326","EPSG:3857");return h.getPixelFromCoordinate(c)},d.redraw=function(){jQuery.each(e,function(a,b){b.redraw()})},d.removeAt=function(a){e=e.filter(function(b,c){return c!==a})},d.removeObjects=function(a){e=e.filter(function(b){return b!==a})},d},s4a.map.MapHelper=function(a,b){var c=this;if(void 0===a)throw"The parameter nodeSelector is mandatory";var d={zoomLevel:14,extent:[-179,-85,179,85],layers:[],center:{lon:6.11,lat:49.58},activeLayer:0,tools:[],activeTool:0,baseMaps:{MAPQUEST:new ol.layer.Tile({source:new ol.source.MapQuest({layer:"osm"})}),OFFLINE:new ol.layer.Vector({source:new ol.source.Vector({format:new ol.format.GeoJSON,projection:"EPSG:3857",url:"../../data/countries.json",style:new ol.style.Style({fill:new ol.style.Fill({color:"rgba(255, 255, 0, 0)"}),stroke:new ol.style.Stroke({color:"#ff0000",width:1})})})})}};void 0!==b&&jQuery.extend(d,b);var e=new ol.Map({layers:[d.baseMaps.OFFLINE],target:a,view:new ol.View({center:ol.proj.transform([d.center.lon,d.center.lat],"EPSG:4326","EPSG:3857"),zoom:d.zoomLevel})});this.transform=function(a,b){var c=null;return c=b===!0?ol.proj.transform(a,"EPSG:3857","EPSG:4326"):ol.proj.transform(a,"EPSG:4326","EPSG:3857")},this.getExtent=function(){return e.getView().calculateExtent(e.getSize())},this.zoomToExtent=function(a,b){b=b||14,e.getView().fit(a,e.getSize()),e.getView().getZoom()>b&&e.getView().setZoom(b)},this.addTool=function(a){return c},this.addData=function(a){var b=new ol.layer.Vector({source:new ol.source.GeoJSON({projection:"EPSG:3857",url:"data/countries.json"})});return e.addLayer(b),c},this.draw=function(){return c},this.listenDoubleClick=function(a){return this.getMap().on("dblclick",a),c},this.listenSingleClick=function(a){return this.getMap().on("singleclick",a),c},this.getMap=function(){return e}},s4a.map.ToolType={BUTTON:"button",TOOL:"tool",INPUT:"input"},s4a.extend("map"),s4a.map.Transform=function(){var a={},b=function(a,b,c){return ol.proj.transform(c,"EPSG:"+a,"EPSG:"+b)};return a.fromTo=function(a,c,d){return b(a,c,d)},a.to3857=function(a){return b(4326,3857,a)},a.to4326=function(a){return b(3857,4326,a)},a.extentTo3857=function(a){var c=b(4326,3857,[a[0],a[1]]),d=b(4326,3857,[a[2],a[3]]);return[c[0],c[1],d[0],d[1]]},a.extentTo4326=function(a){var c=b(3857,4326,[a[0],a[1]]),d=b(3857,4326,[a[2],a[3]]);return[c[0],c[1],d[0],d[1]]},a}(),s4a.map.VizLayer=function(){var a=this,b=!0,c="s4a-map",d=[];a.add=function(b){e(b.getSvg()),$(b).on("resize",a.redraw),d.push(b)};var e=function(a){var b=d3.select("div.ol-viewport"),d=b.select("div."+c);d.empty()&&(d=b.append("div").classed(c,!0)),d.append(function(){return a.node()}),a.style("position","fixed")};return a.getVisible=function(){return b},a.getPosition=function(b){return a.map.projectPoint(b[0],b[1])},a.redraw=function(){a.map&&jQuery.each(d,function(b,c){var d=c.getGeometry(),e=c.getSvg();if(d&&e){var f,g=(e.selectAll("g"),e.attr("width")/2);switch(d.type){case"point":f=a.getPosition(d.coordinates);break;default:console.warn("s4a.map.VizLayer","Unsupported geometry type",d.type)}if(!f)return;f[0]-=g,f[1]-=g,e.style("left",f[0]+"px").style("top",f[1]+"px")}})},a.removeAt=function(b){$(d[b]).unbind("resize",a.redraw),d=d.filter(function(a,c){return c!==b})},a.removeObjects=function(b){$(b).unbind("resize",a.redraw),d=d.filter(function(a){return a!==b})},a.setMap=function(b){a.map=b},a.setVisible=function(a){b=a,d.forEach(function(b){b.setVisible(a)})},a},s4a.extend("mobile"),s4a.mobile.FeatureSync=function(){var a={};return a.CheckOut=function(){},a.CheckIn=function(){},a.GetConflicts=function(){},a.Resolve=function(){},a}(),s4a.extend("mobile"),s4a.mobile.File=function(){var a={};return a.getFileEntry=function(a,b){var c=jQuery.Deferred();return void 0!==window.cordova&&void 0!==window.cordova.file?(void 0===b&&(b=window.cordova.file.dataDirectory),window.resolveLocalFileSystemURL(b,function(b){b.getFile(a,{create:!0},function(a){c.resolve(s4a.mobile.FileResponse.createSuccess(a))},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))})},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))})):c.resolve(s4a.mobile.FileResponse.createError('Requires Cordova with "cordova-plugin-file".')),c},a.writeFile=function(b,c){var d=jQuery.Deferred();return a.getFileEntry(b).then(function(a){a.isSuccess()?a.data.createWriter(function(a){a.onwriteend=function(){d.resolve(s4a.mobile.FileResponse.createSuccess(c))},a.onerror=function(a){d.resolve(s4a.mobile.FileResponse.createError(a.toString()))};var b=new Blob([JSON.stringify(c,null," ")],{type:"text/plain"});a.write(b)}):d.resolve(s4a.mobile.FileResponse.createError(a.messages))}),d},a.readFile=function(b){var c=jQuery.Deferred();return a.getFileEntry(b).then(function(a){a.isSuccess()?a.data.file(function(a){var b=new FileReader;b.onloadend=function(){c.resolve(s4a.mobile.FileResponse.createSuccess(JSON.parse(this.result)))},b.readAsText(a)},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))}):c.resolve(s4a.mobile.FileResponse.createError(a.messages))}),c},a}(),s4a.extend("mobile"),s4a.mobile.FileResponse=function(a,b,c){this.status=void 0,void 0!==a&&null!==a?this.status=a:a=!0,this.data=void 0,void 0!==b&&null!==b&&(this.data=b),this.messages=[],void 0!==c&&null!==c&&this.messages.push(c),this.isSuccess=function(){return this.status===!0?!0:!1},this.isError=function(){return this.status===!1?!0:!1},this.getMessages=function(){for(var a=0;a=e&&" "!==b[g]&&"-"!==b[g];)g-=1,e++;if(console.log(e),d.push(b.substring(f,g).trim()),f=g,g=f+c,g>=b.length){d.push(b.substring(f,g).trim());break}}return d},m=function(a,b){return 0===a?0:b};return b.updateLegend=function(){for(var b=0;bh){o.text(null);for(var q=Math.ceil(1.15*a.fontSize),r=Math.ceil(p/h),s=l(r,n),t=0;t"),jQuery(a).append(x)),i=x.prop("height",w).prop("width",v)[0].getContext("2d"),j=b.domains.map(function(a){return Number(a)})||null,k=null!==b.colors&&b.colors.length>=1?s4a.viz.color[b.colors[0]][j.length]:s4a.viz.color.Reds[j.length],l=null!==b.colors&&b.colors.length>=2?s4a.viz.color[b.colors[1]][j.length]:s4a.viz.color.Blues[j.length],m=s4a.viz.Sizes.medium,n=d3.scale.threshold().domain(j).range(k),o=d3.scale.threshold().domain(j).range(l),p=null!==m?d3.scale.threshold().domain(j).range(m):null,q={},r={},s=[],t={},u=[];for(var y=0,z=b.mapUnitIDs.length;z>y;y++)r[b.mapUnitIDs[y]]=Number(b.seriesData[y]),q[b.mapUnitIDs[y]]=Number(b.seriesData[y][b.showSeries[0]]),s.push(Number(b.seriesData[y][b.showSeries[0]]));if(2===b.showSeries.length)for(y=0,z=b.mapUnitIDs.length;z>y;y++)t[b.mapUnitIDs[y]]=Number(b.seriesData[y][b.showSeries[1]]),u.push(Number(b.seriesData[y][b.showSeries[1]]));(null===b.title||void 0===b.title||""===b.title)&&(b.showSeries.length>1?b.title=b.seriesLabels[b.showSeries[0]]+" / "+b.seriesLabels[b.showSeries[2]]:b.title=b.seriesLabels[b.showSeries[0]]),queue().defer(d3.json,"./data/data-topojson.json").defer(d3.json,"./data/sea.json").await(function(a,j,l){return c=d3.geo.transverseMercator().scale(1).translate([0,0]),d=d3.geo.path().projection(c),e=topojson.feature(j,j.objects.kommune).features.filter(function(a){return-1!==b.mapUnitIDs.indexOf(a.id.toString())}),f=s4a.viz.map.util.getFeatureCollectionBounds(d,e),g=.95/Math.max((f[1][0]-f[0][0])/v,(f[1][1]-f[0][1])/w),h=[(v-g*(f[1][0]+f[0][0]))/2,(w-g*(f[1][1]+f[0][1]))/2],c.scale(g).translate(h),i.clearRect(0,0,v,w),i.fillStyle="#ffffff",i.fillRect(0,0,v,w),s4a.viz.map.shared._drawLand(i,d,l),("choroplethMap"===b.mapType||"bubbleChoroplethMap"===b.mapType)&&s4a.viz.map.shared._drawPolygons(e,q,n,d,i),s4a.viz.map.shared._drawMunicipality(i,d,j),s4a.viz.map.shared._drawCounty(i,d,j),"bubbleMap"===b.mapType?s4a.viz.map.shared._drawBubbles(e,q,p,n,d,i):"bubbleChoroplethMap"===b.mapType?s4a.viz.map.shared._drawBubbles(e,t,p,o,d,i):"pieChartMap"===b.mapType&&s4a.viz.map.shared._drawPieCharts(e,r,k,d,i),s4a.viz.map.shared._drawLabels(i,d,e,b.fontSize-2),s4a.viz.map.shared._drawRectSymMapLegend(i,n,b.title,Number(b.fontSize)),i})},s4a.viz.map.shared={},s4a.viz.map.shared._drawChartTitle=function(a,b,c,d,e){return a.font="bolder "+b+"px Arial",a.textAlign="start",a.fillStyle="#000000",a.fillText(c,d,e),e+=2*b},s4a.viz.map.shared._drawRectSymMapLegend=function(a,b,c,d){d=void 0!==d?d:s4a.viz.map.FontSizes.normal;var e=10,f=10,g=1.8*d,h=20,i=d+4,j=f+d,k=s4a.viz.map.util.getLongestStringInArray(b.domain());a.font=d+"px Arial";var l=2*a.measureText(k).width;void 0!==c&&null!==c&&""!==c&&(j=s4a.viz.map.shared._drawChartTitle(a,d,c,e,j)),a.font=d+"px Arial",a.textAlign="end";for(var m=b.domain().length-1;m>0;m--){var n;n=m===b.domain().length-1?"> "+jQuery.number(b.domain()[m-1]):1===m?"< "+jQuery.number(b.domain()[m]):jQuery.number(b.domain()[m-1])+" - "+jQuery.number(b.domain()[m]),a.fillStyle=b.range()[m],a.strokeStyle="#000000",a.lineWidth=.2,a.beginPath(),a.rect(e,j-d,h,i),a.globalAlpha=s4a.viz.map.StatAreaAlpha,a.fill(),a.globalAlpha=1,a.stroke(),a.fillStyle="#000000",a.fillText(n,e+h+e+l,j),j+=g}},s4a.viz.map.shared._drawPolygons=function(a,b,c,d,e){e.globalAlpha=s4a.viz.map.StatAreaAlpha;var f=c.domain(),g=Math.max.apply(null,f),h=Math.min.apply(null,f);a.forEach(function(a){var f=b[a.id];f=g>f?f:g-1e-4,f=f>=h?f:h;var i=c(f);void 0!==i&&(e.fillStyle=i,e.beginPath(),d.context(e)(a),e.fill())}),e.globalAlpha=1},s4a.viz.map.shared._drawPieCharts=function(a,b,c,d,e){e.globalAlpha=s4a.viz.map.StatAreaAlpha,a.forEach(function(a){for(var f=25,g=s4a.viz.map.util.valuesToSlices(b[a.id]),h=1.5*Math.PI,i=d.centroid(a),j=0,k=g.length;k>j;j++){var l=Number(g[j])*(2*Math.PI)/100,m=h+l;m>2*Math.PI&&(m-=2*Math.PI),e.fillStyle=c[j],e.lineWidth=2,e.strokeStyle="rgba(0,0,0,0.25)",e.beginPath(),e.moveTo(i[0],i[1]),e.arc(i[0],i[1],f,h,m,!1),e.closePath(),e.fill(),e.stroke(),h+=l}})},s4a.viz.map.shared._drawCircleSymMapLegend=function(a,b,c){var d=12,e=10,f=10,g=1.5*d,h=f+d,i=s4a.viz.map.util.getLengthOfLongest(b.domain())*(d/1.5);a.font=d+"px Arial Bold",a.textAlign="start",a.fillStyle="#000000",a.fillText("Teiknforklaring",e,h),h+=g,a.font=d+"px Arial",a.textAlign="end";for(var j=b.domain().length-1;j>0;j--){var k=jQuery.number(b.domain()[j-1])+" - "+jQuery.number(b.domain()[j]);a.fillStyle=b.range()[j],a.strokeStyle="#000000",a.lineWidth=.2,a.beginPath(),a.arc(e,h-d/2,6,0,2*Math.PI,!1),a.globalAlpha=s4a.viz.map.StatAreaAlpha,a.fill(),a.globalAlpha=1,a.stroke(),a.fillStyle="#000000",a.fillText(k,e+i,h),h+=g}},s4a.viz.map.shared._drawBubbles=function(a,b,c,d,e,f){f.globalAlpha=s4a.viz.map.StatAreaAlpha,a.forEach(function(a){var g=c(b[a.id]),h=d(b[a.id]);if(void 0!==g){var i=e.centroid(a);f.beginPath(),f.arc(i[0],i[1],g,0,2*Math.PI,!1),f.fillStyle=h,f.fill(),f.lineWidth=2,f.strokeStyle="rgba(0,0,0,0.25)",f.stroke()}}),f.globalAlpha=1},s4a.viz.map.shared._drawLabels=function(a,b,c,d){d=void 0!==d?d:s4a.viz.map.FontSizes.small,c.forEach(function(c){var e=b.centroid(c);a.font=d+"px Arial",a.textAlign="center",a.fillStyle="#000000",a.fillText(c.properties.name,e[0],e[1])})},s4a.viz.map.shared._drawGeoJson=function(a,b,c,d,e,f){a.strokeStyle=d||"transparent",a.lineWidth=f,a.fillStyle=e||"transparent",a.beginPath(),b.context(a)(c),"transparent"!==e&&a.fill(),"transparent"!==d&&a.stroke()},s4a.viz.map.shared._drawMunicipality=function(a,b,c){var d=topojson.mesh(c,c.objects.kommune,function(a,b){return a.id!==b.id});s4a.viz.map.shared._drawGeoJson(a,b,d,"#000000",null,.5)},s4a.viz.map.shared._drawCounty=function(a,b,c){var d=topojson.mesh(c,c.objects.fylke,function(a,b){return a.id!==b.id});s4a.viz.map.shared._drawGeoJson(a,b,d,"#000000",null,1)},s4a.viz.map.shared._drawLand=function(a,b,c){var d=topojson.feature(c,c.objects.sea);s4a.viz.map.shared._drawGeoJson(a,b,d,"#999999","#eeeeee",.2)},s4a.viz.map.Symbol=function(){},s4a.viz.map.util={},s4a.viz.map.util.secureReload=function(a){var b=a.indexOf(!0)?"?":"&";return a+b+"rnd="+(100*Math.random()).toString()},s4a.viz.map.util.getLengthOfLongest=function(a){var b=0;if(null!==a&&a.length>1)for(var c,d=a.length-1;d>0;d--){var e=jQuery.number(a[d-1])+" - "+jQuery.number(a[d]);c=e.length,c>b&&(b=c)}return b},s4a.viz.map.util.getLongestStringInArray=function(a){var b=a.slice();return b.sort(function(a,b){return b.toString().length-a.toString().length})[0]},s4a.viz.map.util.getTotal=function(a){for(var b=0,c=0;cd;d++){var f=a.bounds(b[d]);(!c[0][0]||f[0][0]c[1][0])&&(c[1][0]=f[1][0]),(!c[1][1]||f[1][1]>c[1][1])&&(c[1][1]=f[1][1])}return c},s4a.viz.map.util.valuesToSlices=function(a){if(void 0!==a&&"object"==typeof a&&Array.isArray(a)===!0){for(var b=0,c=0,d=a.length;d>c;c++)b+=Number(a[c]);var e=[];for(c=0,d=a.length;d>c;c++)e.push(100*Number(a[c])/b);return e}return a},s4a.viz.map.util={},s4a.viz.map.util.secureReload=function(a){var b=a.indexOf(!0)?"?":"&";return a+b+"rnd="+(100*Math.random()).toString()},s4a.viz.map.util.getLengthOfLongest=function(a){var b=0;if(null!==a&&a.length>1)for(var c,d=a.length-1;d>0;d--){var e=jQuery.number(a[d-1])+" - "+jQuery.number(a[d]);c=e.length,c>b&&(b=c)}return b},s4a.viz.map.util.getLongestStringInArray=function(a){var b=a.slice();return b.sort(function(a,b){return b.toString().length-a.toString().length})[0]},s4a.viz.map.util.getTotal=function(a){for(var b=0,c=0;cd;d++){var f=a.bounds(b[d]);(!c[0][0]||f[0][0]c[1][0])&&(c[1][0]=f[1][0]),(!c[1][1]||f[1][1]>c[1][1])&&(c[1][1]=f[1][1])}return c},s4a.viz.map.util.valuesToSlices=function(a){if(void 0!==a&&"object"==typeof a&&Array.isArray(a)===!0){for(var b=0,c=0,d=a.length;d>c;c++)b+=Number(a[c]);var e=[];for(c=0,d=a.length;d>c;c++)e.push(100*Number(a[c])/b);return e}return a}; \ No newline at end of file +"use strict";var s4a=function(){var a={},b="http://portal.sdi4apps.eu/openapi",c=null;return a.version="1.0",a.proxy=function(a){return void 0!==a&&(c=a),c},a.openApiUrl=function(a){return void 0!==a&&(b=a),b},a.extend=function(a){var b,c,d=a.split("."),e=s4a;for(b=d.length,c=0;b>c;c++)"undefined"==typeof e[d[c]]&&(e[d[c]]={}),e=e[d[c]];return e},a.doPost=function(a,b,c){void 0===c&&(c="json");var d=s4a.openApiUrl()+a;return jQuery.post(d,b,null,c)},a.doGet=function(a,b,c){void 0===c&&(c="json");var d=s4a.openApiUrl()+a;return jQuery.get(d,b,null,c)},a}();s4a.extend("config"),s4a.config=function(){var a={};return a.loadConfig=function(a){a=a||{};var b={center:{x:6.45996,y:49.92294,epsg:"EPSG:4326",zoom:4},baselayers:[new ol.layer.Tile({source:new ol.source.TileWMS({url:"http://opencache.statkart.no/gatekeeper/gk/gk.open?",params:{LAYERS:"norges_grunnkart",VERSION:"1.1.1"}})})],layers:[]};return jQuery.extend(b,a)},a}(),s4a.extend("analytics"),s4a.analytics.Routing=function(){var a={},b="/routing";return a.getShortestRoute=function(a,c){var d={action:"GetShortestPath",from:a,to:c};return s4a.doPost(b,d)},a.getNearestNode=function(a,c,d){void 0===d&&(d=100);var e={action:"GetNearestNode",lon:a,lat:c,radius:d};return s4a.doPost(b,e)},a.getOptimalRoute=function(a,c,d){var e={action:"GetOptimalRoute",nodeIds:a.concat([d,c]),start:c,finish:d};return s4a.doPost(b,e)},a.getReachableArea=function(a,c){var d={action:"GetReachableArea",fromNode:a,distance:c};return s4a.doPost(b,d)},a}(),s4a.extend("data"),s4a.data.SensLog=function(){var a={},b="/../SensLog/ControllerServlet",c="/../SensLog/FeederServlet",d="/../SensLog/DataService",e="/../SensLog/SensorService",f=function(a){var b=a.getFullYear(),c=(a.getMonth()+1).toString();1===c.length&&(c="0"+c);var d=a.getDate().toString();1===d.length&&(d="0"+d);var e=a.getHours().toString();1===e.length&&(e="0"+e);var f=a.getMinutes().toString();1===f.length&&(f="0"+f);var g=a.getSeconds().toString();return 1===g.length&&(g="0"+g),b+"-"+c+"-"+d+"T"+e+":"+f+":"+g};a.toSensLogDate=f;var g=function(a){var b=a.split(" "),c=b[0].split("-"),d=b[1].split("+"),e=d[0].split(":"),f=new Date(+c[0],+c[1]-1,+c[2],+e[0],+e[1],+e[2]);return f};a.toJsDate=g;var h=function(a){var b=a.getFullYear(),c=(a.getMonth()+1).toString();1===c.length&&(c="0"+c);var d=a.getDate().toString();1===d.length&&(d="0"+d);var e=a.getHours().toString();1===e.length&&(e="0"+e);var f=a.getMinutes().toString();1===f.length&&(f="0"+f);var g=a.getSeconds().toString();return 1===g.length&&(g="0"+g),b+"-"+c+"-"+d+" "+e+":"+f+":"+g};return a.toIsoDate=h,a.login=function(a,c){return s4a.doPost(b,{username:a,password:c})},a.insertPosition=function(a,b,d,e){return s4a.doGet(c,{Operation:"InsertPosition",lat:a,lon:b,unit_id:d,date:f(e)},"text")},a.insertObservation=function(a,b,d,e){return s4a.doGet(c,{Operation:"InsertObservation",value:a,unit_id:b,sensor_id:d,date:f(e)},"text")},a.getLastPositions=function(a){return s4a.doGet(d,{Operation:"GetLastPositions",user:a})},a.getLastPosition=function(b,c){return a.getLastPositions(c).then(function(a){for(var c=0;ca.maxx)&&(a.maxx=b),(null===a.miny||ca.maxy)&&(a.maxy=c)},this.extendByCoordinate=function(a){return this.extendByXY(a[0],a[1])},this.extent=a},s4a.extend("map"),s4a.map.GeometryType={point:"point",line:"line",polygon:"polygon",none:"none"},s4a.map.ITool={label:"Button",toolType:null,geomType:s4a.map.GeometryType.none,icon:"button.png",onClick:function(a){console.log("Must be overridden by derived class")},onDoubleClick:function(a){console.log("Must be overridden by derived class")},onActivate:function(){console.log("Must be overridden by derived class")},onDeactivate:function(){console.log("Must be overridden by derived class")}},s4a.map.LayerSwitcher=function(){this.test=1},s4a.extend("map"),s4a.map.Map=function(a,b){var c,d=this,e=[];b=b||s4a.config.loadConfig();var f=[b.center.x,b.center.y],g="EPSG:3857";b.center.epsg!==g&&(f=ol.proj.transform(f,b.center.epsg,g));var h=new ol.Map({layers:[new ol.layer.Group({title:"Base layer",layers:b.baselayers}),new ol.layer.Group({title:"Overlays",layers:b.layers})],renderer:"canvas",target:a,view:new ol.View({center:f,zoom:b.center.zoom})});return h.on("postcompose",function(a){d.redraw()}),d.add=function(a){a.setMap(d),e.push(a)},d.addKey=function(a){c=a},d.createMapLayer=function(a,b){var d={key:c,LAYERS:a};return new ol.layer.Image({source:new ol.source.ImageWMS({url:"http://localhost/a_a3_mapserver/mapserv.ashx",params:$.extend(d,b)})})},d.getDomElement=function(){return $(h.getViewport())},d.getOlMap=function(){return h},d.projectPoint=function(a,b){var c=ol.proj.transform([a,b],"EPSG:4326","EPSG:3857");return h.getPixelFromCoordinate(c)},d.redraw=function(){jQuery.each(e,function(a,b){b.redraw()})},d.removeAt=function(a){e=e.filter(function(b,c){return c!==a})},d.removeObjects=function(a){e=e.filter(function(b){return b!==a})},d},s4a.map.MapHelper=function(a,b){var c=this;if(void 0===a)throw"The parameter nodeSelector is mandatory";var d={zoomLevel:14,extent:[-179,-85,179,85],layers:[],center:{lon:6.11,lat:49.58},activeLayer:0,tools:[],activeTool:0,baseMaps:{MAPQUEST:new ol.layer.Tile({source:new ol.source.MapQuest({layer:"osm"})}),OFFLINE:new ol.layer.Vector({source:new ol.source.Vector({format:new ol.format.GeoJSON,projection:"EPSG:3857",url:"../../data/countries.json",style:new ol.style.Style({fill:new ol.style.Fill({color:"rgba(255, 255, 0, 0)"}),stroke:new ol.style.Stroke({color:"#ff0000",width:1})})})})}};void 0!==b&&jQuery.extend(d,b);var e=new ol.Map({layers:[d.baseMaps.MAPQUEST],target:a,view:new ol.View({center:ol.proj.transform([d.center.lon,d.center.lat],"EPSG:4326","EPSG:3857"),zoom:d.zoomLevel})});this.transform=function(a,b){var c=null;return c=b===!0?ol.proj.transform(a,"EPSG:3857","EPSG:4326"):ol.proj.transform(a,"EPSG:4326","EPSG:3857")},this.getExtent=function(){return e.getView().calculateExtent(e.getSize())},this.zoomToExtent=function(a,b){b=b||14,e.getView().fit(a,e.getSize()),e.getView().getZoom()>b&&e.getView().setZoom(b)},this.addTool=function(a){return c},this.addData=function(a){var b=new ol.layer.Vector({source:new ol.source.GeoJSON({projection:"EPSG:3857",url:"data/countries.json"})});return e.addLayer(b),c},this.draw=function(){return c},this.listenDoubleClick=function(a){return this.getMap().on("dblclick",a),c},this.listenSingleClick=function(a){return this.getMap().on("singleclick",a),c},this.getMap=function(){return e}},s4a.map.ToolType={BUTTON:"button",TOOL:"tool",INPUT:"input"},s4a.extend("map"),s4a.map.Transform=function(){var a={},b=function(a,b,c){return ol.proj.transform(c,"EPSG:"+a,"EPSG:"+b)};return a.fromTo=function(a,c,d){return b(a,c,d)},a.to3857=function(a){return b(4326,3857,a)},a.to4326=function(a){return b(3857,4326,a)},a.extentTo3857=function(a){var c=b(4326,3857,[a[0],a[1]]),d=b(4326,3857,[a[2],a[3]]);return[c[0],c[1],d[0],d[1]]},a.extentTo4326=function(a){var c=b(3857,4326,[a[0],a[1]]),d=b(3857,4326,[a[2],a[3]]);return[c[0],c[1],d[0],d[1]]},a}(),s4a.map.VizLayer=function(){var a=this,b=!0,c="s4a-map",d=[];a.add=function(b){e(b.getSvg()),$(b).on("resize",a.redraw),d.push(b)};var e=function(a){var b=d3.select("div.ol-viewport"),d=b.select("div."+c);d.empty()&&(d=b.append("div").classed(c,!0)),d.append(function(){return a.node()}),a.style("position","fixed")};return a.getVisible=function(){return b},a.getPosition=function(b){return a.map.projectPoint(b[0],b[1])},a.redraw=function(){a.map&&jQuery.each(d,function(b,c){var d=c.getGeometry(),e=c.getSvg();if(d&&e){var f,g=(e.selectAll("g"),e.attr("width")/2);switch(d.type){case"point":f=a.getPosition(d.coordinates);break;default:console.warn("s4a.map.VizLayer","Unsupported geometry type",d.type)}if(!f)return;f[0]-=g,f[1]-=g,e.style("left",f[0]+"px").style("top",f[1]+"px")}})},a.removeAt=function(b){$(d[b]).unbind("resize",a.redraw),d=d.filter(function(a,c){return c!==b})},a.removeObjects=function(b){$(b).unbind("resize",a.redraw),d=d.filter(function(a){return a!==b})},a.setMap=function(b){a.map=b},a.setVisible=function(a){b=a,d.forEach(function(b){b.setVisible(a)})},a},s4a.extend("mobile"),s4a.mobile.FeatureSync=function(){var a={};return a.CheckOut=function(){},a.CheckIn=function(){},a.GetConflicts=function(){},a.Resolve=function(){},a}(),s4a.extend("mobile"),s4a.mobile.File=function(){var a={};return a.getFileEntry=function(a,b){var c=jQuery.Deferred();return void 0!==window.cordova&&void 0!==window.cordova.file?(void 0===b&&(b=window.cordova.file.dataDirectory),window.resolveLocalFileSystemURL(b,function(b){b.getFile(a,{create:!0},function(a){c.resolve(s4a.mobile.FileResponse.createSuccess(a))},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))})},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))})):c.resolve(s4a.mobile.FileResponse.createError('Requires Cordova with "cordova-plugin-file".')),c},a.writeFile=function(b,c){var d=jQuery.Deferred();return a.getFileEntry(b).then(function(a){a.isSuccess()?a.data.createWriter(function(a){a.onwriteend=function(){d.resolve(s4a.mobile.FileResponse.createSuccess(c))},a.onerror=function(a){d.resolve(s4a.mobile.FileResponse.createError("Error writing file: "+a.toString()))};var b=new Blob([JSON.stringify(c,null," ")],{type:"text/plain"});a.write(b)}):d.resolve(s4a.mobile.FileResponse.createError("Error getting file entry: "+a.messages))}),d},a.readFile=function(b){var c=jQuery.Deferred();return a.getFileEntry(b).then(function(a){a.isSuccess()?a.data.file(function(a){var b=new FileReader;b.onloadend=function(){c.resolve(s4a.mobile.FileResponse.createSuccess(JSON.parse(this.result)))},b.readAsText(a)},function(a){c.resolve(s4a.mobile.FileResponse.createError(a))}):c.resolve(s4a.mobile.FileResponse.createError(a.messages))}),c},a}(),s4a.extend("mobile"),s4a.mobile.FileResponse=function(a,b,c){this.status=void 0,void 0!==a&&null!==a?this.status=a:a=!0,this.data=void 0,void 0!==b&&null!==b&&(this.data=b),this.messages=[],void 0!==c&&null!==c&&this.messages.push(c),this.isSuccess=function(){return this.status===!0?!0:!1},this.isError=function(){return this.status===!1?!0:!1},this.getMessages=function(){for(var a=0;a=e&&" "!==b[g]&&"-"!==b[g];)g-=1,e++;if(console.log(e),d.push(b.substring(f,g).trim()),f=g,g=f+c,g>=b.length){d.push(b.substring(f,g).trim());break}}return d},m=function(a,b){return 0===a?0:b};return b.updateLegend=function(){for(var b=0;bh){o.text(null);for(var q=Math.ceil(1.15*a.fontSize),r=Math.ceil(p/h),s=l(r,n),t=0;t"),jQuery(a).append(x)),i=x.prop("height",w).prop("width",v)[0].getContext("2d"),j=b.domains.map(function(a){return Number(a)})||null,k=null!==b.colors&&b.colors.length>=1?s4a.viz.color[b.colors[0]][j.length]:s4a.viz.color.Reds[j.length],l=null!==b.colors&&b.colors.length>=2?s4a.viz.color[b.colors[1]][j.length]:s4a.viz.color.Blues[j.length],m=s4a.viz.Sizes.medium,n=d3.scale.threshold().domain(j).range(k),o=d3.scale.threshold().domain(j).range(l),p=null!==m?d3.scale.threshold().domain(j).range(m):null,q={},r={},s=[],t={},u=[];for(var y=0,z=b.mapUnitIDs.length;z>y;y++)r[b.mapUnitIDs[y]]=Number(b.seriesData[y]),q[b.mapUnitIDs[y]]=Number(b.seriesData[y][b.showSeries[0]]),s.push(Number(b.seriesData[y][b.showSeries[0]]));if(2===b.showSeries.length)for(y=0,z=b.mapUnitIDs.length;z>y;y++)t[b.mapUnitIDs[y]]=Number(b.seriesData[y][b.showSeries[1]]),u.push(Number(b.seriesData[y][b.showSeries[1]]));(null===b.title||void 0===b.title||""===b.title)&&(b.showSeries.length>1?b.title=b.seriesLabels[b.showSeries[0]]+" / "+b.seriesLabels[b.showSeries[2]]:b.title=b.seriesLabels[b.showSeries[0]]),queue().defer(d3.json,"./data/data-topojson.json").defer(d3.json,"./data/sea.json").await(function(a,j,l){return c=d3.geo.transverseMercator().scale(1).translate([0,0]),d=d3.geo.path().projection(c),e=topojson.feature(j,j.objects.kommune).features.filter(function(a){return-1!==b.mapUnitIDs.indexOf(a.id.toString())}),f=s4a.viz.map.util.getFeatureCollectionBounds(d,e),g=.95/Math.max((f[1][0]-f[0][0])/v,(f[1][1]-f[0][1])/w),h=[(v-g*(f[1][0]+f[0][0]))/2,(w-g*(f[1][1]+f[0][1]))/2],c.scale(g).translate(h),i.clearRect(0,0,v,w),i.fillStyle="#ffffff",i.fillRect(0,0,v,w),s4a.viz.map.shared._drawLand(i,d,l),("choroplethMap"===b.mapType||"bubbleChoroplethMap"===b.mapType)&&s4a.viz.map.shared._drawPolygons(e,q,n,d,i),s4a.viz.map.shared._drawMunicipality(i,d,j),s4a.viz.map.shared._drawCounty(i,d,j),"bubbleMap"===b.mapType?s4a.viz.map.shared._drawBubbles(e,q,p,n,d,i):"bubbleChoroplethMap"===b.mapType?s4a.viz.map.shared._drawBubbles(e,t,p,o,d,i):"pieChartMap"===b.mapType&&s4a.viz.map.shared._drawPieCharts(e,r,k,d,i),s4a.viz.map.shared._drawLabels(i,d,e,b.fontSize-2),s4a.viz.map.shared._drawRectSymMapLegend(i,n,b.title,Number(b.fontSize)),i})},s4a.viz.map.shared={},s4a.viz.map.shared._drawChartTitle=function(a,b,c,d,e){return a.font="bolder "+b+"px Arial",a.textAlign="start",a.fillStyle="#000000",a.fillText(c,d,e),e+=2*b},s4a.viz.map.shared._drawRectSymMapLegend=function(a,b,c,d){d=void 0!==d?d:s4a.viz.map.FontSizes.normal;var e=10,f=10,g=1.8*d,h=20,i=d+4,j=f+d,k=s4a.viz.map.util.getLongestStringInArray(b.domain());a.font=d+"px Arial";var l=2*a.measureText(k).width;void 0!==c&&null!==c&&""!==c&&(j=s4a.viz.map.shared._drawChartTitle(a,d,c,e,j)),a.font=d+"px Arial",a.textAlign="end";for(var m=b.domain().length-1;m>0;m--){var n;n=m===b.domain().length-1?"> "+jQuery.number(b.domain()[m-1]):1===m?"< "+jQuery.number(b.domain()[m]):jQuery.number(b.domain()[m-1])+" - "+jQuery.number(b.domain()[m]),a.fillStyle=b.range()[m],a.strokeStyle="#000000",a.lineWidth=.2,a.beginPath(),a.rect(e,j-d,h,i),a.globalAlpha=s4a.viz.map.StatAreaAlpha,a.fill(),a.globalAlpha=1,a.stroke(),a.fillStyle="#000000",a.fillText(n,e+h+e+l,j),j+=g}},s4a.viz.map.shared._drawPolygons=function(a,b,c,d,e){e.globalAlpha=s4a.viz.map.StatAreaAlpha;var f=c.domain(),g=Math.max.apply(null,f),h=Math.min.apply(null,f);a.forEach(function(a){var f=b[a.id];f=g>f?f:g-1e-4,f=f>=h?f:h;var i=c(f);void 0!==i&&(e.fillStyle=i,e.beginPath(),d.context(e)(a),e.fill())}),e.globalAlpha=1},s4a.viz.map.shared._drawPieCharts=function(a,b,c,d,e){e.globalAlpha=s4a.viz.map.StatAreaAlpha,a.forEach(function(a){for(var f=25,g=s4a.viz.map.util.valuesToSlices(b[a.id]),h=1.5*Math.PI,i=d.centroid(a),j=0,k=g.length;k>j;j++){var l=Number(g[j])*(2*Math.PI)/100,m=h+l;m>2*Math.PI&&(m-=2*Math.PI),e.fillStyle=c[j],e.lineWidth=2,e.strokeStyle="rgba(0,0,0,0.25)",e.beginPath(),e.moveTo(i[0],i[1]),e.arc(i[0],i[1],f,h,m,!1),e.closePath(),e.fill(),e.stroke(),h+=l}})},s4a.viz.map.shared._drawCircleSymMapLegend=function(a,b,c){var d=12,e=10,f=10,g=1.5*d,h=f+d,i=s4a.viz.map.util.getLengthOfLongest(b.domain())*(d/1.5);a.font=d+"px Arial Bold",a.textAlign="start",a.fillStyle="#000000",a.fillText("Teiknforklaring",e,h),h+=g,a.font=d+"px Arial",a.textAlign="end";for(var j=b.domain().length-1;j>0;j--){var k=jQuery.number(b.domain()[j-1])+" - "+jQuery.number(b.domain()[j]);a.fillStyle=b.range()[j],a.strokeStyle="#000000",a.lineWidth=.2,a.beginPath(),a.arc(e,h-d/2,6,0,2*Math.PI,!1),a.globalAlpha=s4a.viz.map.StatAreaAlpha,a.fill(),a.globalAlpha=1,a.stroke(),a.fillStyle="#000000",a.fillText(k,e+i,h),h+=g}},s4a.viz.map.shared._drawBubbles=function(a,b,c,d,e,f){f.globalAlpha=s4a.viz.map.StatAreaAlpha,a.forEach(function(a){var g=c(b[a.id]),h=d(b[a.id]);if(void 0!==g){var i=e.centroid(a);f.beginPath(),f.arc(i[0],i[1],g,0,2*Math.PI,!1),f.fillStyle=h,f.fill(),f.lineWidth=2,f.strokeStyle="rgba(0,0,0,0.25)",f.stroke()}}),f.globalAlpha=1},s4a.viz.map.shared._drawLabels=function(a,b,c,d){d=void 0!==d?d:s4a.viz.map.FontSizes.small,c.forEach(function(c){var e=b.centroid(c);a.font=d+"px Arial",a.textAlign="center",a.fillStyle="#000000",a.fillText(c.properties.name,e[0],e[1])})},s4a.viz.map.shared._drawGeoJson=function(a,b,c,d,e,f){a.strokeStyle=d||"transparent",a.lineWidth=f,a.fillStyle=e||"transparent",a.beginPath(),b.context(a)(c),"transparent"!==e&&a.fill(),"transparent"!==d&&a.stroke()},s4a.viz.map.shared._drawMunicipality=function(a,b,c){var d=topojson.mesh(c,c.objects.kommune,function(a,b){return a.id!==b.id});s4a.viz.map.shared._drawGeoJson(a,b,d,"#000000",null,.5)},s4a.viz.map.shared._drawCounty=function(a,b,c){var d=topojson.mesh(c,c.objects.fylke,function(a,b){return a.id!==b.id});s4a.viz.map.shared._drawGeoJson(a,b,d,"#000000",null,1)},s4a.viz.map.shared._drawLand=function(a,b,c){var d=topojson.feature(c,c.objects.sea);s4a.viz.map.shared._drawGeoJson(a,b,d,"#999999","#eeeeee",.2)},s4a.viz.map.Symbol=function(){},s4a.viz.map.util={},s4a.viz.map.util.secureReload=function(a){var b=a.indexOf(!0)?"?":"&";return a+b+"rnd="+(100*Math.random()).toString()},s4a.viz.map.util.getLengthOfLongest=function(a){var b=0;if(null!==a&&a.length>1)for(var c,d=a.length-1;d>0;d--){var e=jQuery.number(a[d-1])+" - "+jQuery.number(a[d]);c=e.length,c>b&&(b=c)}return b},s4a.viz.map.util.getLongestStringInArray=function(a){var b=a.slice();return b.sort(function(a,b){return b.toString().length-a.toString().length})[0]},s4a.viz.map.util.getTotal=function(a){for(var b=0,c=0;cd;d++){var f=a.bounds(b[d]);(!c[0][0]||f[0][0]c[1][0])&&(c[1][0]=f[1][0]),(!c[1][1]||f[1][1]>c[1][1])&&(c[1][1]=f[1][1])}return c},s4a.viz.map.util.valuesToSlices=function(a){if(void 0!==a&&"object"==typeof a&&Array.isArray(a)===!0){for(var b=0,c=0,d=a.length;d>c;c++)b+=Number(a[c]);var e=[];for(c=0,d=a.length;d>c;c++)e.push(100*Number(a[c])/b);return e}return a},s4a.viz.map.util={},s4a.viz.map.util.secureReload=function(a){var b=a.indexOf(!0)?"?":"&";return a+b+"rnd="+(100*Math.random()).toString()},s4a.viz.map.util.getLengthOfLongest=function(a){var b=0;if(null!==a&&a.length>1)for(var c,d=a.length-1;d>0;d--){var e=jQuery.number(a[d-1])+" - "+jQuery.number(a[d]);c=e.length,c>b&&(b=c)}return b},s4a.viz.map.util.getLongestStringInArray=function(a){var b=a.slice();return b.sort(function(a,b){return b.toString().length-a.toString().length})[0]},s4a.viz.map.util.getTotal=function(a){for(var b=0,c=0;cd;d++){var f=a.bounds(b[d]);(!c[0][0]||f[0][0]c[1][0])&&(c[1][0]=f[1][0]),(!c[1][1]||f[1][1]>c[1][1])&&(c[1][1]=f[1][1])}return c},s4a.viz.map.util.valuesToSlices=function(a){if(void 0!==a&&"object"==typeof a&&Array.isArray(a)===!0){for(var b=0,c=0,d=a.length;d>c;c++)b+=Number(a[c]);var e=[];for(c=0,d=a.length;d>c;c++)e.push(100*Number(a[c])/b);return e}return a}; \ No newline at end of file diff --git a/src/map/MapHelper.js b/src/map/MapHelper.js index d59b0eb..d51ae0e 100644 --- a/src/map/MapHelper.js +++ b/src/map/MapHelper.js @@ -53,7 +53,7 @@ s4a.map.MapHelper = function(nodeSelector, config) { var _map = new ol.Map({ layers: [ - _config.baseMaps.OFFLINE + _config.baseMaps.MAPQUEST ], target: nodeSelector, view: new ol.View({ diff --git a/src/mobile/File.js b/src/mobile/File.js index fd4101d..bd7f5c9 100644 --- a/src/mobile/File.js +++ b/src/mobile/File.js @@ -68,7 +68,8 @@ s4a.mobile.File = (function() { }; fileWriter.onerror = function(e) { - promise.resolve(s4a.mobile.FileResponse.createError(e.toString())); + promise.resolve(s4a.mobile.FileResponse + .createError('Error writing file: ' + e.toString())); }; var blob = new Blob([JSON.stringify(contents, null, '\t')], {type: 'text/plain'}); @@ -76,7 +77,8 @@ s4a.mobile.File = (function() { }); } else { - promise.resolve(s4a.mobile.FileResponse.createError(fileResponse.messages)); + promise.resolve(s4a.mobile.FileResponse + .createError('Error getting file entry: ' + fileResponse.messages)); } }); diff --git a/test/analytics/Routing.test.html b/test/analytics/Routing.test.html index b79c749..f352423 100644 --- a/test/analytics/Routing.test.html +++ b/test/analytics/Routing.test.html @@ -60,7 +60,13 @@ source: geoJsonSource }); - var myMap = new s4a.map.MapHelper('map'); + var myMap = new s4a.map.MapHelper('map', { + zoomLevel: 8, + center: { + lon: 14.55, + lat: 47.51 + } + }); var myAB = []; @@ -70,7 +76,6 @@ Routing.getOptimalRoute([1, 2, 3, 5, 6, 7, 10, 100, 14, 16, 23, 1204], 2, 3).then(function (res) { - console.log(res); var nodes = res.data; for (var i = 0; i < nodes.length - 1; i++) { Routing.getShortestRoute(nodes[i].id, nodes[i + 1].id).then(function (res) { @@ -122,7 +127,8 @@ geoJsonSource.clear(); if (res.status === 'success' && res.count > 0) { for (var i = 0; i < res.data.length; i++) { - var f = vectorFormat.readFeature({type: 'Feature', geometry: JSON.parse(res.data[i].geoJson)}, { + console.log(res.data[i]); + var f = vectorFormat.readFeature({type: 'Feature', geometry: res.data[i].geometry}, { featureProjection: 'EPSG:3857' }); geoJsonSource.addFeature(f); From b76adc04ecc6baf140a3f46d7cc952ec64542aa5 Mon Sep 17 00:00:00 2001 From: Stein Runar Bergheim Date: Thu, 4 May 2017 11:31:06 +0200 Subject: [PATCH 2/2] Minor bug fixes, upgrades --- README.md | 3 +- dist/s4a.js | 717 +++++++++++++++++++---------------- src/data/SensLog.js | 5 + src/ir/ir.jsdoc | 1 + src/viz/Pie.js | 207 ---------- src/viz/chart/Bubble.js | 11 + src/viz/chart/GroupedBar.js | 11 + src/viz/chart/Line.js | 13 + src/viz/chart/Pie.js | 218 ++++++++++- src/viz/chart/StackedLine.js | 13 + src/viz/chart/StackedRow.js | 11 + src/viz/map/Prism.js | 13 + 12 files changed, 681 insertions(+), 542 deletions(-) delete mode 100644 src/viz/Pie.js create mode 100644 src/viz/chart/Bubble.js create mode 100644 src/viz/chart/GroupedBar.js create mode 100644 src/viz/chart/Line.js create mode 100644 src/viz/chart/StackedLine.js create mode 100644 src/viz/chart/StackedRow.js create mode 100644 src/viz/map/Prism.js diff --git a/README.md b/README.md index 3cb2cc8..4040d48 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ without the workload of running a server, installing and maintaining software an the professional concepts of GIS. ## Status -* The first version of the library was released on the 31st of March 2016 +* The first (1.0) version of the library was released on the 31st of March 2016 +* The seconc (2.0) version of the library was released on the 20th of March 2017 * The library is under still under active development and we advise users to check out the develop branch for the latest features * New releases with incremental functionality are frequent at this stage diff --git a/dist/s4a.js b/dist/s4a.js index ecf06f4..6edcead 100644 --- a/dist/s4a.js +++ b/dist/s4a.js @@ -1,6 +1,6 @@ -/*! s4a - v1.0.0 - 2016-06-21 +/*! s4a - v1.0.0 - 2017-04-03 * https://github.com/SDI4Apps/s4a.js -* Copyright (c) 2016 SDI4Apps Partnership; Licensed */ +* Copyright (c) 2017 SDI4Apps Partnership; Licensed */ 'use strict'; /** @@ -295,6 +295,11 @@ s4a.analytics.Routing = (function() { s4a.extend('data'); +/** + * SensLog communication object + * + * @class + */ s4a.data.SensLog = (function() { /** * Class with methods to interact with SensLog @@ -1507,50 +1512,6 @@ s4a.map.VizLayer = function() { }; -'use strict'; - -s4a.extend('mobile'); - -s4a.mobile.FeatureSync = (function() { - - /** - * [module description] - * @exports s4a.mobile.FeatureSync - */ - var module = {}; - - /** - * Check out a portion of a feature layer - */ - module.CheckOut = function() { - - }; - - /** - * Check in an edited feature layer - */ - module.CheckIn = function() { - - }; - - /** - * Get conflicts if any for a featyre layer - */ - module.GetConflicts = function() { - - }; - - /** - * Resolve conflict - */ - module.Resolve = function() { - - }; - - return module; - -}()); - /* global s4a, LocalFileSystem */ 'use strict'; @@ -1871,6 +1832,50 @@ s4a.mobile.OfflineTileLayer.clearBaseMapCache = function(baseMapId) { }; +'use strict'; + +s4a.extend('mobile'); + +s4a.mobile.FeatureSync = (function() { + + /** + * [module description] + * @exports s4a.mobile.FeatureSync + */ + var module = {}; + + /** + * Check out a portion of a feature layer + */ + module.CheckOut = function() { + + }; + + /** + * Check in an edited feature layer + */ + module.CheckIn = function() { + + }; + + /** + * Get conflicts if any for a featyre layer + */ + module.GetConflicts = function() { + + }; + + /** + * Resolve conflict + */ + module.Resolve = function() { + + }; + + return module; + +}()); + 'use strict'; s4a.extend('viz'); @@ -2531,76 +2536,337 @@ s4a.viz.Legend = function(chartConfig) { 'use strict'; /** - * Pie visualization - * - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {s4a.viz.ChartConfig} mChartConfig - * @constructor + * Enumeration of size-scales + * @readonly + * @enum {number} */ -s4a.viz.Pie = function(viewCoordinator, mChartConfig) { - var chartData, currentData, currentScale, scale, arc, bigArc; - var _self = this; - var transitionTime = 400; - +s4a.viz.Sizes = { /** - * Internal reference to Pie svg element. - * Use getSvg to retrieve it - * - * @private + * From 5px to 19px + * @type Array */ - var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); - - function changeCollapsedState(collapsed) { - currentScale = collapsed ? scale : 1; - - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - var g = svg.selectAll('g'); - - if (currentScale === 1) { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); + 'small': ['5', '7', '9', '11', '13', '15', '17', '19'], + /** + * From 10px to 50px + * @type Array + */ + 'medium': ['10', '15', '25', '30', '35', '40', '45', '50'], + /** + * From 10px to 80px + * @type Array + */ + 'large': ['10', '20', '30', '40', '50', '60', '70', '80'] +}; - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); +/** + * Enumeration for font sizes + * @readonly + * @enum {number} + */ +s4a.viz.FontSizes = { + /** + * Small font size + * @type Number + */ + 'small': 10, + /** + * The default font size + * @type Number + */ + 'normal': 12, + /** + * A bigger font-size + * @type Number + */ + 'medium': 14, + /** + * Large font-size + * @type Number + */ + 'large': 18 +}; - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - } else { - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); +'use strict'; +/* global s4a */ - setTimeout(function() { - svg.attr('width', featureWidth) - .attr('height',featureHeight); +/** + * A top level object that coordinates data and visualizations + * + * @param {Object} pData + * @constructor + * @returns {s4a.viz.ViewCoordinator} + */ +s4a.viz.ViewCoordinator = function(pData) { - $(_self).trigger('resize'); + var _data = pData; + var _listeners = []; + var _self = {}; - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + /** + * Subscribes an object to publish events from the ViewCoordinator + * + * @returns {s4a.viz.ViewCoordinator} + */ + _self.publish = function() { + for (var i = 0; i < _listeners.length; i++) { + var listener = _listeners[i]; + if (listener.update) { + listener.update(_data); + console.info('Published ' + i); + } else { + console.debug('Subscribed object ' + i + ' does not implement the update interface', + listener); + } + } + return _self; + }; - }, transitionTime); + /** + * Update the data object + * + * @param {Object} pData + * @returns {s4a.viz.ViewCoordinator} + */ + _self.setData = function(pData) { + _data = pData; + _self.publish(); + return _self; + }; + /** + * Subscribe an object to the ViewCoordinator + * + * @param {Object} pObj + * @returns {s4a.viz.ViewCoordinator} + */ + _self.subscribe = function(pObj) { + if (_listeners.indexOf(pObj) < 0) { + _listeners.push(pObj); } - } + return _self; + }; /** - * Create new pie chart + * Unsubscribe an object from the ViewCoordinator * - * @param {integer} width optional width of svg - * @param {integer} height optional height of svg - * @private + * @param {Object} pObj + * @returns {s4a.viz.ViewCoordinator} */ - function updateChart(width, height) { - // pick the first series - currentData = chartData.series[0].values; + _self.unsubscribe = function(pObj) { + var _modListeners = []; + for (var i = 0; i < _listeners.length; i++) { + if (_listeners[i] !== pObj) { + _modListeners.push(_listeners[i]); + } + } + _listeners = _modListeners; + return _self; + }; - // and the first color - var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; + _self.applyFilter = function() { + _self.publish(); + return _self; + }; + + return _self; + +}; + +'use strict'; +/* global s4a */ + +/** + *

This is an abstract top-level object that coordinates data and visualizations + * that take part in a coordinated view

+ * + *

Any visualization object must implement an interface that contains the methods + * update and filter

+ * + *

The object receives as part of the constructor a ViewCoordinator object + * that implicitly contains data

+ * + *

The object receives as part of the constructor a DOMElement identified by its + * ID, typically i DIV in which it is to be drawn

+ * + * @abstract + * @constructor + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {DOMElement} domElement + * @returns {s4a.viz.VizObj} + */ +s4a.viz.VizObj = function(viewCoordinator, domElement) { + var _self = this; + + viewCoordinator.subscribe(_self); + + /** + * Update the visualization + * + * @abstract + */ + _self.update = function() { + throw new Error('Must be implemented by sub-class'); + }; + + /** + * Apply a filter to the visualization + * + * @abstract + */ + _self.filter = function(filter) { + throw new Error('Must be implemented by sub-class'); + }; + + _self.get = function() { + throw new Error('Must be implemented by sub-class'); + }; +}; + +'use strict'; +/* global s4a */ + +/** + * Enumeration + * + * @enum {number} + * @readonly + */ +s4a.viz.VizType = { + /** + * Chart + */ + CHART: 1, + + /** + * Map + */ + MAP: 2 +}; + +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new Bar chart object + * + * @class + * @classdesc + * Bar chart object + */ +s4a.viz.chart.Bar = function() { + +}; + +'use strict'; +/** + * Create a new bubble chart object + * + * @class + * @classdesc + * Stacked bubble chart object + */ +s4a.viz.chart.Bubble = function() { + +}; + +'use strict'; +/** + * Create a new row chart object + * + * @class + * @classdesc + * Row chart object + */ +s4a.viz.chart.Row = function() { + +}; + +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new line chart object + * + * @class + * @classdesc + * Bar line chart object + */ +s4a.viz.chart.Line = function() { + +}; + +'use strict'; +/** + * Pie visualization + * + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {s4a.viz.ChartConfig} mChartConfig + * @constructor + */ +s4a.viz.Pie = function(viewCoordinator, mChartConfig) { + var chartData, currentData, currentScale, scale, arc, bigArc; + var _self = this; + var transitionTime = 400; + + /** + * Internal reference to Pie svg element. + * Use getSvg to retrieve it + * + * @private + */ + var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); + + function changeCollapsedState(collapsed) { + currentScale = collapsed ? scale : 1; + + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + var g = svg.selectAll('g'); + + if (currentScale === 1) { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + } else { + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + + setTimeout(function() { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + }, transitionTime); + + } + } + + /** + * Create new pie chart + * + * @param {integer} width optional width of svg + * @param {integer} height optional height of svg + * @private + */ + function updateChart(width, height) { + // pick the first series + currentData = chartData.series[0].values; + + // and the first color + var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; mChartConfig.height = mChartConfig.height || mChartConfig.width; mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; @@ -2739,260 +3005,51 @@ s4a.viz.Pie = function(viewCoordinator, mChartConfig) { 'use strict'; /** - * Enumeration of size-scales - * @readonly - * @enum {number} - */ -s4a.viz.Sizes = { - /** - * From 5px to 19px - * @type Array - */ - 'small': ['5', '7', '9', '11', '13', '15', '17', '19'], - /** - * From 10px to 50px - * @type Array - */ - 'medium': ['10', '15', '25', '30', '35', '40', '45', '50'], - /** - * From 10px to 80px - * @type Array - */ - 'large': ['10', '20', '30', '40', '50', '60', '70', '80'] -}; - -/** - * Enumeration for font sizes - * @readonly - * @enum {number} - */ -s4a.viz.FontSizes = { - /** - * Small font size - * @type Number - */ - 'small': 10, - /** - * The default font size - * @type Number - */ - 'normal': 12, - /** - * A bigger font-size - * @type Number - */ - 'medium': 14, - /** - * Large font-size - * @type Number - */ - 'large': 18 -}; - -'use strict'; -/* global s4a */ - -/** - * A top level object that coordinates data and visualizations - * - * @param {Object} pData - * @constructor - * @returns {s4a.viz.ViewCoordinator} - */ -s4a.viz.ViewCoordinator = function(pData) { - - var _data = pData; - var _listeners = []; - var _self = {}; - - /** - * Subscribes an object to publish events from the ViewCoordinator - * - * @returns {s4a.viz.ViewCoordinator} - */ - _self.publish = function() { - for (var i = 0; i < _listeners.length; i++) { - var listener = _listeners[i]; - if (listener.update) { - listener.update(_data); - console.info('Published ' + i); - } else { - console.debug('Subscribed object ' + i + ' does not implement the update interface', - listener); - } - } - return _self; - }; - - /** - * Update the data object - * - * @param {Object} pData - * @returns {s4a.viz.ViewCoordinator} - */ - _self.setData = function(pData) { - _data = pData; - _self.publish(); - return _self; - }; - - /** - * Subscribe an object to the ViewCoordinator - * - * @param {Object} pObj - * @returns {s4a.viz.ViewCoordinator} - */ - _self.subscribe = function(pObj) { - if (_listeners.indexOf(pObj) < 0) { - _listeners.push(pObj); - } - return _self; - }; - - /** - * Unsubscribe an object from the ViewCoordinator - * - * @param {Object} pObj - * @returns {s4a.viz.ViewCoordinator} - */ - _self.unsubscribe = function(pObj) { - var _modListeners = []; - for (var i = 0; i < _listeners.length; i++) { - if (_listeners[i] !== pObj) { - _modListeners.push(_listeners[i]); - } - } - _listeners = _modListeners; - return _self; - }; - - _self.applyFilter = function() { - _self.publish(); - return _self; - }; - - return _self; - -}; - -'use strict'; -/* global s4a */ - -/** - *

This is an abstract top-level object that coordinates data and visualizations - * that take part in a coordinated view

- * - *

Any visualization object must implement an interface that contains the methods - * update and filter

- * - *

The object receives as part of the constructor a ViewCoordinator object - * that implicitly contains data

- * - *

The object receives as part of the constructor a DOMElement identified by its - * ID, typically i DIV in which it is to be drawn

- * - * @abstract - * @constructor - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {DOMElement} domElement - * @returns {s4a.viz.VizObj} - */ -s4a.viz.VizObj = function(viewCoordinator, domElement) { - var _self = this; - - viewCoordinator.subscribe(_self); - - /** - * Update the visualization - * - * @abstract - */ - _self.update = function() { - throw new Error('Must be implemented by sub-class'); - }; - - /** - * Apply a filter to the visualization - * - * @abstract - */ - _self.filter = function(filter) { - throw new Error('Must be implemented by sub-class'); - }; - - _self.get = function() { - throw new Error('Must be implemented by sub-class'); - }; -}; - -'use strict'; -/* global s4a */ - -/** - * Enumeration - * - * @enum {number} - * @readonly - */ -s4a.viz.VizType = { - /** - * Chart - */ - CHART: 1, - - /** - * Map - */ - MAP: 2 -}; - -'use strict'; -s4a.extend('viz.chart'); - -/** - * Create a new Bar chart object + * Create a new Row chart object * * @class * @classdesc - * Bar chart object + * Row chart object */ -s4a.viz.chart.Bar = function() { +s4a.viz.chart.Row = function() { }; 'use strict'; /** - * Create a new Pie chart object + * Create a new Scatter chart object * * @class * @classdesc - * Pie chart object + * Scatter chart object */ -s4a.viz.chart.Pie = function() { +s4a.viz.chart.Scatter = function() { }; 'use strict'; +s4a.extend('viz.chart'); + /** - * Create a new Row chart object + * Create a new stacked line chart object * * @class * @classdesc - * Row chart object + * Stacked line chart object */ -s4a.viz.chart.Row = function() { +s4a.viz.chart.StackedLine = function() { }; 'use strict'; /** - * Create a new Scatter chart object + * Create a new stacked row chart object * * @class * @classdesc - * Scatter chart object + * Stacked row chart object */ -s4a.viz.chart.Scatter = function() { +s4a.viz.chart.StackedRow = function() { }; @@ -3426,6 +3483,20 @@ s4a.viz.map.getMap = function(pDomNode, pChartData) { }); }; +'use strict'; +s4a.extend('viz.map'); + +/** + * Create a new Prism chart object + * + * @class + * @classdesc + * Prism chart object + */ +s4a.viz.map.Prism = function() { + +}; + 'use strict'; /** * Define namespace utilities diff --git a/src/data/SensLog.js b/src/data/SensLog.js index 6987223..b1babe4 100644 --- a/src/data/SensLog.js +++ b/src/data/SensLog.js @@ -2,6 +2,11 @@ s4a.extend('data'); +/** + * SensLog communication object + * + * @class + */ s4a.data.SensLog = (function() { /** * Class with methods to interact with SensLog diff --git a/src/ir/ir.jsdoc b/src/ir/ir.jsdoc index 6a28a91..0c29496 100644 --- a/src/ir/ir.jsdoc +++ b/src/ir/ir.jsdoc @@ -1,4 +1,5 @@ /** * Information retrieval related methods + * * @namespace s4a.ir */ diff --git a/src/viz/Pie.js b/src/viz/Pie.js deleted file mode 100644 index 8fee5cb..0000000 --- a/src/viz/Pie.js +++ /dev/null @@ -1,207 +0,0 @@ -'use strict'; -/** - * Pie visualization - * - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {s4a.viz.ChartConfig} mChartConfig - * @constructor - */ -s4a.viz.Pie = function(viewCoordinator, mChartConfig) { - var chartData, currentData, currentScale, scale, arc, bigArc; - var _self = this; - var transitionTime = 400; - - /** - * Internal reference to Pie svg element. - * Use getSvg to retrieve it - * - * @private - */ - var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); - - function changeCollapsedState(collapsed) { - currentScale = collapsed ? scale : 1; - - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - var g = svg.selectAll('g'); - - if (currentScale === 1) { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - } else { - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - - setTimeout(function() { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - - }, transitionTime); - - } - } - - /** - * Create new pie chart - * - * @param {integer} width optional width of svg - * @param {integer} height optional height of svg - * @private - */ - function updateChart(width, height) { - // pick the first series - currentData = chartData.series[0].values; - - // and the first color - var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; - - mChartConfig.height = mChartConfig.height || mChartConfig.width; - mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; - - scale = mChartConfig.collapsed ? mChartConfig.collapsedWidth / mChartConfig.width : 1; - - currentScale = scale; - - var radius = Math.min(mChartConfig.width, mChartConfig.height) / 2; - var collapsedRadius = Math.min(mChartConfig.collapsedWidth, mChartConfig.collapsedHeight) / 2; - - var color = d3.scale.ordinal() - .range(colors); - - arc = d3.svg.arc() - .outerRadius(collapsedRadius); - - bigArc = d3.svg.arc() - .outerRadius(radius); - - if (mChartConfig.innerWidth) { - bigArc.innerRadius(radius - mChartConfig.innerWidth); - } - - var pie = d3.layout.pie() - .sort(null) - .value(function(d) { - return d.valx; - }); - - // delete all current objects - if (svg) { - svg.selectAll('*').remove(); - } - - var g = svg.selectAll('.arc') - .data(pie(currentData)) - .enter() - .append('g') - .attr('class', 'arc'); - - // avoid flash - g.attr('transform', 'translate(' + -4000 + ',' + -4000 + ')'); - - g.append('path') - .attr('d', mChartConfig.collapsed ? arc : bigArc) - .style('fill', function(d) { - return color(d.data.label); - }); - - if (mChartConfig.collapsed) { - changeCollapsedState(true); - } - - if (mChartConfig.collapsible) { - g.on('click', function() { - changeCollapsedState(currentScale === 1); - }); - } - } - - /** - * Get the geometry bound to the vizObject - * - * @returns {Object} set of lonlat or null - */ - _self.getGeometry = function() { - return chartData.geometry; - }; - - /** - * Get the svg representation of the vizObject - * - * @returns {d3.svg} set of lonlat or null - */ - _self.getSvg = function() { - return svg; - }; - - /** - * Set the visibility of the pie visualization (`true` or `false`). - * - * @param {boolean} visible The visibility of the layer. - */ - _self.setVisible = function(visible) { - if (svg) { - svg.attr('display', visible ? null : 'none'); - } - }; - - /** - * Redraw the vizObject - */ - _self.redraw = function() { - var g = svg.selectAll('g'); - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - - svg.attr('width', featureWidth) - .attr('height', featureHeight); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - }; - - // Methods inherited from top level vizObj - - /** - * Callback from ViewCoordinator. - * Update data object for the visualization - * - * @param {Object} mChartData - */ - _self.update = function(mChartData) { - chartData = mChartData; - updateChart(); - _self.redraw(); - }; - - /** - * Apply a filter to the visualization - * - * @abstract - */ - _self.filter = function() { - throw new Error('Must be implemented by sub-class'); - }; - - _self.get = function() { - throw new Error('Must be implemented by sub-class'); - }; - - viewCoordinator.subscribe(_self); - - return _self; -}; diff --git a/src/viz/chart/Bubble.js b/src/viz/chart/Bubble.js new file mode 100644 index 0000000..e2fb4e9 --- /dev/null +++ b/src/viz/chart/Bubble.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new bubble chart object + * + * @class + * @classdesc + * Stacked bubble chart object + */ +s4a.viz.chart.Bubble = function() { + +}; diff --git a/src/viz/chart/GroupedBar.js b/src/viz/chart/GroupedBar.js new file mode 100644 index 0000000..9e63815 --- /dev/null +++ b/src/viz/chart/GroupedBar.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new row chart object + * + * @class + * @classdesc + * Row chart object + */ +s4a.viz.chart.Row = function() { + +}; diff --git a/src/viz/chart/Line.js b/src/viz/chart/Line.js new file mode 100644 index 0000000..3879b64 --- /dev/null +++ b/src/viz/chart/Line.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new line chart object + * + * @class + * @classdesc + * Bar line chart object + */ +s4a.viz.chart.Line = function() { + +}; diff --git a/src/viz/chart/Pie.js b/src/viz/chart/Pie.js index 6fc96da..8fee5cb 100644 --- a/src/viz/chart/Pie.js +++ b/src/viz/chart/Pie.js @@ -1,11 +1,207 @@ -'use strict'; -/** - * Create a new Pie chart object - * - * @class - * @classdesc - * Pie chart object - */ -s4a.viz.chart.Pie = function() { - -}; +'use strict'; +/** + * Pie visualization + * + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {s4a.viz.ChartConfig} mChartConfig + * @constructor + */ +s4a.viz.Pie = function(viewCoordinator, mChartConfig) { + var chartData, currentData, currentScale, scale, arc, bigArc; + var _self = this; + var transitionTime = 400; + + /** + * Internal reference to Pie svg element. + * Use getSvg to retrieve it + * + * @private + */ + var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); + + function changeCollapsedState(collapsed) { + currentScale = collapsed ? scale : 1; + + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + var g = svg.selectAll('g'); + + if (currentScale === 1) { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + } else { + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + + setTimeout(function() { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + }, transitionTime); + + } + } + + /** + * Create new pie chart + * + * @param {integer} width optional width of svg + * @param {integer} height optional height of svg + * @private + */ + function updateChart(width, height) { + // pick the first series + currentData = chartData.series[0].values; + + // and the first color + var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; + + mChartConfig.height = mChartConfig.height || mChartConfig.width; + mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; + + scale = mChartConfig.collapsed ? mChartConfig.collapsedWidth / mChartConfig.width : 1; + + currentScale = scale; + + var radius = Math.min(mChartConfig.width, mChartConfig.height) / 2; + var collapsedRadius = Math.min(mChartConfig.collapsedWidth, mChartConfig.collapsedHeight) / 2; + + var color = d3.scale.ordinal() + .range(colors); + + arc = d3.svg.arc() + .outerRadius(collapsedRadius); + + bigArc = d3.svg.arc() + .outerRadius(radius); + + if (mChartConfig.innerWidth) { + bigArc.innerRadius(radius - mChartConfig.innerWidth); + } + + var pie = d3.layout.pie() + .sort(null) + .value(function(d) { + return d.valx; + }); + + // delete all current objects + if (svg) { + svg.selectAll('*').remove(); + } + + var g = svg.selectAll('.arc') + .data(pie(currentData)) + .enter() + .append('g') + .attr('class', 'arc'); + + // avoid flash + g.attr('transform', 'translate(' + -4000 + ',' + -4000 + ')'); + + g.append('path') + .attr('d', mChartConfig.collapsed ? arc : bigArc) + .style('fill', function(d) { + return color(d.data.label); + }); + + if (mChartConfig.collapsed) { + changeCollapsedState(true); + } + + if (mChartConfig.collapsible) { + g.on('click', function() { + changeCollapsedState(currentScale === 1); + }); + } + } + + /** + * Get the geometry bound to the vizObject + * + * @returns {Object} set of lonlat or null + */ + _self.getGeometry = function() { + return chartData.geometry; + }; + + /** + * Get the svg representation of the vizObject + * + * @returns {d3.svg} set of lonlat or null + */ + _self.getSvg = function() { + return svg; + }; + + /** + * Set the visibility of the pie visualization (`true` or `false`). + * + * @param {boolean} visible The visibility of the layer. + */ + _self.setVisible = function(visible) { + if (svg) { + svg.attr('display', visible ? null : 'none'); + } + }; + + /** + * Redraw the vizObject + */ + _self.redraw = function() { + var g = svg.selectAll('g'); + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + + svg.attr('width', featureWidth) + .attr('height', featureHeight); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + }; + + // Methods inherited from top level vizObj + + /** + * Callback from ViewCoordinator. + * Update data object for the visualization + * + * @param {Object} mChartData + */ + _self.update = function(mChartData) { + chartData = mChartData; + updateChart(); + _self.redraw(); + }; + + /** + * Apply a filter to the visualization + * + * @abstract + */ + _self.filter = function() { + throw new Error('Must be implemented by sub-class'); + }; + + _self.get = function() { + throw new Error('Must be implemented by sub-class'); + }; + + viewCoordinator.subscribe(_self); + + return _self; +}; diff --git a/src/viz/chart/StackedLine.js b/src/viz/chart/StackedLine.js new file mode 100644 index 0000000..227d7f6 --- /dev/null +++ b/src/viz/chart/StackedLine.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new stacked line chart object + * + * @class + * @classdesc + * Stacked line chart object + */ +s4a.viz.chart.StackedLine = function() { + +}; diff --git a/src/viz/chart/StackedRow.js b/src/viz/chart/StackedRow.js new file mode 100644 index 0000000..0ba85f0 --- /dev/null +++ b/src/viz/chart/StackedRow.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new stacked row chart object + * + * @class + * @classdesc + * Stacked row chart object + */ +s4a.viz.chart.StackedRow = function() { + +}; diff --git a/src/viz/map/Prism.js b/src/viz/map/Prism.js new file mode 100644 index 0000000..b4010ac --- /dev/null +++ b/src/viz/map/Prism.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.map'); + +/** + * Create a new Prism chart object + * + * @class + * @classdesc + * Prism chart object + */ +s4a.viz.map.Prism = function() { + +};