Can anyone recommend a Java component that lets you create a pretty looking image of a world map, highlighting certain countries (based on some statistics). Something similar to this image:
Something similar to Google Geo Charts (but for Java): https://developers.google.com/chart/interactive/docs/gallery/geochart but runs on the server side, without an internet connection. Ideally I'd like to attach weight to a few countries which would highlight them proportionally.
Either open source or commercial (as long as it's not something ridiculously priced).
I couldn't find a java library to do what you were looking for, so I looked into taking an SVG and modifying its style, and converting it to an image. First thought that came to my mind for this task: Apache Batik.
I chose to use the open source svg maps available on wikimedia (similar to Gregor Opheys answer) because not does it make it so you're not concerned about licensing, it also is already ready-made for simple CSS modifications by country. (See the SVG comments for instructions). There is one hitch, some of those image on wikimedia were generated by a python script, which puts the CSS styling also in the elements. If you want to use one of these SVG files, you'll have to handle for that.
To my happy surprise, there was almost a perfect example on the batik wiki, needing just a couple tweaks. I was able to produce a modified image (png) with one small syntax change (their outfile file is named .jpg but its using a png transcoder) and a small change to load the svg from the project resources instead of disk. Below is the example code with my minor changes:
public class MapMaker {
private final static String MAP_FLAT = "BlankMap-World6-Equirectangular.svg";
private final static String MAP_ROUND = "WorldMap.svg";
public static void main(String... args) {
try {
// make a Document with the base map
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
Document doc = f.createDocument("http://example.com/stuff",
MapMaker.class.getClassLoader().getResourceAsStream(MAP_ROUND));
// prepare to modify and transcode the document
SVGDocument sdoc = (SVGDocument) doc;
Element svgRoot = sdoc.getDocumentElement();
PNGTranscoder t = new PNGTranscoder();
TranscoderInput input = new TranscoderInput(doc);
// find the existing stylesheet in the document
NodeList stylesList = doc.getElementsByTagName("style");
Node styleNode = stylesList.item(0);
// append another stylesheet after the existing one
SVGStyleElement style = (SVGStyleElement) doc.createElementNS(SVG_NAMESPACE_URI, "style");
style.setAttributeNS(null, "type", "text/css");
style.appendChild(doc.createCDATASection(".us {fill: blue;}"));
styleNode.getParentNode().appendChild(style);
// transcode the map
OutputStream ostream = new FileOutputStream("outblue.jpg");
TranscoderOutput output = new TranscoderOutput(ostream);
t.transcode(input, output);
ostream.close();
// replace the appended stylesheet with another
SVGStyleElement oldStyle = style;
style = (SVGStyleElement) doc.createElementNS(SVG_NAMESPACE_URI, "style");
style.setAttributeNS(null, "type", "text/css");
style.appendChild(doc.createCDATASection(".us {fill: green;}"));
styleNode.getParentNode().replaceChild(style, oldStyle);
// transcode the revised map
File outFile = new File(System.getProperty("java.io.tmpdir"), "outgreen.png");
ostream = new FileOutputStream(outFile);
output = new TranscoderOutput(ostream);
t.transcode(input, output);
ostream.close();
System.out.println("Out File: " + outFile);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
As I mentioned, the way this works is by adding CSS to the SVG prior to converting it to the raster image you need. The secret sauce is the SVGStyleElement
, here you can see that the United States is turned green. For any other country, you would simply use their 2-letter digraph and chose the color you would like to fill. Of course, since it's CSS, you can also do things like change the border colors or use a background image instead of a color, so you have a lot of flexibility there.
I did have to play with the dependencies a bit, so to get you past this hurdle, I'll include my maven dependencies:
<dependencies>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-parser</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-css</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svg-dom</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-rasterizer</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.7</version>
</dependency>
</dependencies>
If you use a different build manager, let me know, and I can dump the transitive dependency tree.
Have a look at GeoTools, it may have what you need.
Haven't used it and not sure if it is appropriate for your needs but you can have a look at Nasa WorldWind. It features an SDK and it seems like that there is an off-line mode available.
Check :
http://worldwind.arc.nasa.gov/java/ and http://goworldwind.org/demos/
http://goworldwind.org/examples/#network (for offline mode)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With