diff --git a/main.go b/main.go index ed101bc..2747f5a 100644 --- a/main.go +++ b/main.go @@ -63,20 +63,26 @@ func (web Web) deleteWatch(c *gin.Context) { c.Redirect(http.StatusSeeOther, "/") } -type FilterDepth struct { - Filter *Filter - Depth []struct{} - RevDepth []struct{} -} - -func FilterPrint(filter *Filter, depth int) { - for _, f := range filter.Filters { - log.Println("----") - log.Println(depth, f) - FilterPrint(&f, depth+1) - } +func (web Web) watchView(c *gin.Context) { + id := c.Param("id") + + var watch Watch + web.db.Model(&Watch{}).First(&watch, id) + + var filters []Filter + web.db.Model(&Filter{}).Where("watch_id = ?", watch.ID).Find(&filters) + + var connections []FilterConnection + web.db.Model(&FilterConnection{}).Where("watch_id = ?", watch.ID).Find(&connections) + + c.HTML(http.StatusOK, "watch", gin.H{ + "Watch": watch, + "Filters": filters, + "Connections": connections, + }) } +/* func (web Web) viewWatch(c *gin.Context) { id := c.Param("id") @@ -135,6 +141,7 @@ func (web Web) viewWatch(c *gin.Context) { "ColumnWidth": 100 / numberOfColumns, }) } +*/ func (web Web) createFilter(c *gin.Context) { var filter Filter @@ -161,7 +168,7 @@ func (web Web) updateFilter(c *gin.Context) { filter.Name = filterUpdate.Name filter.Type = filterUpdate.Type filter.Var1 = filterUpdate.From - filter.Var2 = &filterUpdate.To + //filter.Var2 = &filterUpdate.To web.db.Save(&filter) c.Redirect(http.StatusSeeOther, "/group/edit/") } @@ -221,37 +228,40 @@ func main() { } db, _ := gorm.Open(sqlite.Open(viper.GetString("database.dsn"))) - db.AutoMigrate(&Watch{}, &Filter{}) + db.AutoMigrate(&Watch{}, &Filter{}, &FilterConnection{}) - /* - filters := []Filter{} - watch := Watch{ - Name: "LG C2 42", - Interval: 60, - Filters: filters, - } - db.Create(&watch) + watch := Watch{ + Name: "LG C2 42", + Interval: 60, + } + 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) + urlFilter := Filter{ + WatchID: watch.ID, + Name: "PriceWatch Fetch", + X: 100, + Y: 100, + 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) - */ + xpathFilter := Filter{ + WatchID: watch.ID, + Name: "price select", + X: 300, + Y: 300, + Type: "xpath", + Var1: "//td[@class='shop-price']", + } + db.Create(&xpathFilter) + + connection := FilterConnection{ + WatchID: watch.ID, + OutputID: urlFilter.ID, + InputID: xpathFilter.ID, + } + db.Create(&connection) //bot, _ := tgbotapi.NewBotAPI(viper.GetString("telegram.token")) //bot.Debug = true @@ -274,7 +284,7 @@ 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("watch", "templates/base.html", "templates/diagrams.html") templates.AddFromFiles("500", "templates/base.html", "templates/500.html") router.HTMLRender = templates @@ -283,12 +293,12 @@ func main() { router.GET("/watch/new", web.newWatch) router.POST("/watch/create", web.createWatch) router.POST("/watch/delete", web.deleteWatch) - router.GET("/watch/view/:id/", web.viewWatch) + //router.GET("/watch/view/:id/", web.viewWatch) router.POST("/filter/create/", web.createFilter) router.POST("/filter/update/", web.updateFilter) router.POST("/filter/delete/", web.deleteFilter) - router.GET("/canvas/", web.canvas) + router.GET("/watch/:id", web.watchView) router.Run("0.0.0.0:8080") } diff --git a/models.go b/models.go index 9d38b74..d0d175f 100644 --- a/models.go +++ b/models.go @@ -8,20 +8,24 @@ type Watch struct { gorm.Model Name string `form:"watch_name" yaml:"watch_name" binding:"required" validate:"min=1"` Interval int `form:"interval" yaml:"interval" binding:"required"` - Filters []Filter } type Filter struct { gorm.Model - WatchID uint `form:"filter_watch_id" yaml:"filter_watch_id" binding:"required"` - Watch Watch - ParentID *uint `form:"parent_id" yaml:"parent_id"` - Parent *Filter `form:"parent_id" yaml:"parent_id"` - Name string `form:"filter_name" yaml:"filter_name" binding:"required" validate:"min=1"` - Type string `form:"filter_type" yaml:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring"` - Var1 string `form:"var1" yaml:"var1" binding:"required"` - Var2 *string `form:"var2" yaml:"var2"` - Var3 *string `form:"var3" yaml:"var3"` - Filters []Filter `gorm:"-:all"` - Results []string `gorm:"-:all"` + WatchID uint `form:"filter_watch_id" yaml:"filter_watch_id" binding:"required"` + Name string `form:"filter_name" yaml:"filter_name" binding:"required" validate:"min=1"` + X int `form:"x" yaml:"x" validate:"default=0"` + Y int `form:"y" yaml:"y" validate:"default=0"` + Type string `form:"filter_type" yaml:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring"` + Var1 string `form:"var1" yaml:"var1" binding:"required"` + Var2 string `form:"var2" yaml:"var2"` + Var3 string `form:"var3" yaml:"var3"` + Results []string `gorm:"-:all"` +} + +type FilterConnection struct { + gorm.Model + WatchID uint `form:"connection_watch_id" yaml:"connection_watch_id" binding:"required"` + OutputID uint `form:"filter_output_id" yaml:"filter_output_id" binding:"required"` + InputID uint `form:"filter_output_id" yaml:"filter_output_id" binding:"required"` } diff --git a/scraping.go b/scraping.go index 0401a2d..0193295 100644 --- a/scraping.go +++ b/scraping.go @@ -1,18 +1,6 @@ package main -import ( - "bytes" - "log" - "regexp" - "strconv" - "strings" - - "github.com/andybalholm/cascadia" - "github.com/antchfx/htmlquery" - "github.com/tidwall/gjson" - "golang.org/x/net/html" -) - +/* func getFilterResults(filter *Filter) { getFilterResult(filter) for _, filter := range filter.Filters { @@ -208,3 +196,4 @@ func getFilterResultSubstring(filter *Filter) { filter.Results = append(filter.Results, sb.String()) } } +*/ diff --git a/static/diagram.js b/static/diagram.js index 0c8bf3f..01da298 100644 --- a/static/diagram.js +++ b/static/diagram.js @@ -1,3 +1,30 @@ +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __values = (this && this.__values) || function(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +}; var DiagramNode = /** @class */ (function () { function DiagramNode(id, x, y, label, meta) { if (meta === void 0) { meta = {}; } @@ -56,12 +83,12 @@ var DiagramNode = /** @class */ (function () { return [this.x + this.width, this.y + this.height / 2]; }; DiagramNode.prototype.pointInInputCircle = function (x, y) { - var _a = this.getInputCircleXY(), circleX = _a[0], circleY = _a[1]; + var _a = __read(this.getInputCircleXY(), 2), circleX = _a[0], circleY = _a[1]; var radiusSqrd = Math.pow(this.height / 3, 2); return Math.pow(x - circleX, 2) + Math.pow(y - circleY, 2) <= radiusSqrd; }; DiagramNode.prototype.pointInOutputCircle = function (x, y) { - var _a = this.getOutputCircleXY(), circleX = _a[0], circleY = _a[1]; + var _a = __read(this.getOutputCircleXY(), 2), circleX = _a[0], circleY = _a[1]; var radiusSqrd = Math.pow(this.height / 3, 2); return Math.pow(x - circleX, 2) + Math.pow(y - circleY, 2) <= radiusSqrd; }; @@ -99,17 +126,28 @@ var ContextMenu = /** @class */ (function () { this.textMargin = this.textWidth / 8; } ContextMenu.prototype.fitContextMenu = function () { + var e_1, _a; this.width = this.textWidth + this.textMargin * 2; this.height = this.textHeight + this.textMargin * (this.items.length + 2); var index = 0; - for (var _i = 0, _a = this.items; _i < _a.length; _i++) { - var item = _a[_i]; - item.x = this.textMargin; - item.y = this.textHeight * index + this.textMargin * (index + 2); - index++; + try { + for (var _b = __values(this.items), _c = _b.next(); !_c.done; _c = _b.next()) { + var item = _c.value; + item.x = this.textMargin; + item.y = this.textHeight * index + this.textMargin * (index + 2); + index++; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); + } + finally { if (e_1) throw e_1.error; } } }; ContextMenu.prototype.pointIn = function (x, y) { + var e_2, _a; if (x < this.x) { this.mouseOver = false; return false; @@ -126,39 +164,68 @@ var ContextMenu = /** @class */ (function () { this.mouseOver = false; return false; } - for (var _i = 0, _a = this.items; _i < _a.length; _i++) { - var item = _a[_i]; - if (y >= this.y + item.y - this.textHeight && y <= this.y + item.y + this.textHeight) { - item.hover = true; + try { + for (var _b = __values(this.items), _c = _b.next(); !_c.done; _c = _b.next()) { + var item = _c.value; + if (y >= this.y + item.y - this.textHeight && y <= this.y + item.y + this.textHeight) { + item.hover = true; + } + else { + item.hover = false; + } } - else { - item.hover = false; + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); } + finally { if (e_2) throw e_2.error; } } this.mouseOver = true; return true; }; ContextMenu.prototype.clickOn = function () { + var e_3, _a; if (this.contextNode == null) { console.warn("No contextNode"); return; } - for (var _i = 0, _a = this.items; _i < _a.length; _i++) { - var item = _a[_i]; - if (item.hover) { - item.callback(this.contextNode); + try { + for (var _b = __values(this.items), _c = _b.next(); !_c.done; _c = _b.next()) { + var item = _c.value; + if (item.hover) { + item.callback(this.contextNode); + } } } + catch (e_3_1) { e_3 = { error: e_3_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); + } + finally { if (e_3) throw e_3.error; } + } }; ContextMenu.prototype.draw = function () { + var e_4, _a; var cameraX = _diagram.cameraX; var cameraY = _diagram.cameraY; this.ctx.fillStyle = "lightblue"; this.ctx.fillRect(this.x + cameraX, this.y + cameraY, this.width, this.height); - for (var _i = 0, _a = this.items; _i < _a.length; _i++) { - var item = _a[_i]; - this.ctx.fillStyle = this.mouseOver && item.hover ? "red" : "black"; - this.ctx.fillText(item.label, this.x + item.x + cameraX, this.y + item.y + cameraY); + try { + for (var _b = __values(this.items), _c = _b.next(); !_c.done; _c = _b.next()) { + var item = _c.value; + this.ctx.fillStyle = this.mouseOver && item.hover ? "red" : "black"; + this.ctx.fillText(item.label, this.x + item.x + cameraX, this.y + item.y + cameraY); + } + } + catch (e_4_1) { e_4 = { error: e_4_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); + } + finally { if (e_4) throw e_4.error; } } }; return ContextMenu; @@ -186,7 +253,7 @@ var Diagrams = /** @class */ (function () { function Diagrams(canvasId, editNodeCallback, deleteNodeCallback) { if (editNodeCallback === void 0) { editNodeCallback = function () { }; } if (deleteNodeCallback === void 0) { deleteNodeCallback = function () { }; } - this.nodes = new Array(); + this.nodes = new Map(); this.connections = new Array(); this.cameraX = 0; // camera position this.cameraY = 0; @@ -226,6 +293,7 @@ var Diagrams = /** @class */ (function () { this.deleteNodeCallback = deleteNodeCallback; } Diagrams.prototype.onmousemove = function (ev) { + var e_5, _a; var canvasRect = this.canvas.getBoundingClientRect(); this.mouseX = ev.x - canvasRect.left; this.mouseY = ev.y - canvasRect.top; @@ -251,30 +319,40 @@ var Diagrams = /** @class */ (function () { this.nodeDragging.y += ev.movementY; } else { - for (var _i = 0, _a = this.nodes; _i < _a.length; _i++) { - var node = _a[_i]; - if (node.pointNearNode(this.worldX, this.worldY)) { - if (node.pointInInputCircle(this.worldX, this.worldY)) { - node.inputHover = true; - this.nodeHover = node; - break; - } - else if (this.makingConnectionNode == null && node.pointInOutputCircle(this.worldX, this.worldY)) { - node.outputHover = true; - this.nodeHover = node; - break; - } - else if (node.pointInNode(this.worldX, this.worldY)) { - node.hover = true; - this.nodeHover = node; - break; + try { + for (var _b = __values(this.nodes), _c = _b.next(); !_c.done; _c = _b.next()) { + var _d = __read(_c.value, 2), _ = _d[0], node = _d[1]; + if (node.pointNearNode(this.worldX, this.worldY)) { + if (node.pointInInputCircle(this.worldX, this.worldY)) { + node.inputHover = true; + this.nodeHover = node; + break; + } + else if (this.makingConnectionNode == null && node.pointInOutputCircle(this.worldX, this.worldY)) { + node.outputHover = true; + this.nodeHover = node; + break; + } + else if (node.pointInNode(this.worldX, this.worldY)) { + node.hover = true; + this.nodeHover = node; + break; + } } } } + catch (e_5_1) { e_5 = { error: e_5_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); + } + finally { if (e_5) throw e_5.error; } + } } this.draw(); }; Diagrams.prototype.onmousedown = function (ev) { + var e_6, _a; if (ev.button != 0) { return; } @@ -284,36 +362,55 @@ var Diagrams = /** @class */ (function () { this.mouseY = ev.y - canvasRect.top; this.worldX = this.mouseX - this.cameraX; this.worldY = this.mouseY - this.cameraY; - for (var _i = 0, _a = this.nodes; _i < _a.length; _i++) { - var node = _a[_i]; - if (node.pointNearNode(this.worldX, this.worldY)) { - if (node.pointInInputCircle(this.worldX, this.worldY)) { - // no dragging from inputs ? + try { + for (var _b = __values(this.nodes), _c = _b.next(); !_c.done; _c = _b.next()) { + var _d = __read(_c.value, 2), _ = _d[0], node = _d[1]; + if (node.pointNearNode(this.worldX, this.worldY)) { + if (node.pointInInputCircle(this.worldX, this.worldY)) { + // no dragging from inputs ? + } + else if (node.pointInOutputCircle(this.worldX, this.worldY)) { + this.makingConnectionNode = node; + return; + } } - else if (node.pointInOutputCircle(this.worldX, this.worldY)) { - this.makingConnectionNode = node; + if (node.pointInNode(this.worldX, this.worldY)) { + this.nodeDragging = node; return; } } - if (node.pointInNode(this.worldX, this.worldY)) { - this.nodeDragging = node; - return; + } + catch (e_6_1) { e_6 = { error: e_6_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); } + finally { if (e_6) throw e_6.error; } } this.panning = true; }; Diagrams.prototype.onmouseup = function (ev) { + var e_7, _a, e_8, _b, e_9, _c, e_10, _d; if (ev.button == 2) { - for (var _i = 0, _a = this.nodes; _i < _a.length; _i++) { - var node = _a[_i]; - if (node.pointInNode(this.worldX, this.worldY)) { - this.contextMenu.x = this.worldX; - this.contextMenu.y = this.worldY; - this.contextMenu.active = true; - this.contextMenu.contextNode = node; - this.draw(); + try { + for (var _e = __values(this.nodes), _f = _e.next(); !_f.done; _f = _e.next()) { + var _g = __read(_f.value, 2), _ = _g[0], node = _g[1]; + if (node.pointInNode(this.worldX, this.worldY)) { + this.contextMenu.x = this.worldX; + this.contextMenu.y = this.worldY; + this.contextMenu.active = true; + this.contextMenu.contextNode = node; + this.draw(); + } } } + catch (e_7_1) { e_7 = { error: e_7_1 }; } + finally { + try { + if (_f && !_f.done && (_a = _e["return"])) _a.call(_e); + } + finally { if (e_7) throw e_7.error; } + } } if (ev.button != 0) { return; @@ -321,24 +418,42 @@ var Diagrams = /** @class */ (function () { this.panning = false; this.nodeDragging = null; if (this.makingConnectionNode !== null) { - for (var _b = 0, _c = this.nodes; _b < _c.length; _b++) { - var node = _c[_b]; - if (node == this.makingConnectionNode) { - continue; - } - if (node.pointInInputCircle(this.worldX, this.worldY)) { - var connectionExists = false; - for (var _d = 0, _e = this.connections; _d < _e.length; _d++) { - var _f = _e[_d], output = _f[0], input = _f[1]; - if (this.makingConnectionNode.id == output.id && node.id == input.id) { - connectionExists = true; + try { + for (var _h = __values(this.nodes), _j = _h.next(); !_j.done; _j = _h.next()) { + var _k = __read(_j.value, 2), _ = _k[0], node = _k[1]; + if (node == this.makingConnectionNode) { + continue; + } + if (node.pointInInputCircle(this.worldX, this.worldY)) { + var connectionExists = false; + try { + for (var _l = (e_9 = void 0, __values(this.connections)), _m = _l.next(); !_m.done; _m = _l.next()) { + var _o = __read(_m.value, 2), output = _o[0], input = _o[1]; + if (this.makingConnectionNode.id == output.id && node.id == input.id) { + connectionExists = true; + } + } + } + catch (e_9_1) { e_9 = { error: e_9_1 }; } + finally { + try { + if (_m && !_m.done && (_c = _l["return"])) _c.call(_l); + } + finally { if (e_9) throw e_9.error; } + } + if (!connectionExists) { + this.addConnection(this.makingConnectionNode, node); } } - if (!connectionExists) { - this.addConnection(this.makingConnectionNode, node); - } } } + catch (e_8_1) { e_8 = { error: e_8_1 }; } + finally { + try { + if (_j && !_j.done && (_b = _h["return"])) _b.call(_h); + } + finally { if (e_8) throw e_8.error; } + } this.makingConnectionNode = null; } if (this.contextMenu.active) { @@ -348,32 +463,41 @@ var Diagrams = /** @class */ (function () { } this.contextMenu.active = false; } - for (var _g = 0, _h = this.connections; _g < _h.length; _g++) { - var _j = _h[_g], output = _j[0], input = _j[1]; - var _k = output.getOutputCircleXY(), outputX = _k[0], outputY = _k[1]; - outputX += this.cameraX; - outputY += this.cameraY; - var _l = input.getInputCircleXY(), inputX = _l[0], inputY = _l[1]; - inputX += this.cameraX; - inputY += this.cameraY; - var dX = Math.abs(outputX - inputX); - this.ctx.beginPath(); - this.ctx.moveTo(outputX, outputY); - this.ctx.strokeStyle = "black"; - var cp1x = (outputX + dX / 2); - var cp1y = outputY; - var cp2x = (inputX - dX / 2); - var cp2y = inputY; - this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, inputX, inputY); - this.ctx.stroke(); - this.ctx.closePath(); - var halfway = getBezierXY(0.5, outputX, outputY, cp1x, cp1y, cp2x, cp2y, inputX, inputY); - var mouseOnHalfway = Math.pow(this.mouseX - halfway.x, 2) + Math.pow(this.mouseY - halfway.y, 2) <= 10 * 10; - if (mouseOnHalfway) { - this.removeConnection(output, input); - break; + try { + for (var _p = __values(this.connections), _q = _p.next(); !_q.done; _q = _p.next()) { + var _r = __read(_q.value, 2), output = _r[0], input = _r[1]; + var _s = __read(output.getOutputCircleXY(), 2), outputX = _s[0], outputY = _s[1]; + outputX += this.cameraX; + outputY += this.cameraY; + var _t = __read(input.getInputCircleXY(), 2), inputX = _t[0], inputY = _t[1]; + inputX += this.cameraX; + inputY += this.cameraY; + var dX = Math.abs(outputX - inputX); + this.ctx.beginPath(); + this.ctx.moveTo(outputX, outputY); + this.ctx.strokeStyle = "black"; + var cp1x = (outputX + dX / 2); + var cp1y = outputY; + var cp2x = (inputX - dX / 2); + var cp2y = inputY; + this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, inputX, inputY); + this.ctx.stroke(); + this.ctx.closePath(); + var halfway = getBezierXY(0.5, outputX, outputY, cp1x, cp1y, cp2x, cp2y, inputX, inputY); + var mouseOnHalfway = Math.pow(this.mouseX - halfway.x, 2) + Math.pow(this.mouseY - halfway.y, 2) <= 10 * 10; + if (mouseOnHalfway) { + this.removeConnection(output, input); + break; + } } } + catch (e_10_1) { e_10 = { error: e_10_1 }; } + finally { + try { + if (_q && !_q.done && (_d = _p["return"])) _d.call(_p); + } + finally { if (e_10) throw e_10.error; } + } this.draw(); }; Diagrams.prototype.onwheel = function (ev) { @@ -391,12 +515,13 @@ var Diagrams = /** @class */ (function () { this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height); }; Diagrams.prototype.draw = function () { + var e_11, _a, e_12, _b; var scale = 1 / this.scale; this.ctx.clearRect(0, 0, this.canvas.width * scale, this.canvas.height * scale); this.drawBackground(); var fullCircleRadians = Math.PI + (Math.PI * 3); if (this.makingConnectionNode != null) { - var _a = this.makingConnectionNode.getOutputCircleXY(), circleX = _a[0], circleY = _a[1]; + var _c = __read(this.makingConnectionNode.getOutputCircleXY(), 2), circleX = _c[0], circleY = _c[1]; var dX = Math.abs((circleX + this.cameraX) - this.mouseX); this.ctx.beginPath(); this.ctx.moveTo(circleX + this.cameraX, circleY + this.cameraY); @@ -409,52 +534,70 @@ var Diagrams = /** @class */ (function () { this.ctx.stroke(); this.ctx.closePath(); } - for (var _i = 0, _b = this.connections; _i < _b.length; _i++) { - var _c = _b[_i], output = _c[0], input = _c[1]; - var _d = output.getOutputCircleXY(), outputX = _d[0], outputY = _d[1]; - outputX += this.cameraX; - outputY += this.cameraY; - var _e = input.getInputCircleXY(), inputX = _e[0], inputY = _e[1]; - inputX += this.cameraX; - inputY += this.cameraY; - var dX = Math.abs(outputX - inputX); - this.ctx.beginPath(); - this.ctx.moveTo(outputX, outputY); - this.ctx.strokeStyle = "black"; - var cp1x = (outputX + dX / 2); - var cp1y = outputY; - var cp2x = (inputX - dX / 2); - var cp2y = inputY; - this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, inputX, inputY); - this.ctx.stroke(); - this.ctx.closePath(); - var halfway = getBezierXY(0.5, outputX, outputY, cp1x, cp1y, cp2x, cp2y, inputX, inputY); - var mouseOnHalfway = Math.pow(this.mouseX - halfway.x, 2) + Math.pow(this.mouseY - halfway.y, 2) <= 10 * 10; - this.ctx.beginPath(); - this.ctx.strokeStyle = mouseOnHalfway ? "red" : "rgba(200, 200, 200, 0.8)"; - this.ctx.moveTo(halfway.x - 10, halfway.y - 10); - this.ctx.lineTo(halfway.x + 10, halfway.y + 10); - this.ctx.moveTo(halfway.x + 10, halfway.y - 10); - this.ctx.lineTo(halfway.x - 10, halfway.y + 10); - this.ctx.stroke(); - this.ctx.closePath(); + try { + for (var _d = __values(this.connections), _e = _d.next(); !_e.done; _e = _d.next()) { + var _f = __read(_e.value, 2), output = _f[0], input = _f[1]; + var _g = __read(output.getOutputCircleXY(), 2), outputX = _g[0], outputY = _g[1]; + outputX += this.cameraX; + outputY += this.cameraY; + var _h = __read(input.getInputCircleXY(), 2), inputX = _h[0], inputY = _h[1]; + inputX += this.cameraX; + inputY += this.cameraY; + var dX = Math.abs(outputX - inputX); + this.ctx.beginPath(); + this.ctx.moveTo(outputX, outputY); + this.ctx.strokeStyle = "black"; + var cp1x = (outputX + dX / 2); + var cp1y = outputY; + var cp2x = (inputX - dX / 2); + var cp2y = inputY; + this.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, inputX, inputY); + this.ctx.stroke(); + this.ctx.closePath(); + var halfway = getBezierXY(0.5, outputX, outputY, cp1x, cp1y, cp2x, cp2y, inputX, inputY); + var mouseOnHalfway = Math.pow(this.mouseX - halfway.x, 2) + Math.pow(this.mouseY - halfway.y, 2) <= 10 * 10; + this.ctx.beginPath(); + this.ctx.strokeStyle = mouseOnHalfway ? "red" : "rgba(200, 200, 200, 0.8)"; + this.ctx.moveTo(halfway.x - 10, halfway.y - 10); + this.ctx.lineTo(halfway.x + 10, halfway.y + 10); + this.ctx.moveTo(halfway.x + 10, halfway.y - 10); + this.ctx.lineTo(halfway.x - 10, halfway.y + 10); + this.ctx.stroke(); + this.ctx.closePath(); + } } - for (var _f = 0, _g = this.nodes; _f < _g.length; _f++) { - var node = _g[_f]; - this.ctx.fillStyle = node.hover ? "#303030" : "#161616"; - this.ctx.fillRect(node.x + this.cameraX, node.y + this.cameraY, node.width, node.height); - this.ctx.fillStyle = "#D3D3D3"; - this.ctx.font = "20px Helvetica"; - this.ctx.fillText(node.label, node.x + this.cameraX + node.height / 2, node.y + this.cameraY + node.height / 1.5); - this.ctx.fillStyle = node.inputHover ? "red" : "green"; - this.ctx.beginPath(); - this.ctx.arc(node.x + this.cameraX, node.y + node.height / 2 + this.cameraY, node.height / 3, 0, fullCircleRadians); - this.ctx.fill(); - this.ctx.beginPath(); - this.ctx.fillStyle = node.outputHover ? "red" : "green"; - this.ctx.moveTo(node.x + node.width + this.cameraX, node.y + node.height / 2 + this.cameraY); - this.ctx.arc(node.x + node.width + this.cameraX, node.y + node.height / 2 + this.cameraY, node.height / 3, 0, fullCircleRadians); - this.ctx.fill(); + catch (e_11_1) { e_11 = { error: e_11_1 }; } + finally { + try { + if (_e && !_e.done && (_a = _d["return"])) _a.call(_d); + } + finally { if (e_11) throw e_11.error; } + } + try { + for (var _j = __values(this.nodes), _k = _j.next(); !_k.done; _k = _j.next()) { + var _l = __read(_k.value, 2), _ = _l[0], node = _l[1]; + this.ctx.fillStyle = node.hover ? "#303030" : "#161616"; + this.ctx.fillRect(node.x + this.cameraX, node.y + this.cameraY, node.width, node.height); + this.ctx.fillStyle = "#D3D3D3"; + this.ctx.font = "20px Helvetica"; + this.ctx.fillText(node.label, node.x + this.cameraX + node.height / 2, node.y + this.cameraY + node.height / 1.5); + this.ctx.fillStyle = node.inputHover ? "red" : "green"; + this.ctx.beginPath(); + this.ctx.arc(node.x + this.cameraX, node.y + node.height / 2 + this.cameraY, node.height / 3, 0, fullCircleRadians); + this.ctx.fill(); + this.ctx.beginPath(); + this.ctx.fillStyle = node.outputHover ? "red" : "green"; + this.ctx.moveTo(node.x + node.width + this.cameraX, node.y + node.height / 2 + this.cameraY); + this.ctx.arc(node.x + node.width + this.cameraX, node.y + node.height / 2 + this.cameraY, node.height / 3, 0, fullCircleRadians); + this.ctx.fill(); + } + } + catch (e_12_1) { e_12 = { error: e_12_1 }; } + finally { + try { + if (_k && !_k.done && (_b = _j["return"])) _b.call(_j); + } + finally { if (e_12) throw e_12.error; } } if (this.contextMenu.active) { this.contextMenu.draw(); @@ -462,19 +605,42 @@ var Diagrams = /** @class */ (function () { }; Diagrams.prototype.addNode = function (id, x, y, label, meta) { if (meta === void 0) { meta = {}; } - this.nodes.push(new DiagramNode(id, x, y, label, meta)); + this.nodes.set(id, new DiagramNode(id, x, y, label, meta)); }; Diagrams.prototype.addConnection = function (A, B) { this.connections.push([A, B]); }; + Diagrams.prototype.addConnectionById = function (a, b) { + var A = this.nodes.get(a); + if (A === undefined) { + console.error("No node with ID: " + a); + return; + } + var B = this.nodes.get(b); + if (B === undefined) { + console.error("No node with ID: " + b); + return; + } + this.connections.push([A, B]); + }; Diagrams.prototype.removeConnection = function (A, B) { + var e_13, _a; var index = 0; - for (var _i = 0, _a = this.connections; _i < _a.length; _i++) { - var _b = _a[_i], output = _b[0], input = _b[1]; - if (output.id == A.id && input.id == B.id) { - this.connections.splice(index, 1); + try { + for (var _b = __values(this.connections), _c = _b.next(); !_c.done; _c = _b.next()) { + var _d = __read(_c.value, 2), output = _d[0], input = _d[1]; + if (output.id == A.id && input.id == B.id) { + this.connections.splice(index, 1); + } + index++; } - index++; + } + catch (e_13_1) { e_13 = { error: e_13_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); + } + finally { if (e_13) throw e_13.error; } } }; Diagrams.prototype.onresize = function () { diff --git a/static/diagram.ts b/static/diagram.ts index 496560a..568888c 100644 --- a/static/diagram.ts +++ b/static/diagram.ts @@ -214,7 +214,7 @@ class Diagrams { canvas: HTMLCanvasElement; ctx: CanvasRenderingContext2D; - nodes: Array = new Array(); + nodes: Map = new Map(); connections: Array<[DiagramNode, DiagramNode]> = new Array(); @@ -295,7 +295,7 @@ class Diagrams { this.nodeDragging.x += ev.movementX; this.nodeDragging.y += ev.movementY; } else { - for (let node of this.nodes){ + for (let [_, node] of this.nodes){ if (node.pointNearNode(this.worldX, this.worldY)){ if (node.pointInInputCircle(this.worldX, this.worldY)) { node.inputHover = true; @@ -328,7 +328,7 @@ class Diagrams { this.mouseY = ev.y - canvasRect.top; this.worldX = this.mouseX - this.cameraX; this.worldY = this.mouseY - this.cameraY; - for (let node of this.nodes){ + for (let [_, node] of this.nodes){ if (node.pointNearNode(this.worldX, this.worldY)){ if (node.pointInInputCircle(this.worldX, this.worldY)) { // no dragging from inputs ? @@ -348,7 +348,7 @@ class Diagrams { onmouseup(ev: MouseEvent){ if (ev.button == 2) { - for (let node of this.nodes){ + for (let [_, node] of this.nodes){ if (node.pointInNode(this.worldX, this.worldY)){ this.contextMenu.x = this.worldX; this.contextMenu.y = this.worldY; @@ -365,7 +365,7 @@ class Diagrams { this.panning = false; this.nodeDragging = null; if (this.makingConnectionNode !== null){ - for (let node of this.nodes){ + for (let [_, node] of this.nodes){ if (node == this.makingConnectionNode){ continue; } @@ -505,7 +505,7 @@ class Diagrams { this.ctx.stroke(); this.ctx.closePath(); } - for (let node of this.nodes){ + for (let [_, node] of this.nodes){ this.ctx.fillStyle = node.hover ? "#303030" : "#161616"; this.ctx.fillRect(node.x + this.cameraX, node.y + this.cameraY, node.width, node.height); this.ctx.fillStyle = "#D3D3D3"; @@ -531,12 +531,25 @@ class Diagrams { } addNode(id: number, x: number, y: number, label: string, meta: Object = {}){ - this.nodes.push(new DiagramNode(id, x, y, label, meta)); + this.nodes.set(id, new DiagramNode(id, x, y, label, meta)); } addConnection(A: DiagramNode, B: DiagramNode){ this.connections.push([A, B]); } + addConnectionById(a: number, b: number){ + let A = this.nodes.get(a); + if (A === undefined){ + console.error(`No node with ID: ${a}`); + return; + } + let B = this.nodes.get(b); + if (B === undefined){ + console.error(`No node with ID: ${b}`); + return; + } + this.connections.push([A, B]) + } removeConnection(A: DiagramNode, B: DiagramNode){ let index = 0; for (let [output, input] of this.connections){ diff --git a/static/edit.js b/static/edit.js index 817a6ec..9cae844 100644 --- a/static/edit.js +++ b/static/edit.js @@ -1,3 +1,23 @@ +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spread = (this && this.__spread) || function () { + for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); + return ar; +}; function onTypeChange() { var select = document.getElementById("typeInput"); var type = select.value; @@ -74,7 +94,7 @@ function onSubmitNewFilter() { var var1Input = document.getElementById("var1Input"); var var2Input = document.getElementById("var2Input"); var var3Input = document.getElementById("var3Input"); - _diagram.addNode(Math.max.apply(Math, _diagram.nodes.map(function (n) { return n.id; })) + 1, _diagram.canvas.width / 2 - _diagram.cameraX, _diagram.canvas.height / 2 - _diagram.cameraY, name, { + _diagram.addNode(Math.max.apply(Math, __spread(Array.from(_diagram.nodes.values()).map(function (n) { return n.id; }))) + 1, _diagram.canvas.width / 2 - _diagram.cameraX, _diagram.canvas.height / 2 - _diagram.cameraY, name, { type: type, var1: var1Input.value, var2: var2Input.value, @@ -115,16 +135,9 @@ function editNode(node) { submitButton.onclick = function () { submitEditNode(node); }; } function deleteNode(node) { - var index = 0; - for (var _i = 0, _a = _diagram.nodes; _i < _a.length; _i++) { - var n = _a[_i]; - if (node.id == n.id) { - _diagram.nodes.splice(index, 1); - } - index++; - } + _diagram.nodes["delete"](node.id); for (var i = 0; i < _diagram.connections.length; i++) { - var _b = _diagram.connections[i], output = _b[0], input = _b[1]; + var _a = __read(_diagram.connections[i], 2), output = _a[0], input = _a[1]; if (node.id == output.id || node.id == input.id) { _diagram.connections.splice(i, 1); i--; diff --git a/static/edit.ts b/static/edit.ts index e525b44..1227947 100644 --- a/static/edit.ts +++ b/static/edit.ts @@ -84,7 +84,7 @@ function onSubmitNewFilter(){ let var3Input = document.getElementById("var3Input") as HTMLInputElement; _diagram.addNode( - Math.max(..._diagram.nodes.map(n => n.id)) + 1, + Math.max(...Array.from(_diagram.nodes.values()).map(n => n.id)) + 1, _diagram.canvas.width / 2 - _diagram.cameraX, _diagram.canvas.height / 2 - _diagram.cameraY, name, { @@ -137,13 +137,7 @@ function editNode(node: DiagramNode){ } function deleteNode(node: DiagramNode){ - let index = 0; - for (let n of _diagram.nodes){ - if (node.id == n.id){ - _diagram.nodes.splice(index, 1); - } - index++; - } + _diagram.nodes.delete(node.id) for (let i = 0; i < _diagram.connections.length; i++){ let [output, input] = _diagram.connections[i]; if (node.id == output.id || node.id == input.id){ diff --git a/templates/diagrams.html b/templates/diagrams.html index 1229adf..75544fd 100644 --- a/templates/diagrams.html +++ b/templates/diagrams.html @@ -8,6 +8,7 @@ + {{ end }} {{ define "left" }} @@ -64,6 +65,58 @@ + + +
+ +
+ + + + {{ end }} {{define "scripts"}} @@ -71,9 +124,23 @@ var diagrams; function canvasInit() { diagrams = new Diagrams("canvas", editNode, deleteNode); - diagrams.addNode(1, 100, 100, "Test", {type: "json"}); - diagrams.addNode(2, 300, 300, "Test2", {type: "css"}); - diagrams.addNode(3, 500, 500, "A much longer name", {type: "replace"}); + {{ range .Filters }} + diagrams.addNode( + {{ .ID }}, + {{ .X }}, + {{ .Y }}, + {{ .Name }}, + { + type: "{{ .Type }}", + var1: "{{ .Var1 }}", + var2: "{{ .Var2 }}", + var3: "{{ .Var3 }}", + } + ); + {{ end }} + {{ range .Connections }} + diagrams.addConnectionById({{ .OutputID }}, {{ .InputID }}); + {{ end }} diagrams.fillParent(); } document.addEventListener('DOMContentLoaded', canvasInit, false);