diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/css/ueblueprint-style.css b/css/ueblueprint-style.css index 4484390..6f938d3 100644 --- a/css/ueblueprint-style.css +++ b/css/ueblueprint-style.css @@ -14,14 +14,15 @@ url('../font/roboto-regular.woff') format('woff'); } -.ueb { +u-blueprint { + display : block; position : relative; font-family: Roboto, Noto, Oxygen, Ubuntu, 'Open Sans', 'Helvetica Neue', sans-serif; font-size : var(--ueb-fron-size); } .ueb-viewport-header { - display : flexbox; + display : flex; position : absolute; top : 0; right : 0; @@ -32,7 +33,6 @@ } .ueb-viewport-zoom { - float: right; color: #4d4d4db7; } @@ -175,6 +175,7 @@ } .ueb-node { + display : block; position : absolute; transform : translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px)); border-radius: var(--ueb-node-radius); diff --git a/js/UEBlueprint.js b/js/UEBlueprint.js index 6ed429c..e8549bd 100644 --- a/js/UEBlueprint.js +++ b/js/UEBlueprint.js @@ -1,25 +1,35 @@ -import UEBlueprintDOMModel from "./UEBlueprintDOMModel.js" import UEBlueprintDragScroll from "./UEBlueprintDragScroll.js" -export default class UEBlueprint extends UEBlueprintDOMModel { +export default class UEBlueprint extends HTMLElement { - static domTemplate(obj) { + header() { return ` -
-
-
1:1
-
-
-
-
-
- ${obj.nodes.forEach(node => node.getDOMElement()) ?? ''} +
+
1:1
-
-
-
-` + ` + } + + overlay() { + return ` +
+ ` + } + + viewport() { + return ` +
+
+
+
+
+
+ ` + } + + insertChildren() { + this.querySelector('[data-nodes]').append(...this.nodes) } static clamp(val, min, max) { @@ -28,49 +38,60 @@ export default class UEBlueprint extends UEBlueprintDOMModel { constructor() { super() + this.nodes = new Set() this.expandGridSize = 400 - this.gridDOMElement = null + this.gridElement = null + this.viewportElement = null + this.overlayElement = null this.dragObject = null this.additional = /*[2 * this.expandGridSize, 2 * this.expandGridSize]*/[0, 0] this.translateValue = /*[this.expandGridSize, this.expandGridSize]*/[0, 0] this.zoom = 0 - this.nodes = [] + this.headerElement = null } - createDOMElement() { - super.createDOMElement() - this.gridDOMElement = this.domElement.querySelector('.ueb-grid') - let contentElement = this.domElement.querySelector('.ueb-grid-content') - if (!this.gridDOMElement || !contentElement) { - console.error('Some expencted DOM elements not be found, please check domTemplate().') - } - // Populate the grid content with the node elements - this.nodes.forEach(node => { - contentElement.appendChild(node.getDOMElement()) - }) + connectedCallback() { + this.classList.add('ueb', `ueb-zoom-${this.zoom}`) + let aDiv = document.createElement('div'); + // Add header + aDiv.innerHTML = this.header() + this.headerElement = aDiv.firstElementChild + this.appendChild(this.headerElement) + + // Add overlay + aDiv.innerHTML = this.overlay() + this.overlayElement = aDiv.firstElementChild + this.appendChild(this.overlayElement) + + // Add viewport + aDiv.innerHTML = this.viewport() + this.viewportElement = aDiv.firstElementChild + this.appendChild(this.viewportElement) + + this.gridElement = this.viewportElement.querySelector('.ueb-grid') + this.insertChildren() + this.dragObject = new UEBlueprintDragScroll(this, { 'clickButton': 2, 'stepSize': 1 }) } - removeDOMElement() { - if (this.domElement) { - this.dragObject.unlistenDOMElement() - } - return super.removeDOMElement() + getGridDOMElement() { + return this.gridElement } - getGridDOMElement() { - return this.gridDOMElement + disconnectedCallback() { + super.disconnectedCallback() + this.dragObject.unlistenDOMElement() } setScroll(value, smooth = false) { this.scroll = value if (!smooth) { - this.gridDOMElement.parentElement.scroll(value[0], value[1]) + this.viewportElement.scroll(value[0], value[1]) } else { - this.gridDOMElement.parentElement.scroll({ + this.viewportElement.scroll({ left: value[0], top: value[1], behavior: 'smooth' @@ -115,8 +136,7 @@ export default class UEBlueprint extends UEBlueprintDOMModel { } getScroll() { - let parentElement = this.gridDOMElement.parentElement - return [parentElement.scrollLeft, parentElement.scrollTop] + return [this.viewportElement.scrollLeft, this.viewportElement.scrollTop] } scrollCenter() { @@ -138,10 +158,9 @@ export default class UEBlueprint extends UEBlueprintDOMModel { } getViewportSize() { - let parentElement = this.gridDOMElement.parentElement return [ - parentElement.clientWidth, - parentElement.clientHeight + this.viewportElement.clientWidth, + this.viewportElement.clientHeight ] } @@ -150,10 +169,9 @@ export default class UEBlueprint extends UEBlueprintDOMModel { * @return {array} The horizonal and vertical maximum scroll limits */ getScrollMax() { - let parentElement = this.gridDOMElement.parentElement return [ - parentElement.scrollWidth - parentElement.clientWidth, - parentElement.scrollHeight - parentElement.clientHeight + this.viewportElement.scrollWidth - this.viewportElement.clientWidth, + this.viewportElement.scrollHeight - this.viewportElement.clientHeight ] } @@ -166,9 +184,9 @@ export default class UEBlueprint extends UEBlueprintDOMModel { x = Math.round(Math.abs(x)) y = Math.round(Math.abs(y)) this.additional = [this.additional[0] + x, this.additional[1] + y] - if (this.gridDOMElement) { - this.gridDOMElement.style.setProperty('--ueb-additional-x', this.additional[0]) - this.gridDOMElement.style.setProperty('--ueb-additional-y', this.additional[1]) + if (this.gridElement) { + this.gridElement.style.setProperty('--ueb-additional-x', this.additional[0]) + this.gridElement.style.setProperty('--ueb-additional-y', this.additional[1]) } } @@ -181,9 +199,9 @@ export default class UEBlueprint extends UEBlueprintDOMModel { x = Math.round(x) y = Math.round(y) this.translateValue = [this.translateValue[0] + x, this.translateValue[1] + y] - if (this.gridDOMElement) { - this.gridDOMElement.style.setProperty('--ueb-translate-x', this.translateValue[0]) - this.gridDOMElement.style.setProperty('--ueb-translate-y', this.translateValue[1]) + if (this.gridElement) { + this.gridElement.style.setProperty('--ueb-translate-x', this.translateValue[0]) + this.gridElement.style.setProperty('--ueb-translate-y', this.translateValue[1]) } } @@ -201,10 +219,10 @@ export default class UEBlueprint extends UEBlueprintDOMModel { // If the expansion is towards the left or top, then scroll back to give the illusion that the content is in the same position and translate it accordingly this._translate(scaledX < 0 ? -scaledX : 0, scaledY < 0 ? -scaledY : 0) if (x < 0) { - this.gridDOMElement.parentElement.scrollLeft -= x + this.viewportElement.scrollLeft -= x } if (y < 0) { - this.gridDOMElement.parentElement.scrollTop -= y + this.viewportElement.scrollTop -= y } } @@ -222,8 +240,8 @@ export default class UEBlueprint extends UEBlueprintDOMModel { return } let initialScale = this.getScale() - this.domElement.classList.add(`ueb-zoom-${zoom}`) - this.domElement.classList.remove(`ueb-zoom-${this.zoom}`) + this.classList.add(`ueb-zoom-${zoom}`) + this.classList.remove(`ueb-zoom-${this.zoom}`) this.zoom = zoom if (center) { let relativeScale = this.getScale() / initialScale @@ -239,10 +257,16 @@ export default class UEBlueprint extends UEBlueprintDOMModel { } getScale() { - return parseFloat(getComputedStyle(this.gridDOMElement).getPropertyValue('--ueb-grid-scale')) + return parseFloat(getComputedStyle(this.gridElement).getPropertyValue('--ueb-grid-scale')) } - addNode(...blueprintNode) { - this.nodes.push(...blueprintNode) + addNode(...blueprintNodes) { + [...blueprintNodes].reduce((s, e) => s.add(e), this.nodes) + let nodesDestination = this.querySelector('[data-nodes]') + if (nodesDestination) { + nodesDestination.append(...blueprintNodes) + } } } + +customElements.define('u-blueprint', UEBlueprint) diff --git a/js/UEBlueprintDOMModel.js b/js/UEBlueprintDOMModel.js deleted file mode 100644 index b1e7df9..0000000 --- a/js/UEBlueprintDOMModel.js +++ /dev/null @@ -1,35 +0,0 @@ -export default class UEBlueprintDOMModel { - static dummyDiv = document.createElement('div') - - static domTemplate(obj) { - return `` - } - - constructor() { - this.domElement = null - } - - createDOMElement() { - if (this.domElement) { - this.removeDOMElement() - } - this.constructor.dummyDiv.innerHTML = this.constructor.domTemplate(this) - this.domElement = this.constructor.dummyDiv.removeChild(this.constructor.dummyDiv.firstElementChild) - } - - getDOMElement() { - if (!this.domElement) { - this.createDOMElement() - } - return this.domElement - } - - removeDOMElement() { - if (!this.domElement) { - return false - } - this.domElement.parentElement.removeChild(this.domElement) - this.domElement = null - return true - } -} diff --git a/js/UEBlueprintDrag.js b/js/UEBlueprintDrag.js index 0cbcac4..22dd480 100644 --- a/js/UEBlueprintDrag.js +++ b/js/UEBlueprintDrag.js @@ -1,6 +1,6 @@ export default class UEBlueprintDrag { - constructor(draggedNode, options) { - this.blueprintNode = draggedNode; + constructor(blueprintNode, options) { + this.blueprintNode = blueprintNode; this.mousePosition = [0, 0]; this.stepSize = options?.stepSize this.clickButton = options?.clickButton ?? 0 @@ -38,17 +38,13 @@ export default class UEBlueprintDrag { document.removeEventListener('mouseup', self.mouseUpHandler) } }; - let element = this.blueprintNode.getDOMElement() + let element = this.blueprintNode element.addEventListener('mousedown', this.mouseDownHandler) element.addEventListener('contextmenu', e => e.preventDefault()) } unlistenDOMElement() { - if (this.blueprintNode) { - this.blueprintNode.getDOMElement().removeEventListener('mousedown', this.mouseDownHandler) - return true - } - return false + this.blueprintNode.removeEventListener('mousedown', this.mouseDownHandler) } snapToGrid(posX, posY) { @@ -60,7 +56,7 @@ export default class UEBlueprintDrag { clicked(x, y) { if (!this.stepSize) { - this.stepSize = parseInt(getComputedStyle(this.blueprintNode.getDOMElement()).getPropertyValue('--ueb-grid-snap')) + this.stepSize = parseInt(getComputedStyle(this.blueprintNode).getPropertyValue('--ueb-grid-snap')) } // Get the current mouse position this.mousePosition = this.snapToGrid(x, y) diff --git a/js/UEBlueprintDragScroll.js b/js/UEBlueprintDragScroll.js index 52ac390..e272f32 100644 --- a/js/UEBlueprintDragScroll.js +++ b/js/UEBlueprintDragScroll.js @@ -3,7 +3,6 @@ import UEBlueprintDrag from "./UEBlueprintDrag.js" export default class UEBlueprintDragScroll extends UEBlueprintDrag { constructor(scrolledEntity, options) { super(scrolledEntity, options) - this.scrolledDOMElement = scrolledEntity.getGridDOMElement() this.minZoom = options?.minZoom ?? -12 let self = this; this.mouseMoveHandler = function (e) { diff --git a/js/UEBlueprintDraggableObject.js b/js/UEBlueprintDraggableObject.js index 9b2d9a9..be25242 100644 --- a/js/UEBlueprintDraggableObject.js +++ b/js/UEBlueprintDraggableObject.js @@ -1,7 +1,6 @@ -import UEBlueprintDOMModel from "./UEBlueprintDOMModel.js" import UEBlueprintDrag from "./UEBlueprintDrag.js" -export default class UEBlueprintDraggableObject extends UEBlueprintDOMModel { +export default class UEBlueprintDraggableObject extends HTMLElement { constructor() { super() @@ -9,24 +8,18 @@ export default class UEBlueprintDraggableObject extends UEBlueprintDOMModel { this.location = [0, 0] } - createDOMElement() { - super.createDOMElement() + connectedCallback() { this.dragObject = new UEBlueprintDrag(this) } - removeDOMElement() { - if (this.domElement) { - this.dragObject.unlistenDOMElement() - } - return super.removeDOMElement() + disconnectedCallback() { + this.dragObject.unlistenDOMElement() } setLocation(value = [0, 0]) { this.location = value - if (this.domElement) { - this.domElement.style.setProperty('--ueb-position-x', this.location[0]) - this.domElement.style.setProperty('--ueb-position-y', this.location[1]) - } + this.style.setProperty('--ueb-position-x', this.location[0]) + this.style.setProperty('--ueb-position-y', this.location[1]) } addLocation(value) { diff --git a/js/UEBlueprintObject.js b/js/UEBlueprintObject.js index 65819bc..cd16b03 100644 --- a/js/UEBlueprintObject.js +++ b/js/UEBlueprintObject.js @@ -16,39 +16,49 @@ export default class UEBlueprintObject extends UEBlueprintDraggableObject { static classInFlow = false static classOutFlow = false static className = 'Empty node' - static domTemplate(obj) { + + header() { return ` -
-
-
- ${obj.constructor.className} + ${this.constructor.className}
+ ` + } + + body() { + return `
- ${obj.constructor.classInputs.forEach((input, index) => ` + ${this.constructor.classInputs.forEach((input, index) => `
- + ${input.name}
`) ?? ''}
- ${obj.constructor.classOutputs.forEach((output, index) => ` + ${this.constructor.classOutputs.forEach((output, index) => `
${output.name} - +
`) ?? ''}
-
-
-
+ ` + } + + render() { + return ` +
+
+ ${this.header()} + ${this.body()} +
+
` } @@ -67,6 +77,20 @@ export default class UEBlueprintObject extends UEBlueprintDraggableObject { }) } + connectedCallback() { + super.connectedCallback() + this.classList.add('ueb-node') + if (this.selected) { + this.classList.add('ueb-selected') + } + this.style.setProperty('--ueb-position-x', this.location[0]) + this.style.setProperty('--ueb-position-y', this.location[1]) + + let aDiv = document.createElement('div'); + aDiv.innerHTML = this.render() + this.appendChild(aDiv.firstElementChild) + } + isSelected() { return this.selected } @@ -75,3 +99,5 @@ export default class UEBlueprintObject extends UEBlueprintDraggableObject { this.selected = value } } + +customElements.define('u-object', UEBlueprintObject) diff --git a/js/exporting.js b/js/exporting.js new file mode 100644 index 0000000..0fd202d --- /dev/null +++ b/js/exporting.js @@ -0,0 +1,4 @@ +import UEBlueprint from "./UEBlueprint" +import UEBlueprintObject from "./UEBlueprintObject" + +export { UEBlueprint, UEBlueprintObject } \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..48cd031 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "ueblueprint", + "version": "1.0.0", + "description": "Unreal Engine's Blueprint visualisation library", + "main": "index.js", + "scripts": { + "build": "rollup --config" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/barsdeveloper/ueblueprint.git" + }, + "keywords": [ + "unreal", + "engine", + "blueprint" + ], + "author": "barsdeveloper", + "license": "MIT", + "bugs": { + "url": "https://github.com/barsdeveloper/ueblueprint/issues" + }, + "homepage": "https://github.com/barsdeveloper/ueblueprint#readme", + "dependencies": {}, + "devDependencies": {} +} \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..aeb3388 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,7 @@ +export default { + input: 'js/exporting.js', + output: { + file: 'ueblueprint.js', + format: 'es', + }, +}; \ No newline at end of file diff --git a/ueblueprint.html b/ueblueprint.html index 25ff8eb..fd30c8c 100644 --- a/ueblueprint.html +++ b/ueblueprint.html @@ -22,20 +22,18 @@ --ueb-grid-snap: 16px; } - +
Hello