Skip to content

Instantly share code, notes, and snippets.

@rochoa
Last active August 2, 2018 11:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rochoa/4e67ec932e8bb6b17831e0f4a2e0e55d to your computer and use it in GitHub Desktop.
Save rochoa/4e67ec932e8bb6b17831e0f4a2e0e55d to your computer and use it in GitHub Desktop.
[CARTO] basic viewer
'use strict';
var DEFAULTS = {
endpoint: 'https://rochoa.carto.com',
sql: 'select * from airbnb_madrid_oct_2015_listings',
cartocss: `#layer['mapnik::geometry_type'=1] {
marker-width: 7;
marker-fill: #EE4D5A;
marker-fill-opacity: 0.9;
marker-line-color: #FFFFFF;
marker-line-width: 1;
marker-line-opacity: 1;
marker-placement: point;
marker-type: ellipse;
marker-allow-overlap: true;
}
#layer['mapnik::geometry_type'=2] {
line-color: #4CC8A3;
line-width: 1.5;
line-opacity: 1;
}
#layer['mapnik::geometry_type'=3] {
polygon-fill: #826DBA;
polygon-opacity: 0.9;
::outline {
line-color: #FFFFFF;
line-width: 1;
line-opacity: 0.5;
}
}`,
center: [40.419769381446194, -3.715095520019531],
zoom: 12
};
var LOCAL_STORAGE_KEY = 'cartodb-viewer-config';
var Config = {
get: function() {
var config = {
endpoint: DEFAULTS.endpoint,
sql: DEFAULTS.sql,
cartocss: DEFAULTS.cartocss,
center: DEFAULTS.center,
zoom: DEFAULTS.zoom
};
if (window.localStorage) {
var storedConfig = localStorage.getItem(LOCAL_STORAGE_KEY);
if (storedConfig) {
try {
storedConfig = JSON.parse(storedConfig);
config.endpoint = storedConfig.endpoint || config.endpoint;
config.sql = storedConfig.sql || config.sql;
config.cartocss = storedConfig.cartocss || config.cartocss;
config.center = storedConfig.center || config.center;
config.zoom = storedConfig.zoom || config.zoom;
} catch (e) {
// pass
}
}
}
return config;
},
set: function(endpoint, sql, cartocss, center, zoom) {
var config = {};
if (endpoint !== DEFAULTS.endpoint) {
config.endpoint = endpoint;
}
if (sql !== DEFAULTS.sql) {
config.sql = sql;
}
if (cartocss !== DEFAULTS.cartocss) {
config.cartocss = cartocss;
}
config.center = center;
config.zoom = zoom;
if (window.localStorage) {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(config));
return true;
}
return false;
}
};
var map = L.map('map', {
scrollWheelZoom: false,
center: [40.419769381446194, -3.715095520019531],
zoom: 12
});
function onMapChanged() {
console.log('Current zoom = %d', map.getZoom());
var center = [map.getCenter().lat, map.getCenter().lng];
Config.set(currentMapsEndpoint(), sqlEditor.getValue(), cssEditor.getValue(), center, map.getZoom());
}
map.on('zoomend', onMapChanged);
map.on('dragend', onMapChanged);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}@2x.png', {
attribution: '<a href="http://cartodb.com">CartoDB</a> © 2014',
maxZoom: 18
}).addTo(map);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}@2x.png', {
attribution: '<a href="http://cartodb.com">CartoDB</a> © 2014',
maxZoom: 18
}).setZIndex(3).addTo(map);
var sqlEditor = CodeMirror.fromTextArea(document.getElementById('sql_editor'), {
theme: 'monokai',
lineNumbers: true,
lineWrapping: true,
mode: "text/x-plsql",
height: '400px'
});
var cssEditor = CodeMirror.fromTextArea(document.getElementById('css_editor'), {
theme: 'monokai',
lineNumbers: true,
lineWrapping: true,
mode: "text/x-scss",
height: "200px"
});
function tilesEndpoint(layergroupId) {
return currentMapsEndpoint() + '/' + layergroupId + '/{z}/{x}/{y}@2x.png?api_key=' + currentApiKey();
}
var tilesLayer = null;
async function updateMap() {
if (tilesLayer) {
map.removeLayer(tilesLayer);
}
const schemaResponse = await fetch(`${currentSQLEndpoint()}?q=${encodeURIComponent(`SELECT * FROM (${sqlEditor.getValue()}) _q LIMIT 0`)}`);
const schemaResult = await schemaResponse.json();
const geometryColumns = Object.keys(schemaResult.fields).filter(f => schemaResult.fields[f].type === 'geometry');
const geometriesResponse = await fetch(`${currentSQLEndpoint()}?q=${encodeURIComponent(`SELECT ${geometryColumns.map(c => `ST_SRID(${c}) as ${c}`)} FROM (${sqlEditor.getValue()}) _q LIMIT 1`)}`);
const geometriesResult = await geometriesResponse.json();
let srid = 3857;
let geom_column = 'the_geom_webmercator';
// This will use the last geometry column found
if (geometriesResult && geometriesResult.rows && geometriesResult.rows.length) {
const row = geometriesResult.rows[0];
for (let i = 0, len = geometryColumns.length; i < len; i++) {
const column = geometryColumns[i];
const columnSrid = row[column];
srid = columnSrid;
geom_column = column;
}
}
var config = {
version: '1.7.0',
layers: [
{
type: 'cartodb',
options: {
sql: sqlEditor.getValue(),
srid,
geom_column,
cartocss: cssEditor.getValue(),
cartocss_version: '3.0.12'
}
}
]
};
var request = new XMLHttpRequest();
request.open('POST', currentMapsEndpoint() + '?api_key=' + currentApiKey(), true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.onload = function() {
if (this.status >= 200 && this.status < 400){
var layergroup = JSON.parse(this.response);
console.log(layergroup.metadata.layers[0].meta.cartocss);
tilesLayer = L.tileLayer(tilesEndpoint(layergroup.layergroupid), {
maxZoom: 18
}).setZIndex(2).addTo(map);
onMapChanged();
} else {
throw 'Error calling server: Error ' + this.status + ' -> ' + this.response;
}
};
request.send(JSON.stringify(config));
}
function currentSQLEndpoint() {
return currentEndpointOrigin() + '/api/v2/sql';
}
function currentMapsEndpoint() {
return currentEndpointOrigin() + '/api/v1/map';
}
function currentEndpointOrigin() {
return new URL(document.getElementById('endpoint').value).origin;
}
function currentApiKey() {
return document.getElementById('apikey').value;
}
document.getElementById('endpoint').addEventListener('blur', updateMap, false);
CodeMirror.commands.save = function() {
updateMap();
};
var config = Config.get();
document.getElementById('endpoint').value = config.endpoint;
sqlEditor.setValue(config.sql);
cssEditor.setValue(config.cartocss);
map.setView(config.center, config.zoom);
updateMap();
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.3/leaflet.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/theme/monokai.min.css">
<style>
body {
margin: 0;
padding: 0;
border: 0;
height: 100%;
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
.wrap {
width: 100%;
margin: 0 auto;
}
textarea {
padding: 0;
margin: 0;
border: solid 1px #999;
height: 64px;
}
.editor {
float: left;
width: 40%;
height: 100vh;
}
.editor p {
margin: 8px 0;
}
.editor label, .editor input, .editor select {
width: 80%;
margin-bottom: 8px;
margin-left: 10px;
display: block;
}
.CodeMirror {
float: left;
width: 100%;
height: 40vh;
margin-bottom: 8px;
}
#map {
width: 60%;
height: 100vh;
}
</style>
</head>
<body>
<div class="wrap">
<form class="editor">
<p>
<label for="endpoint">Maps API endpoint</label>
<input type="text" name="endpoint" id="endpoint" value="https://rochoa.carto.com/api/v1/map">
</p>
<p>
<label for="apikey">API key</label>
<input type="text" name="apikey" id="apikey" value="" placeholder="YOUR API KEY">
</p>
<p>
<label for="sql_editor">SQL</label>
<textarea id="sql_editor" class="code"></textarea>
</p>
<p>
<label for="css_editor">CartoCSS</label>
<textarea id="css_editor" class="code"></textarea>
</p>
</form>
<div id="map"></div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.3/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/mode/javascript/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/mode/sql/sql.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.39.2/mode/css/css.min.js"></script>
<script src="app.js"></script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment