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

Print support for relative URLs #1797

Merged
merged 2 commits into from
May 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docma-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@

"web/client/utils/index.jsdoc",
"web/client/utils/PluginsUtils.js",
"web/client/utils/PrintUtils.js",
"web/client/utils/ShareUtils.js"
],
"jsapi": "web/client/jsapi/MapStore2.js",
Expand Down
76 changes: 73 additions & 3 deletions web/client/utils/PrintUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright 2016, GeoSolutions Sas.
* All rights reserved.
*
Expand All @@ -21,15 +21,55 @@ const assign = require('object-assign');
const getGeomType = function(layer) {
return (layer.features && layer.features[0]) ? layer.features[0].geometry.type : undefined;
};

/**
* Utilities for Print
* @memberof utils
*/
const PrintUtils = {
/**
* Given a static resource, returns the resource's absolute
* URL. Supports file paths with or without origin/protocol.
* @param {string} uri the uri to transform
* @param {string} [origin=window.location.origin] the origin to use
*/
toAbsoluteURL: (uri, origin) => {
// Handle absolute URLs (with protocol-relative prefix)
// Example: //domain.com/file.png
if (uri.search(/^\/\//) !== -1) {
return window.location.protocol + uri;
}

// Handle absolute URLs (with explicit origin)
// Example: http://domain.com/file.png
if (uri.search(/:\/\//) !== -1) {
return uri;
}

// Handle absolute URLs (without explicit origin)
// Example: /file.png
if (uri.search(/^\//) !== -1) {
return (origin || window.location.origin) + uri;
}
},
/**
* Tranform the original URL configuration of the layer into a URL
* usable for the print service.
* @param {string|array} input Original URL
* @return {string} the URL modified as GeoServer requires
*/
normalizeUrl: (input) => {
let result = isArray(input) ? input[0] : input;
if (result.indexOf('?') !== -1) {
result = result.substring(0, result.indexOf('?'));
}
return result;
return PrintUtils.toAbsoluteURL(result);
},
/**
* Find the layout name for the given options.
* The convention is: `PAGE_FORMAT + ("_2_pages_legend"|"_2_pages_legend"|"") + ("_landscape"|"")``
* @param {object} spec the spec with the options
* @return {string} the layout name.
*/
getLayoutName: (spec) => {
let layoutName = [spec.sheet];
if (spec.includeLegend) {
Expand All @@ -44,15 +84,33 @@ const PrintUtils = {
}
return layoutName.join('_');
},
/**
* Gets the print scales allowed from the capabilities of the print service.
* @param {capabilities} capabilities the capabilities of the print service
* @return {array} the scales array
*/
getPrintScales: (capabilities) => {
return capabilities.scales.slice(0).reverse().map((scale) => parseFloat(scale.value)) || [];
},
/**
* Guest the nearest zoom level in the allowed scales
* @param {number} zoom the zoom level
* @param {array} scales the allowed scales
* @param {array} [mapScales=defaultScales] the map scales
* @return {number} the index that best approximates the current map scale
*/
getNearestZoom: (zoom, scales, mapScales = defaultScales) => {
const mapScale = mapScales[zoom];
return scales.reduce((previous, current, index) => {
return current < mapScale ? previous : index;
}, 0);
},
/**
* Get the mapSize for print preview, parsing the layout and limiting the width.
* @param {object} layout the layout object
* @param {number} maxWidth the max width for the mapSize
* @return {object} width and height of a map limited by the maxWidth and with the same ratio of the layout
*/
getMapSize: (layout, maxWidth) => {
if (layout) {
const width = layout.rotation ? layout.map.height : layout.map.width;
Expand All @@ -67,6 +125,11 @@ const PrintUtils = {
height: 100
};
},
/**
* Creates the mapfish print specification from the current configuration
* @param {object} spec the current configuration
* @return {object} the mapfish print configuration to send to the server
*/
getMapfishPrintSpecification: (spec) => {
const projectedCenter = CoordinatesUtils.reproject(spec.center, 'EPSG:4326', spec.projection);
return {
Expand All @@ -92,6 +155,13 @@ const PrintUtils = {
"legends": PrintUtils.getMapfishLayersSpecification(spec.layers, spec, 'legend')
};
},
/**
* Generate the layers (or legend) specification for print.
* @param {array} layers the layers configurations
* @param {spec} spec the print configurations
* @param {string} purpose allowed values: `map|legend`. Tells which spec to generate.
* @return {array} the configuration array for layers (or legend) to send to the print service.
*/
getMapfishLayersSpecification: (layers, spec, purpose) => {
return layers.filter((layer) => PrintUtils.specCreators[layer.type] && PrintUtils.specCreators[layer.type][purpose])
.map((layer) => PrintUtils.specCreators[layer.type][purpose](layer, spec));
Expand Down
72 changes: 71 additions & 1 deletion web/client/utils/__tests__/PrintUtils-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright 2016, GeoSolutions Sas.
* All rights reserved.
*
Expand Down Expand Up @@ -83,6 +83,50 @@ const mapFishVectorLayer = {
]
}
};

const testSpec = {
"antiAliasing": true,
"iconSize": 24,
"legendDpi": 96,
"fontFamily": "Verdana",
"fontSize": 8,
"bold": false,
"italic": false,
"resolution": "96",
"name": "",
"description": "",
"sheet": "A2",
"includeLegend": true,
"twoPages": true,
"center": {
"x": 8.930511,
"y": 44.417107,
"crs": "EPSG:4326"
},
"zoom": 11,
"scaleZoom": 3,
"scale": 50000,
"layers": [
{
"group": "background",
"source": "osm",
"name": "mapnik",
"title": "Open Street Map",
"type": "osm",
"visibility": true,
"singleTile": false,
"dimensions": [],
"id": "mapnik__0",
"loading": false,
"loadingError": false
}
],
"projection": "EPSG:900913",
"size": {
"height": 462,
"width": 368
}
};
describe('PrintUtils', () => {

it('custom params are applied to wms layers', () => {
Expand All @@ -99,6 +143,11 @@ describe('PrintUtils', () => {
expect(specs.length).toBe(1);
expect(specs[0].geoJson.features[0].geometry.coordinates[0], mapFishVectorLayer).toBe(mapFishVectorLayer.geoJson.features[0].geometry.coordinates[0]);
});
it('vector layer generation for legend', () => {
const specs = PrintUtils.getMapfishLayersSpecification([layer], {projection: "EPSG:3857"}, 'legend');
expect(specs).toExist();
expect(specs.length).toBe(1);
});
it('vector layer default point style', () => {
const style = PrintUtils.getOlDefaultStyle({features: [{geometry: {type: "Point"}}]});
expect(style).toExist();
Expand All @@ -120,4 +169,25 @@ describe('PrintUtils', () => {
expect(style).toExist();
expect(style.strokeWidth).toBe(3);
});
it('toAbsoluteUrl', () => {
const url = PrintUtils.toAbsoluteURL("/geoserver", "http://localhost:8080");
expect(url).toExist();
expect(url).toBe("http://localhost:8080/geoserver");
expect(PrintUtils.toAbsoluteURL("//someurl/geoserver").indexOf("http")).toBe(0);
});
it('getMapSize', () => {
expect(PrintUtils.getMapSize()).toExist(); // check defaults
expect(PrintUtils.getMapSize({map: {width: 200, height: 200}}, 150).height).toBe(150);
expect(PrintUtils.getMapSize({rotation: true, map: {width: 200, height: 100}}, 200).height).toBe(400);
});
it('getNearestZoom', () => {
const scales = [1000, 1000, 1000000, 10000000];
expect(PrintUtils.getNearestZoom(0, scales)).toBe(0);
});
it('getMapfishPrintSpecification', () => {
const printSpec = PrintUtils.getMapfishPrintSpecification(testSpec);
expect(printSpec).toExist();
expect(printSpec.dpi).toBe(96);
expect(printSpec.layers.length).toBe(1);
});
});