Information and Resources

User Tools

Site Tools


Simple JournalMap API Example - Collections

This page goes through a simple example of accessing a JournalMap collection through the API and displaying the points on a Leaflet map. Make sure to check out the JournalMap API documentation for all the specifics on working with the API. Note that you'll need to get an API key to make this example work. Also, JournalMap's API paginates responses into groups of 30. This example does handle API pagination for a collection with more than 30 articles. This example uses D3.js, Leaflet, and the Leaflet Marker Cluster plugin. It also uses queue.js to hold processing of the articles until all the pages have been loaded, and spin.js for a nifty spinning wheel icon while the map loads.

Example of an Embedded Collection Map via the JournalMap API


Steps for creating the example

To see the full script put together, see our example on GitHub.

1. Add the script references to the page header

Add the following references to the <head> section of your webpage:

	<script src="" charset="utf-8"></script>
	<script src=""></script>
	<script src=""></script>
	<link rel="stylesheet" href="" />
	<link rel="stylesheet" href="" />
	<link rel="stylesheet" href="" />
	<script src=""></script>
        <script src=""></script>

2. Add a container to hold the map

Put the HTML <div> tags in the body of your page where you want your map to be. For this example I added a couple of <div> tags before the map for the collection title, intro, and description. Note the ids of each of these that are used to identify them later on and put the right text in them. For the map, I added a <div> tag and gave it an id=“jmap”. Finally, I added a footer with a nice little JournalMap logo. I wrapped my example in a container <div> and created some simple CSS styling for good measure.

	.spinner {
		position: relative;
		top: 50%;
		left: 10%;
	h3 {
		border: none;
  		font: normal normal bold 22px/1 Georgia, serif;
  		color: black;
  		text-align: center;
  		margin: 0 0 6px;
		padding: 4px;
	.intro {
		border: none;
		font: italic normal 16px/1 Arial, Helvetica, sans-serif;
		color: black;
		margin: 3 3 4px;
		padding: 3px;
	.description {
		border: none;
		font: normal 13px/1 Arial, Helvetica, sans-serif;
		color: black;
		margin: 3 3 4px;
		padding: 3px;
	.container {
		margin: 3px;
		border:thin solid black;
		box-shadow: 5px 5px 2px #888888
<h2>Example of an Embedded Collection Map via the JournalMap API</h2>
  <div class="container">
 	<h3 id="collectionName" class="title">Collection</h3>
 	<div id="intro" class="intro"></div>
 	<div id="description" class="description"></div>
	<div id="jmap" style="height:400px;" >
		<div class="spinner" id="jmapSpin"></div>
	<a href=""><img src="" width="150px"></a>

3. Add a script block for the map coding

Add a <script> tag after your <div> container. In the script tag, we'll set some of the initial values that we'll use in the map. You'll need to know the exact name of your collection from JournalMap, the coordinate of where you want the map centered, a map zoom level, and your API key. We'll also set up the parameters for the progress spinning wheel.

	var collectionName = "My Spatial Ecology Articles";
	var centerLat = 40;
	var centerLon = -100;
	var Zoom = 3;
	var apikey = "<ENTER YOUR API KEY HERE>";
	var data = []; // a global to store the json response
	var spinner = new Spinner({
		lines: 12, // The number of lines to draw
		length: 7, // The length of each line
		width: 3, // The line thickness
		radius: 10, // The radius of the inner circle
		color: '#000', // #rbg or #rrggbb
		speed: 1, // Rounds per second
		trail: 100, // Afterglow percentage
		shadow: false // Whether to render a shadow

The API will return all the parts of a citation, but as separate data fields. So you'll need some functions to assemble the pieces into a decent looking citation and construct links from the DOI numbers.

	String.prototype.trimRight = function(charlist) {
  			if (charlist === undefined)
			    charlist = "\s";
			return this.replace(new RegExp("[" + charlist + "]+$"), "");
		// Function to build citations from JournalMap database fields
	var buildCitation = function(title,authors,year,journal,vol,iss,spage,epage) {
		authorlist = '';
		for (i = 0; i < authors.length; i++) {
			if (i===0) {
				var sep = '';
			} else if (i===(authors.length-1)) {
				sep = ' and ';
			} else {
				sep = ', ';
			authorlist += sep+authors[i];
		var vips = '';
		if (vol!='') { vips+=vol; }
		if (iss!='') { vips+='('+iss+')'; }
		if (vips!='') { vips+=':'; }
		if (spage!='') { vips+=spage; }
		if (epage!='') { vips+='-'+epage; }
		return(authorlist.trimRight('.')+'. '+year+'. '+title.trimRight('.')+'. '+'<em>'+journal.trimRight('.')+'</em> '+vips);
	// Function to build HTML link from DOI numbers
	var buildDOIlink = function(doi) {
		return('<a href="'+doi+'" target="_blank">'+doi+'</a>');
	// function to build HTML for the popup box for each marker
	var buildPopupHTML = function(id,title,citation,doi,url) {
		var html = "<strong><a href='"+id+"/' target='_blank'>"+
			title+"</a></strong><p>"+citation+"<p><strong>DOI: </strong>"+buildDOIlink(doi)+
			"<br><strong>URL: </strong>"+url;
		return html;

5. Fetch the collection information from the API

Now we start the magic of getting the data from the API. We'll first start by calling the collections endpoint of the API to get the collection title, intro, and description and set the text for those HTML elements. The data returned from the collection will also have the collection ID number we need to grab the articles for the collection from the articles endpoint. We're using D3's JSON method to make the call. Note, though, that I haven't closed out the d3.json call yet. We're going to nest the call to the articles API endpoint inside this d3.json function.

	d3.json(""+apikey+"&version=1.0&query="+collectionName,function (error,collection){
		var title = collection[0].title;
		var description = collection[0].description;
		var intro = collection[0].intro;
		var id = collection[0].id;"#collectionName").text(title);"#intro").text(intro);"#description").text(description);

6. Setup the Leaflet map

The next step is to initialize the Leaflet map and set some of its basic properties. We'll create a marker cluster group to hold the points that we'll generate next.

		// Initialize the map
		var map ='jmap').setView([centerLat, centerLon], Zoom);
		L.tileLayer('http://{s}{z}/{x}/{y}.png', {
		   maxZoom: 18,
		var markers = L.markerClusterGroup();

7. Fetch the articles from the JournalMap API

Now we call the API again to get the articles. Once we've iterated over all the articles, we'll add the marker layer to the map. This time we're using D3's XHR method to return the article data. The reason for this has to do with the API pagination - the pagination information we need is contained in the response headers from the API and we can't get to those from the d3.json function. Because JavaScript is asynchronous, it will keep going and execute subsequent code even while it's waiting to hear back from the API. Normally this isn't an issue, but when we need to iterate over many pages it creates a problem. The solution here is to use queue.js to make JavaScript wait until all the pages from the API are loaded before going on. The output from the q.defer statement is a list of json “files” that need to be appended together into a single dataset we can use for our map. Also, note that I've left the d3.xhr statement open here. We'll need to add our code for building the citation and map markers in here before we close it.

		// Fetch the articles in the collection and build the points.
		d3.xhr(""+apikey+"&page=1&collection_id="+id+"&version=1.0", function(error,pubjson) {
			var pages = pubjson.getResponseHeader('X-Pages');
			var articles = [];
			q = queue();
			for(page=1;page<=pages;page++) {
				q.defer(d3.json, ""+apikey+"&page="+page+"&collection_id="+id+"&version=1.0")
			q.awaitAll(function(error,files) { 
				for (f=0;f<files.length;f++) { 

8. Get article info and build the map markers

For this step we iterate through all the articles in the collection (articles.forEach statement). For each article, first we assemble the author list and then build the citation. Then we loop through all of the article's locations and create a new map marker. We use our buildPopupHTML function to create the content for our popups. Finally we add the markers to the map and stop the spinning wheel. Don't forget to close out the q.awaitAll and d3.xhr functions that we left open.

				// Assemble the markers for the map
				markers = L.markerClusterGroup();  // Empty out the markers if they exist already
					var authorlist = []
					article.authors.forEach(function(author) {
						authorlist.push(author.last_name + ", " + author.first_name);
    				var citation = buildCitation(article.title,authorlist,article.publish_year,,article.volume,article.issue,article.start_page,article.end_page);
						var marker = L.marker([location.latitude,location.longitude]);
			});  // Close the q.awaitAll
		});  // Close the d3.xhr call

9. Add map attribution

Finally, we'll add some attribution lines to the map. Lastly, we need to close out the original d3.json that we left open.

		// Set the map source attribution
  		maplink = '<a href="">OpenStreetMap</a>';
		landlink = '<a href="">Thunderforest</a>'; 
		cclink = '<a href="">CC-BY-SA</a>';
		leaflink = '<a href="">Leaflet</a>';
		map.attributionControl.addAttribution('Maps &copy; '+landlink+', Data &copy; '+maplink+', '+cclink+' | <a href="">JournalMap</a> data provided CC-BY-SA');
	});   	// Close the original d3.json that fetched the collection info.  
api/collections_simple.txt · Last modified: 2015/01/23 21:38 by jkarl


JournalMap data is licensed under a
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
Creative Commons License