Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quad feature #528

Merged
merged 12 commits into from
Feb 10, 2016
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"proj4": "=2.3.3",
"bootstrap": "~3.3.0",
"bootswatch": "~3.3",
"vgl": "0.3.5"
"vgl": "0.3.6"
},
"devDependencies": {
"codemirror": "~4.7.0",
Expand Down
9 changes: 9 additions & 0 deletions examples/quads/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"path": "quads",
"title": "Quad features",
"exampleCss": ["main.css"],
"exampleJs": ["main.js"],
"about": {
"text": "This example shows how to add dynamic quads to a map."
}
}
Binary file added examples/quads/flower1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/quads/flower2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/quads/flower3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/quads/index.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extends ../common/templates/index.jade
Empty file added examples/quads/main.css
Empty file.
144 changes: 144 additions & 0 deletions examples/quads/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
var quadDebug = {};

// Run after the DOM loads
$(function () {
'use strict';

var map = geo.map({
node: '#map',
center: {
x: -88.0,
y: 29
},
zoom: 4
});
var layer = map.createLayer('feature', {renderer: 'vgl'});
var quads = layer.createFeature('quad', {selectionAPI: true});
var previewImage = new Image();
previewImage.onload = function () {

quads
.data([{
ll: {x: -108, y: 29},
ur: {x: -88, y: 49},
image: '/data/tilefancy.png'
}, {
ll: {x: -88, y: 29},
ur: {x: -58, y: 49},
image: 'flower1.jpg',
opacity: 0.75
}, {
ul: {x: -108, y: 29},
ur: {x: -58, y: 29},
ll: {x: -98, y: 9},
lr: {x: -68, y: 9},
previewImage: null,
image: 'flower3.jpg'
}, {
lr: {x: -58, y: 29},
ur: {x: -58, y: 49},
ul: {x: -38, y: 54},
ll: {x: -33, y: 34},
image: 'flower2.jpg',
opacity: 0.15
}, {
ll: {x: -33, y: 34},
lr: {x: -33, y: 9},
ur: {x: -68, y: 9},
ul: {x: -58, y: 29},
image: '/data/tilefancy.png'
}, {
ll: {x: -128, y: 29},
ur: {x: -108, y: 49},
image: '/data/nosuchimage.png'
}, {
ul: {x: -128, y: 29},
ur: {x: -108, y: 29},
ll: {x: -123, y: 9},
lr: {x: -98, y: 9},
previewImage: null,
image: '/data/nosuchimage.png'
}, {
ul: {x: -148, y: 29},
ur: {x: -128, y: 29},
ll: {x: -148, y: 9},
lr: {x: -123, y: 9},
previewImage: previewImage,
image: '/data/nosuchimage.png'
}, {
ll: {x: -138, y: 29},
ur: {x: -128, y: 39},
color: '#FF0000'
}, {
ll: {x: -148, y: 39},
ur: {x: -138, y: 49},
color: '#FF0000'
}, {
ll: {x: -138, y: 39},
ur: {x: -128, y: 49},
color: '#00FFFF'
}, {
ll: {x: -148, y: 29},
ur: {x: -138, y: 39},
opacity: 0.25,
color: '#0000FF'
/* You can specify quads so that the corners are 'twisted' and the quad
* would be non-convex. In this case, the quads are each rendered as a
* pair of triangles, but they probably aren't what is desired.
}, {
ll: {x: -108, y: 49},
lr: {x: -88, y: 49},
ur: {x: -108, y: 59},
ul: {x: -88, y: 59},
image: '/data/tilefancy.png'
}, {
ll: {x: -88, y: 49},
ur: {x: -68, y: 49},
ul: {x: -88, y: 59},
lr: {x: -68, y: 59},
image: '/data/tilefancy.png'
*/
}])
.style({
opacity: function (d) {
return d.opacity !== undefined ? d.opacity : 1;
},
color: function (d) {
return d.color;
},
previewColor: {r: 1, g: 0.75, b: 0.75},
previewImage: function (d) {
return d.previewImage !== undefined ? d.previewImage : previewImage;
}
})
.geoOn(geo.event.feature.mouseover, function (evt) {
if (evt.data.orig_opacity === undefined) {
evt.data.orig_opacity = (evt.data.opacity || null);
}
evt.data.opacity = 0.5;
// we either have to clear the internal cache on the item, or have
// asked for it not to have been cached to begin with.
delete evt.data._cachedQuad;
this.modified();
layer.map().draw();
})
.geoOn(geo.event.feature.mouseout, function (evt) {
if (evt.data.orig_opacity === undefined) {
evt.data.orig_opacity = (evt.data.opacity || null);
}
evt.data.opacity = evt.data.orig_opacity || undefined;
delete evt.data._cachedQuad;
this.modified();
layer.map().draw();
})
.draw();

map.draw();

quadDebug.map = map;
quadDebug.layer = layer;
quadDebug.quads = quads;
};

previewImage.src = '/data/grid.jpg';
});
Binary file added examples/quads/thumb.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions examples/tiles/index.jade
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ block append mainContent
label(for="layer-opacity") Opacity
input#layer-opacity.layerparam(param-name="opacity", placeholder="1.0")

//- Although the projection can be changed, this currently has odd
repercussions when using a standard EPSG:3857 tile set. If wrapping is
turned on, an infinite number of tiles may be requested, and, in general,
the number of tiles for a particular zoom level can be significantly
wrong. Using a projection that differs from the tile set could be useful
for localized data, but probably won't work as expected for the entire
world map.
//- form-group(title="Web maps are most often rendered using a Mercator geographic coordinate system, but other projections can be used. Many projections will only work with the VGL renderer.")
label(for="map-gcs") Map GCS
select#map-gcs.mapparam(param-name="gcs", placeholder="EPSG:3857 - Web Mercator", reload="true")
option(value="EPSG:3857") Web Mercator
option(value="SR-ORG:6865") MODIS Sinusoidal
option(value="ESRI:54028") Cassini

.form-group(title="The camera can use a parallel or perspective projection. The difference is subtly unless the data has non-zero z-values.")
label(for="camera-projection") Camera Projection
select#camera-projection.cameraparam(param-name="projection", placeholder="parallel")
Expand Down
76 changes: 53 additions & 23 deletions examples/tiles/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ var tileDebug = {};
$(function () {
'use strict';

// Most map tile servers use EPSG:3857 (Web Mercator). Using a tile server
// with a different projection works correctly in all renderers. Using a
// different projection for the tiles and the map can work in the vgl
// renderer, but may have problems as the tile density is not uniform or
// regular.
var gcsTable = {
'EPSG:3857': 'EPSG:3857',
'SR-ORG:6865': '+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs',
'ESRI:54028': '+proj=cass +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs'
};

// Parse query parameters into an object for ease of access
var query = document.location.search.replace(/(^\?)/, '').split(
'&').map(function (n) {
Expand Down Expand Up @@ -100,15 +111,19 @@ $(function () {
y: 39.5
},
maxBounds: {},
zoom: query.zoom !== undefined ? parseFloat(query.zoom) : 3
zoom: query.zoom !== undefined ? parseFloat(query.zoom) : 3,
gcs: gcsTable[query.gcs] || query.gcs
};
// Set the tile layer defaults to use the specified renderer and opacity
var layerParams = {
renderer: query.renderer || 'vgl',
opacity: query.opacity || '1',
/* Always use a larger cache so if keepLower is changed, we still have a
* big enough cache. */
cacheSize: 600
cacheSize: 600,
/* Most map sources are in Web Mercator, so specify it here if the map's
* gcs has been specified. */
gcs: query.gcs ? 'EPSG:3857' : undefined
};
if (layerParams.renderer === 'null' || layerParams.renderer === 'html') {
layerParams.renderer = null;
Expand All @@ -130,8 +145,8 @@ $(function () {
// a pixel coordinate system.
var w, h;
if (query.w && query.h) {
w = parseInt(query.w);
h = parseInt(query.h);
w = parseInt(query.w, 10);
h = parseInt(query.h, 10);
// Set a pixel coordinate system where 0, 0 is the upper left and w, h is
// the lower-right.
/* If both ingcs and gcs are set to an empty string '', the coordinates
Expand All @@ -142,6 +157,7 @@ $(function () {
* The 'longlat' projection functionally is a no-op in this case. */
mapParams.ingcs = '+proj=longlat +axis=esu';
mapParams.gcs = '+proj=longlat +axis=enu';
layerParams.gcs = undefined; /* use the map gcs */
/* mapParams.ingcs = mapParams.gcs = ''; */
mapParams.maxBounds = {left: 0, top: 0, right: w, bottom: h};
mapParams.center = {x: w / 2, y: h / 2};
Expand Down Expand Up @@ -187,10 +203,10 @@ $(function () {
layerParams.tileRounding = Math[query.round];
}
if (query.tileWidth) {
layerParams.tileWidth = parseInt(query.tileWidth);
layerParams.tileWidth = parseInt(query.tileWidth, 10);
}
if (query.tileHeight) {
layerParams.tileHeight = parseInt(query.tileHeight);
layerParams.tileHeight = parseInt(query.tileHeight, 10);
}
if (w && h) {
mapParams.max = Math.ceil(Math.log(Math.max(
Expand All @@ -201,6 +217,12 @@ $(function () {
if (query.max !== undefined) {
mapParams.max = parseFloat(query.max);
}
if (query.minLevel !== undefined) {
layerParams.minLevel = parseInt(query.minLevel, 10);
}
if (query.maxLevel !== undefined) {
layerParams.maxLevel = parseInt(query.maxLevel, 10);
}
// allow a generous max tile level so it is never the limit
if (!layerParams.maxLevel) {
layerParams.maxLevel = 25;
Expand All @@ -215,25 +237,25 @@ $(function () {
}
// Populate boolean flags for the map
$.each({
clampBoundsX: 'clampBoundsX',
clampBoundsY: 'clampBoundsY',
clampZoom: 'clampZoom',
discrete: 'discreteZoom'
}, function (qkey, mkey) {
if (query[qkey] !== undefined) {
mapParams[mkey] = query[qkey] === 'true';
}
});
clampBoundsX: 'clampBoundsX',
clampBoundsY: 'clampBoundsY',
clampZoom: 'clampZoom',
discrete: 'discreteZoom'
}, function (qkey, mkey) {
if (query[qkey] !== undefined) {
mapParams[mkey] = query[qkey] === 'true';
}
});
// Populate boolean flags for the tile layer
$.each({
lower: 'keepLower',
wrapX: 'wrapX',
wrapY: 'wrapY'
}, function (qkey, lkey) {
if (query[qkey] !== undefined) {
layerParams[lkey] = query[qkey] === 'true';
}
});
lower: 'keepLower',
wrapX: 'wrapX',
wrapY: 'wrapY'
}, function (qkey, lkey) {
if (query[qkey] !== undefined) {
layerParams[lkey] = query[qkey] === 'true';
}
});
// Create a map object
var map = geo.map(mapParams);
// Set the projection. This has to be set on the camera, not in the map
Expand Down Expand Up @@ -292,6 +314,13 @@ $(function () {
case 'fade':
$('#map').toggleClass('fade-image', processedValue);
break;
case 'gcs':
mapParams.gcs = gcsTable[processedValue] || 'EPSG:3857';
map.gcs(mapParams.gcs);
map.deleteLayer(osmLayer);
osmLayer = map.createLayer('osm', layerParams);
tileDebug.osmLayer = osmLayer;
break;
case 'lower':
layerParams.keepLower = (value === 'true');
break;
Expand Down Expand Up @@ -345,6 +374,7 @@ $(function () {
if (ctl.is('.layerparam') && ctl.attr('reload') === 'true') {
map.deleteLayer(osmLayer);
osmLayer = map.createLayer('osm', layerParams);
tileDebug.osmLayer = osmLayer;
}
// update the url to reflect the changes
query[param] = value;
Expand Down
2 changes: 2 additions & 0 deletions sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"pathFeature.js",
"polygonFeature.js",
"planeFeature.js",
"quadFeature.js",
"vectorFeature.js",
"geomFeature.js",
"graphFeature.js",
Expand Down Expand Up @@ -63,6 +64,7 @@
"pointFeature.js",
"geomFeature.js",
"planeFeature.js",
"quadFeature.js",
"polygonFeature.js",
"contourFeature.js",
"vglRenderer.js",
Expand Down
4 changes: 2 additions & 2 deletions src/core/imageTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
this._image.crossOrigin = this._cors;
}
defer = new $.Deferred();
this._image.onload = function () { defer.resolve(); };
this._image.onerror = function () { defer.reject(); };
this._image.onload = defer.resolve;
this._image.onerror = defer.reject;
this._image.src = this._url;

// attach a promise interface to `this`
Expand Down
6 changes: 3 additions & 3 deletions src/core/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ geo.map = function (arg) {

camera_bounds(m_this.boundsFromZoomAndCenter(
m_zoom, m_center, m_rotation, null), m_rotation);
m_this.modified();
// trigger a pan event
m_this.geoTrigger(
geo.event.pan,
Expand Down Expand Up @@ -620,13 +621,13 @@ geo.map = function (arg) {
m_width = w;
m_height = h;

m_this.camera().viewport = {width: w, height: h};

reset_minimum_zoom();
var newZoom = fix_zoom(m_zoom);
if (newZoom !== m_zoom) {
m_this.zoom(newZoom);
}
m_this.camera().viewport = {width: w, height: h};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manthey why was this necessary?

m_this.center(oldCenter);

m_this.geoTrigger(geo.event.resize, {
type: geo.event.resize,
Expand All @@ -637,7 +638,6 @@ geo.map = function (arg) {
height: h
});

m_this.center(oldCenter);
m_this.modified();
return m_this;
};
Expand Down
Loading