├── app.py ├── busdata1.py ├── busdata2.py ├── busdata3.py ├── data ├── bus1.json ├── bus2.json └── bus3.json ├── static └── leaf.js └── templates └── index.html /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, Response 2 | from pykafka import KafkaClient 3 | 4 | def get_kafka_client(): 5 | return KafkaClient(hosts='127.0.0.1:9092') 6 | 7 | app = Flask(__name__) 8 | 9 | @app.route('/') 10 | def index(): 11 | return(render_template('index.html')) 12 | 13 | #Consumer API 14 | @app.route('/topic/') 15 | def get_messages(topicname): 16 | client = get_kafka_client() 17 | def events(): 18 | for i in client.topics[topicname].get_simple_consumer(): 19 | yield 'data:{0}\n\n'.format(i.value.decode()) 20 | return Response(events(), mimetype="text/event-stream") 21 | 22 | if __name__ == '__main__': 23 | app.run(debug=True, port=5001) 24 | -------------------------------------------------------------------------------- /busdata1.py: -------------------------------------------------------------------------------- 1 | from pykafka import KafkaClient 2 | import json 3 | from datetime import datetime 4 | import uuid 5 | import time 6 | 7 | #READ COORDINATES FROM GEOJSON 8 | input_file = open('./data/bus1.json') 9 | json_array = json.load(input_file) 10 | coordinates = json_array['features'][0]['geometry']['coordinates'] 11 | 12 | #GENERATE UUID 13 | def generate_uuid(): 14 | return uuid.uuid4() 15 | 16 | #KAFKA PRODUCER 17 | client = KafkaClient(hosts="localhost:9092") 18 | topic = client.topics['geodata_final123'] 19 | producer = topic.get_sync_producer() 20 | 21 | #CONSTRUCT MESSAGE AND SEND IT TO KAFKA 22 | data = {} 23 | data['busline'] = '00001' 24 | 25 | def generate_checkpoint(coordinates): 26 | i = 0 27 | while i < len(coordinates): 28 | data['key'] = data['busline'] + '_' + str(generate_uuid()) 29 | data['timestamp'] = str(datetime.utcnow()) 30 | data['latitude'] = coordinates[i][1] 31 | data['longitude'] = coordinates[i][0] 32 | message = json.dumps(data) 33 | print(message) 34 | producer.produce(message.encode('ascii')) 35 | time.sleep(1) 36 | 37 | #if bus reaches last coordinate, start from beginning 38 | if i == len(coordinates)-1: 39 | i = 0 40 | else: 41 | i += 1 42 | 43 | generate_checkpoint(coordinates) 44 | -------------------------------------------------------------------------------- /busdata2.py: -------------------------------------------------------------------------------- 1 | from pykafka import KafkaClient 2 | import json 3 | from datetime import datetime 4 | import uuid 5 | import time 6 | 7 | #READ COORDINATES FROM GEOJSON 8 | input_file = open('./data/bus2.json') 9 | json_array = json.load(input_file) 10 | coordinates = json_array['features'][0]['geometry']['coordinates'] 11 | 12 | #GENERATE UUID 13 | def generate_uuid(): 14 | return uuid.uuid4() 15 | 16 | #KAFKA PRODUCER 17 | client = KafkaClient(hosts="localhost:9092") 18 | topic = client.topics['geodata_final123'] 19 | producer = topic.get_sync_producer() 20 | 21 | #CONSTRUCT MESSAGE AND SEND IT TO KAFKA 22 | data = {} 23 | data['busline'] = '00002' 24 | 25 | def generate_checkpoint(coordinates): 26 | i = 0 27 | while i < len(coordinates): 28 | data['key'] = data['busline'] + '_' + str(generate_uuid()) 29 | data['timestamp'] = str(datetime.utcnow()) 30 | data['latitude'] = coordinates[i][1] 31 | data['longitude'] = coordinates[i][0] 32 | message = json.dumps(data) 33 | print(message) 34 | producer.produce(message.encode('ascii')) 35 | time.sleep(1) 36 | 37 | #if bus reaches last coordinate, start from beginning 38 | if i == len(coordinates)-1: 39 | i = 0 40 | else: 41 | i += 1 42 | 43 | generate_checkpoint(coordinates) 44 | -------------------------------------------------------------------------------- /busdata3.py: -------------------------------------------------------------------------------- 1 | from pykafka import KafkaClient 2 | import json 3 | from datetime import datetime 4 | import uuid 5 | import time 6 | 7 | #READ COORDINATES FROM GEOJSON 8 | input_file = open('./data/bus3.json') 9 | json_array = json.load(input_file) 10 | coordinates = json_array['features'][0]['geometry']['coordinates'] 11 | 12 | #GENERATE UUID 13 | def generate_uuid(): 14 | return uuid.uuid4() 15 | 16 | #KAFKA PRODUCER 17 | client = KafkaClient(hosts="localhost:9092") 18 | topic = client.topics['geodata_final123'] 19 | producer = topic.get_sync_producer() 20 | 21 | #CONSTRUCT MESSAGE AND SEND IT TO KAFKA 22 | data = {} 23 | data['busline'] = '00003' 24 | 25 | def generate_checkpoint(coordinates): 26 | i = 0 27 | while i < len(coordinates): 28 | data['key'] = data['busline'] + '_' + str(generate_uuid()) 29 | data['timestamp'] = str(datetime.utcnow()) 30 | data['latitude'] = coordinates[i][1] 31 | data['longitude'] = coordinates[i][0] 32 | message = json.dumps(data) 33 | print(message) 34 | producer.produce(message.encode('ascii')) 35 | time.sleep(1) 36 | 37 | #if bus reaches last coordinate, start from beginning 38 | if i == len(coordinates)-1: 39 | i = 0 40 | else: 41 | i += 1 42 | 43 | generate_checkpoint(coordinates) 44 | -------------------------------------------------------------------------------- /data/bus1.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": {}, 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | -0.10445594787597656, 12 | 51.503667218218546 13 | ], 14 | [ 15 | -0.10454177856445312, 16 | 51.5050562876173 17 | ], 18 | [ 19 | -0.10445594787597656, 20 | 51.50665900738443 21 | ], 22 | [ 23 | -0.10445594787597656, 24 | 51.5077274559105 25 | ], 26 | [ 27 | -0.10445594787597656, 28 | 51.50949034120275 29 | ], 30 | [ 31 | -0.1043701171875, 32 | 51.51093265116127 33 | ], 34 | [ 35 | -0.10428428649902344, 36 | 51.51205441622754 37 | ], 38 | [ 39 | -0.1043701171875, 40 | 51.51384384141771 41 | ], 42 | [ 43 | -0.10441303253173828, 44 | 51.51413762092547 45 | ], 46 | [ 47 | -0.10634422302246094, 48 | 51.514217742280586 49 | ], 50 | [ 51 | -0.10999202728271484, 52 | 51.514030792232774 53 | ], 54 | [ 55 | -0.11299610137939453, 56 | 51.513336399623476 57 | ], 58 | [ 59 | -0.11565685272216795, 60 | 51.51253516422883 61 | ], 62 | [ 63 | -0.1187896728515625, 64 | 51.51152024583139 65 | ], 66 | [ 67 | -0.1192617416381836, 68 | 51.51135999349115 69 | ], 70 | [ 71 | -0.11827468872070311, 72 | 51.5100245354003 73 | ], 74 | [ 75 | -0.11724472045898438, 76 | 51.50876916910042 77 | ], 78 | [ 79 | -0.11621475219726562, 80 | 51.50762061218536 81 | ], 82 | [ 83 | -0.11484146118164062, 84 | 51.506285044481096 85 | ], 86 | [ 87 | -0.11398315429687499, 88 | 51.50537683608064 89 | ], 90 | [ 91 | -0.11312484741210938, 92 | 51.50502957514356 93 | ], 94 | [ 95 | -0.11312484741210938, 96 | 51.5043884710761 97 | ], 98 | [ 99 | -0.11183738708496094, 100 | 51.50409462869737 101 | ], 102 | [ 103 | -0.11119365692138672, 104 | 51.50331994425266 105 | ], 106 | [ 107 | -0.11020660400390625, 108 | 51.50230482056266 109 | ], 110 | [ 111 | -0.10934829711914062, 112 | 51.501610249219446 113 | ], 114 | [ 115 | -0.10728836059570312, 116 | 51.499953920988176 117 | ], 118 | [ 119 | -0.10582923889160156, 120 | 51.4987249934006 121 | ], 122 | [ 123 | -0.10540008544921875, 124 | 51.49861812856609 125 | ], 126 | [ 127 | -0.10505676269531249, 128 | 51.49875170957007 129 | ], 130 | [ 131 | -0.1048421859741211, 132 | 51.49901887040353 133 | ], 134 | [ 135 | -0.10471343994140624, 136 | 51.49957990305636 137 | ], 138 | [ 139 | -0.1045846939086913, 140 | 51.503400084633526 141 | ] 142 | ] 143 | } 144 | } 145 | ] 146 | } 147 | -------------------------------------------------------------------------------- /data/bus2.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": {}, 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | -0.12694358825683594, 12 | 51.50767403407925 13 | ], 14 | [ 15 | -0.12303829193115234, 16 | 51.50981085847289 17 | ], 18 | [ 19 | -0.11844635009765626, 20 | 51.511600371790095 21 | ], 22 | [ 23 | -0.11492729187011717, 24 | 51.51269541243519 25 | ], 26 | [ 27 | -0.11278152465820314, 28 | 51.51349664501128 29 | ], 30 | [ 31 | -0.10934829711914062, 32 | 51.51413762092547 33 | ], 34 | [ 35 | -0.10462760925292969, 36 | 51.514217742280586 37 | ], 38 | [ 39 | -0.10432720184326172, 40 | 51.51413762092547 41 | ], 42 | [ 43 | -0.10475635528564453, 44 | 51.51614061252578 45 | ], 46 | [ 47 | -0.10514259338378906, 48 | 51.51723554403216 49 | ], 50 | [ 51 | -0.11046409606933594, 52 | 51.51806340159923 53 | ], 54 | [ 55 | -0.11587142944335936, 56 | 51.51814351604911 57 | ], 58 | [ 59 | -0.1199054718017578, 60 | 51.51766282723606 61 | ], 62 | [ 63 | -0.12050628662109375, 64 | 51.51763612215324 65 | ], 66 | [ 67 | -0.11969089508056639, 68 | 51.51632755391457 69 | ], 70 | [ 71 | -0.12106418609619139, 72 | 51.51563319631723 73 | ], 74 | [ 75 | -0.12205123901367186, 76 | 51.51467176063095 77 | ], 78 | [ 79 | -0.1242828369140625, 80 | 51.51317615367198 81 | ], 82 | [ 83 | -0.12848854064941406, 84 | 51.5112531582845 85 | ], 86 | [ 87 | -0.12831687927246094, 88 | 51.51018479243817 89 | ], 90 | [ 91 | -0.12763023376464844, 92 | 51.50949034120275 93 | ], 94 | [ 95 | -0.1272439956665039, 96 | 51.508662327818094 97 | ], 98 | [ 99 | -0.12707233428955078, 100 | 51.50780758853995 101 | ] 102 | ] 103 | } 104 | } 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /data/bus3.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": {}, 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | -0.12617111206054688, 12 | 51.50099581189912 13 | ], 14 | [ 15 | -0.12402534484863281, 16 | 51.50091566729007 17 | ], 18 | [ 19 | -0.12260913848876953, 20 | 51.506285044481096 21 | ], 22 | [ 23 | -0.12076377868652344, 24 | 51.50850206542486 25 | ], 26 | [ 27 | -0.11737346649169922, 28 | 51.5102649207457 29 | ], 30 | [ 31 | -0.11346817016601562, 32 | 51.51098606917176 33 | ], 34 | [ 35 | -0.10630130767822266, 36 | 51.51101277815347 37 | ], 38 | [ 39 | -0.10342597961425781, 40 | 51.511092905004745 41 | ], 42 | [ 43 | -0.10359764099121094, 44 | 51.51296249152639 45 | ], 46 | [ 47 | -0.1036405563354492, 48 | 51.51413762092547 49 | ], 50 | [ 51 | -0.10471343994140624, 52 | 51.51419103517789 53 | ], 54 | [ 55 | -0.10647296905517578, 56 | 51.51413762092547 57 | ], 58 | [ 59 | -0.10591506958007812, 60 | 51.512882367963456 61 | ], 62 | [ 63 | -0.10677337646484375, 64 | 51.51266870443993 65 | ], 66 | [ 67 | -0.10776042938232422, 68 | 51.51427115643904 69 | ], 70 | [ 71 | -0.11432647705078125, 72 | 51.51282895217651 73 | ], 74 | [ 75 | -0.11891841888427736, 76 | 51.51133328471298 77 | ], 78 | [ 79 | -0.12196540832519531, 80 | 51.5102649207457 81 | ], 82 | [ 83 | -0.1258707046508789, 84 | 51.50836851299987 85 | ], 86 | [ 87 | -0.12767314910888672, 88 | 51.507406923983446 89 | ], 90 | [ 91 | -0.12715816497802734, 92 | 51.50583094254364 93 | ], 94 | [ 95 | -0.12629985809326172, 96 | 51.50452203516731 97 | ], 98 | [ 99 | -0.12617111206054688, 100 | 51.501262959578035 101 | ] 102 | ] 103 | } 104 | } 105 | ] 106 | } -------------------------------------------------------------------------------- /static/leaf.js: -------------------------------------------------------------------------------- 1 | var mymap = L.map('mapid').setView([51.505, -0.09], 13); 2 | L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', { 3 | attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox', 4 | maxZoom: 18, 5 | id: 'mapbox.streets', 6 | accessToken: 'ABCDEFG' //ENTER YOUR ACCESS TOKEN HERE 7 | }).addTo(mymap); 8 | 9 | mapMarkers1 = []; 10 | mapMarkers2 = []; 11 | mapMarkers3 = []; 12 | 13 | var source = new EventSource('/topic/TOPICNAME'); //ENTER YOUR TOPICNAME HERE 14 | source.addEventListener('message', function(e){ 15 | 16 | console.log('Message'); 17 | obj = JSON.parse(e.data); 18 | console.log(obj); 19 | 20 | if(obj.busline == '00001') { 21 | for (var i = 0; i < mapMarkers1.length; i++) { 22 | mymap.removeLayer(mapMarkers1[i]); 23 | } 24 | marker1 = L.marker([obj.latitude, obj.longitude]).addTo(mymap); 25 | mapMarkers1.push(marker1); 26 | } 27 | 28 | if(obj.busline == '00002') { 29 | for (var i = 0; i < mapMarkers2.length; i++) { 30 | mymap.removeLayer(mapMarkers2[i]); 31 | } 32 | marker2 = L.marker([obj.latitude, obj.longitude]).addTo(mymap); 33 | mapMarkers2.push(marker2); 34 | } 35 | 36 | if(obj.busline == '00003') { 37 | for (var i = 0; i < mapMarkers3.length; i++) { 38 | mymap.removeLayer(mapMarkers3[i]); 39 | } 40 | marker3 = L.marker([obj.latitude, obj.longitude]).addTo(mymap); 41 | mapMarkers3.push(marker3); 42 | } 43 | }, false); 44 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 12 | 13 | London Live Map 14 | 15 | 16 |

London Bus Live Map

17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | --------------------------------------------------------------------------------