add +over to proj4 mercator definitions - see https://github.com/mapbox/tilemill/issues/330

This commit is contained in:
Dane Springmeyer 2011-05-10 17:07:23 -07:00
commit c03b6334c6
15 changed files with 176 additions and 123 deletions

View File

@ -1,7 +0,0 @@
node 0.2.3
module isaacs sax-js v0.1.1
module documentcloud underscore 1.1.4
module visionmedia expresso 0.7.2
module creationix step v0.0.3
module springmeyer node-zipfile
module tmcw node-get

View File

@ -2,15 +2,21 @@
# Run all tests
#
expresso = ./node_modules/.bin/expresso
docco = ./node_modules/.bin/docco
lint:
./node_modules/.bin/jshint lib/carto/*.js lib/carto/tree/*.js
ifndef only
test:
bin/expresso -I lib test/*.test.js
$(expresso) -I lib test/*.test.js
else
test:
bin/expresso -I lib test/${only}.test.js
$(expresso) -I lib test/${only}.test.js
endif
doc:
docco lib/carto/*.js lib/carto/tree/*.js
$(docco) lib/carto/*.js lib/carto/tree/*.js
.PHONY: test

View File

@ -231,6 +231,11 @@ The `Renderer` interface is the main API for developers, and it takes an MML fil
There's a TextMate bundle that offers syntax highlighting for `.mss` and `.mml` files in the `build` directory. To install, download or clone this repository, then double-click on the `carto.tmbundle` icon in that folder.
The TextMate bundle **requires** [node-mapnik](https://github.com/mapnik/node-mapnik) and Carto installed globally - the versions that are installed locally in TileMill or other tools can't be automatically discovered.
npm install mapnik -g
npm install carto -g
## Credits
`carto.js` is based on [less.js](https://github.com/cloudhead/less.js), a CSS compiler written by Alexis Sellier.
@ -248,6 +253,19 @@ Only for running tests:
* [expresso](https://github.com/visionmedia/expresso)
* [sax-js](https://github.com/isaacs/sax-js/)
## Changelog
### 0.1.5
* Using npm devDependencies in place of ndistro
* Updated package.json format
* Fixes tests
### 0.1.4
* Fix bug in which SRS autodetection broke error handling
* Update carto
## Authors

View File

@ -1,5 +1,5 @@
var fs = require('fs'),
get = require('node-get'),
get = require('get'),
url = require('url'),
sys = require('sys'),
EventEmitter = require('events').EventEmitter,
@ -10,7 +10,7 @@ var fs = require('fs'),
Step = require('step');
// node compatibility for mkdirs below
var constants = (!process.EEXIST >= 1) ?
var constants = ((!process.EEXIST) >= 1) ?
require('constants') :
{ EEXIST: process.EEXIST };
@ -30,7 +30,7 @@ function External(env, uri) {
this._callbacks = [];
this.done = false;
External.mkdirp(this.env.data_dir, 0755);
External.mkdirp(this.env.data_dir, '0755');
if (local) {
this.localFile();
@ -66,8 +66,8 @@ External.prototype.localFile = function() {
External.prototype.downloadFile = function() {
this.tempPath = path.join(
this.env.data_dir,
crypto.createHash('md5').update(this.uri).digest('hex')
+ path.extname(this.uri));
crypto.createHash('md5').update(this.uri).digest('hex') +
path.extname(this.uri));
fs.stat(this.path(), function(err, stats) {
if (err) {
@ -120,9 +120,9 @@ External.prototype.findDataFile = function(callback) {
};
External.prototype.findOneByExtension = function(ext, callback) {
var cb = function(err, files) { callback(null, files.pop()); }
var cb = function(err, files) { callback(null, files.pop()); };
this.findByExtension(ext, cb);
}
};
// Find a file by extension in `this.path()`.
// Ignores .directories and .files
@ -137,7 +137,6 @@ External.prototype.findByExtension = function(ext, callback) {
running = 0;
callback(err);
return;
i;
}
files.forEach(function(file) {
// Ignore dotfiles and dot-directories
@ -186,42 +185,42 @@ External.mkdirp = function mkdirP(p, mode, f) {
External.types = [
{
extension: /\.zip/,
datafile: function(d, c) { d.findOneByExtension('.shp', c) },
datafile: function(d, c) { d.findOneByExtension('.shp', c); },
ds_options: {
type: 'shape'
}
},
{
extension: /\.shp/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); },
ds_options: {
type: 'shape'
}
},
{
extension: /\.png/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); }
},
{
extension: /\.jpe?g/,
extension: /\.jpe?g/
},
{
extension: /\.geotiff?|\.tiff?/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); },
ds_options: {
type: 'gdal'
}
},
{
extension: /\.vrt/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); },
ds_options: {
type: 'gdal'
}
},
{
extension: /\.kml/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); },
ds_options: {
type: 'ogr',
layer_by_index: 0
@ -229,7 +228,7 @@ External.types = [
},
{
extension: /\.geojson|\.json/,
datafile: function(d, c) { c(null, d.path()) },
datafile: function(d, c) { c(null, d.path()); },
ds_options: {
type: 'ogr',
layer_by_index: 0
@ -237,7 +236,7 @@ External.types = [
},
{
extension: /\.rss/,
datafile: function(d, c) { c(d.path()) },
datafile: function(d, c) { c(d.path()); },
ds_options: {
type: 'ogr',
layer_by_index: 0
@ -245,7 +244,7 @@ External.types = [
},
{
extension: /.*/g,
datafile: function(d, c) { c(d.path()) },
datafile: function(d, c) { c(d.path()); }
}
];
@ -290,17 +289,17 @@ External.processors['.zip'] = function(tempPath, destPath, callback) {
zf.names.forEach(function(name) {
var next = group();
var uncompressed = path.join(destPath, name);
External.mkdirp(path.dirname(uncompressed), 0755, function(err) {
External.mkdirp(path.dirname(uncompressed), '0755', function(err) {
if (err && err.errno != constants.EEXIST) {
callback("Couldn't create directory " + path.dirname(name));
}
else {
// if just a directory skip ahead
if (!path.extname(name)) {
if (!path.extname(name) || name[0] === '.') {
next();
} else {
var buffer = zf.readFile(name, function(err, buffer) {
fd = fs.open(uncompressed, 'w', 0755, function(err, fd) {
fd = fs.open(uncompressed, 'w', '0755', function(err, fd) {
sys.debug('saving to: ' + uncompressed);
fs.write(fd, buffer, 0, buffer.length, null,
function(err, written) {

View File

@ -5,7 +5,7 @@ tree.functions = {
return this.rgba(r, g, b, 1.0);
},
rgba: function (r, g, b, a) {
var rgb = [r, g, b].map(function (c) { return number(c) }),
var rgb = [r, g, b].map(function (c) { return number(c); }),
a = number(a);
return new tree.Color(rgb, a);
},

View File

@ -18,7 +18,7 @@ var carto = {
options = options || {};
if (options.silent) { return }
if (options.silent) { return; }
options.indent = options.indent || '';
@ -33,9 +33,9 @@ var carto = {
if (extract[1] === '' && typeof extract[2] === 'undefined') {
extract[1] = '¶';
}
error.push(ctx.line + ' ' + extract[1].slice(0, ctx.column)
+ stylize(stylize(extract[1][ctx.column], 'bold')
+ extract[1].slice(ctx.column + 1), 'yellow'));
error.push(ctx.line + ' ' + extract[1].slice(0, ctx.column) +
stylize(stylize(extract[1][ctx.column], 'bold') +
extract[1].slice(ctx.column + 1), 'yellow'));
if (typeof(extract[2]) === 'string') {
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
@ -51,7 +51,7 @@ var carto = {
sys.error(stylize('from ', 'red') + (ctx.filename || ''));
sys.error(stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract);
}
if (ctx.stack) { sys.error(stylize(ctx.stack, 'red')) }
if (ctx.stack) { sys.error(stylize(ctx.stack, 'red')); }
}
};
@ -99,7 +99,7 @@ carto.Parser.importer = function(file, paths, callback) {
require('carto/functions');
for (var k in carto) { exports[k] = carto[k] }
for (var k in carto) { exports[k] = carto[k]; }
// Stylize a string
function stylize(str, style) {

View File

@ -1,11 +1,11 @@
var carto, tree;
if (typeof(process) !== 'undefined') {
carto = exports,
carto = exports;
tree = require('carto/tree');
} else {
if (typeof(window.carto) === 'undefined') { window.carto = {} }
carto = window.carto,
if (typeof(window.carto) === 'undefined') { window.carto = {}; }
carto = window.carto;
tree = window.carto.tree = {};
}
//
@ -76,13 +76,21 @@ carto.Parser = function Parser(env) {
callback(root);
if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
if (that.queue.length === 0) { finish(); } // Call `finish` if we're done importing
}, env);
}
};
function save() { temp = chunks[j], memo = i, current = i }
function restore() { chunks[j] = temp, i = memo, current = i }
function save() {
temp = chunks[j];
memo = i;
current = i;
}
function restore() {
chunks[j] = temp;
i = memo;
current = i;
}
function sync() {
if (i > current) {
@ -132,13 +140,13 @@ carto.Parser = function Parser(env) {
while (i < endIndex) {
c = input.charCodeAt(i);
if (! (c === 32 || c === 10 || c === 9)) { break }
if (! (c === 32 || c === 10 || c === 9)) { break; }
i++;
}
chunks[j] = chunks[j].slice(length + (i - mem));
current = i;
if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
if (chunks[j].length === 0 && j < chunks.length - 1) { j++; }
if (typeof(match) === 'string') {
return match;
@ -167,7 +175,7 @@ carto.Parser = function Parser(env) {
lines = input.split('\n');
line = (input.slice(0, i).match(/\n/g) || '').length + 1;
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++; }
return {
name: 'ParseError',
@ -209,7 +217,7 @@ carto.Parser = function Parser(env) {
chunks = (function(chunks) {
var j = 0,
skip = /[^"'`\{\}\/]+/g,
comment = /\/\*(?:[^*]+|\*+[^\/*])*\*+\/|\/\/.*/g,
comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
level = 0,
match,
chunk = chunks[0],

View File

@ -4,9 +4,11 @@ var path = require('path'),
Step = require('step'),
_ = require('underscore')._,
sys = require('sys'),
srs = require('srs'),
carto = require('carto'),
tree = require('carto/tree');
require.paths.unshift(path.join(__dirname, '..', 'lib'));
// Rendering circuitry for JSON map manifests.
@ -28,6 +30,10 @@ carto.Renderer = function Renderer(env) {
// - @param {Object} m map object.
// - @param {Function} callback
ensureSRS: function(m, callback) {
if (env.only_validate === true) {
callback(null, m);
return;
}
Step(
function autodetectSRS() {
var group = this.group();
@ -39,7 +45,7 @@ carto.Renderer = function Renderer(env) {
fs.readdir(path.dirname(l.Datasource.file), this);
},
function(err, files) {
// Confirm that layers have .prj files
// Confirm that layers have .prj files
// in line with the .shp and .dbf, etc files.
var prj = _.detect(files, function(f) {
return path.extname(f).toLowerCase() == '.prj';
@ -51,15 +57,17 @@ carto.Renderer = function Renderer(env) {
this(new Error('No projection found'));
}
},
function(err, srs) {
function(err, srs_txt) {
if (!err) {
try {
l.srs = require('srs').parse(srs).proj4;
} catch (err) {}
l.srs = srs.parse(srs_txt).proj4;
} catch (exc) {}
if (!l.srs) {
try {
l.srs = require('srs').parse('ESRI::' + srs).proj4;
} catch(err) {}
l.srs = srs.parse('ESRI::' + srs_txt).proj4;
} catch (exc) {
// TODO: handle parse problems
}
}
}
next(err);
@ -109,7 +117,7 @@ carto.Renderer = function Renderer(env) {
next(null);
}
else {
next("No .shp file found in zipfile.");
next('No .shp file found in zipfile.');
}
});
});
@ -144,6 +152,9 @@ carto.Renderer = function Renderer(env) {
.on('complete', function(external) {
m.Stylesheet[k] = external.path();
next();
})
.on('err', function(err) {
throw 'Stylesheet "' + s + '" could not be loaded.';
});
}
});
@ -175,21 +186,21 @@ carto.Renderer = function Renderer(env) {
// as well which can be parsed directly
if (s.id) {
next(null, [s.id, s.data]);
// Otherwise the value is assumed to be a
// Otherwise the value is assumed to be a
// string and is read from the filesystem
} else {
fs.readFile(s, 'utf-8', function(err, data) {
next(err, [s, data]);
next(err, [s, data, 'first callback!']);
});
}
});
},
function compileStyles(e, results) {
var options = {},
group = this.group();
results.forEach(function(result) {
function compileStyles(err, res) {
var group = this.group();
if (err) { throw err; }
res.forEach(function(r) {
var next = group();
var parsingTime = +new Date;
var parsingTime = +new Date();
// Maintain a parsing environment from
// stylesheet to stylesheet, so that frames
// and effects are maintained.
@ -197,25 +208,19 @@ carto.Renderer = function Renderer(env) {
_.extend(
that.env,
this.env
), { filename: result[0] });
new carto.Parser(parse_env).parse(result[1],
), { filename: r[0] });
(new carto.Parser(parse_env)).parse(r[1],
function(err, tree) {
if (env.benchmark) console.warn('Parsing time: '
+ ((new Date - parsingTime))
+ 'ms');
try {
next(err, [
result[0],
tree]);
return;
} catch (e) {
throw e;
return;
}
if (env.benchmark) {
console.warn('Parsing time: '
+ ((new Date() - parsingTime))
+ 'ms');
}
next(err, tree, 'second callback!');
});
});
},
function waitForCompilation(err, res) {
function waitForCompilation(err, res, res2) {
callback(err, m, res);
}
);
@ -283,7 +288,7 @@ carto.Renderer = function Renderer(env) {
result.push(byAttachment[attachment]);
}
current = [ definitions[i] ];
current = [definitions[i]];
// Iterate over all subsequent rules.
for (var j = i + 1; j < definitions.length; j++) {
if (definitions[j].attachment === attachment) {
@ -292,13 +297,13 @@ carto.Renderer = function Renderer(env) {
}
}
for (var j = 0; j < current.length; j++) {
byFilter[attachment][current[j].filters] = current[j];
byAttachment[attachment].push(current[j]);
for (var k = 0; k < current.length; k++) {
byFilter[attachment][current[k].filters] = current[k];
byAttachment[attachment].push(current[k]);
}
}
if (env.benchmark) console.warn('Inheritance time: ' + ((new Date - inheritTime)) + 'ms');
if (env.benchmark) console.warn('Inheritance time: ' + ((new Date() - inheritTime)) + 'ms');
return result;
},
@ -356,8 +361,8 @@ carto.Renderer = function Renderer(env) {
return;
}
var rulesets = _.flatten(stylesheets.map(function(rulesets) {
return rulesets[1].toList(env);
var rulesets = _.flatten(stylesheets.map(function(ruleset) {
return ruleset.toList(env);
}));
// Iterate through layers and create styles custom-built
@ -396,7 +401,7 @@ carto.Renderer = function Renderer(env) {
var group = this.group();
try {
var map_properties = that.getMapProperties(rulesets, env);
} catch(err) {
} catch (err) {
env.error(err);
callback(env.errors);
return;
@ -443,7 +448,7 @@ carto.Renderer = function Renderer(env) {
if (env.errors.length) {
callback(env.errors);
} else {
callback(null, output.join('\n'))
callback(null, output.join('\n'));
}
}
);
@ -456,20 +461,20 @@ carto.Renderer = function Renderer(env) {
// - @param {Function} callback to be called with err,
// XML representation.
render: function(str, callback) {
var m = (typeof str == "string") ? JSON.parse(str) : str,
var m = (typeof str === 'string') ? JSON.parse(str) : str,
that = this;
var localizingTime = +new Date;
var localizingTime = +new Date();
this.localizeExternals(m, function(err, res) {
that.ensureSRS(res, function(err, res) {
that.localizeStyle(res, function(err, res) {
if (env.benchmark) console.warn('Localizing time: '
+ ((new Date - localizingTime)) + 'ms');
+ ((new Date() - localizingTime)) + 'ms');
that.style(res, function(err, m, res) {
var compilingTime = +new Date;
var compilingTime = +new Date();
that.template(err, m, res, function(err, res) {
if (env.benchmark) console.warn('Compiling time: '
+ ((new Date - compilingTime)) + 'ms');
+ ((new Date() - compilingTime)) + 'ms');
callback(err, res);
});
});

View File

@ -8,7 +8,7 @@ tree.Alpha.prototype = {
return 'alpha(opacity=' +
(this.value.toString ? this.value.toString() : this.value) + ')';
},
eval: function() { return this }
eval: function() { return this; }
};
})(require('carto/tree'));

View File

@ -7,7 +7,7 @@ tree.Anonymous.prototype = {
toString: function() {
return this.value;
},
eval: function() { return this }
eval: function() { return this; }
};
})(require('carto/tree'));

View File

@ -21,7 +21,7 @@ tree.Call.prototype = {
// The function should receive the value, not the variable.
//
eval: function(env) {
var args = this.args.map(function(a) { return a.eval(env) });
var args = this.args.map(function(a) { return a.eval(env); });
for (var i = 0; i < args.length; i++) {
if (args[i].is === 'undefined') {
@ -36,7 +36,7 @@ tree.Call.prototype = {
return tree.functions[this.name].apply(tree.functions, args);
} else { // 2.
return new tree.Anonymous(this.name +
'(' + args.map(function(a) { return a.toString() }).join(', ') + ')');
'(' + args.map(function(a) { return a.toString(); }).join(', ') + ')');
}
},

View File

@ -24,7 +24,7 @@ tree.Color = function Color(rgb, a) {
this.alpha = typeof(a) === 'number' ? a : 1;
};
tree.Color.prototype = {
eval: function() { return this },
eval: function() { return this; },
//
// If we have some transparency, the only way to represent it

View File

@ -8,7 +8,7 @@ tree.Comment.prototype = {
toString: function(env) {
return '<!--' + this.value + '-->';
},
eval: function() { return this }
eval: function() { return this; }
};
})(require('carto/tree'));

View File

@ -1,26 +1,50 @@
{
"name" : "carto",
"description" : "Mapnik Stylesheet Compiler",
"url" : "https://github.com/mapbox/carto",
"keywords" : ["mapnik", "maps", "css"],
"author" : "Tom MacWright <macwright@gmail.com>, Konstantin Käfer, Alexis Sellier <self@cloudhead.net>",
"contributors" : [],
"version" : "0.1.3",
"bin" : { "carto": "./bin/carto",
"cartox": "./bin/cartox",
"mml2json.js": "./bin/mml2json.js"
},
"main" : "./lib/carto/index",
"directories" : { "test": "./test" },
"engines" : { "node": ">=0.2.4" },
"dependencies" : {
"underscore" : ">= 1.0.3",
"step" : ">= 0.0.3",
"zipfile" : ">= 0.1.0",
"xml2js" : ">= 0.1.0",
"srs" : ">= 0.1.0",
"node-get" : "= 0.1.0",
"step" : ">= 0.0.3",
"expresso" : ">= 0.0.0"
"name": "carto",
"description": "Mapnik Stylesheet Compiler",
"url": "https://github.com/mapbox/carto",
"repositories": [{
"type": "git",
"url": "http://github.com/mapbox/carto.git"
}],
"keywords": [
"mapnik",
"maps",
"css",
"stylesheets"
],
"contributors": [
"Tom MacWright <macwright@gmail.com>",
"Konstantin Käfer",
"Alexis Sellier <self@cloudhead.net>"
],
"version": "0.1.5",
"licenses": [{
"type": "Apache"
}],
"bin": {
"carto": "./bin/carto",
"cartox": "./bin/cartox",
"mml2json.js": "./bin/mml2json.js"
},
"main": "./lib/carto/index",
"directories": {
"test": "./test"
},
"engines": {
"node": ">=0.2.4"
},
"dependencies": {
"underscore": ">= 1.0.3",
"step": ">= 0.0.3",
"zipfile": ">= 0.1.0",
"xml2js": ">= 0.1.0",
"srs": ">= 0.1.0",
"get": ">= 0.1.0",
"step": ">= 0.0.3"
},
"devDependencies": {
"expresso" : "= 0.7.x",
"docco" : "= 0.2.x",
"jshint" : "= 0.2.x"
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]>
<Map srs="+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 +no_defs +over">
<Map srs="+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 +no_defs">
<Style name="world" filter-mode="first">
@ -15,7 +15,7 @@
</Style>
<Layer
name="world"
srs="+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 +no_defs +over">
srs="+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 +no_defs">
<StyleName>world</StyleName>
<Datasource>
<Parameter name="file">[absolute path]</Parameter>
@ -79,7 +79,7 @@
</Style>
<Layer
name="countries"
srs="+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 +no_defs +over">
srs="+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 +no_defs">
<StyleName>countries</StyleName>
<Datasource>
<Parameter name="file">[absolute path]</Parameter>