Anton Linus
4 years ago
18 changed files with 555 additions and 352 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 4.9 MiB |
Binary file not shown.
Binary file not shown.
@ -1,350 +0,0 @@ |
|||||
<?php |
|
||||
// Notes |
|
||||
// The api key from Scooty's app/account: iPtAHWdOVLEtgkaymXoMHVVg |
|
||||
// Below is the static html to generate the map, it can also be done more dynamically using https://github.com/LuminFire/leaflet-php but that might be overkill |
|
||||
|
|
||||
//debugging, enable all error reporting |
|
||||
// ini_set('display_errors', 1); |
|
||||
// ini_set('display_startup_errors', 1); |
|
||||
// error_reporting(E_ALL); |
|
||||
//measure script execution time |
|
||||
$start_time = microtime(true); |
|
||||
$a=1; |
|
||||
|
|
||||
|
|
||||
|
|
||||
// array of scooters, artist, title, description |
|
||||
global $scooters; |
|
||||
|
|
||||
$scooters = array( |
|
||||
array('https://opencoil.show/test-json.php?scooterID=1', 'artist name 0', 'title 0', 'desciption 0' ), |
|
||||
array('https://opencoil.show/test-json.php?scooterID=2', 'artist name 1', 'title 1', 'desciption 1' ), |
|
||||
array('https://opencoil.show/test-json.php?scooterID=3', 'artist name 2', 'title 2', 'desciption 2' ), |
|
||||
//array('https://platform.tier-services.io/v1/vehicle/fbd739d6-554f-4eaf-bd9c-afe3d501c94b', 'artist name 1', 'title', 'desciption'), |
|
||||
|
|
||||
); |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
// for each scooter in array get the json (TODO, for each, safe to file/database?) $scooters is a multidimensional array: $scooter[0][0] = the first data (api url) of the first scooter, $scooter[1][0] = the first data (api url) of the second scooter, $scooter[0][1] = the artist name of the first scooter etcetc. |
|
||||
|
|
||||
//$id = 0; //get the first scooter for now |
|
||||
|
|
||||
|
|
||||
function saveLatestJSON(){ |
|
||||
global $scooters; //"import" the global variable into the function's scope |
|
||||
|
|
||||
//TODO if latestData.json = older than ..2 minutes...call the API again |
|
||||
$id = 0; //start id |
|
||||
foreach($scooters as $item) { |
|
||||
$getJSON = callAPI($scooters[$id][0]); //abstract callAPI for neater reuse |
|
||||
// GET RID OF JSON DECODE! |
|
||||
$arr = json_decode($getJSON, true); // decode JSON data to PHP associative array |
|
||||
// access values from the associative array |
|
||||
$lat = $arr["data"]["attributes"]["lat"]; // get lattitude |
|
||||
$lng = $arr["data"]["attributes"]["lng"]; // get longitude |
|
||||
$pos = $lat.', '.$lng; // construct lat/lon for use in leafet |
|
||||
$lst = $arr["data"]["attributes"]["lastLocationUpdate"]; // get time of last position |
|
||||
$rnt = $arr["data"]["attributes"]["isRentable"]; // check if scooter is rentable, |
|
||||
$act = $arr["data"]["attributes"]["state"]; // check if scooter is ACTIVE or MAINTAINANCE |
|
||||
// access values from the multidimensional $scooters array |
|
||||
$nam = $scooters[$id][1]; // get the artist name |
|
||||
$tit = $scooters[$id][2]; // get the works title |
|
||||
$des = $scooters[$id][3]; // get the works description |
|
||||
|
|
||||
//construct json with latest data |
|
||||
$latestData[] = array( "ID" => $id, |
|
||||
"lastPos" => $pos, |
|
||||
"lastLocationUpdate" => $lst, |
|
||||
"isRentable" => $rnt, |
|
||||
"state" => $act, |
|
||||
"name" => $nam, |
|
||||
"title" => $tit, |
|
||||
"desc" => $des); |
|
||||
$id++; |
|
||||
} |
|
||||
|
|
||||
return $latestData; //return array |
|
||||
|
|
||||
} |
|
||||
|
|
||||
// THIS ONLY NEEDS TO RUN EVERY 1 or 2 minutes, possibly in the background, als this should construct historical json as per tom martins post here: https://stackoverflow.com/questions/7895335/append-data-to-a-json-file-with-php/7895384 |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
//TODO make historical json file.. |
|
||||
//see: https://stackoverflow.com/questions/7895335/append-data-to-a-json-file-with-php/7895384 |
|
||||
//add something like: |
|
||||
// $inp = file_get_contents('./latestData.json'); |
|
||||
// $tempArray = json_decode($inp); |
|
||||
// $tempArray[] .= $latestData; |
|
||||
// $jsonData = json_encode($tempArray); |
|
||||
// file_put_contents('./latestData.json', $jsonData); |
|
||||
|
|
||||
|
|
||||
function makeMarker(int $id){ // generate appropriate markers based on latest JSON |
|
||||
|
|
||||
$readJSON = file_get_contents('./latestData.json'); //read latest data |
|
||||
$arr = json_decode($readJSON, true); |
|
||||
|
|
||||
$pos = $arr[$id]["lastPos"]; // get last known position |
|
||||
$lst = $arr[$id]["lastLocationUpdate"]; // get time of last position |
|
||||
$rnt = $arr[$id]["isRentable"]; // check if scooter is rentable, |
|
||||
$act = $arr[$id]["state"]; // check if scooter is ACTIVE or MAINTAINANCE |
|
||||
// access values from the multidimensional $scooters array |
|
||||
$nam = $arr[$id]["name"]; // get the artist name |
|
||||
$tit = $arr[$id]["title"]; // get the works title |
|
||||
$des = $arr[$id]["desc"]; // get the works description |
|
||||
|
|
||||
|
|
||||
|
|
||||
//check scooter status and construct marker with corresponding icon |
|
||||
|
|
||||
//check if scooter is rentable |
|
||||
if($rnt == true && $act === 'ACTIVE'){ |
|
||||
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
|
||||
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst.'<br>Status: Rentable, Gallery Offline") |
|
||||
.bindTooltip("'.$nam.'").setIcon(availableIcon);'; |
|
||||
|
|
||||
} elseif ($rnt == false && $act === 'ACTIVE') { |
|
||||
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
|
||||
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst.'<br>Status: Rented Out, Gallery Online") |
|
||||
.bindTooltip("'.$nam.'").setIcon(isRentedIcon);'; |
|
||||
|
|
||||
}; |
|
||||
//check if scooter is in maintenace |
|
||||
if($act !== "ACTIVE"){ |
|
||||
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
|
||||
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst.'") |
|
||||
.bindTooltip("'.$nam.'").setIcon(isMaintenanceIcon);'; |
|
||||
}; |
|
||||
|
|
||||
return $marker; |
|
||||
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
function appendJSON($filename, $data){ // create historical json data for documentation over time |
|
||||
|
|
||||
// read the file if present |
|
||||
$handle = @fopen($filename, 'r+'); |
|
||||
|
|
||||
// create the file if needed |
|
||||
if ($handle === null) |
|
||||
{ |
|
||||
$handle = fopen($filename, 'w+'); |
|
||||
} |
|
||||
|
|
||||
if ($handle) |
|
||||
{ |
|
||||
// seek to the end |
|
||||
fseek($handle, 0, SEEK_END); |
|
||||
|
|
||||
// are we at the end of is the file empty |
|
||||
if (ftell($handle) > 0) |
|
||||
{ |
|
||||
// move back a byte |
|
||||
fseek($handle, -1, SEEK_END); |
|
||||
|
|
||||
// add the trailing comma |
|
||||
fwrite($handle, ',', 1); |
|
||||
|
|
||||
// add the new json string |
|
||||
fwrite($handle, json_encode($data) . ']'); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
// write the first event inside an array |
|
||||
fwrite($handle, json_encode(array($data))); |
|
||||
} |
|
||||
|
|
||||
// close the handle on the file |
|
||||
fclose($handle); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
//// make date time file------ |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
///..mmm one big one? seperate ones, timestamped ones? |
|
||||
// 60 second update interval |
|
||||
|
|
||||
// make timestamp file like original python one! to check for updates |
|
||||
// make new custom json: |
|
||||
// scooter 1/marker time1 { lat long } |
|
||||
// time2 { lat long } |
|
||||
// scooter 2/marker time1 { lat long } |
|
||||
// time2 { lat long } |
|
||||
// |
|
||||
// |
|
||||
|
|
||||
|
|
||||
// for each |
|
||||
// check if lastlocation is different...if update > latest file (map file..) |
|
||||
// check if is rentable |
|
||||
|
|
||||
// TODO make two files |
|
||||
// 1: current position and state of scooter, latlong, id, status |
|
||||
// 2: historical json file, contains all scooters, updated everytime php file is loaded (or every 60 sec). No state changes, only lat long and time. even if time does not change |
|
||||
|
|
||||
|
|
||||
|
|
||||
// Custom functions |
|
||||
|
|
||||
|
|
||||
function callAPI($url){ |
|
||||
$curl = curl_init($url); |
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, true); |
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); |
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); |
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); |
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array( |
|
||||
'x-api-key: bpEUTJEBTf74oGRWxaIcW7aeZMzDDODe1yBoSxi2', |
|
||||
'Content-Type: application/json', |
|
||||
)); // set the api key |
|
||||
curl_setopt($curl, CURLOPT_USERAGENT,'ProductionRelease/3.8.2 (app.tier.sharing; build:3.8.2.0; iOS 12.4.4) Alamofire/4.9.1'); // set user-agent to that of the Tier.app, sniffed by burpsuite |
|
||||
|
|
||||
$result = curl_exec($curl); |
|
||||
if(!$result){die("Connection Failure");} |
|
||||
curl_close($curl); |
|
||||
return $result; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
?> |
|
||||
|
|
||||
|
|
||||
<html> |
|
||||
<head> |
|
||||
<meta charset="utf-8"> |
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> |
|
||||
|
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> |
|
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css"> |
|
||||
<script src='https://unpkg.com/leaflet@1.3.3/dist/leaflet.js'></script> |
|
||||
<!-- icons --> |
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> |
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script> |
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.6.0/dist/leaflet.css"/> |
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/> |
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/> |
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/> |
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/> |
|
||||
<link rel="stylesheet" href="https://rawcdn.githack.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css"/> |
|
||||
|
|
||||
<!-- begin timeslider --> |
|
||||
|
|
||||
<script src="SliderControl.js"></script> |
|
||||
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script> |
|
||||
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css"/> |
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.2/jquery.ui.touch-punch.min.js"></script> |
|
||||
<!-- end of timeslider --> |
|
||||
<style> |
|
||||
#map { |
|
||||
height: 500px |
|
||||
} |
|
||||
</style> |
|
||||
<script> |
|
||||
L_NO_TOUCH = false; |
|
||||
L_DISABLE_3D = false; |
|
||||
</script> |
|
||||
</head> |
|
||||
<body> |
|
||||
<div id="map"></div> |
|
||||
<script> |
|
||||
// define icons |
|
||||
// prefix: glyphicon = bootstrap, list can be found here: https://getbootstrap.com/docs/3.3/components/ |
|
||||
// prefix: fa = fontawesome, list is here: https://fontawesome.com/v4.7.0/cheatsheet/ |
|
||||
var availableIcon = L.AwesomeMarkers.icon( |
|
||||
{"icon": "wifi", "iconColor": "white", "markerColor": "purple", "prefix": "fa"} |
|
||||
); |
|
||||
var isRentedIcon = L.AwesomeMarkers.icon( |
|
||||
{"icon": "hourglass-half", "iconColor": "white", "spin": "true", "markerColor": "pink", "prefix": "fa"} |
|
||||
); |
|
||||
var isMaintenanceIcon = L.AwesomeMarkers.icon( |
|
||||
{"icon": "wrench", "iconColor": "white", "markerColor": "black", "prefix": "fa"} |
|
||||
); |
|
||||
|
|
||||
|
|
||||
var map = L.map('map').setView([52.516190, 13.377693], 13); |
|
||||
|
|
||||
var Stamen_Toner = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.{ext}', { |
|
||||
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', |
|
||||
subdomains: 'abcd', |
|
||||
minZoom: 0, |
|
||||
maxZoom: 20, |
|
||||
ext: 'png' |
|
||||
}); |
|
||||
map.addLayer(Stamen_Toner); |
|
||||
|
|
||||
|
|
||||
//the magic: for each scooter in $scooters array, request status and construct marker |
|
||||
<?php |
|
||||
|
|
||||
$filename = "./latestData.json"; //latest locations, 1 entry per scooter |
|
||||
$filename_history = "./historicalData.json"; //historical locations |
|
||||
|
|
||||
// check how old the latest json is |
|
||||
if (time()-filemtime($filename) > 60) { //if older than 60 seconds |
|
||||
$arrayToEcho = saveLatestJSON(); |
|
||||
//append to historical json |
|
||||
appendJSON($filename_history, $arrayToEcho); |
|
||||
|
|
||||
$latestData = json_encode($arrayToEcho, JSON_FORCE_OBJECT); // force object accepts 0 as a key for the array and not NULL |
|
||||
file_put_contents($filename, $latestData, LOCK_EX); |
|
||||
|
|
||||
|
|
||||
$id = 0; //start id |
|
||||
foreach($scooters as $item) { |
|
||||
echo makeMarker($id); |
|
||||
$id++; |
|
||||
} |
|
||||
|
|
||||
} else { // file younger than 60 seconds |
|
||||
|
|
||||
$id = 0; //start id |
|
||||
foreach($scooters as $item) { |
|
||||
echo makeMarker($id); |
|
||||
$id++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
?> |
|
||||
|
|
||||
// time slider |
|
||||
|
|
||||
//test markers |
|
||||
//var marker1 = L.marker([52.504926, 13.358061], {time: "2020-10-09T08:00:29Z"}); |
|
||||
//var marker2 = L.marker([52.506926, 13.358061], {time: "2020-10-09T09:00:29Z"}); |
|
||||
//var marker3 = L.marker([52.508926, 13.358061], {time: "2020-10-09T10:00:29Z"}); |
|
||||
|
|
||||
// var map = marker1; |
|
||||
// layerGroup = L.layerGroup([marker_e7a96a6d6b08479ba6d17d42769e5202]); |
|
||||
layerGroup = L.layerGroup([scooter0, scooter1, scooter2]); //make this dynamic |
|
||||
var sliderControl = L.control.sliderControl({layer:layerGroup}); |
|
||||
map.addControl(sliderControl); |
|
||||
sliderControl.startSlider(); |
|
||||
</script> |
|
||||
</body> |
|
||||
</html> |
|
||||
|
|
||||
<?php //end of measuring script execution time
|
|
||||
//end clock time in seconds |
|
||||
$end_time = microtime(true); |
|
||||
//calculate script execution time |
|
||||
$execution_time = ($end_time - $start_time); |
|
||||
echo " Execution time of script = ".$execution_time." sec"; |
|
||||
?> |
|
@ -1 +0,0 @@ |
|||||
[[{"ID":0,"lastPos":"52.57619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 0","title":"title 0","desc":"desciption 0"},{"ID":1,"lastPos":"52.55619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 1","title":"title 1","desc":"desciption 1"},{"ID":2,"lastPos":"52.53619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 2","title":"title 2","desc":"desciption 2"}]] |
|
@ -1 +0,0 @@ |
|||||
{"0":{"ID":0,"lastPos":"52.58619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 0","title":"title 0","desc":"desciption 0"},"1":{"ID":1,"lastPos":"52.58619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 1","title":"title 1","desc":"desciption 1"},"2":{"ID":2,"lastPos":"52.53619, 13.358061","lastLocationUpdate":"2020-10-09T08:00:29Z","isRentable":true,"state":"ACTIVE","name":"artist name 2","title":"title 2","desc":"desciption 2"}} |
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -0,0 +1,404 @@ |
|||||
|
<?php |
||||
|
// array of scooters, artist, title, description |
||||
|
global $scooters; |
||||
|
|
||||
|
$scooters = array( |
||||
|
//array('https://opencoil.show/test-json.php?scooterID=1', 'artist name 0', 'title 0', 'desciption 0' ), |
||||
|
//array('https://opencoil.show/test-json.php?scooterID=2', 'artist name 1', 'title 1', 'desciption 1' ), |
||||
|
//array('https://opencoil.show/test-json.php?scooterID=3', 'artist name 2', 'title 2', 'desciption 2' ), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/fbd739d6-554f-4eaf-bd9c-afe3d501c94b', 'artist name 0', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/530b66c9-e5f9-47ac-ba31-2e357dc4c735', 'artist name 1', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/aa9cedf8-ab8e-4651-8b43-93079179f26a', 'artist name 2', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/9df16c74-4a88-4f21-acf5-12ba401ca15a', 'artist name 3', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/4763ce60-5b2e-44cf-919e-fffbff26a15e', 'artist name 4', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/ca884ba2-b0a6-4f3f-b727-fcc33d10182c', 'artist name 5', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/78e9b9f1-0cf1-4415-9301-e2fe01d39bce', 'artist name 6', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/0b939caf-80e9-4d6b-8454-4a7f8eaf088c', 'artist name 7', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/0f7fa267-4bc1-439a-8fd0-43b98b9ffba7', 'artist name 8', 'title', 'desciption'), |
||||
|
array('https://platform.tier-services.io/v1/vehicle/8732f342-df2f-475f-b0f6-c0032743a944', 'artist name 9', 'title', 'desciption'), |
||||
|
|
||||
|
); |
||||
|
|
||||
|
|
||||
|
function saveLatestJSON(){ |
||||
|
global $scooters; //"import" the global variable into the function's scope |
||||
|
|
||||
|
//TODO if latestData.json = older than ..2 minutes...call the API again |
||||
|
$id = 0; //start id |
||||
|
foreach($scooters as $item) { |
||||
|
$getJSON = callAPI($scooters[$id][0]); //abstract callAPI for neater reuse |
||||
|
// GET RID OF JSON DECODE! |
||||
|
$arr = json_decode($getJSON, true); // decode JSON data to PHP associative array |
||||
|
// access values from the associative array |
||||
|
$lat = $arr["data"]["attributes"]["lat"]; // get lattitude |
||||
|
$lng = $arr["data"]["attributes"]["lng"]; // get longitude |
||||
|
$pos = $lat.', '.$lng; // construct lat/lon for use in leafet |
||||
|
$lst = $arr["data"]["attributes"]["lastLocationUpdate"]; // get time of last position |
||||
|
$rnt = $arr["data"]["attributes"]["isRentable"]; // check if scooter is rentable, |
||||
|
$act = $arr["data"]["attributes"]["state"]; // check if scooter is ACTIVE or MAINTAINANCE |
||||
|
// access values from the multidimensional $scooters array |
||||
|
$nam = $scooters[$id][1]; // get the artist name |
||||
|
$tit = $scooters[$id][2]; // get the works title |
||||
|
$des = $scooters[$id][3]; // get the works description |
||||
|
|
||||
|
//construct json with latest data |
||||
|
$latestData[] = array( "ID" => $id, |
||||
|
"lastPos" => $pos, |
||||
|
"lastLocationUpdate" => $lst, |
||||
|
"isRentable" => $rnt, |
||||
|
"state" => $act, |
||||
|
"name" => $nam, |
||||
|
"title" => $tit, |
||||
|
"desc" => $des); |
||||
|
$id++; |
||||
|
} |
||||
|
|
||||
|
return $latestData; //return array |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function makeMarker(int $id){ // generate appropriate markers based on latest JSON |
||||
|
|
||||
|
$readJSON = file_get_contents('./latestData.json'); //read latest data |
||||
|
$arr = json_decode($readJSON, true); |
||||
|
|
||||
|
$pos = $arr[$id]["lastPos"]; // get last known position |
||||
|
$lst = $arr[$id]["lastLocationUpdate"]; // get time of last position |
||||
|
$rnt = $arr[$id]["isRentable"]; // check if scooter is rentable, |
||||
|
$act = $arr[$id]["state"]; // check if scooter is ACTIVE or MAINTAINANCE |
||||
|
// access values from the multidimensional $scooters array |
||||
|
$nam = $arr[$id]["name"]; // get the artist name |
||||
|
$tit = $arr[$id]["title"]; // get the works title |
||||
|
$des = $arr[$id]["desc"]; // get the works description |
||||
|
|
||||
|
|
||||
|
|
||||
|
//check scooter status and construct marker with corresponding icon |
||||
|
|
||||
|
//check if scooter is rentable |
||||
|
if($rnt == true && $act === 'ACTIVE'){ |
||||
|
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
||||
|
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'<br>Status: rentable, Gallery available") |
||||
|
.bindTooltip("'.$nam.'").setIcon(availableIcon);'; |
||||
|
|
||||
|
} elseif ($rnt == false && $act === 'ACTIVE') { |
||||
|
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
||||
|
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'<br>Status: rented Out, Gallery unavailable") |
||||
|
.bindTooltip("'.$nam.'").setIcon(isRentedIcon);'; |
||||
|
|
||||
|
}; |
||||
|
//check if scooter is in maintenace |
||||
|
if($act !== "ACTIVE"){ |
||||
|
$marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) |
||||
|
.bindPopup("<b>'.$tit.'</b><br>'.$des.'<br>Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'<br>Status: unavailable, in maintenace") |
||||
|
.bindTooltip("'.$nam.'").setIcon(isMaintenanceIcon);'; |
||||
|
}; |
||||
|
|
||||
|
return $marker; |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
function appendJSON($filename, $data){ // create historical json data for documentation over time |
||||
|
|
||||
|
// read the file if present |
||||
|
$handle = @fopen($filename, 'r+'); |
||||
|
|
||||
|
// create the file if needed |
||||
|
if ($handle === null) |
||||
|
{ |
||||
|
$handle = fopen($filename, 'w+'); |
||||
|
} |
||||
|
|
||||
|
if ($handle) |
||||
|
{ |
||||
|
// seek to the end |
||||
|
fseek($handle, 0, SEEK_END); |
||||
|
|
||||
|
// are we at the end of is the file empty |
||||
|
if (ftell($handle) > 0) |
||||
|
{ |
||||
|
// move back a byte |
||||
|
fseek($handle, -1, SEEK_END); |
||||
|
|
||||
|
// add the trailing comma |
||||
|
fwrite($handle, ',', 1); |
||||
|
|
||||
|
// add the new json string |
||||
|
fwrite($handle, json_encode($data) . ']'); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// write the first event inside an array |
||||
|
fwrite($handle, json_encode(array($data))); |
||||
|
} |
||||
|
|
||||
|
// close the handle on the file |
||||
|
fclose($handle); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
function callAPI($url){ |
||||
|
$curl = curl_init($url); |
||||
|
curl_setopt($curl, CURLOPT_FAILONERROR, true); |
||||
|
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); |
||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
||||
|
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); |
||||
|
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); |
||||
|
curl_setopt($curl, CURLOPT_HTTPHEADER, array( |
||||
|
'x-api-key: bpEUTJEBTf74oGRWxaIcW7aeZMzDDODe1yBoSxi2', |
||||
|
'Content-Type: application/json', |
||||
|
)); // set the api key |
||||
|
curl_setopt($curl, CURLOPT_USERAGENT,'ProductionRelease/3.8.2 (app.tier.sharing; build:3.8.2.0; iOS 12.4.4) Alamofire/4.9.1'); // set user-agent to that of the Tier.app, sniffed by burpsuite |
||||
|
|
||||
|
$result = curl_exec($curl); |
||||
|
if(!$result){die("Connection Failure");} |
||||
|
curl_close($curl); |
||||
|
return $result; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
?> |
||||
|
|
||||
|
<html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> |
||||
|
<title>OPENCOIL</title> |
||||
|
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> |
||||
|
<link rel="stylesheet" type="text/css" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css"> |
||||
|
<script src='https://unpkg.com/leaflet@1.3.3/dist/leaflet.js'></script> |
||||
|
<!-- icons --> |
||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script> |
||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.6.0/dist/leaflet.css"/> |
||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/> |
||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/> |
||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/> |
||||
|
<link rel="stylesheet" href="https://rawcdn.githack.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css"/> |
||||
|
<link rel="stylesheet" href="main.css"/> |
||||
|
|
||||
|
<!-- begin timeslider |
||||
|
<script src="SliderControl.js"></script> |
||||
|
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script> |
||||
|
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css"/> |
||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.2/jquery.ui.touch-punch.min.js"></script> |
||||
|
<!-- end of timeslider --> |
||||
|
|
||||
|
<script> |
||||
|
L_NO_TOUCH = false; |
||||
|
L_DISABLE_3D = false; |
||||
|
</script> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="map"></div> |
||||
|
<div id="title-container"> |
||||
|
<h1>OPENCOIL</h1> |
||||
|
<h2>a roaming speedshow</h2> |
||||
|
<p>legendary code has once been written on a cold rainy night in october. it was 2 nay 1 day before the opening of this show when i typed this silly code. it was legendary. both the situation as well as the code. thanks for reading. bye</p> |
||||
|
<div id="bottom_menu"> |
||||
|
<a href="#" onclick="document.getElementById('infotext').style.visibility='visible';document.getElementById('infotext').style.opacity='1';">info</a> |
||||
|
<a href="#" onclick="document.getElementById('abouttext').style.visibility='visible';document.getElementById('infotext').style.opacity='1';">about</a> |
||||
|
<a href="#" onclick="document.getElementById('contacttext').style.visibility='visible';document.getElementById('infotext').style.opacity='1';">contact</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="infotext"> |
||||
|
<div id="infobuttons"> |
||||
|
<div id="closeButton" onclick="document.getElementById('infotext').style.visibility='hidden';document.getElementById('infotext').style.opacity='0';">X</div> |
||||
|
<div id="enButton" onclick="document.getElementById('infotext_en').style.visibility='visible';document.getElementById('infotext_en').style.opacity='1';">EN</div> |
||||
|
</div> |
||||
|
<p> |
||||
|
OPENCOIL – a roaming Speedshow <br><br> |
||||
|
|
||||
|
Die Ausstellung OPENCOIL setzt sich mit den Auswirkungen von Mikro-Mobilitätsdiensten auf den Stadtraum auseinander, indem sie ihre dezentrale Infrastruktur als Ausstellungsraum nutzt und gleichzeitig die Bedingungen und Auswirkungen dieser Infrastrukturen auch zum Thema macht. |
||||
|
|
||||
|
<br><br> |
||||
|
11 Künstler*innen wurden eingeladen, ihre Arbeiten auf einem kleinen Wifi Controller mit ~2MB Offline-Speicher zu präsentieren. |
||||
|
|
||||
|
<br><br> |
||||
|
Diese „digitalen Galerieräume“ werden an 11 zufällig ausgewählten E-Scootern angebracht. |
||||
|
|
||||
|
<br> |
||||
|
|
||||
|
So fährt die Ausstellung, von den Nutzer*Innen der Roller unbemerkt, als „roaming Speedshow“ durch die Stadt. |
||||
|
|
||||
|
<br><br> |
||||
|
Der aktuelle Standort der Kunstwerke kann ab dem 26. Oktober über diese Website verfolgt werden. Damit die Werke betrachtet werden können, muss die „Roller-Galerie“ im Stadtraum gefunden werden. |
||||
|
|
||||
|
<br><br> |
||||
|
Sobald der Roller angemietet ist, erhalten die Besucher*innen über ihr persönliches Smartphone, Zugang zu dem 2MB großen Galerieraum und den ausgestellten Werken. |
||||
|
<br><br> |
||||
|
Während Kapazitätsbeschränkungen und die bevorzugte Vermeidung von Zusammenkünften in geschlossenen Räumen, traditionelle Galerien und Museen vor Herausforderungen stellen, zielt OPENCOIL darauf ab, die Ortsunabhängigkeit des Online mit der Materialität des Offline (und umgekehrt) zu verbinden. Die Infrastruktur der „Mikro-Mobiltitätsdienste“ wird übernommen – klimaneutral und dezentral. |
||||
|
<br><br> |
||||
|
Die Gehwege vieler Städte auf der ganzen Welt wurden in den letzten Jahren von sogenannten 'dockless sharing vehicles' regelrecht überflutet. Mit Versprechungen von Umweltfreundlichkeit und Elektromobilität, besetzten diese Risikokapitalismus Aktivisten die Grauzone zwischen privatem und öffentlichem Raum auf den Straßen unserer Städte. Diese gewissenlose Gewissenhaftigkeit der "Mikro-Mobilitätsdienste" wirft jedoch wichtige Fragen zu städtischem Raum, Eigentum, Agentur, Produktion, Ökologie und sehr spätem Kapitalismus auf. |
||||
|
<br><br> |
||||
|
Wie umgehen mit der Inbesitznahme öffentlichen Raums?<br> |
||||
|
Welche Werkzeuge und Wege gibt es sich diesen zurückzuerobern?<br> |
||||
|
<br> |
||||
|
OPENCOIL soll nicht nur ein Pandemie-tauglicher Weg sein, um Kunst im öffentlichen Offline-Raum zu zeigen. OPENCOIL ist auch eine kreative (Um-)Nutzung von E-Scootern, ein Versuch, sich ihnen mit künstlerischen Mitteln zu nähern. |
||||
|
<br> |
||||
|
Gezeigt werden Arbeiten, die sich mit Fragen der Überschneidung von öffentlichem und privatem Raum, dem Umgang mit Ressourcen sowie mit Greenwashing, Risikokapitalismus und Vandalismus befassen. |
||||
|
<br><br> |
||||
|
Die teilnehmenden Künstler*innen sind: |
||||
|
<br><br> |
||||
|
Aram Bartholl<br> |
||||
|
Constant Dullaart<br> |
||||
|
Dennis de Bel & Anton Jehle<br> |
||||
|
JODI<br> |
||||
|
Jonas Lund<br> |
||||
|
Martin Howse<br> |
||||
|
!Mediengruppe Bitnik<br> |
||||
|
Rosa Menkman<br> |
||||
|
Sarah Grant<br> |
||||
|
Sofya Aleynikova<br> |
||||
|
Danja Vasiliev<br> |
||||
|
<br><br> |
||||
|
Sonstige Erläuterungen: |
||||
|
<br><br> |
||||
|
Die künstlerischen Beiträge sind jeweils auf einem Wifi Mikrocontroller gespeichert, welcher mit einem Tretroller verbunden ist und so, sobald der Roller ausgeliehen ist, mit Strom versorgt wird. Um die Arbeiten zu sehen verbindet man sich mit dem vom Wifi Chip gesendeten, lokalen unverschlüsselten WiFi Netzwerk. Es öffnet sich automatisch ein Webportal, indem die Arbeit zu sehen ist. Es ist keine mobile Datenverbindung notwendig. |
||||
|
Alle Arbeiten wurden von den Künstler*innen speziell für die Betrachtung auf Smartphones optimiert. |
||||
|
<br><br> |
||||
|
OPENCOIL ist in keiner Weise mit der den „Mikro-Mobilitätsdiensten“ assoziiert, sondern bedient sich lediglich am bestehenden Rollernetzwerk. Die Umnutzung der Roller zu einem Ausstellungsort ist nach der Ausstellung komplett reversibel und schränkt den herkömmlichen Gebrauch der Roller (auch während der Ausstellung) in keiner Weise ein. Die Roller werden nicht beschädigt.<br><br> |
||||
|
Die Ausstellung startet am 26. Oktober auf dem öffentlichen Platz vor dem Zentrum für Netzkunst (Haus der Statistik) und wird in der Woche bis zum 1. November täglich von unserem Team gewartet und am Laufen gehalten. Sollte eine Arbeit beschädigt oder nicht auffindbar sein bitte per Mail (<a id="infolink" href="mailto:service@opencoil.show">service@opencoil.show</a>) oder über die Telegram App (<a id="infolink" href="https://t.me/opencoil">https://t.me/opencoil</a>)<br><br> |
||||
|
</p> |
||||
|
<div id="closeButtonbottom" onclick="document.getElementById('infotext').style.visibility='hidden';">less info</div> |
||||
|
</div> |
||||
|
<div id="infotext_en"> |
||||
|
<div id="closeButton" onclick="document.getElementById('infotext_en').style.visibility='hidden'; document.getElementById('infotext').style.visibility='hidden';">X</div> |
||||
|
<p> |
||||
|
OPENCOIL - a roaming speed show |
||||
|
<br><br> |
||||
|
The OPENCOIL exhibition explores the impact of micro-mobility services on urban space by using its decentralised infrastructure as an exhibition space, while also addressing the conditions and effects of this infrastructure. |
||||
|
<br><br> |
||||
|
11 artists were invited to present their work on a small Wifi controller with ~2MB offline memory. |
||||
|
<br><br> |
||||
|
These "digital gallery spaces" are attached to 11 randomly selected e-scooters. |
||||
|
Thus the exhibition, unnoticed by the regular users of these scooters, drives through the city as a "roaming speed show". |
||||
|
<br><br> |
||||
|
From October 26th onwards the current location of the artworks will be displayed here on this website. In order to view the works the corresponding "Scooter Gallery" must be found in the offline urban space. |
||||
|
<br><br> |
||||
|
Once the scooter is rented, visitors will be able to access the 2MB gallery space and the exhibited works via their personal smartphone. |
||||
|
<br><br> |
||||
|
While capacity restrictions and the preferred avoidance of gatherings in closed spaces pose challenges on traditional galleries and museums, OPENCOIL aims to combine the independence of the online with the materiality of the offline (and vice versa). The infrastructure of "micro-mobility services" will be taken over - climate-neutral and decentralised. |
||||
|
<br><br> |
||||
|
The pavements of many cities around the world have been flooded in recent years by so-called 'dockless sharing vehicles'. With promises of eco-friendliness and electromobility, these risk capitalism activists have occupied the grey zone between private and public space on the streets of our cities. However, this unscrupulous conscientiousness of 'micro-mobility services' raises important questions about urban space, ownership, agency, production, ecology and very late capitalism. |
||||
|
<br><br> |
||||
|
How to deal with the occupation of public space? |
||||
|
What tools and ways are there to reclaim it? |
||||
|
<br><br> |
||||
|
OPENCOIL is not only meant to be a pandemic-proof way to show art in public offline space. OPENCOIL is also a creative (re)use of e-scooters, an attempt to approach them by artistic means. |
||||
|
On show are works that deal with questions of the overlap between public and private space, the use of resources, as well as greenwashing, risk capitalism and vandalism. |
||||
|
<br><br> |
||||
|
The participating artists are: |
||||
|
<br><br> |
||||
|
Aram Bartholl<br> |
||||
|
Constant Dullaart<br> |
||||
|
Dennis de Bel & Anton Jehle<br> |
||||
|
JODI<br> |
||||
|
Jonas Lund<br> |
||||
|
Martin Howse<br> |
||||
|
!Mediengruppe Bitnik<br> |
||||
|
Rosa Menkman<br> |
||||
|
Sarah Grant<br> |
||||
|
Sofya Aleynikova<br> |
||||
|
Danja Vasiliev<br> |
||||
|
<br><br><br> |
||||
|
|
||||
|
Other explanatory notes: |
||||
|
<br><br> |
||||
|
The artistic contributions are each stored on a Wifi microcontroller, which is connected to a scooter and is thus supplied with power as soon as the scooter is rented. To view the works, you connect to the local unencrypted WiFi network sent by the Wifi chip. A web portal opens automatically, where the work can be viewed. No mobile data connection is necessary. All works have been specially optimised by the artists to be viewed on smartphones. |
||||
|
<br><br> |
||||
|
OPENCOIL is in no way associated with the "micro-mobility services", but only uses the existing scooter network. The conversion of the scooters into an exhibition space is completely reversible after the exhibition ends and in no way restricts the conventional use of the scooters (even during the exhibition). The scooters will not be damaged. |
||||
|
<br><br> |
||||
|
The exhibition will start on October 26th in the public space in front of Zentrum für Netzkunst (Haus der Statistik). For one week, until November 1st, the exhibition will be serviced and kept running daily by our team. Should a work be damaged or not be found, please send an e-mail (<a id="infolink" href="mailto:service@opencoil.show">service@opencoil.show</a>) or use the Telegram App (<a id="infolink" href="https://t.me/opencoil">https://t.me/opencoil</a>) |
||||
|
</p> |
||||
|
<div id="closeButtonbottom" onclick="document.getElementById('infotext').style.visibility='hidden'; document.getElementById('infotext_en').style.visibility='hidden';">less info</div> |
||||
|
</div> |
||||
|
|
||||
|
<script> |
||||
|
// define icons |
||||
|
// prefix: glyphicon = bootstrap, list can be found here: https://getbootstrap.com/docs/3.3/components/ |
||||
|
// prefix: fa = fontawesome, list is here: https://fontawesome.com/v4.7.0/cheatsheet/ |
||||
|
var availableIcon = L.AwesomeMarkers.icon( |
||||
|
{"icon": "wifi", "iconColor": "white", "markerColor": "purple", "prefix": "fa"} |
||||
|
); |
||||
|
var isRentedIcon = L.AwesomeMarkers.icon( |
||||
|
{"icon": "hourglass-half", "iconColor": "white", "spin": "true", "markerColor": "pink", "prefix": "fa"} |
||||
|
); |
||||
|
var isMaintenanceIcon = L.AwesomeMarkers.icon( |
||||
|
{"icon": "wrench", "iconColor": "white", "markerColor": "black", "prefix": "fa"} |
||||
|
); |
||||
|
|
||||
|
|
||||
|
var map = L.map('map', { zoomControl: false, attributionControl: false }).setView([52.516190, 13.377693], 11.5); |
||||
|
|
||||
|
var Stamen_Toner = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.{ext}', { |
||||
|
attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', |
||||
|
subdomains: 'abcd', |
||||
|
minZoom: 0, |
||||
|
maxZoom: 20, |
||||
|
ext: 'png' |
||||
|
}); |
||||
|
map.addLayer(Stamen_Toner); |
||||
|
|
||||
|
|
||||
|
//the magic: for each scooter in $scooters array, request status and construct marker |
||||
|
<?php |
||||
|
|
||||
|
$filename = "./latestData.json"; //latest locations, 1 entry per scooter |
||||
|
$filename_history = "./historicalData.json"; //historical locations |
||||
|
|
||||
|
// check how old the latest json is |
||||
|
if (time()-filemtime($filename) > 60) { //if older than 60 seconds |
||||
|
$arrayToEcho = saveLatestJSON(); |
||||
|
//append to historical json |
||||
|
appendJSON($filename_history, $arrayToEcho); |
||||
|
|
||||
|
$latestData = json_encode($arrayToEcho, JSON_FORCE_OBJECT); // force object accepts 0 as a key for the array and not NULL |
||||
|
file_put_contents($filename, $latestData, LOCK_EX); |
||||
|
|
||||
|
|
||||
|
$id = 0; //start id |
||||
|
foreach($scooters as $item) { |
||||
|
echo makeMarker($id); |
||||
|
$id++; |
||||
|
} |
||||
|
|
||||
|
} else { // file younger than 60 seconds |
||||
|
|
||||
|
$id = 0; //start id |
||||
|
foreach($scooters as $item) { |
||||
|
echo makeMarker($id); |
||||
|
$id++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
?> |
||||
|
|
||||
|
// time slider |
||||
|
|
||||
|
//test markers |
||||
|
//var marker1 = L.marker([52.504926, 13.358061], {time: "2020-10-09T08:00:29Z"}); |
||||
|
//var marker2 = L.marker([52.506926, 13.358061], {time: "2020-10-09T09:00:29Z"}); |
||||
|
//var marker3 = L.marker([52.508926, 13.358061], {time: "2020-10-09T10:00:29Z"}); |
||||
|
|
||||
|
// var map = marker1; |
||||
|
// layerGroup = L.layerGroup([marker_e7a96a6d6b08479ba6d17d42769e5202]); |
||||
|
layerGroup = L.layerGroup([scooter0, scooter1, scooter2]); //make this dynamic |
||||
|
var sliderControl = L.control.sliderControl({layer:layerGroup}); |
||||
|
map.addControl(sliderControl); |
||||
|
sliderControl.startSlider(); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1 @@ |
|||||
|
{"0":{"ID":0,"lastPos":"52.516922, 13.494012","lastLocationUpdate":"2020-10-15T00:51:13Z","isRentable":true,"state":"ACTIVE","name":"artist name 0","title":"title","desc":"desciption"},"1":{"ID":1,"lastPos":"52.461506, 13.321215","lastLocationUpdate":"2020-10-15T00:48:45Z","isRentable":true,"state":"ACTIVE","name":"artist name 1","title":"title","desc":"desciption"},"2":{"ID":2,"lastPos":"52.491178, 13.385457","lastLocationUpdate":"2020-10-15T00:46:28Z","isRentable":true,"state":"ACTIVE","name":"artist name 2","title":"title","desc":"desciption"},"3":{"ID":3,"lastPos":"52.474423, 13.365387","lastLocationUpdate":"2020-10-15T00:48:04Z","isRentable":false,"state":"INACTIVE","name":"artist name 3","title":"title","desc":"desciption"},"4":{"ID":4,"lastPos":"52.512192, 13.376707","lastLocationUpdate":"2020-10-15T00:46:40Z","isRentable":true,"state":"ACTIVE","name":"artist name 4","title":"title","desc":"desciption"},"5":{"ID":5,"lastPos":"52.529781, 13.401221","lastLocationUpdate":"2020-10-15T00:54:37Z","isRentable":true,"state":"ACTIVE","name":"artist name 5","title":"title","desc":"desciption"},"6":{"ID":6,"lastPos":"52.507063, 13.31256","lastLocationUpdate":"2020-10-15T00:47:27Z","isRentable":true,"state":"ACTIVE","name":"artist name 6","title":"title","desc":"desciption"},"7":{"ID":7,"lastPos":"52.545109, 13.359456","lastLocationUpdate":"2020-10-15T00:51:35Z","isRentable":true,"state":"ACTIVE","name":"artist name 7","title":"title","desc":"desciption"},"8":{"ID":8,"lastPos":"52.511562, 13.310639","lastLocationUpdate":"2020-10-13T00:02:27Z","isRentable":false,"state":"GPS_ISSUE","name":"artist name 8","title":"title","desc":"desciption"},"9":{"ID":9,"lastPos":"52.548454, 13.366208","lastLocationUpdate":"2020-10-15T00:50:36Z","isRentable":true,"state":"ACTIVE","name":"artist name 9","title":"title","desc":"desciption"}} |
@ -0,0 +1,149 @@ |
|||||
|
body { |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
#map { |
||||
|
position: absolute; |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
border: none; |
||||
|
} |
||||
|
|
||||
|
#title-container { |
||||
|
position: absolute; |
||||
|
display: flex; |
||||
|
flex-flow: row wrap; |
||||
|
pointer-events: none; |
||||
|
z-index: 1000; |
||||
|
text-align: right; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
h1, h2, h3, p { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
pointer-events: none; |
||||
|
font-family: Courier; |
||||
|
color: #d152b8; |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
padding-top: 2%; |
||||
|
padding-right: 2%; |
||||
|
font-size: 15vw; |
||||
|
align-self: flex-start; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
h2 { |
||||
|
padding-top: 15%; |
||||
|
padding-right: 2.5%; |
||||
|
font-size: 5vw; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
h3 { |
||||
|
padding-top: 18%; |
||||
|
font-size: 2rem; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
p { |
||||
|
font-size: 5vw; |
||||
|
padding-right: 2.5%; |
||||
|
align-self: flex-end; |
||||
|
padding-bottom: 2.5%; |
||||
|
} |
||||
|
|
||||
|
#bottom_menu { |
||||
|
position: absolute; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-self: flex-end; |
||||
|
z-index: 1000; |
||||
|
background: white; |
||||
|
height: 3%; |
||||
|
width: 100%; |
||||
|
font-family: Courier; |
||||
|
font-weight: bold; |
||||
|
font-size: 2.5vw; |
||||
|
text-align: center; |
||||
|
align-items: center; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#bottom_menu a { |
||||
|
padding: 1vw 3vw 1vw 3vw; |
||||
|
color: #d152b8; |
||||
|
} |
||||
|
|
||||
|
#infotext, #infotext_en { |
||||
|
visibility: hidden; |
||||
|
opacity:0; |
||||
|
overflow-x: hidden !important; |
||||
|
overflow-y: scroll !important; |
||||
|
position: absolute; |
||||
|
z-index: 400; |
||||
|
width: 80%; |
||||
|
height: 70%; |
||||
|
max-height: 100%; |
||||
|
max-width: 100%; |
||||
|
word-wrap: break-word; |
||||
|
background-color: #d152b8; |
||||
|
color: white; |
||||
|
margin: 12% 20% 20% 10%; |
||||
|
transition: opacity 1s; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#infobuttons { |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
#closeButton { |
||||
|
height: min-content; |
||||
|
width: min-content; |
||||
|
font-family: Arial; |
||||
|
font-size:2vw; |
||||
|
font-weight:bold; |
||||
|
padding:1%; |
||||
|
cursor: pointer; |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
#enButton { |
||||
|
position: relative; |
||||
|
height: min-content; |
||||
|
width: min-content; |
||||
|
margin: 0; |
||||
|
font-family: Arial; |
||||
|
font-size:2vw; |
||||
|
font-weight:bold; |
||||
|
color: white; |
||||
|
padding:1%; |
||||
|
text-align: right; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
#closeButtonbottom { |
||||
|
font-family: Arial; |
||||
|
font-size:2vw; |
||||
|
font-weight:bold; |
||||
|
text-align: center; |
||||
|
padding-bottom: 5vh; |
||||
|
margin: 0; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
#infotext p, #infotext_en p { |
||||
|
padding: 0% 10% 10% 10%; |
||||
|
font-family: Arial; |
||||
|
font-weight: bold; |
||||
|
font-size: 2.0vw; |
||||
|
} |
Binary file not shown.
Loading…
Reference in new issue