Send drawing to server - WIP

This commit is contained in:
Ruben van de Ven 2019-09-11 18:16:33 +02:00
commit 6c908a572f
4 changed files with 231 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
venv/

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
tornado
coloredlogs

105
server.py Normal file
View File

@ -0,0 +1,105 @@
import tornado.ioloop
import tornado.web
import tornado.websocket
import logging
import coloredlogs
import argparse
import json
from urllib.parse import urlparse
logger = logging.getLogger("drawing")
argParser = argparse.ArgumentParser(description='Start up the server to have non-Mechanical Turks draw their sketches.')
argParser.add_argument(
'--port',
'-p',
default=8888,
help='The port for the server to listen'
)
argParser.add_argument(
'--verbose',
'-v',
action="store_true",
)
class StaticFileWithHeaderHandler(tornado.web.StaticFileHandler):
def set_extra_headers(self, path):
"""For subclass to add extra headers to the response"""
if path[-5:] == '.html':
self.set_header("Access-Control-Allow-Origin", "*")
class WebSocketHandler(tornado.websocket.WebSocketHandler):
CORS_ORIGINS = ['localhost', '.mturk.com']
connections = set()
def check_origin(self, origin):
parsed_origin = urlparse(origin)
# parsed_origin.netloc.lower() gives localhost:3333
valid = any([parsed_origin.hostname.endswith(origin) for origin in self.CORS_ORIGINS])
return valid
# the client connected
def open(self, p = None):
self.__class__.connections.add(self)
logger.info("New client connected")
self.write_message("hello!")
# the client sent the message
def on_message(self, message):
logger.debug(f"recieve: {message}")
try:
msg = json.loads(message)
if msg['action'] == 'move':
pass
elif msg['action'] == 'up':
logger.info(f'up: {msg}')
elif msg['action'] == 'submit':
logger.info(f'up: {msg}')
self.write_message(json.dumps('submitted'))
elif msg['action'] == 'down':
# not used, implicit in move?
pass
else:
# self.send({'alert': 'Unknown request: {}'.format(message)})
logger.warn('Unknown request: {}'.format(message))
except Exception as e:
# self.send({'alert': 'Invalid request: {}'.format(e)})
logger.exception(e)
# client disconnected
def on_close(self):
self.__class__.rmConnection(self)
logger.info("Client disconnected")
@classmethod
def rmConnection(cls, client):
if client not in cls.connections:
return
cls.connections.remove(client)
if __name__ == "__main__":
args = argParser.parse_args()
print(logger.level)
coloredlogs.install(
level=logging.DEBUG if args.verbose else logging.INFO,
)
logger.addHandler(
logging.handlers.RotatingFileHandler(
'mt_server.log',
maxBytes=1024*512,
backupCount=5
)
)
application = tornado.web.Application([
(r"/ws(.*)", WebSocketHandler),
(r"/(.*)", StaticFileWithHeaderHandler,
{"path": 'www', "default_filename": 'index.html'}),
], debug=True)
application.listen(args.port)
tornado.ioloop.IOLoop.current().start()

123
www/index.html Normal file
View File

@ -0,0 +1,123 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>MT Request: draw over the image</title>
<style media="screen">
svg{
height:600px;
width:600px;
border:solid 1px;
}
path {
fill: none;
stroke: red;
stroke-width: 2px;
}
</style>
</head>
<body>
<div id='interface'>
<img src="" id='sample'>
<svg id="canvas">
<path d="" id="stroke">
</svg>
<button id='submit'>Submit</button>
</div>
<script type="text/javascript">
let url = window.location.origin.replace('http', 'ws') +'/ws';
let svgEl = document.getElementById("canvas");
let strokeEl = document.getElementById('stroke');
let submitEl = document.getElementById('submit');
let strokes = [];
let isDrawing = false;
let draw = function(e) {
let pos = svgEl.getBoundingClientRect()
let x = e.x - pos['left'];
let y = e.y - pos['top'];
strokes.push([x, y, 0]);
let d = strokes2D(strokes);
console.log(d);
strokeEl.setAttribute('d', d);
socket.send(JSON.stringify({
'action': 'move',
'direction': [x, y]
}));
};
let penup = function(e) {
if(!isDrawing) {
return;
}
isDrawing = false;
document.body.removeEventListener('mousemove', draw);
if(strokes.length > 0){
// mark point as last of stroke
strokes[strokes.length - 1][2] = 1;
}
socket.send(JSON.stringify({
'action': 'up',
}));
};
let strokes2D = function(strokes) {
// strokes to a d attribute for a path
let d = "";
let last_stroke = undefined;
let cmd = "";
for (let stroke of strokes) {
if(!last_stroke) {
d += `M${stroke[0]},${stroke[1]} `;
cmd = 'M';
} else {
if (last_stroke[2] == 1) {
d += " m";
cmd = 'm';
} else if (cmd != 'l') {
d+=' l ';
cmd = 'l';
}
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
d += `${rel_stroke[0]},${rel_stroke[1]} `;
}
last_stroke = stroke;
}
return d;
}
let socket = new WebSocket(url);
socket.addEventListener('message', function(e){
console.log('receive', e.data);
if(e.data == 'submitted') {
// TODO close the interface
}
});
document.body.addEventListener('mouseup', penup);
svgEl.addEventListener('mousedown', function(e){
isDrawing = true;
// start drawing
document.body.addEventListener('mousemove', draw);
});
submitEl.addEventListener('click', function(e){
if(!strokes.length){
alert('please draw before submitting');
return;
}
socket.send(JSON.stringify({
'action': 'submit'
}));
});
</script>
</body>
</html>