diff --git a/.gitignore b/.gitignore index fc2d791a..3cc3aae3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ storage.db *.sublime-workspace *.css !helpers/item-tooltip/styles.css +!helpers/passives/styles.css diff --git a/helpers/passives/generator.js b/helpers/passives/generator.js index 480157e6..fbe7a0f9 100644 --- a/helpers/passives/generator.js +++ b/helpers/passives/generator.js @@ -2,7 +2,7 @@ var generator = { nodes: [], init: function () { - this.addNode({ + this.actions.addNode.call(this, null, { x: 100, y: 100 }); @@ -10,21 +10,78 @@ var generator = { renderer.center(this.nodes[0]); }, - addNode: function (options) { - var nodes = this.nodes; - nodes.push(tplNode.build({ - id: nodes.length, - x: options.x, - y: options.y - })); + onClick: function (button, x, y) { + var node = this.findNode(x, y); + if (!node) + return; + + if (button == 0) + this.actions.addNode.call(this, node); + else if (button == 1) + this.actions.rotateNode.call(this, node); + else if (button == 2) + this.actions.extendNode.call(this, node); renderer.makeDirty(); + }, + + findNode: function (x, y, nodes) { + nodes = nodes || this.nodes; + + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + + if (!( + (n.pos.x > x) || + (n.pos.y > y) || + (n.pos.x + constants.blockSize <= x) | + (n.pos.y + constants.blockSize <= y) + )) + return n; + else { + var f = this.findNode(x, y, n.children); + if (f) + return f; + } + } + }, + + actions: { + addNode: function (parent, options = {}) { + var nodes = this.nodes; + + if (parent) + options.angle = constants.defaultAngle; + + var node = tplNode.build({ + id: nodes.length, + angle: options.angle, + x: options.x, + y: options.y, + parent: parent, + distance: constants.defaultDistance + }); + + if (parent) + parent.children.push(node); + else + nodes.push(node); + }, + + rotateNode: function (node) { + var newAngle = node.angle - constants.defaultAngleInc; + node.parent.children.forEach(n => (n.angle = newAngle)); + console.log(node.parent); + }, + + extendNode: function (node) { + node.distance += constants.defaultDistanceInc; + } } }; var tplNode = { id: 0, - parents: [], children: [], pos: { x: 0, @@ -32,12 +89,16 @@ var tplNode = { }, build: function (options) { - var res = $.extend(true, {}, this, { - id: options.id, + var res = $.extend(true, { + parent: options.parent + }, this, { + id: this.id++, pos: { x: options.x, y: options.y - } + }, + distance: options.distance, + angle: options.angle }); delete res.build; diff --git a/helpers/passives/renderer.js b/helpers/passives/renderer.js index c755b677..e1adb6cc 100644 --- a/helpers/passives/renderer.js +++ b/helpers/passives/renderer.js @@ -3,8 +3,8 @@ var renderer = { ctx: null, screen: { - width: 0, - height: 0 + w: 0, + h: 0 }, pos: { @@ -14,23 +14,24 @@ var renderer = { dirty: false, - constants: { - lineWidth: 5, - blockSize: 40 - }, - init: function () { this.canvas = $('canvas')[0]; - this.screen.width = this.canvas.width = $('body').width(); - this.screen.height = this.canvas.height = $('body').height(); + this.screen.w = this.canvas.width = $('body').width(); + this.screen.h = this.canvas.height = $('body').height(); this.ctx = this.canvas.getContext('2d'); + $(this.canvas) + .on('mousedown', this.events.onClick.bind(this)) + .on('contextmenu', function () { + return false; + }); + this.update(); }, center: function (node) { - this.pos.x = node.pos.x + (this.constants.blockSize / 2) - (this.screen.width / 2); - this.pos.y = node.pos.y + (this.constants.blockSize / 2) - (this.screen.height / 2); + this.pos.x = node.pos.x + (constants.blockSize / 2) - (this.screen.w / 2); + this.pos.y = node.pos.y + (constants.blockSize / 2) - (this.screen.h / 2); this.ctx.translate(-this.pos.x, -this.pos.y); this.makeDirty(); @@ -40,15 +41,40 @@ var renderer = { this.dirty = true; }, - render: function () { - var nodes = generator.nodes; + render: function (nodes) { + var nodes = nodes || generator.nodes; + + nodes.forEach(function (n) { + var x = n.pos.x; + var y = n.pos.y; + + if (n.parent) { + var childIndex = n.parent.children.findIndex(c => (c == n)); + n.pos.x = x = n.parent.pos.x + (Math.cos(n.angle * childIndex) * n.distance); + n.pos.y = y = n.parent.pos.y + (Math.sin(n.angle * childIndex) * n.distance); + } + + if (n.children.length > 0) + this.render(n.children); + + n.children.forEach(function (c) { + this.renderers.line.call(this, n, c); + }, this); + + }, this); + + nodes.forEach(function (n) { + if (n.children.length > 0) + this.render(n.children); - nodes.forEach(n => this.renderers.node.call(this, n)); + this.renderers.node.call(this, n, n.pos.x, n.pos.y); + }, this); }, update: function () { if (this.dirty) { this.dirty = false; + this.renderers.clear.call(this); this.render(); } @@ -56,9 +82,42 @@ var renderer = { }, renderers: { - node: function (node) { + clear: function () { + this.ctx.clearRect(this.pos.x, this.pos.y, this.screen.w, this.screen.h); + }, + + node: function (node, x, y) { this.ctx.fillStyle = '#c0c3cf'; - this.ctx.fillRect(node.pos.x, node.pos.y, this.constants.blockSize, this.constants.blockSize) + this.ctx.fillRect(x, y, constants.blockSize, constants.blockSize) + }, + + line: function (fromNode, toNode) { + var ctx = this.ctx; + var halfSize = constants.blockSize / 2; + + ctx.strokeStyle = '#69696e'; + ctx.beginPath(); + ctx.moveTo(~~(fromNode.pos.x + halfSize) + 0.5, ~~(fromNode.pos.y + halfSize) + 0.5); + ctx.lineTo(~~(toNode.pos.x + halfSize) + 0.5, ~~(toNode.pos.y + halfSize) + 0.5); + ctx.closePath(); + ctx.stroke(); + } + }, + + events: { + onClick: function (e) { + generator.onClick(e.button, e.clientX + this.pos.x, e.clientY + this.pos.y); + e.preventDefault(); + return false; } } }; + +var constants = { + lineWidth: 5, + blockSize: 40, + defaultDistance: 100, + defaultDistanceInc: 50, + defaultAngle: Math.PI / 2, + defaultAngleInc: Math.PI / 8 +}; diff --git a/helpers/passives/styles.css b/helpers/passives/styles.css new file mode 100644 index 00000000..ffd7fa86 --- /dev/null +++ b/helpers/passives/styles.css @@ -0,0 +1,10 @@ +html, body { + height: 100vh; +} + +body { + background-color: #2d2136; + padding: 0px; + margin: 0px; + overflow: hidden; +}