I'm trying to build my own vector tile server using Mapnik. Now I've created a XML style using Tilemill and exported this to include in the Mapnik node server.
Below the code of the server to render te .mvt tiles.
app.get('/tiles/:z/:x/:y.mvt', (req, res, next) => {
var projection = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs';
var map = new mapnik.Map(256, 256, projection);
map.load('./mapgather-style/mapgather.xml', {strict: false}, function(err, map) {
if(err) {
console.log(err);
}
let vtile = new mapnik.VectorTile(parseFloat(req.params.z), parseFloat(req.params.x), parseFloat(req.params.y));
map.render(vtile, {}, function(err, response) {
if (err) { console.log(err) }
res.setHeader('Content-Encoding', 'deflate');
res.setHeader('Content-Type', 'application/vnd.vector-tile');
zlib.deflate(response.getData(), (err, mvt) => {
if(err) { console.log(err) }
res.send(mvt);
});
})
})
})
I've also created a Leaflet map with the leaflet.vectorgrid plugin for rendering the vector tiles. The http://localhost:8080/tiles/{z}/{x}/{y}.mvt request returns the tiles, but without any styes.. Only blue lines as you can see on the screenshot below.
I've figured out that I can style the tiles using the Vector grid plugin. But I'm wondering if it is possible to pre-render the style from the server. In Tilemill I've created a style, but it seems that Mapnik doesn't include this style in the .mvt response.
Is it possible at all to pre-render the map styles? Hope someone can help!
Related
I'm using ArcGIS JS 4.16 to allow users to draw a polygon on the map. The idea is that there will only be one polygon at any given time and when you connect two dots, it makes sense that it would complete the polygon. Double clicking or pressing "C" seems a bit more complex for the average use case.
const drawLayer = new GraphicsLayer();
const map = new Map({
basemap: 'streets-vector',
layers: [drawLayer],
});
const view = new MapView({
container: mapRef.current,
map: map,
center: [-73.93, 40.73],
zoom: 10,
});
const draw = new Draw({ view: view });
document
.getElementById('enableCreatePolygon')
.addEventListener('click', () => {
enableCreatePolygon(draw, view);
});
const enableCreatePolygon = (draw, view) => {
const action = draw.create('polygon');
action.on('vertex-add', (evt) => {
createPolygonGraphic(evt.vertices);
});
action.on('vertex-remove', (evt) => {
createPolygonGraphic(evt.vertices);
});
action.on('cursor-update', (evt) => {
createPolygonGraphic(evt.vertices);
});
action.on('draw-complete', (evt) => {
createPolygonGraphic(evt.vertices);
});
};
const createPolygonGraphic = (vertices) => {
view.graphics.removeAll();
const polygon = {
type: 'polygon',
rings: vertices,
spatialReference: view.spatialReference,
};
const graphic = new Graphic({
geometry: polygon,
symbol: {
type: 'simple-fill',
color: [51, 51, 204, 0.15],
style: 'solid',
outline: {
color: [51, 51, 204, 0.8],
width: 2,
},
},
});
I see two options, implement the "logic" or use SketchViewModel where is it already implemented. Btw, with the "logic" I mean complete polygon when the last vertex is equal (with a tolerance) to the first vertex.
Take a look at this links,
ArcGIS JS API Docs - SketchViewModel
You can implement your own UI to interact with the model or use the SketchWidget.
ArcGIS JS API Examples - Using custom UI or interaction
ArcGIS JS API Examples - Using SketchWidget
The component:
https://ant.design/components/tree-select/
There is no example with the loadData option.
async getChildren(node) {
console.log(node);
let r = $.get("/tree", {id: node.value})
console.log(await r); // request works
return r;
}
With this code I just see the tree loading and nothing happens. Not an error, but the child nodes are not appended to the tree.
If I don't return a Promise, I get a huge error and a blank page.
this is an example of loadData function:
onLoadData = (treeNode) => {
console.log('load data...');
return new Promise((resolve) => {
setTimeout(() => {
const treeData = [...this.state.treeData];
getNewTreeData(treeData, treeNode.props.eventKey, generateTreeNodes(treeNode), 2);
this.setState({ treeData });
resolve();
}, 500);
});
}
You can find it here with more in-deep examples
To make it clearer:
TreeData is an Array of TreeNode
source
antd tree select uses rc-tree because antd is built on top of rc-components you can see the source
For lazy load you need to manipulate the treeNode, what above snippet
does is: everytime loaded new data it will be a treeNode object, and
will call the onLoadData() callback where you provide the code what
to do with that node. (the sample just append to the state's treeData
variable]
I'm using intern.js to test a web app. I can execute tests and create screenshots when they fail. I want to create a screenshot for specific element in order to do some CSS regression testing using tools like resemble.js. Is it possible? How can I do? Thank you!
driver.get("http://www.google.com");
WebElement ele = driver.findElement(By.id("hplogo"));
//Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
//Get the location of element on the page
Point point = ele.getLocation();
//Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
//Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(), eleWidth,
eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
//Copy the element screenshot to disk
File screenshotLocation = new File("C:\\images\\GoogleLogo_screenshot.png");
FileUtils.copyFile(screen, screenshotLocation);
Taken from here.
There isn't a built in way to do this with Intern. The takeScreenshot method simply calls Selenium's screenshot service, which returns a screenshot of the entire page as a base-64 encoded PNG. Intern's takeScreenshot converts this to a Node buffer before handing the result to the user.
To crop the image you will need to use an external library or tool such as png-crop (note that I've never used this). The code might look like the following (untested):
var image;
var size;
var position;
return this.remote
// ...
.takeScreenshot()
.then(function (imageBuffer) {
image = imageBuffer;
})
.findById('element')
.getSize()
.then(function (elementSize) {
size = elementSize;
})
.getPosition()
.then(function (elementPosition) {
position = elementPosition;
})
.then(function () {
// assuming you've loaded png-crop as PNGCrop
var config = {
width: size.width,
height: size.height,
top: position.y,
left: position.x
};
// need to return a Promise since PNGCrop.crop is an async method
return new Promise(function (resolve, reject) {
PNGCrop.crop(image, 'cropped.png', config, function (err) {
if (err) {
reject(err);
}
else {
resolve();
}
});
});
})
I'm currently trying to reactively show markers on a Mapbox map. My approach was to observe a collection and while doing so, create a GeoJSON object. Changes in that particular object do not reflect on the map however.
var featureArray = [];
CollectionName.find({}).observe({
added: function(item) {
featureArray.push({
type: "Feature",
geometry: {
type: "Point",
coordinates: [+item.location.coordinates[0], +item.location.coordinates[1]]
},
properties: {
_id: item._id,
}
});
},
changedAt: function(newDocument, oldDocument, atIndex) {
//..
},
removed: function(oldDocument, atIndex) {
//..
}
});
var CollectionGeoJSON = {
'type': 'FeatureCollection',
'features': testmarkers
};
var markers = L.mapbox.featureLayer().setGeoJSON(CollectionGeoJSON);
// add cluster markers and add them to map
My idea was to manually add/remove/change the markers on the client (as changes are synced to the server anyway), however also no success here as I'm not sure how to do that using the Mapbox API.
Any hints are greatly appreciated.
I've created a meteorpad example, showing this.
The reactivity is created by calling template.autorun in the onRendered callback. The template.autorun callback is triggered by any changes to the results of Cities.find(), and updates the map with .setGeoJSON
this.autorun(function () {
if (Mapbox.loaded()) {
geojson = Cities.find().fetch()
view.featureLayer.setGeoJSON(geojson);
}
});
In this example the contents of the Cities collection are already in the correct format to be passed to .setGeoJSON, but if you prefer you could have a different Colleciton schema, and create the list in this format within the template.autorun callback.
I would like to build a reactive input for R shiny that returns the row.name of a table row on hover.
In R Shiny, the table is made with renderTable and output through tableOutput.
This should work similar to the already built clickID and hoverID for plotOutput (for click & hover respectively).
I don't quite understand the JavaScript or jQuery well enough yet to follow these instructions and build it myself:
http://rstudio.github.io/shiny/tutorial/#building-inputs
Thank you!
Update:
This is the jQuery I have so far:
$(document).on('hover', '.table-hover tr', function(){
var el = $(this);
$(this).closest("tr").index();
});
var selectRowBinding = new Shiny.InputBinding();
$.extend(selectRowBinding, {
find: function(scope) {
return $(scope).find(".table-hover");
},
getValue: function(el){
return $(el).closest("tr").index();
},
setValue: function(el, value) {
},
subscribe: function(el, callback) {
$(el).on("change.selectRowBinding", function(e) {
callback();
});
},
unsubscribe: function(el) {
$(el).off(".selectRowBinding");
}
});
Shiny.inputBindings.register(selectRowBinding);
but input$selectRowBinding is still returning NULL.
I'm quite sure I have not properly defined the bindings.
I've been working off of these 2 resources:
https://groups.google.com/forum/#!searchin/shiny-discuss/selectablerows/shiny-discuss/ZaYYmFLHA6U/-cL62wQp0HUJ
and
Shiny R application that allows users to modify data