HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id='map'></div>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
mapboxgl.accessToken = '<YOUR_ACCESS_TOKEN>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
center: [8.677067,50.108],
zoom: 12
});
// multimodal routing
var coordinates_array_charging_around_origin;
var coordinates_array_charging_around_destination;
var mapClickCount = 0;
var origin_selected;
var destination_selected;
//Create geoJSON object for displaying RouteLine on Map
var geojson_walking_1 = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
]
}
}
var geojson_cycling_1 = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
]
}
}
var geojson_walking_2 = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
]
}
}
//create empty geoJSON that will be appended with data from tilequery requests around waypoints of route
var source_data = {
"type" : "FeatureCollection",
"features": []
}
map.on('load', function() {
var marker = new mapboxgl.Marker({'color': '#008000'})
map.addSource('tilequery_origin', {
type: "geojson",
data: {
"type": "FeatureCollection",
"features": []
}
});
map.addLayer({
id: "tilequery-points-origin",
type: "circle",
source: "tilequery_origin",
paint: {
"circle-stroke-color": "blue",
"circle-stroke-width": {
stops: [
[0, 0.1],
[18, 3]
],
base: 5
},
"circle-radius": {
stops: [
[12, 5],
[22, 180]
],
base: 5
},
"circle-color": "blue"
}
});
map.addSource('tilequery_destination', {
type: "geojson",
data: {
"type": "FeatureCollection",
"features": []
}
});
map.addLayer({
id: "tilequery-points-destination",
type: "circle",
source: "tilequery_destination",
paint: {
"circle-stroke-color": "red",
"circle-stroke-width": {
stops: [
[0, 0.1],
[18, 3]
],
base: 5
},
"circle-radius": {
stops: [
[12, 5],
[22, 180]
],
base: 5
},
"circle-color": "red"
}
});
var popup = new mapboxgl.Popup;
map.on('mouseenter', 'tilequery-points', function(e) {
map.getCanvas().style.cursor = 'pointer';
var title = '<h3>' + e.features[0].properties.STORE_NAME + '</h3>';
var storeType = '<h4>' + e.features[0].properties.STORE_TYPE + '</h4>';
var storeAddress = '<p>' + e.features[0].properties.ADDRESS_LINE1 + '</p>';
var obj = JSON.parse(e.features[0].properties.tilequery);
var distance = '<p>' + (obj.distance / 1000).toFixed(2) + ' km from route' + '</p>';
var lon = e.features[0].properties.longitude;
var lat = e.features[0].properties.latitude;
var coordinates = new mapboxgl.LngLat(lon, lat);
var content = title + storeType + storeAddress + distance;
popup.setLngLat(coordinates)
.setHTML(content)
.addTo(map);
})
map.on('mouseleave', 'tilequery-points', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});
// select start and destination location from map
map.on('click', (e) => {
if(mapClickCount == 0){ // initial click --> get origin
origin_selected = e.lngLat;
mapClickCount++;
const marker_orig = new mapboxgl.Marker({
color: "#54E1E5",
draggable: false
}).setLngLat(e.lngLat)
.addTo(map);
}else{
if(mapClickCount == 1){ // get destination
destination_selected = e.lngLat;
// init getting multi modal route
getParkingFromTilequery(origin_selected, destination_selected);
mapClickCount++;
const marker_destination = new mapboxgl.Marker({
color: "#E5D654",
draggable: false
}).setLngLat(e.lngLat)
.addTo(map);
}
}
console.log(`A click event has occurred at ${e.lngLat}`);
});
})
function concatGeoJSON(g1, g2){
return {
"type" : "FeatureCollection",
"features": g1.features.concat(g2.features)
}
}
function directionsRequest(url, step){
var request = new XMLHttpRequest();
var iterator = 0;
var geojson_1 = {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
]
}
}
// make a GET request to parse the GeoJSON at the url
request.open('GET', url, true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// retrieve the JSON from the response
var json = JSON.parse(this.response);
for (var i2 = 0; i2 < json.routes[0].geometry.coordinates.length; i2++){
var coordinates_1 = json.routes[0].geometry.coordinates[i2];
geojson_1.geometry.coordinates.push(coordinates_1);
}
if(step == 0){
geojson_walking_1 = geojson_1;
try {
map.getSource('route_0').setData(geojson_walking_1); //populate the route source
} catch (error) {
//Add directions route on map
map.addSource('route_0', {
'type': 'geojson',
'data': geojson_walking_1
});
map.addLayer({
'id': 'route_0',
'type': 'line',
'source': 'route_0',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#8F3A84',
'line-width': 8
}
});
}
}
if(step == 1){
geojson_cycling_1 = geojson_1;
try {
map.getSource('route_1').setData(geojson_cycling_1); //populate the route source
} catch (error) {
//Add directions route on map
map.addSource('route_1', {
'type': 'geojson',
'data': geojson_cycling_1
});
map.addLayer({
'id': 'route_1',
'type': 'line',
'source': 'route_1',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#3A8F47',
'line-width': 10
}
});
}
}
if(step == 2){
geojson_walking_2 = geojson_1;
try {
map.getSource('route_2').setData(geojson_walking_2); //populate the route source
} catch (error) {
//Add directions route on map
map.addSource('route_2', {
'type': 'geojson',
'data': geojson_walking_2
});
map.addLayer({
'id': 'route_2',
'type': 'line',
'source': 'route_2',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#F5ACC3',
'line-width': 8
}
});
}
}
};
}
request.send();
}
function getParkingFromTilequery(origin_selected, destination_selected){
// get charging stations around origin and destination
tilequery_get_charging_stations(origin_selected, destination_selected, 0);
}
function createMatrixRequests(origin_selected, destination_selected){
//get 3 cost matrices: origin -> parking, parking -> parking, parking -> destination
// first cost matrix: origin -> parkings
var matrix_request_url_1 = "https://api.mapbox.com/directions-matrix/v1/mapbox/walking/" + origin_selected.lng + ',' + origin_selected.lat + ';';
var limit_parking_1 = 5;
if(coordinates_array_charging_around_origin.features.length < 5){ // cap number of parking to 5
limit_parking_1 = coordinates_array_charging_around_origin.features.length;
}
for (var i = 0; i < limit_parking_1; i++){
matrix_request_url_1 = matrix_request_url_1 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[0] + ",";
matrix_request_url_1 = matrix_request_url_1 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[1] + ";";
}
matrix_request_url_1 = matrix_request_url_1.slice(0, -1); // remove the comma
matrix_request_url_1 = matrix_request_url_1 + "?sources=0&destinations=all&access_token=<YOUR_ACCESS_TOKEN>";
// second cost matrix: parkings -> parkings_2
var matrix_request_url_2 = "https://api.mapbox.com/directions-matrix/v1/mapbox/cycling/" ;
var limit_parking_2 = 5;
if(coordinates_array_charging_around_destination.features.length < 5){ // cap number of parking to 5
limit_parking_2 = coordinates_array_charging_around_destination.features.length;
}
var sourcesString = "?sources=";
for (var i = 0; i < limit_parking_1; i++){
matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[0] + ",";
matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_origin.features[i].geometry.coordinates[1] + ";";
sourcesString += i + ";";
}
sourcesString = sourcesString.slice(0, -1);
var destinationsString = "&destinations=";
for (var i2 = 0; i2 < limit_parking_2; i2++){
matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_destination.features[i2].geometry.coordinates[0] + ",";
matrix_request_url_2 = matrix_request_url_2 + coordinates_array_charging_around_destination.features[i2].geometry.coordinates[1] + ";";
destinationsString += (i + i2) + ";";
}
destinationsString = destinationsString.slice(0, -1); // remove the comma
matrix_request_url_2 = matrix_request_url_2.slice(0, -1); // remove the comma
matrix_request_url_2 = matrix_request_url_2 + sourcesString + destinationsString;
matrix_request_url_2 = matrix_request_url_2 + "&access_token=<YOUR_ACCESS_TOKEN>";
// third cost matrix: parkings_2 -> destination
var matrix_request_url_3 = "https://api.mapbox.com/directions-matrix/v1/mapbox/walking/" + destination_selected.lng + ',' + destination_selected.lat + ';';
for (var i = 0; i < limit_parking_2; i++){
matrix_request_url_3 = matrix_request_url_3 + coordinates_array_charging_around_destination.features[i].geometry.coordinates[0] + ",";
matrix_request_url_3 = matrix_request_url_3 + coordinates_array_charging_around_destination.features[i].geometry.coordinates[1] + ";";
}
matrix_request_url_3 = matrix_request_url_3.slice(0, -1); // remove the comma
matrix_request_url_3 = matrix_request_url_3 + "?sources=all&destinations=0&access_token=<YOUR_ACCESS_TOKEN>";
// send requests
matrixRequest(matrix_request_url_1, matrix_request_url_2, matrix_request_url_3, 0);
}
var matrixArray = [];
function matrixRequest(matrixUrl1, matrixUrl2, matrixUrl3, step){
var request = new XMLHttpRequest();
var matrixURL = "";
if(step == 0){
matrixURL = matrixUrl1;
}
if(step == 1){
matrixURL = matrixUrl2;
}
if(step == 2){
matrixURL = matrixUrl3;
}
// make a GET request to parse the GeoJSON at the url
request.open('GET', matrixURL, true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// retrieve the JSON from the response
var json = JSON.parse(this.response);
matrixArray.push(json);
if(step < 2){
step++;
matrixRequest(matrixUrl1, matrixUrl2, matrixUrl3, step);
}else{
//continue
parseMatrices_computeOptimalEdges();
}
}
};
request.send();
}
var tilequery_executed = false;
function tilequery_get_charging_stations(origin_selected, destination_selected, step){
if(step == 0){
coordinates = origin_selected;
}else{
coordinates = destination_selected;
}
var tileset = '<YOUR_TILESET>'; // your tileset holding parking location data
var radius = 30000; //30km distance from route
var limit = 3;
var query = 'https://api.mapbox.com/v4/' + tileset + '/tilequery/' + coordinates.lng + ',' + coordinates.lat + '.json?radius=' + radius + '&limit= ' + limit + ' &access_token=' + mapboxgl.accessToken;
$.ajax({
method: 'GET',
url: query,
}).done(function(data) {
if(step == 0){
step++;
map.getSource('tilequery_origin').setData(data);
coordinates_array_charging_around_origin = data;
tilequery_get_charging_stations(origin_selected, destination_selected, step);
}
if(step == 1){
map.getSource('tilequery_destination').setData(data);
coordinates_array_charging_around_destination = data;
// create Matrix requests
if(tilequery_executed == false){
createMatrixRequests(origin_selected, destination_selected);
}
tilequery_executed = true;
}
})
}
function parseMatrices_computeOptimalEdges(){
// given the 3 cost matrices in matrixArray, compute all permutations and find cheapest path
const matrix1 = matrixArray[0];
var lowestCost = 9999999; // start with a high value
var lowestCostSeries = ""; // 0,1 --> means in first node on level 1 and second node on level 2
for(var i = 1; i < matrixArray[0].durations[0].length; i++){ // do not iterate over distance to origin (0) --> i=1
var cost = 0;
var currentSeries = "";
for(var i2 = 0; i2 < matrixArray[1].durations.length; i2++){ // iterate over array of lists (2d-matrix)
for(var i3 = 0; i3 < matrixArray[1].durations[i2].length; i3++){ // iterate over list (connections from one node)
if(matrixArray[1].durations[i2][i3] != 0){ // do not take self connections into account
// iterate over third matrix
for(var i4 = 1; i4 < matrixArray[2].durations.length; i4++){
if(matrixArray[2].durations[i4][0] != 0){// do not take self connections into account
cost = matrixArray[0].durations[0][i] + matrixArray[1].durations[i2][i3] + matrixArray[2].durations[i4][0];
currentSeries = i + "," + i2 + "," + i3 + "," + i4;
if(cost < lowestCost){
lowestCost = cost;
lowestCostSeries = currentSeries;
}
}
}
}
}
}
}
var lowestCost_ = lowestCost;
var nodesArray = lowestCostSeries.split(",");
const first_parking_geometry = coordinates_array_charging_around_origin.features[nodesArray[1]].geometry;
const second_parking_geometry = coordinates_array_charging_around_destination.features[nodesArray[3] - 1].geometry;
// nodesArray[1] = index of first parking
// nodesArray[3] - 1 = index of second parking (index 0 is destination)
// create 3 directions API requests to return route geometry, then draw route
var url1 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + origin_selected.lng + ',' + origin_selected.lat + ";";
url1 += first_parking_geometry.coordinates[0] + "," + first_parking_geometry.coordinates[1];
url1 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
directionsRequest(url1, 0);
var url2 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + first_parking_geometry.coordinates[0] + ',' + first_parking_geometry.coordinates[1] + ";";
url2 += second_parking_geometry.coordinates[0] + "," + second_parking_geometry.coordinates[1];
url2 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
directionsRequest(url2, 1);
var url3 = 'https://api.mapbox.com/directions/v5/mapbox/walking/' + second_parking_geometry.coordinates[0] + ',' + second_parking_geometry.coordinates[1] + ";";
url3 += destination_selected.lng + "," + destination_selected.lat;
url3 += '?geometries=geojson&access_token=<YOUR_ACCESS_TOKEN>';
directionsRequest(url3, 2);
}
Also see: Tab Triggers