generate svg with XML
This commit is contained in:
		
						commit
						436a00d8ce
					
				| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
from json import loads, dumps
 | 
			
		||||
 | 
			
		||||
with open('all-time.txt', 'r') as fin:
 | 
			
		||||
	(last_t, last_ev, last_evt, last_ps) = (0, 'error', 0, [])
 | 
			
		||||
 | 
			
		||||
	with open('events.json', 'w') as fout:
 | 
			
		||||
		cur_t = 0
 | 
			
		||||
		cur_ps = []
 | 
			
		||||
 | 
			
		||||
		for line in fin:
 | 
			
		||||
			current = loads(line)
 | 
			
		||||
			cur_t = current['time']
 | 
			
		||||
			cur_ps = current['players']
 | 
			
		||||
 | 
			
		||||
			if last_t == 0:
 | 
			
		||||
				(last_t, last_ev, last_evt, last_ps) = (cur_t, 'online', cur_t, cur_ps)
 | 
			
		||||
			else:
 | 
			
		||||
				if cur_t - last_t > 70:
 | 
			
		||||
					if last_ev == 'online':
 | 
			
		||||
						fout.write(dumps({'period': [last_evt, last_t], 'status': last_ev, 'players': last_ps})+'\n')
 | 
			
		||||
						(last_ev, last_evt, last_ps) = ('unreachable', last_t, cur_ps)
 | 
			
		||||
				else:
 | 
			
		||||
					if last_ev != 'online':
 | 
			
		||||
						fout.write(dumps({'period': [last_evt, last_t], 'status': last_ev})+'\n')
 | 
			
		||||
						(last_ev, last_evt, last_ps) = ('online', last_t, last_ps)
 | 
			
		||||
 | 
			
		||||
					if last_ps != cur_ps:
 | 
			
		||||
						fout.write(dumps({'period': [last_evt, cur_t], 'status': last_ev, 'players': last_ps})+'\n')
 | 
			
		||||
						(last_ev, last_evt, last_ps) = ('online', cur_t, cur_ps)
 | 
			
		||||
 | 
			
		||||
				last_t = cur_t
 | 
			
		||||
 | 
			
		||||
	with open('current-state.json', 'w') as fout:
 | 
			
		||||
		fout.write(dumps({'period': [last_evt, last_t], 'status': 'online', 'players': last_ps}))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# scale down coordinates to dx=1 per day to prevent SVG coordinate overflows
 | 
			
		||||
scale = 1/60/60/24
 | 
			
		||||
 | 
			
		||||
def get_date(dtime):
 | 
			
		||||
    return datetime.fromtimestamp(dtime).strftime('%Y-%m-%d %H:%M')
 | 
			
		||||
 | 
			
		||||
def make_line(event):
 | 
			
		||||
    evstart = event['period'][0]
 | 
			
		||||
    evstop = event['period'][1]
 | 
			
		||||
    return '<line{type} x1="{start}" x2="{stop}" y1="{height}" y2="{height}"><title>{text} ({start_date} — {stop_date})</title></line>'.format(
 | 
			
		||||
        type = '' if event['status'] == 'online' else ' class="error"',
 | 
			
		||||
        start = scale*evstart,
 | 
			
		||||
        stop = scale*evstop,
 | 
			
		||||
        start_date = get_date(evstart),
 | 
			
		||||
        stop_date = get_date(evstop),
 | 
			
		||||
        height = len(event['players']) if 'players' in event else 0,
 | 
			
		||||
        text = ('no one' if len(event['players']) == 0 else ', '.join(event['players'])) if event['status'] == 'online' else event['status']
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
def events_to_lines():
 | 
			
		||||
    with open('events.json', 'r') as fin:
 | 
			
		||||
        with open('events.log', 'w') as fout:
 | 
			
		||||
            for l in fin:
 | 
			
		||||
                fout.write(make_line(loads(l))+'\n')
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
from json import loads
 | 
			
		||||
from xml.etree.ElementTree import Element, tostring
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
def readEvents():
 | 
			
		||||
	events = []
 | 
			
		||||
	with open('events.json', 'r') as f:
 | 
			
		||||
		for line in f:
 | 
			
		||||
			events.append(loads(line))
 | 
			
		||||
 | 
			
		||||
	with open('current-state.json', 'r') as f:
 | 
			
		||||
		events.append(loads(f.read()))
 | 
			
		||||
 | 
			
		||||
	return events
 | 
			
		||||
 | 
			
		||||
def getSVG(events):
 | 
			
		||||
	scale = 1/60/60/24
 | 
			
		||||
	period = 3*30 *60*60*24
 | 
			
		||||
	end = datetime.now().timestamp()
 | 
			
		||||
	start = end-period
 | 
			
		||||
#	start = events[0]['period'][0]
 | 
			
		||||
#	end = events[-1]['period'][1]
 | 
			
		||||
	root = Element('svg', {
 | 
			
		||||
		'version': '1.1',
 | 
			
		||||
		'xmlns': 'http://www.w3.org/2000/svg',
 | 
			
		||||
		'viewBox': '0 0 {} 200'.format(scale*period*200),
 | 
			
		||||
		'width': str(scale*period*200),
 | 
			
		||||
		'height': '200',
 | 
			
		||||
	})
 | 
			
		||||
	group = Element('svg', {
 | 
			
		||||
		'viewBox': '{} 0 {} 10'.format(scale*start,scale*period),
 | 
			
		||||
		'width': '100%',
 | 
			
		||||
		'height': '100%',
 | 
			
		||||
		'preserveAspectRatio': 'none'
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	for i in range(0,10+1):
 | 
			
		||||
		num = Element('text', {
 | 
			
		||||
			'x': str(scale*period*200-20),
 | 
			
		||||
			'y': str((1-i/10)*200)
 | 
			
		||||
		})
 | 
			
		||||
		num.text = str(i)
 | 
			
		||||
		root.append(num)
 | 
			
		||||
	root.append(group)
 | 
			
		||||
 | 
			
		||||
	for event in events:
 | 
			
		||||
		evstart = event['period'][0]
 | 
			
		||||
		evend = event['period'][1]
 | 
			
		||||
 | 
			
		||||
		if evend < start or evstart > end:
 | 
			
		||||
			continue
 | 
			
		||||
 | 
			
		||||
		props = { 'x1': str(scale*evstart), 'x2': str(scale*evend), 'y1': '0', 'y2': '0' }
 | 
			
		||||
		titletext = 'unknown'
 | 
			
		||||
 | 
			
		||||
		if 'players' in event:
 | 
			
		||||
			y = str(len(event['players']))
 | 
			
		||||
			props['y1'] = y
 | 
			
		||||
			props['y2'] = y
 | 
			
		||||
			if len(event['players']) == 0:
 | 
			
		||||
				titletext = '(no one)'
 | 
			
		||||
			else:
 | 
			
		||||
				titletext = ', '.join(event['players'])
 | 
			
		||||
 | 
			
		||||
		if event['type'] == 'error':
 | 
			
		||||
			props['class'] = 'error'
 | 
			
		||||
			titletext = 'error'
 | 
			
		||||
 | 
			
		||||
		ev = Element('line', props)
 | 
			
		||||
		title = Element('title')
 | 
			
		||||
		title.text = '{} ({} — {})'.format(titletext, datetime.fromtimestamp(evstart).strftime('%Y-%m-%d %H:%M'), datetime.fromtimestamp(evend).strftime('%Y-%m-%d %H:%M'))
 | 
			
		||||
		ev.append(title)
 | 
			
		||||
		group.append(ev)
 | 
			
		||||
 | 
			
		||||
	return root
 | 
			
		||||
 | 
			
		||||
def dumpHTML(arg):
 | 
			
		||||
	with open('index.html', 'r') as f:
 | 
			
		||||
		html = f.read()
 | 
			
		||||
		print( html.format(arg) )
 | 
			
		||||
 | 
			
		||||
dumpHTML(tostring(getSVG(readEvents()), encoding='unicode'))
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<!doctype html>
 | 
			
		||||
<html>
 | 
			
		||||
	<head>
 | 
			
		||||
		<meta charset='utf-8'>
 | 
			
		||||
		<link rel='stylesheet' href='style.css'>
 | 
			
		||||
	</head>
 | 
			
		||||
	<body>
 | 
			
		||||
		{}
 | 
			
		||||
	</body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
#graph {
 | 
			
		||||
	background-color: #EEE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#events {
 | 
			
		||||
	transform: scaleY(-1) translateY(-100%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
text {
 | 
			
		||||
	dominant-baseline: central;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#days {
 | 
			
		||||
	stroke: grey;
 | 
			
		||||
	stroke-width: 30;
 | 
			
		||||
	stroke-dasharray: 0.01, 0.99;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
line {
 | 
			
		||||
	stroke: black;
 | 
			
		||||
	stroke-width: 0.4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
line.error {
 | 
			
		||||
	stroke: red;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
line:hover {
 | 
			
		||||
	stroke-width: 0.6;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue