diff --git a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.idx b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.idx similarity index 98% rename from pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.idx rename to pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.idx index f0ad81a0..a115939c 100644 Binary files a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.idx and b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.idx differ diff --git a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.pack b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.pack similarity index 99% rename from pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.pack rename to pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.pack index d3aa6714..32e760c1 100644 Binary files a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.pack and b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.pack differ diff --git a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.rev b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.rev similarity index 91% rename from pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.rev rename to pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.rev index e75cea26..e8974c33 100644 Binary files a/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-cee964a1e325ed338ecd63a990839efa6ecdd023.rev and b/pr-preview/pr-65/bare_pr_preview/objects/pack/pack-fd5e4e256db2022cde860fee7431094e5989400b.rev differ diff --git a/pr-preview/pr-65/js/draw/app.js b/pr-preview/pr-65/js/draw/app.js index 2f045b71..b978ca0b 100644 --- a/pr-preview/pr-65/js/draw/app.js +++ b/pr-preview/pr-65/js/draw/app.js @@ -1,6 +1,6 @@ import { Application, Container } from "../pixi.min.mjs"; -const SPEED = 0.3; +const SPEED = 0.5; const MARGIN = 100; const pixi = { diff --git a/pr-preview/pr-65/js/draw/box.js b/pr-preview/pr-65/js/draw/box.js index 69603e57..327a8a9a 100644 --- a/pr-preview/pr-65/js/draw/box.js +++ b/pr-preview/pr-65/js/draw/box.js @@ -1,7 +1,57 @@ -import { Graphics, BitmapText, Assets } from "../pixi.min.mjs"; +import { Graphics, Assets, Sprite, Text, TextStyle } from "../pixi.min.mjs"; import { getContainer, getElements } from "./app.js"; -const TOP_MARGIN = 20; +const MARGIN = 20; +const PADDING = 5; + +function createText(text, { fontFamily, fontSize, fontWeight, align, fill }) { + return new Text({ + text, + style: new TextStyle({ + fontFamily, + fontSize, + fontWeight, + align, + fill, + }), + resolution: 2, + }); +} + +function createObjectModal(lines) { + const text = createText(lines.join("\n"), { + fontFamily: "sans-serif", + fontSize: 14, + fontWeight: "normal", + align: "center", + fill: "black", + }); + + const width = text.width + PADDING; + const height = text.height + 2 * MARGIN; + + const box = new Graphics(); + box.roundRect(0, 0, width + PADDING, height + PADDING, 5); + box.fill("#f1f1f1"); + box.stroke({ width: 1, color: "#000000" }); + box.addChild(text); + text.position.set((box.width - text.width) / 2, MARGIN); + + return box; +} + +function renderObjectModal(objectModal, x, y) { + const container = getContainer(); + objectModal.position.set(x, y); + container.addChild(objectModal); +} + +function removeObjectModal(objectModal) { + const container = getContainer(); + if (objectModal !== null) { + container.removeChild(objectModal); + } +} export function addBox(box) { const elements = getElements(); @@ -12,64 +62,72 @@ export function addBox(box) { export function buildBox(object) { const box = new Graphics(); - box.roundRect(object.x, object.y, object.width, object.height, object.radius); + box.roundRect(0, 0, object.width, object.height, object.radius); box.fill(object.color); box.stroke({ width: 2, color: "#000000" }); return box; } +export function addHoverModal(box, lines) { + let objectModal = null; + + box + .on("pointerover", () => { + objectModal = createObjectModal(lines, box.width); + const objectModalWidth = parseInt(objectModal.width); + const boxWidth = parseInt(box.width); + const x = parseInt(box.position.x); + const xPosition = (boxWidth - objectModalWidth) / 2 + x; + const y = box.position.y; + + renderObjectModal(objectModal, xPosition, y); + + box.on("pointerdown", () => { + removeObjectModal(objectModal); + }); + }) + .on("pointerout", () => { + removeObjectModal(objectModal); + }); +} + export function addTitleToBox(title, box) { - const boxTitle = new BitmapText({ - text: title, - style: { - fontFamiliy: "sans-serif", - fontSize: 16, - align: "center", - fill: "black", - fontWeight: "bold", - }, + const boxTitle = createText(title, { + fontFamily: "sans-serif", + fontSize: 20, + align: "center", + fill: "black", + fontWeight: "bold", }); box.addChild(boxTitle); - boxTitle.y = box.y + TOP_MARGIN; - boxTitle.x = box.x + (box.width - boxTitle.width) / 2; - return boxTitle.y; + boxTitle.position.set((box.width - boxTitle.width) / 2, MARGIN); + return boxTitle.position.y + boxTitle.height + 12; } export function addLinesToBox(lines, box, y) { - let prevY = y; - lines.forEach((line) => { - const boxLine = new BitmapText({ - text: line, - style: { - fontFamily: "sans-serif", - fontSize: 14, - align: "center", - fill: "black", - }, - }); - box.addChild(boxLine); - boxLine.y = prevY + 10; - boxLine.x = box.x + (box.width - boxLine.width) / 2; - prevY = boxLine.y + boxLine.height; + const text = createText(lines.join("\n"), { + fontFamily: "sans-serif", + fontSize: 16, + fontWeight: "normal", + align: "center", + fill: "black", + width: box.width, }); - - return prevY; + box.addChild(text); + text.position.set((box.width - text.width) / 2, y); + return text.position.y + text.height; } export async function svgElementToPixiSprite(src) { - const sprite = await Assets.load({ - src, - data: { - parseAsGraphicsContext: true, - }, - }); - const graphics = new Graphics(sprite); - return graphics; + const asset = await Assets.load(src); + const sprite = Sprite.from(asset); + sprite.width = 50; + sprite.height = 50; + return sprite; } export function addImageToBox(sprite, box, y) { box.addChild(sprite); - sprite.y = y; - sprite.x = box.x + (box.width - sprite.width) / 2; - return sprite.y + sprite.height; + sprite.position.set((box.width - sprite.width) / 2, y); + return sprite.position.y + sprite.height; } diff --git a/pr-preview/pr-65/js/draw/link.js b/pr-preview/pr-65/js/draw/link.js new file mode 100644 index 00000000..8137383b --- /dev/null +++ b/pr-preview/pr-65/js/draw/link.js @@ -0,0 +1,121 @@ +import { Graphics } from "../pixi.min.mjs"; +import { getContainer } from "./app.js"; + +function fromPoints(boxFrom) { + return [boxFrom.x + boxFrom.width / 2, boxFrom.y + boxFrom.height]; +} + +function toPoints(boxFrom, boxTo) { + const fromX = boxFrom.x + boxFrom.width / 2; + const fromY = boxFrom.y + boxFrom.height; + const toX = boxTo.x + boxTo.width / 2; + const toY = boxTo.y; + + let cpFromY, cpToY, cpFromX, cpToX; + + if (toY > fromY) { + cpFromY = (toY - fromY) / 2 + fromY; + cpToY = cpFromY; + } else { + cpFromY = (fromY - toY) / 2 + fromY; + cpToY = toY - (fromY - toY) / 2; + } + if (toX > fromX) { + cpFromX = (toX - fromX) / 4 + fromX; + cpToX = (3 * (toX - fromX)) / 4 + fromX; + } else { + cpFromX = (3 * (fromX - toX)) / 4 + toX; + cpToX = (fromX - toX) / 4 + toX; + } + return [cpFromX, cpFromY, cpToX, cpToY, toX, toY]; +} + +function bezierCurve({ + fromX, + fromY, + cpFromX, + cpFromY, + cpToX, + cpToY, + toX, + toY, + color, +}) { + const curve = new Graphics(); + curve.moveTo(fromX, fromY); + curve.bezierCurveTo(cpFromX, cpFromY, cpToX, cpToY, toX, toY); + curve.stroke({ width: 2, color }); + return curve; +} + +export function drawBezierLink(link) { + const [fromX, fromY] = fromPoints(link.from); + const [cpFromX, cpFromY, cpToX, cpToY, toX, toY] = toPoints( + link.from, + link.to + ); + + let curve = bezierCurve({ + fromX: fromX + link.xShift, + fromY: fromY, + cpFromX: cpFromX + link.xShift, + cpFromY: cpFromY, + cpToX: cpToX + link.xShift, + cpToY: cpToY, + toX: toX + link.xShift, + toY: toY, + color: link.color, + }); + + const boxFrom = link.from.renderedBox; + const boxTo = link.to.renderedBox; + + const container = getContainer(); + boxFrom.on("pointerdown", () => { + boxFrom.on("pointermove", () => { + container.removeChild(curve); + const [fromX, fromY] = fromPoints(boxFrom); + const [cpFromX, cpFromY, cpToX, cpToY, toX, toY] = toPoints( + boxFrom, + boxTo + ); + curve = bezierCurve({ + fromX: fromX + link.xShift, + fromY: fromY, + cpFromX: cpFromX + link.xShift, + cpFromY: cpFromY, + cpToX: cpToX + link.xShift, + cpToY: cpToY, + toX: toX + link.xShift, + toY: toY, + color: link.color, + }); + container.addChild(curve); + }); + }); + + boxTo.on("pointerdown", () => { + boxTo.on("pointermove", () => { + container.removeChild(curve); + const [fromX, fromY] = fromPoints(boxFrom); + const [cpFromX, cpFromY, cpToX, cpToY, toX, toY] = toPoints( + boxFrom, + boxTo + ); + curve = bezierCurve({ + fromX: fromX + link.xShift, + fromY: fromY, + cpFromX: cpFromX + link.xShift, + cpFromY: cpFromY, + cpToX: cpToX + link.xShift, + cpToY: cpToY, + toX: toX + link.xShift, + toY: toY, + color: link.color, + }); + container.addChild(curve); + }); + }); + + container.addChild(curve); +} diff --git a/pr-preview/pr-65/js/draw/render.js b/pr-preview/pr-65/js/draw/render.js index dc209035..dee61bff 100644 --- a/pr-preview/pr-65/js/draw/render.js +++ b/pr-preview/pr-65/js/draw/render.js @@ -2,29 +2,29 @@ export async function renderObjects(objects) { const datatypes = objects.datatypes; const associations = objects.associations; - for (const collection of Object.values(associations)) { - for (const association of collection) { - await association.draw(); - } - } - for (const elements of Object.values(datatypes)) { const { collection, oneToMany, oneToOne } = elements; + for (const object of collection) { + await object.draw(); + } + for (const links of Object.values(oneToMany)) { for (const link of links) { - await link.draw(); + link.draw(); } } for (const links of Object.values(oneToOne)) { for (const link of links) { - await link.draw(); + link.draw(); } } + } - for (const object of collection) { - await object.draw(); + for (const collection of Object.values(associations)) { + for (const association of collection) { + association.draw(); } } } diff --git a/pr-preview/pr-65/js/lib/generate-svg.js b/pr-preview/pr-65/js/lib/generate-svg.js index e0490f1b..39088ed4 100644 --- a/pr-preview/pr-65/js/lib/generate-svg.js +++ b/pr-preview/pr-65/js/lib/generate-svg.js @@ -1,5 +1,9 @@ export async function textToSVG(text) { - const svg = await MathJax.tex2svg(text).firstElementChild; + const mathjaxContainer = await MathJax.tex2svgPromise(text); + const svg = mathjaxContainer.firstElementChild; + + svg.setAttribute("width", "50px"); + svg.setAttribute("height", "50px"); const src = "data:image/svg+xml;base64," + diff --git a/pr-preview/pr-65/js/lib/graphic-primitives.js b/pr-preview/pr-65/js/lib/graphic-primitives.js index 96ed49a7..121ea2af 100644 --- a/pr-preview/pr-65/js/lib/graphic-primitives.js +++ b/pr-preview/pr-65/js/lib/graphic-primitives.js @@ -44,39 +44,10 @@ export function drawTextLines(ctx, lines, boxCenterX, y, n) { } export function drawBezierLink(ctx, link) { - // const boxFrom = link.from; - // const boxTo = link.to; - // const fromX = boxFrom.x + boxFrom.width / 2; - // const fromY = boxFrom.y + boxFrom.height; - // const toX = boxTo.x + boxTo.width / 2; - // const toY = boxTo.y; - // if (toY > fromY) { - // var cpFromY = (toY - fromY) / 2 + fromY; - // var cpToY = cpFromY; - // } else { - // cpFromY = (fromY - toY) / 2 + fromY; - // cpToY = toY - (fromY - toY) / 2; - // } - // if (toX > fromX) { - // var cpFromX = (toX - fromX) / 4 + fromX; - // var cpToX = (3 * (toX - fromX)) / 4 + fromX; - // } else { - // cpFromX = (3 * (fromX - toX)) / 4 + toX; - // cpToX = (fromX - toX) / 4 + toX; - // } // ctx.save(); // ctx.strokeStyle = link.color; // ctx.lineWidth = 2; // ctx.beginPath(); - // ctx.moveTo(fromX + link.xShift, fromY); - // ctx.bezierCurveTo( - // cpFromX + link.xShift, - // cpFromY, - // cpToX + link.xShift, - // cpToY, - // toX + link.xShift, - // toY - // ); // ctx.stroke(); // ctx.restore(); } diff --git a/pr-preview/pr-65/js/types/links.js b/pr-preview/pr-65/js/types/links.js index 5a7c7391..ed710760 100644 --- a/pr-preview/pr-65/js/types/links.js +++ b/pr-preview/pr-65/js/types/links.js @@ -1,4 +1,5 @@ -import { drawBezierLink, drawStraightLink } from "../lib/graphic-primitives.js"; +import { drawStraightLink } from "../lib/graphic-primitives.js"; +import { drawBezierLink } from "../draw/link.js"; const colors = { "parents": "#AA0000", @@ -20,8 +21,8 @@ export class Link { this.xShift = 0; } - draw(ctx) { - drawBezierLink(ctx, this); + draw() { + drawBezierLink(this); } isVisible(x, y, width, height) { diff --git a/pr-preview/pr-65/js/types/objects.js b/pr-preview/pr-65/js/types/objects.js index 133b6e51..d4cd81e7 100644 --- a/pr-preview/pr-65/js/types/objects.js +++ b/pr-preview/pr-65/js/types/objects.js @@ -9,10 +9,13 @@ import { addLinesToBox, svgElementToPixiSprite, addImageToBox, + addHoverModal, } from "../draw/box.js"; import { textToSVG } from "../lib/generate-svg.js"; const TOP_MARGIN = 45; +const IMAGE_MARGIN = 10; +const IMAGE_HEIGHT = 30; class EDMObject { constructor() { @@ -29,8 +32,51 @@ class EDMObject { async draw() { const box = buildBox(this); - const nextY = addTitleToBox(this.collectionName, box); + this.renderedBox = box; addBox(box); + box.position.set(this.x, this.y); + const nextY = addTitleToBox(this.constructor.name, box); + + box.cursor = "pointer"; + box.eventMode = "static"; + + let prevX = box.x + box.width / 2; + let prevY = box.y + box.height / 2; + + box + .on( + "pointerdown", + function () { + this.on( + "pointermove", + function (event) { + const container = box.parent; + + const eventX = container.toLocal(event.data.global).x; + const eventY = container.toLocal(event.data.global).y; + + const deltaX = eventX - prevX; + const deltaY = eventY - prevY; + + this.position.x += deltaX; + this.position.y += deltaY; + prevX = eventX; + prevY = eventY; + }, + box + ); + }, + box + ) + .on( + "pointerup", + function () { + this.off("pointermove"); + }, + box + ); + + addHoverModal(box, this.objectModalLines()); return [box, nextY]; } @@ -52,11 +98,9 @@ class EDMObject { ); } - showObjectTip(ctx) { - const x = this.x; - const y = this.y - 10; + objectModalLines() { const collectionName = "Collection: " + this.collectionName; - drawObjectInfoTip(ctx, x, y, collectionName); + return [collectionName]; } } @@ -71,19 +115,6 @@ export class MCParticle extends EDMObject { } async draw() { - // const boxCenterX = this.x + this.width / 2; - // const topY = this.y + TOP_MARGIN; - - // const bottomY = this.y + this.height * 0.65; - // const bottomLines = []; - // bottomLines.push("p = " + this.momentum + " GeV"); - // bottomLines.push("d = " + this.vertex + " mm"); - // bottomLines.push("t = " + this.time + " ns"); - // bottomLines.push("m = " + this.mass + " GeV"); - // bottomLines.push(parseCharge(this.charge)); - // const svgElement = textToSVGElement(this.name); - // addBox(this); - let [box, nextY] = await super.draw(); const topLines = []; @@ -102,20 +133,35 @@ export class MCParticle extends EDMObject { topLines.push("Sim. stat.: " + simulatorStatusString); nextY = addLinesToBox(topLines, box, nextY); - const svg = await textToSVG(this.name); - const sprite = await svgElementToPixiSprite(svg); - nextY = addImageToBox(sprite, box, nextY); + + const imageY = nextY + IMAGE_MARGIN; + + textToSVG(this.name) + .then((src) => { + const sprite = svgElementToPixiSprite(src); + return sprite; + }) + .then((sprite) => addImageToBox(sprite, box, imageY)) + .catch((e) => console.error("Error loading SVG: ", e)); + + nextY += IMAGE_HEIGHT + 2 * IMAGE_MARGIN; + + const bottomLines = []; + bottomLines.push("p = " + this.momentum + " GeV"); + bottomLines.push("d = " + this.vertex + " mm"); + bottomLines.push("t = " + this.time + " ns"); + bottomLines.push("m = " + this.mass + " GeV"); + bottomLines.push(parseCharge(this.charge)); + + addLinesToBox(bottomLines, box, nextY); } - showObjectTip(ctx) { - const x = this.x; - const y = this.y - 10; + objectModalLines() { const collectionName = "Collection: " + this.collectionName; const simulatorStatus = getSimStatusDisplayValuesFromBit( this.simulatorStatus ); - - drawObjectInfoTip(ctx, x, y, collectionName, ...simulatorStatus); + return [collectionName, ...simulatorStatus]; } static setup(mcCollection) { diff --git a/pr-preview/pr-65/js/views/views.js b/pr-preview/pr-65/js/views/views.js index ee9c9efd..9f2443c6 100644 --- a/pr-preview/pr-65/js/views/views.js +++ b/pr-preview/pr-65/js/views/views.js @@ -73,8 +73,8 @@ const drawView = async (view) => { // } await renderObjects(viewObjects); - setInfoButtonName(getView()); scrollFunction(); + setInfoButtonName(getView()); // filters(viewObjects, viewCurrentObjects, viewVisibleObjects); };