mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-03 23:55:04 +08:00
Initial commit
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 barsdeveloper
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2
README.md
Normal file
2
README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# ueblueprint
|
||||
Unreal Engine's Blueprint visualisation library
|
||||
9
css/ueblueprint-draggable.css
Normal file
9
css/ueblueprint-draggable.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.ueb-draggable,
|
||||
.ueb-node {
|
||||
/* Indicate the element draggable */
|
||||
cursor : move;
|
||||
/* It will be positioned absolutely */
|
||||
position : absolute;
|
||||
/* Doesn't allow to select the content inside */
|
||||
user-select: none;
|
||||
}
|
||||
35
css/ueblueprint-node-value-type-color.css
Normal file
35
css/ueblueprint-node-value-type-color.css
Normal file
@@ -0,0 +1,35 @@
|
||||
.ueb {
|
||||
--ueb-node-value-color: white;
|
||||
}
|
||||
|
||||
.ueb-node-value-boolean {
|
||||
--ueb-node-value-color: #930000;
|
||||
}
|
||||
|
||||
.ueb-node-value-integer {
|
||||
--ueb-node-value-color: #1fe0ad;
|
||||
}
|
||||
|
||||
.ueb-node-value-float {
|
||||
--ueb-node-value-color: #9ffb44;
|
||||
}
|
||||
|
||||
.ueb-node-value-vector {
|
||||
--ueb-node-value-color: #fcc823;
|
||||
}
|
||||
|
||||
.ueb-node-value-rotator {
|
||||
--ueb-node-value-color: #9eb1fc;
|
||||
}
|
||||
|
||||
.ueb-node-value-string {
|
||||
--ueb-node-value-color: #fc00d2;
|
||||
}
|
||||
|
||||
.ueb-node-value-name {
|
||||
--ueb-node-value-color: #cb81fc;
|
||||
}
|
||||
|
||||
.ueb-node-value-objectreference {
|
||||
--ueb-node-value-color: #00a8f2;
|
||||
}
|
||||
274
css/ueblueprint-style.css
Normal file
274
css/ueblueprint-style.css
Normal file
@@ -0,0 +1,274 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style : light;
|
||||
src :
|
||||
url('../font/roboto-light.woff2') format('woff2'),
|
||||
url('../font/roboto-light.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style : regular;
|
||||
src :
|
||||
url('../font/roboto-regular.woff2') format('woff2'),
|
||||
url('../font/roboto-regular.woff') format('woff');
|
||||
}
|
||||
|
||||
.ueb {
|
||||
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;
|
||||
position : absolute;
|
||||
top : 0;
|
||||
right : 0;
|
||||
left : 0;
|
||||
height : 1.5em;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index : 1;
|
||||
}
|
||||
|
||||
.ueb-viewport-zoom {
|
||||
float: right;
|
||||
color: #4d4d4db7;
|
||||
}
|
||||
|
||||
.ueb-viewport-body {
|
||||
position : relative;
|
||||
height : var(--ueb-viewport-height);
|
||||
width : var(--ueb-viewport-width);
|
||||
overflow : scroll;
|
||||
scrollbar-width: 0;
|
||||
}
|
||||
|
||||
.ueb-grid {
|
||||
--ueb-grid-line-actual-width: calc(var(--ueb-grid-line-width) / var(--ueb-grid-scale));
|
||||
position : absolute;
|
||||
min-width : 100%;
|
||||
min-height : 100%;
|
||||
width : calc(100% + var(--ueb-additional-x) * 1px);
|
||||
height : calc(100% + var(--ueb-additional-y) * 1px);
|
||||
background-color : #262626;
|
||||
background-image :
|
||||
/* Axis lines */
|
||||
linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),
|
||||
linear-gradient(var(--ueb-grid-axis-line-color), var(--ueb-grid-axis-line-color)),
|
||||
/* Dark bigger grid */
|
||||
linear-gradient(to right,
|
||||
var(--ueb-grid-set-line-color),
|
||||
var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width),
|
||||
transparent var(--ueb-grid-line-actual-width),
|
||||
transparent),
|
||||
linear-gradient(to bottom,
|
||||
var(--ueb-grid-set-line-color),
|
||||
var(--ueb-grid-set-line-color) var(--ueb-grid-line-actual-width),
|
||||
transparent var(--ueb-grid-line-actual-width),
|
||||
transparent),
|
||||
/* Light grid */
|
||||
linear-gradient(to right,
|
||||
var(--ueb-grid-line-color),
|
||||
var(--ueb-grid-line-color) var(--ueb-grid-line-actual-width),
|
||||
transparent var(--ueb-grid-line-actual-width),
|
||||
transparent),
|
||||
linear-gradient(to bottom,
|
||||
var(--ueb-grid-line-color),
|
||||
var(--ueb-grid-line-color)var(--ueb-grid-line-actual-width),
|
||||
transparent var(--ueb-grid-line-actual-width),
|
||||
transparent);
|
||||
background-size:
|
||||
/* Axis lines */
|
||||
100% var(--ueb-grid-line-actual-width),
|
||||
var(--ueb-grid-line-actual-width) 100%,
|
||||
/* Dark bigger grid */
|
||||
calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)),
|
||||
calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)) calc(var(--ueb-grid-set) * var(--ueb-grid-actual-size)),
|
||||
/* Light grid */
|
||||
var(--ueb-grid-actual-size) var(--ueb-grid-actual-size),
|
||||
var(--ueb-grid-actual-size) var(--ueb-grid-actual-size);
|
||||
background-position: calc(var(--ueb-translate-x) * 1px) calc(var(--ueb-translate-y) * 1px);
|
||||
background-repeat : repeat-x, repeat-y, repeat, repeat, repeat, repeat;
|
||||
transform : scale(var(--ueb-grid-scale), var(--ueb-grid-scale));
|
||||
transform-origin : 0 0;
|
||||
overflow : hidden;
|
||||
}
|
||||
|
||||
.ueb-zoom--.ueb,
|
||||
.ueb {
|
||||
/* 16/16 */
|
||||
--ueb-grid-scale : 1;
|
||||
--ueb-grid-actual-size: var(--ueb-grid-size);
|
||||
}
|
||||
|
||||
.ueb-zoom--1.ueb {
|
||||
/* 14/16 */
|
||||
--ueb-grid-scale: 0.875
|
||||
}
|
||||
|
||||
.ueb-zoom--2.ueb {
|
||||
/* 12/16 */
|
||||
--ueb-grid-scale: 0.75
|
||||
}
|
||||
|
||||
.ueb-zoom--3.ueb {
|
||||
/* 10.8/16 */
|
||||
--ueb-grid-scale: 0.675
|
||||
}
|
||||
|
||||
.ueb-zoom--4.ueb {
|
||||
/* 8/16 */
|
||||
--ueb-grid-scale : 0.5;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2)
|
||||
}
|
||||
|
||||
.ueb-zoom--5.ueb {
|
||||
/* 6/16 */
|
||||
--ueb-grid-scale : 0.375;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 2);
|
||||
}
|
||||
|
||||
.ueb-zoom--6.ueb {
|
||||
--ueb-grid-scale : 0.333333;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3);
|
||||
}
|
||||
|
||||
.ueb-zoom--7.ueb {
|
||||
--ueb-grid-scale : 0.3;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3);
|
||||
}
|
||||
|
||||
.ueb-zoom--8.ueb {
|
||||
--ueb-grid-scale : 0.266666;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3);
|
||||
}
|
||||
|
||||
.ueb-zoom--9.ueb {
|
||||
--ueb-grid-scale : 0.233333;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3);
|
||||
}
|
||||
|
||||
.ueb-zoom--10.ueb {
|
||||
/* 12/16 */
|
||||
--ueb-grid-scale : 0.2;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 3);
|
||||
}
|
||||
|
||||
.ueb-zoom--11.ueb {
|
||||
/* 12/16 */
|
||||
--ueb-grid-scale : 0.166666;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6);
|
||||
}
|
||||
|
||||
.ueb-zoom--12.ueb {
|
||||
/* 12/16 */
|
||||
--ueb-grid-scale : 0.133333;
|
||||
--ueb-grid-actual-size: calc(var(--ueb-grid-size) * 6);
|
||||
}
|
||||
|
||||
.ueb-grid-content {
|
||||
position : relative;
|
||||
width : 0;
|
||||
height : 0;
|
||||
transform: translateX(calc(var(--ueb-translate-x) * 1px)) translateY(calc(var(--ueb-translate-y) * 1px))
|
||||
}
|
||||
|
||||
.ueb-node {
|
||||
position : absolute;
|
||||
transform : translateX(calc(var(--ueb-position-x) * 1px)) translateY(calc(var(--ueb-position-y) * 1px));
|
||||
border-radius: var(--ueb-node-radius);
|
||||
box-shadow : 0 0 1px 0 black, 1px 4px 6px 0 rgba(0, 0, 0, 0.3);
|
||||
will-change : transform;
|
||||
}
|
||||
|
||||
.ueb-node-border {
|
||||
margin : -3px;
|
||||
padding : 3px;
|
||||
border-radius: calc(var(--ueb-node-radius) * 1.4);
|
||||
}
|
||||
|
||||
.ueb-selected>.ueb-node-border {
|
||||
background-image:
|
||||
linear-gradient(to right, #f1b000 0%, #f1b000 100%),
|
||||
linear-gradient(to bottom, #f1b000 0%, #cc6700 100%),
|
||||
linear-gradient(to right, #cc6700 0%, #cc6700 100%),
|
||||
linear-gradient(to bottom, #f1b000 0%, #cc6700 100%);
|
||||
background-size : 100% 7px, 7px 100%, 100% 7px, 7px 100%;
|
||||
background-position: top, right, bottom, left;
|
||||
background-repeat : repeat-x, repeat-y, repeat-x, repeat-y;
|
||||
}
|
||||
|
||||
.ueb-node-content {
|
||||
padding : 1px;
|
||||
box-shadow : inset 0 0 2px 0 black;
|
||||
border-radius: var(--ueb-node-radius);
|
||||
background : rgba(0, 0, 0, 0.7);
|
||||
overflow : hidden;
|
||||
}
|
||||
|
||||
.ueb-node-header {
|
||||
padding : 0.2em 0.7em;
|
||||
box-shadow : inset 0 1px 2px 0 #313631, inset 0 2px 0 0 #92c381;
|
||||
border-radius: var(--ueb-node-radius) var(--ueb-node-radius) 0 0;
|
||||
background : linear-gradient(170deg, #5f815a 0%, #5f815a 50%, transparent 100%);
|
||||
color : #c0c0c0;
|
||||
font-weight : 600;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
.ueb-node-name {
|
||||
background: radial-gradient(closest-side, rgba(0, 0, 0, 0.5) 0%, transparent 90%);
|
||||
margin : -0.1em -1.6em;
|
||||
padding : 0.1em 1.6em;
|
||||
}
|
||||
|
||||
.ueb-node-body {
|
||||
display : flex;
|
||||
padding : 0.6em 0.8em;
|
||||
color : white;
|
||||
font-weight: 100;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ueb-node-inputs {
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
.ueb-node-value-icon {
|
||||
display : inline-block;
|
||||
position : relative;
|
||||
width : 0.85em;
|
||||
height : 0.85em;
|
||||
vertical-align: baseline;
|
||||
margin : 0 0.4em -1px 0.3em;
|
||||
}
|
||||
|
||||
.ueb-node-value-icon::before {
|
||||
content : "";
|
||||
display : block;
|
||||
position : absolute;
|
||||
top : 0;
|
||||
right : 0;
|
||||
bottom : 0;
|
||||
left : 0;
|
||||
border : 2px solid var(--ueb-node-value-color);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.ueb-node-value-fill::before {
|
||||
background: var(--ueb-node-value-color);
|
||||
}
|
||||
|
||||
.ueb-node-value-icon::after {
|
||||
content : "";
|
||||
display : block;
|
||||
position : absolute;
|
||||
top : calc(50% - 0.3em);
|
||||
left : calc(100% + 1px);
|
||||
width : 0;
|
||||
height : 0;
|
||||
border-top : 0.3em solid transparent;
|
||||
border-bottom: 0.3em solid transparent;
|
||||
border-left : 0.3em solid var(--ueb-node-value-color);
|
||||
}
|
||||
BIN
font/roboto-bold.woff
Normal file
BIN
font/roboto-bold.woff
Normal file
Binary file not shown.
BIN
font/roboto-bold.woff2
Normal file
BIN
font/roboto-bold.woff2
Normal file
Binary file not shown.
BIN
font/roboto-light.woff
Normal file
BIN
font/roboto-light.woff
Normal file
Binary file not shown.
BIN
font/roboto-light.woff2
Normal file
BIN
font/roboto-light.woff2
Normal file
Binary file not shown.
BIN
font/roboto-regular.woff
Normal file
BIN
font/roboto-regular.woff
Normal file
Binary file not shown.
BIN
font/roboto-regular.woff2
Normal file
BIN
font/roboto-regular.woff2
Normal file
Binary file not shown.
35
js/UEBlueprintDOMModel.js
Normal file
35
js/UEBlueprintDOMModel.js
Normal file
@@ -0,0 +1,35 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
69
js/UEBlueprintDrag.js
Normal file
69
js/UEBlueprintDrag.js
Normal file
@@ -0,0 +1,69 @@
|
||||
export default class UEBlueprintDrag {
|
||||
constructor(draggedNode, options) {
|
||||
this.blueprintNode = draggedNode;
|
||||
this.mousePosition = [0, 0];
|
||||
this.stepSize = 1
|
||||
this.clickButton = options?.clickButton ?? 0
|
||||
this.exitGrabSameButtonOnly = options?.exitGrabSameButtonOnly ?? false
|
||||
let self = this;
|
||||
this.mouseDownHandler = function (e) {
|
||||
switch (e.button) {
|
||||
case self.clickButton:
|
||||
self.clicked(e.clientX, e.clientY)
|
||||
break;
|
||||
default:
|
||||
if (!self.exitGrabSameButtonOnly) {
|
||||
self.mouseUpHandler(e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
this.mouseMoveHandler = function (e) {
|
||||
let mousePosition = self.snapToGrid(e.clientX, e.clientY)
|
||||
const d = [mousePosition[0] - self.mousePosition[0], mousePosition[1] - self.mousePosition[1]]
|
||||
|
||||
if (d[0] == 0 && d[1] == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.blueprintNode.addLocation(d)
|
||||
|
||||
// Reassign the position of mouse
|
||||
self.mousePosition = mousePosition
|
||||
};
|
||||
this.mouseUpHandler = function (e) {
|
||||
if (!self.exitGrabSameButtonOnly || e.button == self.clickButton) {
|
||||
// Remove the handlers of `mousemove` and `mouseup`
|
||||
document.removeEventListener('mousemove', self.mouseMoveHandler)
|
||||
document.removeEventListener('mouseup', self.mouseUpHandler)
|
||||
}
|
||||
};
|
||||
let element = this.blueprintNode.getDOMElement()
|
||||
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
|
||||
}
|
||||
|
||||
snapToGrid(posX, posY) {
|
||||
return [
|
||||
this.stepSize * Math.round(posX / this.stepSize),
|
||||
this.stepSize * Math.round(posY / this.stepSize)
|
||||
]
|
||||
}
|
||||
|
||||
clicked(x, y) {
|
||||
// Get the current mouse position
|
||||
this.mousePosition = this.snapToGrid(x, y)
|
||||
this.stepSize = parseInt(getComputedStyle(this.blueprintNode.getDOMElement()).getPropertyValue('--ueb-grid-snap'))
|
||||
// Attach the listeners to `document`
|
||||
document.addEventListener('mousemove', this.mouseMoveHandler)
|
||||
document.addEventListener('mouseup', this.mouseUpHandler)
|
||||
}
|
||||
}
|
||||
78
js/UEBlueprintDragScroll.js
Normal file
78
js/UEBlueprintDragScroll.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import UEBlueprintDrag from "./UEBlueprintDrag.js"
|
||||
|
||||
export default class UEBlueprintDragScroll extends UEBlueprintDrag {
|
||||
constructor(scrolledEntity, options) {
|
||||
super(scrolledEntity, options)
|
||||
this.scrolledDOMElement = scrolledEntity.getGridDOMElement()
|
||||
this.expandGridSize = options?.expandGridSize ?? 200
|
||||
this.initialExpandGridSize = this.expandGridSize
|
||||
this.minZoom = options?.minZoom ?? -12
|
||||
let self = this;
|
||||
this.mouseMoveHandler = function (e) {
|
||||
const scrollMaxX = self.scrolledDOMElement.parentElement.scrollWidth - self.scrolledDOMElement.parentElement.clientWidth
|
||||
const scrollMaxY = self.scrolledDOMElement.parentElement.scrollHeight - self.scrolledDOMElement.parentElement.clientHeight
|
||||
let expandX = self.scrolledDOMElement.parentElement.scrollLeft < self.expandGridSize * 0.5 ? -1 : 0
|
||||
+ self.scrolledDOMElement.parentElement.scrollLeft > scrollMaxX - self.expandGridSize * 0.5 ? 1 : 0
|
||||
let expandY = self.scrolledDOMElement.parentElement.scrollTop < self.expandGridSize * 0.5 ? -1 : 0
|
||||
+ self.scrolledDOMElement.parentElement.scrollTop > scrollMaxY - self.expandGridSize * 0.5 ? 1 : 0
|
||||
|
||||
if (expandX != 0 || expandY != 0) {
|
||||
|
||||
/* Managining infinite scrolling: when the scrollbar reaches the end, the grid is expanded and the elements inside translated to give the illusion that they stayed in the same position*/
|
||||
self.expandAndTranslate(expandX * self.expandGridSize, expandY * self.expandGridSize)
|
||||
}
|
||||
|
||||
let mousePosition = self.snapToGrid(e.clientX, e.clientY)
|
||||
|
||||
// How far the mouse has been moved
|
||||
const dx = mousePosition[0] - self.mousePosition[0]
|
||||
const dy = mousePosition[1] - self.mousePosition[1]
|
||||
|
||||
self.scrolledDOMElement.parentElement.scrollLeft = self.scrolledDOMElement.parentElement.scrollLeft - dx
|
||||
self.scrolledDOMElement.parentElement.scrollTop = self.scrolledDOMElement.parentElement.scrollTop - dy
|
||||
|
||||
// Reassign the position of mouse
|
||||
self.mousePosition = mousePosition
|
||||
};
|
||||
this.mouseWheelHandler = function (e) {
|
||||
let blueprintRoot = self.elem.parentElement.parentElement
|
||||
let zoomLevel = 0
|
||||
let zoomLevelClass = "ueb-zoom-0"
|
||||
let classes = blueprintRoot.classList.values()
|
||||
for (let className of classes) {
|
||||
let v = className.match(/ueb\-zoom\-(\-?\d+)/)
|
||||
if (v) {
|
||||
zoomLevelClass = v[0]
|
||||
zoomLevel = parseInt(v[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
zoomLevel -= Math.round(e.deltaY / 50)
|
||||
zoomLevel = self.clamp(zoomLevel, -12, 0)
|
||||
blueprintRoot.classList.remove(zoomLevelClass)
|
||||
blueprintRoot.classList.add("ueb-zoom-" + zoomLevel)
|
||||
let scale = blueprintNode.getScale()
|
||||
let additionalX = Math.ceil(self.scrolledDOMElement.clientWidth * (1 - 1 / scale))
|
||||
let additionalY = Math.ceil(self.scrolledDOMElement.clientHeight * (1 - 1 / scale))
|
||||
self.blueprintNode.expand(additionalX, additionalY)
|
||||
|
||||
}
|
||||
this.blueprintNode.getGridDOMElement().addEventListener('wheel', this.mouseWheelHandler)
|
||||
this.blueprintNode.getGridDOMElement().addEventListener('wheel', e => e.preventDefault())
|
||||
this.blueprintNode.getGridDOMElement().parentElement.addEventListener('wheel', e => e.preventDefault())
|
||||
}
|
||||
|
||||
expandAndTranslate(x, y) {
|
||||
this.blueprintNode.expand(x, y)
|
||||
this.blueprintNode.translate(-x, -y)
|
||||
}
|
||||
|
||||
scaledExpand(x, y, scale) {
|
||||
|
||||
}
|
||||
|
||||
clamp(val, min, max) {
|
||||
return Math.min(Math.max(val, min), max);
|
||||
}
|
||||
|
||||
}
|
||||
40
js/UEBlueprintDraggableObject.js
Normal file
40
js/UEBlueprintDraggableObject.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import UEBlueprintDOMModel from "./UEBlueprintDOMModel.js"
|
||||
import UEBlueprintDrag from "./UEBlueprintDrag.js"
|
||||
|
||||
export default class UEBlueprintDraggableObject extends UEBlueprintDOMModel {
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.dragObject = null
|
||||
this.location = [0, 0]
|
||||
}
|
||||
|
||||
createDOMElement() {
|
||||
super.createDOMElement()
|
||||
this.dragObject = new UEBlueprintDrag(this)
|
||||
}
|
||||
|
||||
removeDOMElement() {
|
||||
if (this.domElement) {
|
||||
this.dragObject.unlistenDOMElement()
|
||||
}
|
||||
return super.removeDOMElement()
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
addLocation(value) {
|
||||
this.setLocation([this.location[0] + value[0], this.location[1] + value[1]])
|
||||
}
|
||||
|
||||
getLocation() {
|
||||
return this.location
|
||||
}
|
||||
|
||||
}
|
||||
77
js/UEBlueprintObject.js
Normal file
77
js/UEBlueprintObject.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import UEBlueprintDraggableObject from "./UEBlueprintDraggableObject.js"
|
||||
|
||||
export default class UEBlueprintObject extends UEBlueprintDraggableObject {
|
||||
static classInputs = [/*
|
||||
{
|
||||
name: "Input Example",
|
||||
type: 'integer'
|
||||
}
|
||||
*/]
|
||||
static classOutputs = [/*
|
||||
{
|
||||
name: "Return Value",
|
||||
type: 'string'
|
||||
}*/
|
||||
]
|
||||
static classInFlow = false
|
||||
static classOutFlow = false
|
||||
static className = 'Empty node'
|
||||
static domTemplate(obj) {
|
||||
return `
|
||||
<div class="ueb-node ${obj.selected ? 'ueb-selected' : ''}"
|
||||
style="--ueb-position-x:${obj.location[0]}; --ueb-position-y:${obj.location[1]}">
|
||||
<div class="ueb-node-border">
|
||||
<div class="ueb-node-content">
|
||||
<div class="ueb-node-header">
|
||||
<span class="ueb-node-name">
|
||||
<span class="ueb-node-symbol"></span>
|
||||
<span class="ueb-node-text">${obj.constructor.className}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ueb-node-body">
|
||||
<div class="ueb-node-inputs">
|
||||
${obj.constructor.classInputs.forEach((input, index) => `
|
||||
<div class="ueb-node-input ueb-node-value-${input.type}">
|
||||
<span class="ueb-node-value-icon ${obj.inputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
|
||||
${input.name}
|
||||
</div>
|
||||
`) ?? ''}
|
||||
</div>
|
||||
<div class="ueb-node-outputs">
|
||||
${obj.constructor.classOutputs.forEach((output, index) => `
|
||||
<div class="ueb-node-output ueb-node-value-${output.type}">
|
||||
${output.name}
|
||||
<span class="ueb-node-value-icon ${obj.outputs[index].connected ? 'ueb-node-value-fill' : ''}"></span>
|
||||
</div>
|
||||
`) ?? ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.selected = false
|
||||
this.inputs = this.constructor.classInputs.map(value => {
|
||||
return {
|
||||
connected: null
|
||||
}
|
||||
})
|
||||
this.outputs = this.constructor.classOutputs.map(value => {
|
||||
return {
|
||||
connected: null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
isSelected() {
|
||||
return this.selected
|
||||
}
|
||||
|
||||
setSelected(value = true) {
|
||||
this.selected = value
|
||||
}
|
||||
}
|
||||
103
js/ueblueprint.js
Normal file
103
js/ueblueprint.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import UEBlueprintDOMModel from "./UEBlueprintDOMModel.js";
|
||||
import UEBlueprintDragScroll from "./UEBlueprintDragScroll.js";
|
||||
|
||||
export default class UEBlueprint extends UEBlueprintDOMModel {
|
||||
|
||||
static domTemplate(obj) {
|
||||
return `
|
||||
<div class="ueb" style="--ueb-grid-scale:${obj.scale}">
|
||||
<div class="ueb-viewport-header">
|
||||
<div class="ueb-viewport-zoom">1:1</div>
|
||||
</div>
|
||||
<div class="ueb-viewport-overlay"></div>
|
||||
<div class="ueb-viewport-body">
|
||||
<div class="ueb-grid"
|
||||
style="--ueb-additional-x:${obj.additional[0]}; --ueb-additional-y:${obj.additional[1]}; --ueb-translate-x:${obj.translate[0]}; --ueb-translate-y:${obj.translate[1]}">
|
||||
<div class="ueb-grid-content">
|
||||
${obj.nodes.forEach(node => node.getDOMElement()) ?? ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.gridDOMElement = null
|
||||
this.dragObject = null
|
||||
this.additional = [0, 0]
|
||||
this.translateValue = [0, 0]
|
||||
this.scale = 1
|
||||
this.nodes = []
|
||||
}
|
||||
|
||||
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())
|
||||
})
|
||||
this.dragObject = new UEBlueprintDragScroll(this, {
|
||||
'clickButton': 2
|
||||
})
|
||||
}
|
||||
|
||||
removeDOMElement() {
|
||||
if (this.domElement) {
|
||||
this.dragObject.unlistenDOMElement()
|
||||
}
|
||||
return super.removeDOMElement()
|
||||
}
|
||||
|
||||
getGridDOMElement() {
|
||||
return this.gridDOMElement
|
||||
}
|
||||
|
||||
setScroll(value = [0, 0]) {
|
||||
this.scroll = value
|
||||
}
|
||||
|
||||
addScroll(value) {
|
||||
this.setLocation([this.scroll[0] + value[0], this.scroll[1] + value[1]])
|
||||
}
|
||||
|
||||
getScroll() {
|
||||
return this.scroll
|
||||
}
|
||||
|
||||
expand(x, y) {
|
||||
x = Math.round(x)
|
||||
y = Math.round(y)
|
||||
this.additional = [this.additional[0] + Math.abs(x), this.additional[1] + Math.abs(y)]
|
||||
if (this.domElement) {
|
||||
this.domElement.style.setProperty('--ueb-additional-x', this.additional[0])
|
||||
this.domElement.style.setProperty('--ueb-additional-y', this.additional[1])
|
||||
this.domElement.parentElement.scrollLeft -= x
|
||||
this.domElement.parentElement.scrollTop -= y
|
||||
}
|
||||
}
|
||||
|
||||
translate(x, y) {
|
||||
x = Math.round(x)
|
||||
y = Math.round(y)
|
||||
this.translateValue = [this.translateValue[0] + x, this.translateValue[1] + y]
|
||||
if (this.domElement) {
|
||||
this.domElement.style.setProperty('--ueb-translate-x', this.translateValue[0])
|
||||
this.domElement.style.setProperty('--ueb-translate-y', this.translateValue[1])
|
||||
}
|
||||
}
|
||||
|
||||
getScale() {
|
||||
return this.scale
|
||||
}
|
||||
|
||||
addNode(...blueprintNode) {
|
||||
this.nodes.push(...blueprintNode)
|
||||
}
|
||||
}
|
||||
68
ueblueprint.html
Normal file
68
ueblueprint.html
Normal file
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title></title>
|
||||
<style>
|
||||
body {
|
||||
--ueb-fron-size: 13px;
|
||||
--ueb-viewport-height: 30rem;
|
||||
--ueb-viewport-width: 100%;
|
||||
--ueb-grid-size: 16px;
|
||||
--ueb-grid-line-width: 2px;
|
||||
--ueb-grid-line-color: #353535;
|
||||
--ueb-grid-set: 8;
|
||||
--ueb-grid-set-line-color: #161616;
|
||||
--ueb-grid-axis-line-color: black;
|
||||
--ueb-grid-snap: 16px;
|
||||
--ueb-grid-min-scale: 0.2;
|
||||
--ueb-node-radius: 7px;
|
||||
--ueb-grid-snap: 16px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/ueblueprint-style.css">
|
||||
<link rel="stylesheet" href="css/ueblueprint-node-value-type-color.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Hello</div>
|
||||
<script type="module">
|
||||
import UEBlueprintObject from "./js/UEBlueprintObject.js"
|
||||
import UEBlueprint from "./js/UEBlueprint.js"
|
||||
let node1 = new UEBlueprintObject()
|
||||
node1.addLocation([100, 100])
|
||||
let blueprint = new UEBlueprint()
|
||||
blueprint.addNode(node1)
|
||||
document.querySelector('body').appendChild(blueprint.getDOMElement())
|
||||
</script>
|
||||
<script type="module">
|
||||
/*
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
let leftmost = Number.MAX_SAFE_INTEGER;
|
||||
let topmost = Number.MAX_SAFE_INTEGER;
|
||||
let draggableElements = document.querySelectorAll('.ueb-node').forEach(function (node) {
|
||||
new UEBlueprintDrag(node)
|
||||
leftmost = Math.min(leftmost, node.offsetLeft)
|
||||
topmost = Math.min(leftmost, node.offsetTop)
|
||||
})
|
||||
document.querySelectorAll('.ueb-grid').forEach(function (grid) {
|
||||
let obj = new UEBlueprintDragScrollGrid(grid, {
|
||||
'clickButton': 2,
|
||||
'exitGrabSameButtonOnly': true,
|
||||
'expandGridSize': 200
|
||||
})
|
||||
obj.stepSize = 1
|
||||
let viewportWidth = grid.parentElement.clientWidth
|
||||
let viewportHeight = grid.parentElement.clientHeight
|
||||
grid.style.setProperty('--ueb-translateX', Math.round(viewportWidth / 2))
|
||||
grid.style.setProperty('--ueb-translateY', Math.round(viewportHeight / 2))
|
||||
grid.style.setProperty('--ueb-additionalX', 0)
|
||||
grid.style.setProperty('--ueb-additionalY', 0)
|
||||
})
|
||||
});*/
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user