absolute coordinates
This commit is contained in:
parent
d7319a0c6d
commit
8e6274601e
5 changed files with 71 additions and 32 deletions
|
@ -23,7 +23,6 @@ class Annotation:
|
|||
def id(self) -> str:
|
||||
return f'{self.drawing.id}:{self.tag}:{self.t_in}:{self.t_out}'
|
||||
|
||||
|
||||
def getAnimationSlice(self) -> AnimationSlice:
|
||||
return self.drawing.get_animation().getSlice(self.t_in, self.t_out)
|
||||
|
||||
|
@ -96,7 +95,7 @@ class Drawing:
|
|||
strokes.append(
|
||||
Stroke(
|
||||
event["color"],
|
||||
[Point.fromTuple(tuple(p)).scaled(self.get_canvas_metadata()['dimensions']) for p in event["points"]],
|
||||
[Point.fromTuple(tuple(p)) for p in event["points"]],
|
||||
)
|
||||
)
|
||||
return AnimationSlice(strokes, audioslice=self.get_audio() )
|
||||
|
@ -363,8 +362,9 @@ class Point:
|
|||
def fromTuple(cls, p: tuple[float, float, int, float]):
|
||||
return cls(p[0], p[1], bool(p[2]), p[3])
|
||||
|
||||
def scaled(self, dimensions: dict[str, float]) -> Point:
|
||||
return Point(self.x*dimensions['width'], self.y * dimensions['height'], self.last, self.t)
|
||||
def scaledToFit(self, dimensions: dict[str, float]) -> Point:
|
||||
# TODO: change so that it actually scales to FIT dimensions
|
||||
return Point(self.x, self.y, self.last, self.t)
|
||||
|
||||
|
||||
Points = list[Point]
|
||||
|
|
46
webserver.py
46
webserver.py
|
@ -47,6 +47,7 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|||
self.strokes = []
|
||||
self.hasWritten = False
|
||||
self.prev_file = None
|
||||
self.prev_file_duration = 0
|
||||
self.dimensions = [None, None]
|
||||
|
||||
# def check_origin(self, origin):
|
||||
|
@ -126,15 +127,42 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|||
|
||||
self.prev_file = prev_file
|
||||
|
||||
with open(self.prev_file, "r") as fp:
|
||||
metadata = self.getFileMetadata(self.prev_file)
|
||||
self.prev_file_duration = self.getLastTimestampInFile(self.prev_file)
|
||||
logger.info(
|
||||
"Previous file set. {self.prev_file} {metadata=} time: {self.prev_file_duration}")
|
||||
|
||||
self.write_message(json.dumps(
|
||||
{"preloaded_svg": f"/drawing/{file}", "dimensions": [metadata[1], metadata[2]], "time": self.prev_file_duration}))
|
||||
|
||||
def getFileMetadata(self, filename):
|
||||
with open(filename, "r") as fp:
|
||||
first_line = fp.readline().strip()
|
||||
if first_line.endswith(","):
|
||||
first_line = first_line[:-1]
|
||||
|
||||
metadata = json.loads(first_line)
|
||||
|
||||
self.write_message(json.dumps(
|
||||
{"preloaded_svg": f"/drawing/{file}", "dimensions": [metadata[1], metadata[2]]}))
|
||||
return metadata
|
||||
|
||||
def getLastTimestampInFile(self, filename):
|
||||
with open(filename, "r") as fp:
|
||||
for line in fp:
|
||||
pass # loop until the end
|
||||
last_line = line.strip()
|
||||
if last_line.endswith(","):
|
||||
last_line = last_line[:-1]
|
||||
|
||||
data = json.loads(last_line)
|
||||
if type(data) is list:
|
||||
raise Exception("Oddly, the file ends with merely metadata")
|
||||
|
||||
if data['event'] == 'stroke':
|
||||
return data['points'][-1][3]
|
||||
elif data['event'] == 'viewbox':
|
||||
return data['viewboxes'][-1]['t']
|
||||
else:
|
||||
raise Exception("Unknown last event")
|
||||
|
||||
# the client sent the message
|
||||
def on_message(self, message):
|
||||
|
@ -144,13 +172,20 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|||
msg = json.loads(message)
|
||||
if msg["event"] == "stroke":
|
||||
logger.info("stroke")
|
||||
for i in range(len(msg['points'])):
|
||||
msg['points'][i][3] += self.prev_file_duration
|
||||
self.appendEvent(msg)
|
||||
elif msg["event"] == "dimensions":
|
||||
self.dimensions = [int(msg["width"]), int(msg["height"])]
|
||||
logger.info(f"{self.dimensions=}")
|
||||
elif msg["event"] == "viewbox":
|
||||
logger.info("move or resize")
|
||||
self.appendEvent(msg)
|
||||
if len(msg['viewboxes']) == 0:
|
||||
logger.warn("Empty viewbox array")
|
||||
else:
|
||||
for i in range(len(msg['viewboxes'])):
|
||||
msg['viewboxes'][i]['t'] += self.prev_file_duration
|
||||
self.appendEvent(msg)
|
||||
elif msg["event"] == "preload":
|
||||
self.preloadFile(msg["file"])
|
||||
else:
|
||||
|
@ -253,6 +288,9 @@ class AnimationHandler(tornado.web.RequestHandler):
|
|||
drawing["time"] = event[0]
|
||||
drawing["dimensions"] = [event[1], event[2]]
|
||||
else:
|
||||
if type(event) is list:
|
||||
# ignore double metadatas, which appear when continuaing an existing drawing
|
||||
continue
|
||||
if event["event"] == "viewbox":
|
||||
pass
|
||||
if event["event"] == "stroke":
|
||||
|
|
|
@ -56,7 +56,7 @@ class StrokeGroup {
|
|||
let cmd = "";
|
||||
for (let stroke of strokes) {
|
||||
if (!last_stroke) {
|
||||
d += `M${stroke[0] * this.player.dimensions[0]},${stroke[1] * this.player.dimensions[1]} `;
|
||||
d += `M${stroke[0]},${stroke[1]} `;
|
||||
cmd = 'M';
|
||||
} else {
|
||||
if (last_stroke[2] == 1) {
|
||||
|
@ -67,7 +67,7 @@ class StrokeGroup {
|
|||
cmd = 'l';
|
||||
}
|
||||
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
|
||||
d += `${rel_stroke[0] * this.player.dimensions[0]},${rel_stroke[1] * this.player.dimensions[1]} `;
|
||||
d += `${rel_stroke[0]},${rel_stroke[1]} `;
|
||||
}
|
||||
last_stroke = stroke;
|
||||
|
||||
|
|
17
www/draw.js
17
www/draw.js
|
@ -61,7 +61,7 @@ class Canvas {
|
|||
})
|
||||
|
||||
|
||||
this.colors = ["black", "red", "blue", "green"];
|
||||
this.colors = ["black", "#cc1414", "blue", "green"];
|
||||
|
||||
this.resize();
|
||||
|
||||
|
@ -292,14 +292,15 @@ class Canvas {
|
|||
getCoordinates(e) {
|
||||
// convert event coordinates into relative positions on x & y axis
|
||||
let box = this.svgEl.getBoundingClientRect();
|
||||
let x = (e.x - box['left'] + this.viewbox.x) / box['width'];
|
||||
let y = (e.y - box['top'] + this.viewbox.y) / box['height'];
|
||||
let x = (e.x - box['left'] + this.viewbox.x);
|
||||
let y = (e.y - box['top'] + this.viewbox.y);
|
||||
return { 'x': x, 'y': y };
|
||||
}
|
||||
|
||||
isInsideBounds(pos) {
|
||||
return !(pos['x'] < 0 || pos['y'] < 0 || pos['x'] > 1 || pos['y'] > 1);
|
||||
}
|
||||
// isInsideBounds(pos) {
|
||||
// let box = this.svgEl.getBoundingClientRect();
|
||||
// return !(pos['x'] < 0 || pos['y'] < 0 || pos['x'] > box['width'] || pos['y'] > box['height']);
|
||||
// }
|
||||
|
||||
|
||||
draw(e) {
|
||||
|
@ -377,7 +378,7 @@ class Canvas {
|
|||
let cmd = "";
|
||||
for (let stroke of strokes) {
|
||||
if (!last_stroke) {
|
||||
d += `M${stroke[0] * this.viewbox.width},${stroke[1] * this.viewbox.height} `;
|
||||
d += `M${stroke[0]},${stroke[1]} `;
|
||||
cmd = 'M';
|
||||
} else {
|
||||
if (last_stroke[2] == 1) {
|
||||
|
@ -388,7 +389,7 @@ class Canvas {
|
|||
cmd = 'l';
|
||||
}
|
||||
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
|
||||
d += `${rel_stroke[0] * this.viewbox.width},${rel_stroke[1] * this.viewbox.height} `;
|
||||
d += `${rel_stroke[0]},${rel_stroke[1]} `;
|
||||
}
|
||||
last_stroke = stroke;
|
||||
|
||||
|
|
28
www/play.js
28
www/play.js
|
@ -74,13 +74,13 @@ class Player {
|
|||
if (
|
||||
this.currentPathI < this.inPointPosition[0] ||
|
||||
this.currentPointI < this.inPointPosition[1]) {
|
||||
this.drawStrokePosition(
|
||||
// this.inPointPosition[0],
|
||||
// this.inPointPosition[1],
|
||||
// always draw at out position, as to see the whole shape of the range
|
||||
this.outPointPosition[0],
|
||||
this.outPointPosition[1],
|
||||
);
|
||||
this.drawStrokePosition(
|
||||
// this.inPointPosition[0],
|
||||
// this.inPointPosition[1],
|
||||
// always draw at out position, as to see the whole shape of the range
|
||||
this.outPointPosition[0],
|
||||
this.outPointPosition[1],
|
||||
);
|
||||
}
|
||||
}
|
||||
if (handle === 1) {
|
||||
|
@ -122,7 +122,7 @@ class Player {
|
|||
// inactive is what comes before and after.
|
||||
// then, playing the video is just running pathRanghe(0, playhead)
|
||||
drawStrokePosition(path_i, point_i, show_all) {
|
||||
if(typeof show_all === 'undefined')
|
||||
if (typeof show_all === 'undefined')
|
||||
show_all = false;
|
||||
|
||||
// check if anything is placed that is in the future from the current playhead
|
||||
|
@ -194,7 +194,7 @@ class Player {
|
|||
}
|
||||
|
||||
// when an outpoint is set, stop playing there
|
||||
if(next_path > this.outPointPosition[0] || next_point > this.outPointPosition[1]){
|
||||
if (this.outPointPosition && (next_path > this.outPointPosition[0] || next_point > this.outPointPosition[1])) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
|
@ -202,12 +202,12 @@ class Player {
|
|||
}
|
||||
|
||||
playStrokePosition(path_i, point_i, allow_interrupt) {
|
||||
if(allow_interrupt) {
|
||||
if(!this.isPlaying) {
|
||||
if (allow_interrupt) {
|
||||
if (!this.isPlaying) {
|
||||
console.log('not playing because of interrupt');
|
||||
return;
|
||||
}
|
||||
} else{
|
||||
} else {
|
||||
this.isPlaying = true;
|
||||
}
|
||||
this.drawStrokePosition(path_i, point_i);
|
||||
|
@ -281,7 +281,7 @@ class Player {
|
|||
let cmd = "";
|
||||
for (let stroke of strokes) {
|
||||
if (!last_stroke) {
|
||||
d += `M${stroke[0] * this.dimensions[0]},${stroke[1] * this.dimensions[1]} `;
|
||||
d += `M${stroke[0]},${stroke[1]} `;
|
||||
cmd = 'M';
|
||||
} else {
|
||||
if (last_stroke[2] == 1) {
|
||||
|
@ -292,7 +292,7 @@ class Player {
|
|||
cmd = 'l';
|
||||
}
|
||||
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
|
||||
d += `${rel_stroke[0] * this.dimensions[0]},${rel_stroke[1] * this.dimensions[1]} `;
|
||||
d += `${rel_stroke[0]},${rel_stroke[1]} `;
|
||||
}
|
||||
last_stroke = stroke;
|
||||
|
||||
|
|
Loading…
Reference in a new issue