Open Freight App is a project by the Delaware Valley Regional Planning Commission (DVRPC) to share with regional and national transportation planning partners the framework that is the basis for the PhillyFreightFinder web mapping and data application. Through this effort, DVRPC hopes that county planning agencies, metropolitan planning organizations and state departments of transportation, and economic development agencies can leverage this framework to further their efforts in making freight transportation data public. By utilizing the Open Freight App framework, rather than building from scratch, planning agencies can focus their time and resources on the development of data sets that can serve to improve the access to information on freight facilities and their role in economic development and transportation across the country. Open Freight App would serve as a self-hosted solution to offer these datasets to other planners, economic developers, public officials, decision-makers and the general public.
Open Freight App, is a white-label, open source version of the DVRPC PhillyFreightFinder application. This version is available for download and open for replication by any user. This version will have no branding or color styling applied and a standardized icon set will be provided for a sample set of data. In addition, the project will include the following:
Advanced coding support is not included with this product. While staff at DVRPC can field general questions and assist with certain aspects of the project, formal support in the form of coding, styling, graphic design and advanced development must be done by an outside consultant. If you require more advanced support please contact us for more information.
PhillyFreightFinder is built using the Leaflet JavaScript mapping library, a lightweight mobile friendly framework that provides developers an open flexible environment for the development of web maps and applications. The web application leverages the Bootstrap 3.0 front end framework for styling and interface. The application is the core of DVRPC's freight data program and provide partners with a way of accessing and exploring local freight data.
The Open Freight App Project is led by the Office of Freight and Aviation planning as an effort to provide the tool to other agencies for replicaiton. In addition, the open project can be further improved through feedback an collaboration as other begin to implement and explore new uses for the product. The current Open Freight Applicaiton build is intended to streamline the app development process by creating built in shortcuts. As this product is a "live" project updates will be provided periodically.
Michael Ruane
Transportation Planner
Office of Freight and Aviation Planning
p: 215.238.2888
c: 215.588.8226
e: mruane@dvrpc.org
This is a product of:
Delaware Valley Regional Planning CommissionThe Open Freight Application was developed by the Delaware Valley Regional Planning Commission's as a way to share the components and code base of the PhillyFreightFinder Application. The code provided represents the core structure of the web interface that forms the PhillyFreightFinder App and can be used to create similar application once customized with your data.
The application is available under the MIT Open Source License, allowing any public or private entity to leverage and customize the platform to meet their needs. This documentation is intended to help those with some development backgournd to better understand the structure of the application and how to customize the interface with their own data.
In order to utilize this code set, users should be familiar with:
It is important to note that the Open Freight Application was built for use in modern browsers. This means that support is limited to newer browser versions. Windows XP users with only IE will not be able to access web applications built with this framework.
![]() |
![]() |
|
Firefox |
12.0+
|
9.0+
8 and below
|
Internet Explorer |
9.0+
8.0 and below
|
No Versions Supported
|
Chrome |
Most Recent Stable Version
|
Most Recent Stable Version
|
Safari |
No Versions Supported |
5+
|
![]() |
![]() |
![]() |
4.3+
(iPhone 4S/iPad 2 and newer) |
4.0.3+ (device performance varies)
|
8.1+ (limited support)
|
The core code of Open Freight App includes all HTML, CSS and Javascript files necessary to build your own application. The following is an explanation of the organization of directories and what each file contains.
File/directory | Description |
---|---|
/data | Location for all .geojson, .json, .js and other geographic data sets |
/lib | Location of all script, style and image files (component sources) |
index.htm | The primary HTML document file that contains the core structure and text content of the application, other than the mapping components. |
LICENSE.md | Open Freight Application is licensed under an MIT license which must be included with all derivative builds. More info... |
File/directory | Description |
---|---|
/assets | Location of all script, style and image files for all application dependencies. |
/core | Location for all script, style and image files that constitute the core of Open Freight App. These files will be updated as the project evolves and should be modified with care. |
/images | Location of all image files |
actions.js | (Customization Required)The Javascript file that builds the actions which are called when a feature in the map is clicked. |
map.js | (Customization Required)The Javascript file that builds the map, layer features and search functionality. |
style.css | (Customization Required)The stylesheet file that establishes the color scheme and can be used for overriding the core styles. |
File/directory | Description |
---|---|
/dist | Location of all core files in an uncompressed, annotated format. |
/fonts | Location of all font types for Dynamic Icon Markers. |
/images | Location of all images for Dynamic Icon Markers. |
core.js | (Advanced Only)The Javascript file that builds the actions powering the interface of the application. |
core.css | (Advanced Only)The stylesheet file that establishes the core formatting and color scheme for the application. |
dyna.css | (Advanced Only)The stylesheet file that Open Freight Icon set. |
dyna-icons.js | (Advanced Only)The script file that provides Dynamic Icon functionality. |
It is recommended that when preparing a project, if you plan to continue to utilize updates from the Open Freight Project that you do not make revisions to the "core.js" or asset/ files as these will the location of updated elements. If you have any bugs or issues please contact DVRPC to report them.
The first step in creating your web application is to produce your georeferenced data sets. These compilations of features will form the core of the data that will be illustrated and shared through the application. Datasets should contain individual fields for the various types of data that you would like to show in your application as shown in the figure to the right.
Your completed GIS files will need to be converted to an open format in order to be used with this application framework. The Leaflet mapping API supports several file types and integration with geodatabases, however we will only document methods of exporting to simple geojson files which can be served from any web server. The following are three methods to convert GIS shapefiles to GeoJSONs for use with this mapping framework:
Exporting from ArcGIS to GeoJSON
In order to convert your shapefiles in ArcGIS, we recommend using esri2open a free tool set available at through Project Open Data on GitHub. Documentation is available at the link provided.
Exporting from QGIS to GeoJSON
For those with access to a hosted ArcServer, feature sets can be served from there. For more information on that process consult ESRI and Leaflet documentation.
When all file sets have been created they should be placed in the "/data" directory in the project folder. Be sure to save the file sets with simple clear names. If your web server is capable of utilizing geoJSON files then your data is ready for use. If your server is not you can a)contact your server adminstrator to enable this file type or b)convert all geoJSONs to .js (Javascript) files.
Converting geoJSON to Javascript
The Open Freight App comes preconfigured with a div element in the "index.htm" file of the application that is designed to contain the Leaflet map instance. This element has an ID of "mapDIV". This HTML content is necessary in order to populate the application with map elements, the ID will be used later to tell Leaflet where to put the map.
<div class="col-sm-9 col-lg-9 mapUI" id="mapDIV" style="display:none;">
<div id="loading" style="display: block;">
<div class="loading-indicator">
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%"></div>
</div>
</div>
</div>
</div>
This code does not need to be edited in order for the application to work.
In order for the map to show your region in the default view it necessary to identify the appropriate center point of the region and the scale level at which the full extent is shown. You will need the lat/long coordinates and the correct scale level. Once you have acquired these open the "map.js" file and add the appropriate values for oLat, oLng and zLevel for your region.
//declare boundary of region
var oLat = 40.018, oLng = -75.148, zLevel = 10;
Basemap layers are tiled image layers that provide static data such as aerial imagery, roads, land features and labels. Many different basemap layers are available "out of the box" in Leaflet applications. To see all options check out Leaflet Providers.
In order to add basemap layers, we use the Leaflet API to declare them:
// Basemap Layers
var Esri_WorldImagery = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
var Esri_WorldGrayCanvas = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ',
maxZoom: 16
});
With map context and basemaps declare we are now able to create the map instance using Leaflet API. To do this we create a variable "map" that uses the Leaflet API to create a map instance in the HTML DOM element "mapDIV" that is located in the "index.htm" file. In the "options" variables we can adjust the baselayer that loads by default using the "Layers" attribute.
//create map instance
var map = L.map("mapDIV", {
minZoom: zLevel,
zoomControl: false,
layers: [Esri_WorldGrayCanvas]
}).setView([oLat, oLng],zLevel);
To allow users to control the visible base layer we use the default Leaflet base layer control. If this is not desired, simply do not add or remove the following code:
//add Layer Control to map
var baseLayers = {
"Street Map": Esri_WorldGrayCanvas,
"Satellite": Esri_WorldImagery
};
L.control.layers(baseLayers).addTo(map);
With the core map elements now declared and pushed to the index file custom data layers can now be added to the "map" instance.
The Open Freight Application has been built to simplify and partially automate the production of a web mapping application leveraging the Leaflet Javascript library. The creation of Map Layers and the variables declared in these steps are essential for the application to build and render the map features, legend and the associated information popup window.
The application includes a plugin capable of building map markers and associated legend icons from a selection of predefined markers and any icon font that user selects. This Dynamic Icon Marker plugin is an expansion on the Awesome Marker project. Learn more about Dynamic Icon Marker.
(a) The first step is define the Dynamic Icon Marker presets as the variable "IconPresets". These will be used to style the map and legend markers as well as tell the plugin which icon set to draw from. The required options are as follows:
//define Icon Set and Marker Types
var IconPresets = {iconSet:'dynico', markerSet: 'open-freight', mapMarker: 'circle-cm', legendMarker: 'circle-md'};
As noted in the Dynamic Icon Marker plugin docs the "legendMarker" is optional and will match the mapMarker is desired. Learn more about variable options...
(b) The next step is to define an icon for each layer that will be: i. clickable in the map (all poly, point, or combo layers), ii. toggled by the sidebar layer control. If a layer is represented by both point and poly features it only require the declaration of one icon. In the options that are declared the "layer:" is most important as it will be related to layer control functions later in the application's development. In this case the code is declared for four layers: layer1, layer2, layer3, and layer4. Each layer will require an icon, markerColor, layer name, title(label) and the inclusion of the "IconPresets" variable.
var layer1icon = L.OpenFreightMarkers.icon({
icon: 'nhs', markerColor: 'red', layer:'layer1', title: 'Layer 1'}, IconPresets),
layer2icon = L.OpenFreightMarkers.icon({
icon: 'parking', markerColor: 'red', layer:'layer2', title: 'Layer 2'}, IconPresets),
layer3icon = L.OpenFreightMarkers.icon({
icon: 'nhs', markerColor: 'teal', layer:'layer3', title: 'Layer 3'}, IconPresets),
layer4icon = L.OpenFreightMarkers.icon({
icon: 'bridge', markerColor: 'teal', layer:'layer4', title: 'Layer 4'}, IconPresets);
In the Leaflet API polylines and polygons are handled in a similar way. The following steps outline the declaration of these feature types. These declarations should be placed in the "map.js" file.
(a) Create a new variable with a name for your layer and activate the Leaflet geoJSON function:var layer1 = L.geoJson(null, {
(b) Add style elements for the feature to be rendered with. Consult Leaflet Documentation on styles for help.style: {fillColor: "#F9AB90", fillOpacity:.50, weight:1, color:"#E0E0E0 ", opacity:.75},
(c) Define actions to be applied on each feature in the layer.onEachFeature: function (feature, layer){
(d) Define actions during mouse events for layer.layer.on({
//action on click --> function must be created in actions.js
click: highlightLayer1,
//action on double click --> zoom to polygon function predefined in action.js
dblclick: zoomToFeature
});
(e) Push search parameters to the corresponding array for use by Typeahead.js and then close layer declaration. Note the variable "bounds" necessary for a poly feature layer.layer1Search.push({
//search name: based on field name "Name"
name: layer.feature.properties.Name,
//layer source for use as title in Typeahead
source: "Layer 1",
//leaflet id for callback
id: L.stamp(layer),
//geometric bounds declaration for polygon
bounds: layer.getBounds()
});
}
});
(f) Get data from geoJSON using getJSON function. The last line is necessary for all poly features in order to maintain style settings. Layers will added to the map after all have been declared.$.getJSON("data/layer1.json", function (data) {
layer1.addData(data);
});
polyLayer.push('layer1');
The final compiled code for declaring a polygon data layer should include all of the following:
//define Layer 1 (poly feature only)
var layer1 = L.geoJson(null, {
style: {fillColor: "#F9AB90", fillOpacity:.50, weight:1, color:"#E0E0E0 ", opacity:.75},
onEachFeature: function (feature, layer){
layer.on({
click: highlightLayer1,
dblclick: zoomToFeature
});
layer1Search.push({
name: layer.feature.properties.Name,
source: "Layer 1",
id: L.stamp(layer),
bounds: layer.getBounds()
});
}
});
$.getJSON("data/layer1.json", function (data) {
layer1.addData(data);
});
polyLayer.push('layer1');
In the Leaflet API points from a geoJson can be added using the following steps. These declarations should be placed in the "map.js" file.
(a) Create a new variable with a name for your layer and activate the Leaflet geoJSON function:var layer2 = L.geoJson(null, {
(b) Using Leaflet API convert the geoJSON points to marker layers and declare the icon value for the given layer.pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: layer2icon});
},
(c) Define actions to be applied on each feature in the layer.onEachFeature: function (feature, layer){
(d) Define actions during mouse events for layer.layer.on({
//action on click --> function must be created in actions.js
click: highlightLayer2,
//action on double click --> zoom to point function predefined in action.js
dblclick: zoomToPoint
});
(e) Push search parameters to the corresponding array for use by Typeahead.js and then close layer declaration. Note the variables "lat" and "lng" necessary for a point feature layer.layer2Search.push({
//search name: based on field name "Name"
name: layer.feature.properties.Name,
//layer source for use as title in Typeahead
source: "Layer 2",
//leaflet id for callback
id: L.stamp(layer),
//geometric bounds declaration for points (requires lat and lng)
lat: layer.feature.geometry.coordinates[1],
lng: layer.feature.geometry.coordinates[0]
});
}
});
(f) Get data from geoJSON using getJSON function. Layers will added to the map after all data has been declared.$.getJSON("data/layer2.json", function (data) {
layer2.addData(data);
});
The final compiled code for declaring a polygon data layer should include all of the following:
//define Layer 2 (point feature only)
var layer2 = L.geoJson(null, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: layer2icon});
},
onEachFeature: function (feature, layer){
layer.on({
click: highlightLayer2,
dblclick: zoomToPoint
});
layer2Search.push({
name: layer.feature.properties.Name,
source: "Layer 2",
id: L.stamp(layer),
lat: layer.feature.geometry.coordinates[1],
lng: layer.feature.geometry.coordinates[0]
});
}
});
$.getJSON("data/layer2.json", function (data) {
layer2.addData(data);
});
In certain cases it may be necessary to represent individual features using both point icons and a polyline or polygon. This type of representation is helpful for small geographic facilities to be clearly visible at a large regional scale. The steps to adding data is similar to the steps used for adding a point or poly feature. However in this case, the Typeahead search functionality should only be added to the poly feature. After these are added it is important to utilize the "L.FeatureGroup" function to instruct Leaflet to treat the data sets as a single layer. It is important in data preparation that the point geoJSON and poly geoJSON have the same data fields.
The final compiled code for declaring point and poly data sets added as a layer should look like the following:
//define Layer 3 (point and poly combo)
//declare point data first
var layer3pt = L.geoJson(null, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {icon: layer3icon});
},
onEachFeature: function (feature, layer){
layer.on({
click: highlightLayer3,
dblclick: zoomToPoint
});
}
});
$.getJSON("data/layer3pt.json", function (data) {
layer3pt.addData(data);
});
//declare polygon data
var layer3poly = L.geoJson(null, {
style: {fillColor: "#C1332B", fillOpacity:.50, weight:1, color:"#E0E0E0 ", opacity:.75},
onEachFeature: function (feature, layer){
layer.on({
click: highlightLayer3,
dblclick: zoomToFeature
});
layer4Search.push({
name: layer.feature.properties.Name,
source: "Layer 3",
id: L.stamp(layer),
bounds: layer.getBounds()
});
}
});
$.getJSON("data/layer3poly.json", function (data) {
layer3poly.addData(data);
});
polyLayer.push('layer3poly');
//create layer group for Layer 3 point and polyline features
var layer3 = new L.FeatureGroup([layer3pt, layer3poly]);
The Open Freight Application leverages the Typeahead.js library to provide a simple search functionality. In order to make use of the framework each data set pushes search criteria to a corresponding array and the following code processes that data for use and consumption in the Typeahead search box. These code elements should be added in the "map.js" file.
This tutorial will walk through the process for adding two layers to the functionality, Layer 1 (poly) and Layer 2 (point). (a) The first step is to declare the necessary click function for the "#searchbox" element and ensure that AJAX functions have completed.$("#searchbox").click(function () {
$(this).select();
});
// Typeahead search functionality
$(document).one("ajaxStop", function() {
$("#loading").hide();
(b) Add data for each of the layers using the following code, followed by an initialization call.var layer1BH = new Bloodhound({
name: "Layer 1",
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: layer1Search,
limit: 10
});
var layer2BH = new Bloodhound({
name: "Layer 2",
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: layer2Search,
limit: 10
});
//intialize
layer1BH.initialize();
layer2BH.initialize();
(c) Activate the Typeahead functionality for the "#searchbox" element. A set of options is declared followed by each layer.$("#searchbox").typeahead({
//define options (see Typeahead documentation)
minLength: 2,
highlight: true,
hint: false
},{
name: "Layer1data",
displayKey: "name",
source: layer1BH.ttAdapter(),
templates: {
header: "<h5 class='typeahead-header'><img src='lib/images/flat/layer1.png' class='searchico'>Layer 1</h5>"
}
},{
name: "Layer2data",
displayKey: "name",
source: layer2BH.ttAdapter(),
templates: {
header: "<h5 class='typeahead-header'><img src='lib/images/flat/layer2.png' class='searchico'>Layer 2</h5>"
}
})
(d) Define actions on the event of a result being selected..on("typeahead:selected", function (obj, datum) { //define action on selection of a search result
if (datum.source === "Layer 1") {
if (!map.hasLayer(layer1)) {
map.addLayer(layer1);
$("#layer1").prop("checked", true);
};
map.fitBounds(datum.bounds);
if (map._layers[datum.id]) {
map._layers[datum.id].fire("click");
};
};
if (datum.source === "Layer 2") {
if (!map.hasLayer(layer2)) {
map.addLayer(layer2);
$("#layer2").prop("checked", true);
};
map.setView([datum.lat, datum.lng], 17);
if (map._layers[datum.id]) {
map._layers[datum.id].fire("click");
};
};
All other code related to the Typeahead functionality provides the formatting for the search box.
Once a feature layer is declared, it is neccesary to create the action that populates the info window on a click event with the feature's data. This action will be created in the "action.js" file. Multiple data layers can use the same highlight function only if they share the same field names and data structure. Otherwise, each data layer will require its own highlight function.
(a) Create new function with action name created in the click event and declare the "initializeHL" function which is necessary to identify the source of the action and clear previously highlighted features.function highlightLayer1(e) {
initializeHL(e);
(b) Extract data from feature and create HTML content. The extraction of data is simple and based on the field name within the data set that is desired. Every data point you use will be formatted as "props.'FIELDNAME'". So for a field name of 'Center_Typ' in the GIS data the call in this function would be written "props.Center_Typ". For the default info window there are two sets of HTML content being created. The first is "header" which contains the desired feature title or name. The second is "content" which can contain any data you wish to express in the body of the info windows. For readability the application includes HTML formatted as a multiline variable with a backslash used to tell the Javascript engine that the string continues. For the variable "props.Acres" the numeral.js plugin is used to format the data, for more information consult the plugin docs.header = '<p>' + props.Name + '</p>',
content = "<div id='baseInfo'>\
<div class='datafield'>" + props.Center_Typ + "</div><div class='labelfield'>Type</div>\
<div class='datafield'>" + props.Township_s + "</div><div class='labelfield'>Municipality(ies): </div>\
</div><!--close baseInfo-->\
<div class='infoDivider'></div>\
<div id='indactorInfo'>\
<ul class='nav nav-tabs'><!--tabs for indicators-->\
<li class='active'><a href='#Cap' data-toggle='tab'>Capacity & Activity</a></li></ul></ul>\
<div id='indicator' class='tab-content'><!--tab panes-->\
<div class='tab-pane active' id='Cap' style='padding-bottom: 12px;'>\
<table class='table table-hover'>\
<tr class='active'><td><strong>Acres: </strong></td><td>" + numeral(props.Acres).format('0,0.0') + "</td></tr>\
<tr><td><strong>Output: </strong></td><td>not available</td></tr></table>\
</div></div>\
<div class='labelfield source'>Data Source: " + props.Source + "</div></div>",
(c) (Optional) The default functionality of the Dynamic Icon Markers component of the Open Freight Application utilizes the variables declared in the "map.js" file to style the info window. However, if there is a need to override the "Title" or header class, those values must be declared in this action. These are optional and only necessary in advanced uses.//optional featureName override for use in place of title variable
titleName = '<p>Type: '+ props.Name +'</p>',
//optional header class override
headerClass = 'layer1NewClass',
(d) Declare layer name that corresponds to the layer name established in the icon declarations made in "map.js". This will instruct the application how to build and style the info window. Then add the "contentPush()" function as written below.layerName = 'layer1';
contentPush(header, content, layerName, titleName, headerClass);
The final compiled function to highlight a feature should look like this and be located in the "actions.js" file.function highlightLayer1(e) {
initializeHL(e);
header = '<p>' + props.Name + '</p>',
content = "<div id='baseInfo'>\
<div class='datafield'>" + props.Center_Typ + "</div><div class='labelfield'>Type</div>\
<div class='datafield'>" + props.Township_s + "</div><div class='labelfield'>Municipality(ies): </div>\
</div><!--close baseInfo-->\
<div class='infoDivider'></div>\
<div id='indactorInfo'>\
<ul class='nav nav-tabs'><!--tabs for indicators-->\
<li class='active'><a href='#Cap' data-toggle='tab'>Capacity & Activity</a></li></ul></ul>\
<div id='indicator' class='tab-content'><!--tab panes-->\
<div class='tab-pane active' id='Cap' style='padding-bottom: 12px;'>\
<table class='table table-hover'>\
<tr class='active'><td><strong>Acres: </strong></td><td>" + numeral(props.Acres).format('0,0.0') + "</td></tr>\
<tr><td><strong>Output: </strong></td><td>not available</td></tr></table>\
</div></div>\
<div class='labelfield source'>Data Source: " + props.Source + "</div></div>",
layerName = 'layer1';
contentPush(header, content, layerName, titleName, headerClass);
};
Adding layer control functionality to the application when using Dynamic Icon Marker. The layer controls are built based on the declarations of the layers in the "map.js", however in order to render them properly it is necessary to build out some HTML components in the sidebar. These components are built using the bootstrap accordion panels. The can be divided by groupings or as a single panel. This example demonstrates adding a single panel with all the necessary code elements for the application helpers to populate the elements.
(a) In the sidebar HTML element of the "index.html" add a panel by first creating the panel-group heading wrapper.<div class="panel-group legend">
<div class="panel panel-default">
<div class="panel-heading">
(b) If there is additional information to be provided about the layer group, add this line to create a link to trigger a modal window that should created and populated with the appropriate information. The "panelinfo" class is essential for creating the icon, while the "group1_panel" is optional and can be matched to a CSS style to color code the heading elements.<a href="modal_1.html" data-toggle="modal" data-target="#modal_1"><div class="panelinfo group1_panel"></div></a>
(c) The next grouping is the header name and link to toggle the accrodion open/closed. The "panellink" class is essential for creating the functionality, while the "group1_panel" is optional and can be matched to a CSS style to color code the heading elements by grouping. The href declares the group name/id.<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion_" href="#Group_1">
<div class="panellink group1_panel">
<span>Layer Group 1</span>
</div>
</a>
(d) The next line provides the ability to toggle all layers in the group on and off. The "group1_panel" class is optional to match a CSS header style.<a class="checked_all togglebox group1_panel"></a>
The final compiled panel heading should look like this
<div class="panel-heading">
<a href="modal_1.html" data-toggle="modal" data-target="#modal_1"><div class="panelinfo group1_panel"></div></a>
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion_" href="#Group_1">
<div class="panellink group1_panel">
<span>Layer Group 1</span>
</div>
</a>
<a class="checked_all togglebox"></a>
</div>
(e) Next add the panel body elements. In the first line the div id should match href declared in the header content above. <div id="Group_1" class="panel-collapse collapse in">
<div class="panel-body legPanel">
(f) Inside the panel body elements declare, in the desired order, each of the layers of the grouping. Each input element for the layers will require an id with the layer name declared for the layer in the "map.js" and a z-index value to help the application add the layers in order when toggled. <input type="checkbox" name="LayerCont" id="layer1" class="dyna layer" z-index="2" >
<input type="checkbox" name="LayerCont" id="layer2" class="dyna layer" z-index="3" >
</div>
</div>
The full final compiled legend panel should look like this
<div class="panel-group legend">
<div class="panel panel-default">
<div class="panel-heading">
<a href="modal_1.html" data-toggle="modal" data-target="#modal_1"><div class="panelinfo group1_panel"></div></a>
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion_" href="#Group_1">
<div class="panellink group1_panel">
<span>Layer Group 1</span>
</div>
</a>
<a class="checked_all togglebox"></a>
</div>
<div id="Group_1" class="panel-collapse collapse in">
<div class="panel-body legPanel">
<input type="checkbox" name="LayerCont" id="layer1" class="dyna layer" z-index="2" >
<input type="checkbox" name="LayerCont" id="layer2" class="dyna layer" z-index="3" >
</div>
</div>
</div>
</div>
This functionality provides users of the Open Freight Application an easy, streamlined method for creating custom map markers using any icon font set. For those requiring custom icons, the IcoMoon App can be used to create icon fonts from SVG source files. Using Dynamic Icon Markers and Layer Control functionality, the user can declare a series of options that will create a uniform identity for individual layers across the applicaiton. Using this functionality much of the layer control panel is built automatically and the styling for infowindows is created to the selected layer.
Below are the options that can be declared in the "map.js" file, when creating custom layers.
Option | Type | Default | Description |
---|---|---|---|
Marker Options | |||
markerSet | string | 'open-freight' | Determines the marker set that will be utilized for the application. Explanation of market sets and value options are available here. |
mapMarker | string | 'circle-md' | Declares the marker class for the style of markers to be used to render points in the map. Map markers can be declared globally or by layer. A reference for marker class options is available here. |
legendMarker | string | 'circle-md' | Declares the marker class for the style of markers to be used to render markers in the legend. Legend markers can be declared globally or by layer. A reference for marker class options is available here. A value of 'checkbox' will replace legend markers with a simple checkbox. |
markerColor | string | 'blue' | The marker color is based on the value from the corresponding marker set that has been selectee for use. This variable can be set globally and/or by layer. |
Icon Options | |||
iconSet | string | 'dynico' | Identifies the icon set that will be used to call icons into the application. Variable can be set globally and/or by layer. The value is based on the prefix of the icon font to utilized, including custom made icon fonts. |
iconColor | string | Color | 'white' | Determines the color for the icon element of the marker. The variable can be 'black' or 'white' or any hex color formatted as '#ffffff'. |
icon | string | '' | Identifies the icon to appear as the symbol for a given layer or all layers if declared globally. The icon name corresponds to the icon name established by the icon set selected for use. Information on the icon options for the Open Freight Icon set available here. |
Map Layer Options | |||
layer | string | '' | Identifies the variable name for the layer associated with the variable options declared. This variable is declared with each layer declaration and should be consistent with value used for the corresponding input id in the legend panels. See legend documentation for more information. |
title | string | '' | Identifies the proper name of the layer with which variables are associated. This title will be used for the label value in the sidebar legend as well as the layer identification in the Info Window pop-up, unless otherwise over written. This variable is declared by layer. |
onLoad | boolean | true | Determines if a layer is added to the map on initialization of the Leaflet map instance with which the layer is associated. |
This icon set has been created as a part of the Open Freight App project and is a launching point for agencies to identify key freight facilities in their region. The guide below shows the usage classes for each of the icons within the font set.
The prefix for the Open Freight Icon set is 'dynico'To utilize other icon fonts for icons you need to replace the "iconSet" option with the prefix of that icon font such as "fa" for Font Awesome or "glyphicon" for Glyphicons.
The Dynamic Icon and Layer Control system includes several marker options to be used with the application framework. In addition, you will find an editable file in the "lib/core/dist/" folder of the project that can be used to create new color palettes using predesigned markers.
Copyright (c) 2014 Delaware Valley Regional Planning Commission
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The Open Freight Application includes elements of other software, their licenses are as follows:
Copyright (C) 2013 L. Voogdt
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.