From 551a2d8e46f5165ae8fb916b1c1c85f50db6d340 Mon Sep 17 00:00:00 2001 From: Rob Brackett Date: Thu, 3 Apr 2014 20:15:31 -0700 Subject: [PATCH 1/2] First pass at customizable buffering of render bounds. Ref #75. --- lib/Map.js | 41 +++++++++++++---- test/Map.spec.js | 111 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 test/Map.spec.js diff --git a/lib/Map.js b/lib/Map.js index 385afe4..d548864 100644 --- a/lib/Map.js +++ b/lib/Map.js @@ -18,16 +18,21 @@ var BUFFER_RATIO = 0.25; var DEFAULT_PROJECTION = "EPSG:900913";//"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"; var Map = function(options) { + options = options || {}; + this.datasources = []; this.styles = []; this.projection = DEFAULT_PROJECTION; this.assetsPath = "."; - if (options && options.projection){ + if (options.projection){ this.projection = projector.util.cleanProjString(options.projection); console.log(this.projection); } + this.boundsBuffer = + ("boundsBuffer" in options) ? options.boundsBuffer : BUFFER_RATIO; + this._renderer = cartoRenderer; }; @@ -35,8 +40,7 @@ Map.prototype = { constructor: Map, render: function(options) { - var bounds = options.bounds; - this._getData(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY, function(error, shapes) { + this._getData(options.bounds, options.boundsBuffer, function(error, shapes) { if (error) { options.callback(error); } @@ -54,8 +58,7 @@ Map.prototype = { // Should this really be here, or should it exist on a different object entirely? renderGrid: function(options) {//minX, minY, maxX, maxY, width, height, asImage, callback) { - var bounds = options.bounds; - this._getData(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY, function(error, shapes) { + this._getData(options.bounds, options.boundsBuffer, function(error, shapes) { if (error) { options.callback(error); console.error("ERROR! "+error); @@ -73,8 +76,8 @@ Map.prototype = { }.bind(this)); }, - _getData: function(minX, minY, maxX, maxY, callback) { - var buffer = (maxX - minX) * BUFFER_RATIO; + _getData: function(bounds, buffer, callback) { + var dataBounds = this._bufferedBounds(bounds, buffer); // this is a bit quick and dirty - we could possibly use style data // to figure out more detailed queries than just geographic bounds @@ -96,7 +99,7 @@ Map.prototype = { } // allow simple sources to just return results immediately - var syncData = datasource(minX - buffer, minY - buffer, maxX + buffer, maxY + buffer, projection, preCallback); + var syncData = datasource(dataBounds.minX, dataBounds.minY, dataBounds.maxX, dataBounds.maxY, projection, preCallback); if (syncData) { preCallback(null, syncData); } @@ -115,6 +118,28 @@ Map.prototype = { ); }, + _bufferedBounds: function(bounds, buffer) { + if (buffer == null) { + buffer = this.boundsBuffer; + } + + if (typeof buffer === "function") { + return buffer.call(this, bounds); + } + + if (typeof buffer !== "number") { + buffer = BUFFER_RATIO; + } + + amount = (bounds.maxX - bounds.minX) * buffer; + return { + minX: bounds.minX - amount, + minY: bounds.minY - amount, + maxX: bounds.maxX + amount, + maxY: bounds.maxY + amount + }; + }, + addData: function(datasource) { // validate datasource if (!(typeof datasource === "function" || typeof datasource.getShapes === "function")) { diff --git a/test/Map.spec.js b/test/Map.spec.js new file mode 100644 index 0000000..ab17601 --- /dev/null +++ b/test/Map.spec.js @@ -0,0 +1,111 @@ +var expect = require("chai").expect; +var sinon = require("sinon"); +var Map = require(__dirname + '/../index').Map; + +describe("Map", function() { + + describe("bounds buffering", function() { + + it("should default to 25%", function() { + var data = sinon.stub().returns([]); + var map = new Map(); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10 + }); + expect(data.calledWith(-2.5, -2.5, 12.5, 12.5)).to.be.true; + }); + + it("should accept a custom value per map", function() { + var data = sinon.stub().returns([]); + var map = new Map({ + boundsBuffer: 0.5 + }); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10 + }); + expect(data.calledWith(-5, -5, 15, 15)).to.be.true; + }); + + it("should accept a custom function per map", function() { + var data = sinon.stub().returns([]); + var map = new Map({ + boundsBuffer: function() { + return {minX: -1, minY: 1, maxX: 12, maxY: 9}; + } + }); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10 + }); + expect(data.calledWith(-1, 1, 12, 9)).to.be.true; + }); + + it("should accept a custom value per render", function() { + var data = sinon.stub().returns([]); + var map = new Map({ + boundsBuffer: 0.5 + }); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10, + boundsBuffer: 0.1 + }); + expect(data.calledWith(-1, -1, 11, 11)).to.be.true; + }); + + it("should accept a custom function per render", function() { + var data = sinon.stub().returns([]); + var map = new Map({ + boundsBuffer: 0.5 + }); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10, + boundsBuffer: function() { + return {minX: -1, minY: 1, maxX: 12, maxY: 9}; + } + }); + expect(data.calledWith(-1, 1, 12, 9)).to.be.true; + }); + + it("should be able to be 0", function() { + var data = sinon.stub().returns([]); + var map = new Map({ + boundsBuffer: 0 + }); + map.addData(data); + map.addStyle("Map { background-color: #999; }"); + map.render({ + bounds: {minX: 0, minY: 0, maxX: 10, maxY: 10}, + width: 256, + height: 256, + zoom: 10 + }); + expect(data.calledWith(0, 0, 10, 10)).to.be.true; + }); + + }); + +}); From 793c4e303840ec56b27abbcecdaeaeff2851cb96 Mon Sep 17 00:00:00 2001 From: Rob Brackett Date: Fri, 4 Apr 2014 14:32:04 -0700 Subject: [PATCH 2/2] Bump version to 0.0.4 for the added boundsBuffer feature; update copyright dates. Closes #75. --- LICENSE | 2 +- README.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 20d7245..4e81754 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2013, Code for America +Copyright (c) 2012-2014, Code for America All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 4f040f8..bf17773 100644 --- a/README.md +++ b/README.md @@ -81,5 +81,5 @@ Projections Copyright --------- -Copyright (c) 2012-2013 Code for America. See LICENSE for details. +Copyright (c) 2012-2014 Code for America. See LICENSE for details. diff --git a/package.json b/package.json index 5527024..f6233f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodetiles-core", - "version": "0.0.3", + "version": "0.0.4", "description": "Joyful map rendering with Node.js.", "contributors": [ {