diff --git a/main.go b/main.go index 7e9377e..ed101bc 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,10 @@ func (web Web) index(c *gin.Context) { c.HTML(http.StatusOK, "index", watches) } +func (web Web) canvas(c *gin.Context) { + c.HTML(http.StatusOK, "canvas", gin.H{}) +} + func (web Web) newWatch(c *gin.Context) { c.HTML(http.StatusOK, "newWatch", gin.H{}) } @@ -219,34 +223,35 @@ func main() { db, _ := gorm.Open(sqlite.Open(viper.GetString("database.dsn"))) db.AutoMigrate(&Watch{}, &Filter{}) - filters := []Filter{} - watch := Watch{ - Name: "LG C2 42", - Interval: 60, - Filters: filters, - } - db.Create(&watch) + /* + filters := []Filter{} + watch := Watch{ + Name: "LG C2 42", + Interval: 60, + Filters: filters, + } + db.Create(&watch) - urlFilter := Filter{ - WatchID: watch.ID, - ParentID: nil, - Parent: nil, - Name: "PriceWatch Fetch", - Type: "url", - Var1: "https://tweakers.net/pricewatch/1799060/lg-c2-42-inch-donkerzilveren-voet-zwart.html", - } - db.Create(&urlFilter) - - xpathFilter := Filter{ - WatchID: watch.ID, - Watch: watch, - ParentID: &urlFilter.ID, - Name: "price select", - Type: "xpath", - Var1: "//td[@class='shop-price']", - } - db.Create(&xpathFilter) + urlFilter := Filter{ + WatchID: watch.ID, + ParentID: nil, + Parent: nil, + Name: "PriceWatch Fetch", + Type: "url", + Var1: "https://tweakers.net/pricewatch/1799060/lg-c2-42-inch-donkerzilveren-voet-zwart.html", + } + db.Create(&urlFilter) + xpathFilter := Filter{ + WatchID: watch.ID, + Watch: watch, + ParentID: &urlFilter.ID, + Name: "price select", + Type: "xpath", + Var1: "//td[@class='shop-price']", + } + db.Create(&xpathFilter) + */ //bot, _ := tgbotapi.NewBotAPI(viper.GetString("telegram.token")) //bot.Debug = true @@ -269,6 +274,8 @@ func main() { templates.AddFromFiles("viewWatch", "templates/base.html", "templates/viewWatch.html") templates.AddFromFiles("editGroup", "templates/base.html", "templates/editGroup.html") + templates.AddFromFiles("canvas", "templates/base.html", "templates/diagrams.html") + templates.AddFromFiles("500", "templates/base.html", "templates/500.html") router.HTMLRender = templates @@ -281,5 +288,7 @@ func main() { router.POST("/filter/update/", web.updateFilter) router.POST("/filter/delete/", web.deleteFilter) + router.GET("/canvas/", web.canvas) + router.Run("0.0.0.0:8080") } diff --git a/static/diagram.js b/static/diagram.js new file mode 100644 index 0000000..acf64e7 --- /dev/null +++ b/static/diagram.js @@ -0,0 +1,131 @@ +var DiagramNode = /** @class */ (function () { + function DiagramNode(x, y, width, height, label) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.label = label; + } + DiagramNode.prototype.pointInDiagram = function (x, y) { + if (x < this.x) { + return false; + } + if (y < this.y) { + return false; + } + if (x > this.x + this.width) { + return false; + } + if (y > this.y + this.height) { + return false; + } + return true; + }; + return DiagramNode; +}()); +var _diagram; +function diargramOnResize() { + _diagram.fillParent(); +} +function diagramOnMouseDown(ev) { + _diagram.onmousedown(ev); +} +function diagramOnMouseUp(ev) { + _diagram.onmouseup(ev); +} +function diagramOnMouseMove(ev) { + _diagram.onmousemove(ev); +} +var Diagrams = /** @class */ (function () { + function Diagrams(canvasId) { + this.canvas = document.getElementById(canvasId); + if (this.canvas === null) { + throw "Could not getElementById " + canvasId; + } + var ctx = this.canvas.getContext("2d"); + if (ctx === null) { + throw "Could not get 2d rendering context"; + } + _diagram = this; + this.ctx = ctx; + this.ctx.font = "30px Arial"; + this.canvas.onmousemove = diagramOnMouseMove; + this.canvas.onmousedown = diagramOnMouseDown; + this.canvas.onmouseup = diagramOnMouseUp; + window.onresize = diargramOnResize; + this.nodes = new Array(); + this.connections = new Array(); + this.cameraX = 0; + this.cameraY = 0; + } + Diagrams.prototype.onmousemove = function (ev) { + if (this.panning) { + this.cameraX += ev.movementX; + this.cameraY += ev.movementY; + } + if (this.nodeDrag) { + if (this.nodeDragged === null) { + console.error("nodeDrag==true but nodeDragged==null"); + return; + } + this.nodeDragged.x += ev.movementX; + this.nodeDragged.y += ev.movementY; + } + this.draw(); + }; + Diagrams.prototype.onmousedown = function (ev) { + if (ev.button != 0) { + return; + } + var canvasRect = this.canvas.getBoundingClientRect(); + var mouseX = ev.x - canvasRect.left; + var mouseY = ev.y - canvasRect.top; + for (var _i = 0, _a = this.nodes; _i < _a.length; _i++) { + var node = _a[_i]; + if (node.pointInDiagram(mouseX, mouseY)) { + this.nodeDrag = true; + this.nodeDragged = node; + return; + } + } + this.panning = true; + }; + Diagrams.prototype.onmouseup = function (ev) { + this.panning = false; + this.nodeDrag = false; + this.nodeDragged = null; + }; + Diagrams.prototype.drawBackground = function () { + this.ctx.fillStyle = "#D8D8D8"; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.ctx.strokeStyle = "#888"; + this.ctx.lineWidth = 5; + this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height); + }; + Diagrams.prototype.draw = function () { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.drawBackground(); + for (var _i = 0, _a = this.nodes; _i < _a.length; _i++) { + var node = _a[_i]; + this.ctx.fillStyle = "gray"; + this.ctx.fillRect(node.x + this.cameraX, node.y + this.cameraY, node.width, node.height); + this.ctx.fillStyle = "black"; + this.ctx.font = "30px Arial"; + this.ctx.fillText(node.label, node.x + this.cameraX + node.height / 2, node.y + this.cameraY + node.height / 1.5); + } + }; + Diagrams.prototype.addNode = function (x, y, label) { + var textSize = this.ctx.measureText(label); + var textHeight = 2 * (textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent); + this.nodes.push(new DiagramNode(x, y, textSize.width + textHeight, textHeight, label)); + }; + Diagrams.prototype.addConnection = function (A, B) { + this.connections.push([A, B]); + }; + Diagrams.prototype.fillParent = function () { + this.canvas.width = this.canvas.clientWidth; + this.canvas.height = this.canvas.clientHeight; + this.draw(); + }; + return Diagrams; +}()); diff --git a/static/diagram.ts b/static/diagram.ts new file mode 100644 index 0000000..235f685 --- /dev/null +++ b/static/diagram.ts @@ -0,0 +1,175 @@ +class DiagramNode { + x: number; + y: number; + label: string; + width: number; + height: number; + + parents: Array; + children: Array; + + constructor( + x: number, + y: number, + width: number, + height: number, + label: string, + ){ + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.label = label; + } + + pointInDiagram(x: number, y: number){ + if (x < this.x){ + return false; + } + if (y < this.y){ + return false; + } + if (x > this.x + this.width) { + return false; + } + if (y > this.y + this.height) { + return false + } + return true; + } +} + +let _diagram: Diagrams; +function diargramOnResize(){ + _diagram.fillParent(); +} +function diagramOnMouseDown(ev: MouseEvent){ + _diagram.onmousedown(ev); +} +function diagramOnMouseUp(ev: MouseEvent){ + _diagram.onmouseup(ev); +} +function diagramOnMouseMove(ev: MouseEvent){ + _diagram.onmousemove(ev); +} + +class Diagrams { + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + + nodes: Array; + + connections: Array<[DiagramNode, DiagramNode]>; + + cameraX: number; + cameraY: number; + + panning: boolean; + + nodeDrag: boolean; + nodeDragged: DiagramNode | null; + + constructor(canvasId: string){ + this.canvas = document.getElementById(canvasId) as HTMLCanvasElement; + if (this.canvas === null){ + throw `Could not getElementById ${canvasId}`; + } + let ctx = this.canvas.getContext("2d"); + if (ctx === null){ + throw `Could not get 2d rendering context` + } + _diagram = this; + this.ctx = ctx; + this.ctx.font = "30px Arial"; + this.canvas.onmousemove = diagramOnMouseMove; + this.canvas.onmousedown = diagramOnMouseDown; + this.canvas.onmouseup = diagramOnMouseUp; + window.onresize = diargramOnResize; + + this.nodes = new Array(); + this.connections = new Array(); + + this.cameraX = 0; + this.cameraY = 0; + } + + onmousemove(ev: MouseEvent){ + if (this.panning){ + this.cameraX += ev.movementX; + this.cameraY += ev.movementY; + } + if (this.nodeDrag){ + if (this.nodeDragged === null){ + console.error("nodeDrag==true but nodeDragged==null"); + return + } + this.nodeDragged.x += ev.movementX; + this.nodeDragged.y += ev.movementY; + } + this.draw(); + } + + onmousedown(ev: MouseEvent){ + if (ev.button != 0){ + return; + } + let canvasRect = this.canvas.getBoundingClientRect(); + let mouseX = ev.x - canvasRect.left; + let mouseY = ev.y - canvasRect.top; + for (let node of this.nodes){ + if (node.pointInDiagram(mouseX, mouseY)) { + this.nodeDrag = true; + this.nodeDragged = node; + return; + } + } + + this.panning = true; + } + + onmouseup(ev: MouseEvent){ + this.panning = false; + this.nodeDrag = false; + this.nodeDragged = null; + } + + drawBackground(){ + this.ctx.fillStyle = "#D8D8D8"; + this.ctx.fillRect(0,0,this.canvas.width, this.canvas.height); + this.ctx.strokeStyle = "#888"; + this.ctx.lineWidth = 5; + this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height); + } + + draw(){ + this.ctx.clearRect(0,0, this.canvas.width, this.canvas.height); + this.drawBackground(); + for (let node of this.nodes){ + this.ctx.fillStyle = "gray"; + this.ctx.fillRect(node.x + this.cameraX, node.y + this.cameraY, node.width, node.height); + this.ctx.fillStyle = "black"; + this.ctx.font = "30px Arial"; + this.ctx.fillText( + node.label, + node.x + this.cameraX + node.height / 2, + node.y + this.cameraY + node.height / 1.5 + ); + } + } + + addNode(x: number, y: number, label: string){ + let textSize = this.ctx.measureText(label); + let textHeight = 2 * (textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent); + this.nodes.push(new DiagramNode(x, y, textSize.width + textHeight, textHeight, label)); + } + + addConnection(A: DiagramNode, B: DiagramNode){ + this.connections.push([A, B]); + } + + fillParent(){ + this.canvas.width = this.canvas.clientWidth; + this.canvas.height = this.canvas.clientHeight; + this.draw(); + } +} \ No newline at end of file diff --git a/static/style.css b/static/style.css index 7d99361..29f23dd 100644 --- a/static/style.css +++ b/static/style.css @@ -19,4 +19,14 @@ .pointer { cursor: pointer; -} \ No newline at end of file +} + +.canvas_parent { + width: 100%; + height: 95vh; + position: relative; +} +#canvas { + width: 100%; + height: 100%; +} diff --git a/templates/diagrams.html b/templates/diagrams.html new file mode 100644 index 0000000..d6f1bf5 --- /dev/null +++ b/templates/diagrams.html @@ -0,0 +1,25 @@ +{{define "head"}} + +{{ end }} +{{define "content"}} +
+ + + +
+{{ end }} + +{{define "scripts"}} + +{{ end }} \ No newline at end of file