NameSpace Issue in JointJS version 3 - javascript

I am trying to convert a legacy app from JointJS v2.2.1 to v3.0.2. I’m hitting an error others have found:
Uncaught Error: dia.ElementView: markup required. (joint.min.js:8)
A helpful person said: “Please note you need to be careful with the cellViewNamespace for the dia.Paper and cellNamespace option for the dia.Graph in this setup. Running this snippet is a quick check you've set up the namespaces correctly:
const cells = JSON.stringify(graph.toJSON());
graph.clear();
graph.fromJSON(JSON.parse(cells));
”
Can anyone offer additional help? I don’t know enough about JointJS to resolve this issue and I don’t really understand the code snippet.

I met a similar error saying 'markup required' just today when using jointjs with Vue. I followed the code and found that it is assuming 'joint' is present in global environment. So I add the following line in my code, and the error is gone:
import * as joint from 'jointjs'
window.joint = joint
Hopefully this helps.

If there is no joint variable in the global environment, you need to pass the shapes namespace explicitly to the graph (for models) and the paper (for views).
If you do not mind adding joint reference to the window object see #duanbw answer.
Built-in shapes
import { shapes, dia } from 'jointjs'
const graph = new dia.Graph({ /* attributes of the graph */ }, { cellNamespace: shapes });
const paper = new dia.Paper({ cellViewNamespace: shapes });
Custom shapes
If you define your own shapes do not forget to add it to the namespace as well (this also apply for the custom views).
const { standard, devs } = shapes;
// Custom Element Model
const MyRectangle = standard.Rectangle.define('myNamespace.Rectangle', {
size: { width: 100, height: 100 },
attrs: { body: { fill: 'red' }}
});
const graph = new dia.Graph({}, {
cellNamespace: {
// Optionally, cherry-pick namespaces/shapes you will use in your application
standard,
devs,
myNamespace: { Rectangle: MyRectangle }
}
});
const myRectangle = new MyRectangle();
myRectangle.addTo(graph);
const circle = new standard.Circle();
circle.addTo(graph);

Related

Three.js : Box3 from an object not in scene

I have a problem adding a Bounding Box from an object in a different module. Right now, it is working fine as long as I write everything in my main function, but as soon as I create my function in a different file, and import in in the main file, it's not working anymore.
The error code I get :
Uncaught TypeError: Cannot read properties of undefined (reading 'updateWorldMatrix')
at Box3.expandByObject (three.module.js:4934:10)
at Box3.setFromObject (three.module.js:4852:15)
at camCollision (camColliders.js:68:37)
at HTMLDocument.<anonymous> (World.js:355:7)
camColliders.js being the file I'm trying to put the function in, and World.js my main file.
Here is the function :
function camCollision() {
const camBB = new Box3().setFromObject(camSphereDetector);
const boule1BB = new Box3().setFromObject(boule1Obj);
boule1BB.name = 'first';
const boule2BB = new Box3().setFromObject(boule2Obj);
boule2BB.name = 'second';
const boule3BB = new Box3().setFromObject(boule3Obj);
boule3BB.name = 'third';
const boulesBB = [boule1BB, boule2BB, boule3BB];
boulesBB.forEach((bbs) => {
if (bbs.intersectsBox(camBB)) {
console.log('got it');
}
});
}
document.addEventListener('mouseup', () => {
camCollision();
});
When I'm doing this in a separate file, i'm first importing the objects from another file and they are all Mesh.
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene first, and I'm only adding them in the scene in World.js. Yet, the error is leading me to line 68, the variable for 'boule1BB', which is weird because 'camBB' should have the problem first ?
Here is how I'm creating the Box3 (these are just copying some GLTF objects position and size, cause I can't manage to get a Box3 from it) :
const boule1Obj = new Mesh(
new SphereGeometry(2, 32, 16),
new MeshBasicMaterial({ color: 'red', transparent: true, opacity: 0 }),
);
boule1Obj.position.set(10, -3.5, 0);
Then, I would like to know, if I got the problem right : is there a way to create a Box3 in a different js file, from an object that is not added to the scene yet (even if it should when the function is being called) ? With a different way than 'setFromObject' maybe ? Or am I not understanding the real problem.
For a bit of context, the aim is to provide some informations about each model when the user clicks on it, and I'm planning on putting the informations as '.name' for each Mesh corresponding to a model. So I don't want to write all this stuff in the main file, but rather on a separate one.
I hope this is clear enough, and I've given enough content for a solution to be found. I couldn't find anyone else having this problem. If you need anything else, please tell me !
Thanks already for your help !
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene in World.js.
Not so. Since a constructed THREE.Mesh has a shape with extents (from its geometry) and a transform (by default, translated to the origin, with no scaling or rotation), Three.js can and will determine a bounding box from that information as though the mesh were in the scene. I've posted a demo of this on CodePen.
Nor should defining the object in one file and referencing it another make any difference, as long as the object is in scope and initialized at the time it's bound to.
Here, I suspect that you're assigning boule1Obj, boule2Obj, and boule3Obj in World.js. In that case, the imported function is being hoisted before the variables are assigned, and the function is seeingbinding to them as unassignedundefined.
Try changing camCollision() to accept the bouleXObjs as arguments.
function camCollision(...objs) {
const camBB = new Box3().setFromObject(camSphereDetector);
for(let i = 0; i < objs.length; i++) {
const objBB = new Box3().setFromGeometry(objs[i]);
objBB.name = `Bounding Box ${i + 1}`;
if(objBB.intersectsBox(camBB)) {
console.log("Got it!");
}
}
}
And then call it as
document.addEventListener("mouseup", () => {
camCollision(boule1Obj, boule2Obj, boule3Obj);
});

How to make Phaser3 GlowFilterPostFx work in an ES6 project?

I'm trying to apply a dynamic glow effect to some of my Phaser3 game objects.
There's no built-in glow effect, but the framework author publishes a separate package with a bunch of plugins that includes a glow effect. There's also a codepen demo of that plugin, although that code is unusable because it relies on direct download of the plugin at runtime.
There is also a separate doc page for that plugin which enumerates the recipes a dev might choose.
I have not been able to adapt a working version from any of this. The best I can do is to have my project build and run with no visible change, and zero proof that the glow tech is even engaged. The worst is that I get a fatal runtime error as soon as I attempt to reference the glow plugin.
Here's a version based on the recipes from "Notes of Phaser 3":
import Phaser from 'phaser'
import GlowFilterPostFx from 'phaser3-rex-plugins/plugins/glowfilterpipeline.js'
new Phaser.Game({
type: Phaser.CANVAS,
canvas,
width: 550, height: 400,
scene: [SceneWithGlow],
pipeline: [GlowFilterPostFx]
})
class SceneWithGlow extends Phaser.Scene {
preload() {
this.load.image('shroom', '/shroom.png')
}
create() {
let shroom = this.add.image(100, 100, 'shroom')
this.add.existing(shroom)
// this version runs but has no effect
shroom.setPostPipeline(GlowFilterPostFx)
// also no effect; I have no idea this signature is correct
shroom.setPostPipeline(GlowFilterPostFx, { intensity: 1 })
// also has no effect, and would affect things that shouldn't glow
this.cameras.main.setPostPipeline(GlowFilterPostFx)
// this version throws `pipelineInstance is null` when .add() is called
let pipelineInstance = this.plugins.get('rexGlowFilterPipeline')
pipelineInstance.add(shroom)
pipelineInstance.intensity = 1
}
}
And here's an alternative version based on a sample from the repo that publishes the effect, which appears to a module-based version of that codepen demo:
import Phaser from 'phaser'
import GlowFilterPipelinePlugin from 'phaser3-rex-plugins/plugins/glowfilterpipeline-plugin.js'
new Phaser.Game({
type: Phaser.CANVAS,
canvas,
width: 550, height: 400,
scene: [SceneWithGlow],
plugins: {
global: [{
key: 'rexGlowFilterPostFx',
plugin: GlowFilterPipelinePlugin,
start: true
}]
}
})
class SceneWithGlow extends Phaser.Scene {
preload() {
this.load.image('shroom', '/shroom.png')
}
create() {
let shroom = this.add.image(100, 100, 'shroom')
this.add.existing(shroom)
// this version throws `pipeline is undefined` when .add() is called
let postFxPlugin = this.plugins.get('rexGlowFilterPostFx')
postFxPlugin.add(shroom)
postFxPlugin.intensity = 1
}
}
It should be possible to apply a fixed-intensity glow effect without downloading the glow tech from github at runtime.
I don't think I care whether it's registered as a "pipeline" or a "plugin." I just want it to work, and despite what appears to be an abundance of help directly from the framework creator, none of the material online can be refactored in a working version.
TL;DR
I added type: Phaser.WEBGL to my gameConfig and also added GlowFilterPipelinePlugin as a GLOBAL plugin.
Works like a charm.
Summary
I'm not sure if you're still looking for an answer here, but for everyone having trouble implementing this on Typescript. Here's an issue I opened on the official repo This really helps me a lot.
Here is an example of the Typescript implementation.

Style node of Dabeng's OrgChart library

I am using the Dabeng Orgchart library, but I would like to customize the nodes, specifically creating a diamond instead of the squares they have in most examples. I have seen the createNode method, and I have found various CSS for creating a diamond but I can't figure out how to integrate it in dabeng org chart. What I want to do is display a diamond if some conditions are met, and the default square shapes if others are met. I have searched the web, but no example for changing the shape.
I am currently using the nodeTemplate attribute for the orgchart. Example:
var oc = $('#container').orgchart({
...
'nodeTemplate': orgTemplate,
...
});
In your orgtemplate function, data is whatever you have included in your orgchart data (in the example it would be name and title). You can stuff this object with other flags. For example, I have a chart in which I create new nodes and allow users to enter data into the node before committing it to the graph. I have a flag in my data object for data.isSaved to tell my template whether or not this node is saved or not. If it is saved, I have inline html checks (in AngularJS using ngIf's and the like, if you're familiar with AngularJS at all) to change the template based on the data.
In VanillaJS, you can just return pure HTML without the $compile and all that attached to pump in your own node template. You could actually do your check within the function for example:
function orgTemplate(data) {
if(data.isDiamond) {
return '<div class="diamond">...</div>';
} else {
return '<div class="square">...</div>';
}
}
I'm using AngularJS in my website so I define new scopes and use angular directives to make it more expandable. This is for reference for anyone else who stumbles upon this. My orgTemplate function is defined below.
function orgTemplate(data) {
var newScope = $scope.$new(true);
newScope.data = data;
return ( $compile('<div data-ng-include="\'.../template.html\'"></div>')(newScope));
}
Here's the orgChart Github as I'm sure you've browsed many times. If you look at the bottom you will see the nodeTemplate attribute definition I mention above. Hope this helps!
Side Note: I have had some trouble with styling when using custom templates, especially when defining different graph directions (i.e. 'l2r').
You can now customize your own node structure or shape with option "ndoeTemplate":
var nodeTemplate = function(data) {
return `
<span class="office">${data.office}</span>
<div class="title">${data.name}</div>
<div class="content">${data.title}</div>
`;
}
var oc = $('#chart-container').orgchart({
'data' : ds,
'nodeTemplate': nodeTemplate
});
Feel free to play around with this demo.
I would suggest you to use getorgchart instead it is highly customizable
http://www.getorgchart.com/Demos/Create-Your-Own-Theme-4

Cesium - why is scene.pickPositionSupported false

I'm ultimately trying to draw a polygon on top of my house. I can do that.
The problem is that on zoom-out, zoom-in, and rotation (or camera move) the polygon doesn't stick to the top of my house. I received great help from this answer. So, now I'm trying to go through the sample code but there is a lot of Cesium methods and functionality that I need to learn.
The sample code I am trying to follow is located in the gold standard that appears to be baked into the existing camera controller here.
I call testMe with the mousePosition as Cartesian3 and the SceneMode is 3D, so pickGlobe is executed.
Here is my code:
var pickedPosition;
var scratchZoomPickRay = new Cesium.Ray();
var scratchPickCartesian = new Cesium.Cartesian3();
function testMe(mousePosition) {
if (Cesium.defined(scene.globe)) {
if(scene.mode !== Cesium.SceneMode.SCENE2D) {
pickedPosition = pickGlobe(viewer, mousePosition, scratchPickCartesian);
} else {
pickedPosition = camera.getPickRay(mousePosition, scratchZoomPickRay).origin;
}
}
}
var pickGlobeScratchRay = new Cesium.Ray();
var scratchDepthIntersection = new Cesium.Cartesian3();
var scratchRayIntersection = new Cesium.Cartesian3();
function pickGlobe(viewer, mousePosition, result) {
var globe = scene.globe;
var camera = scene.camera;
if (!Cesium.defined(globe)) {
return undefined;
}
var depthIntersection;
if (scene.pickPositionSupported) {
depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
}
var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);
var pickDistance;
if(Cesium.defined(depthIntersection)) {
pickDistance = Cesium.Cartesian3.distance(depthIntersection, camera.positionWC);
} else {
pickDistance = Number.POSITIVE_INFINITY;
}
var rayDistance;
if(Cesium.defined(rayIntersection)) {
rayDistance = Cesium.Cartesian3.distance(rayIntersection, camera.positionWC);
} else {
rayDistance = Number.POSITIVE_INFINITY;
}
var scratchCenterPosition = new Cesium.Cartesian3();
if (pickDistance < rayDistance) {
var cart = Cesium.Cartesian3.clone(depthIntersection, result);
return cart;
}
var cart = Cesium.Cartesian3.clone(rayIntersection, result);
return cart;
}
Here is my problem:
Here is the result:
Here are my questions to get this code working:
1. How do I get the scene.pickPositionSupported set to true? I'm using Chrome on Windows 10. I cannot find in the sample code anything about this and I haven't had much luck with the documentation or Google.
2. Why is rayIntersection not getting set? ray and scene have values and scratchRayIntersection in an empty Cartesian3.
I think if I can get those two statements working, I can probably get the rest of the pickGlobe method working.
WebGLGraphics Report:
I clicked on Get WebGL and the cube is spinning!
Picking positions requires that the underlying WebGL implementation support depth textures, either through the WEBGL_depth_texture or WEBKIT_WEBGL_depth_texture extensions. scene.pickPositionSupported is returning false because this extension is missing. You can verify this by going to http://webglreport.com/ and looking at the list of extensions; I have both of the above listed there. There is nothing you can do in your code itself to make it suddenly return true, it's a reflection of the underlying browser.
That being said, I know for a fact that Chrome supports the depth texture and it works on Windows 10, so this sounds like a likely video card driver issue. I full expect downloading and installing the latest drivers for your system to solve the problem.
As for rayIntersection, from a quick look at your code I only expect it to be defined if the mouse is actually over the globe, which may not always be the case. If you can reduce this to a runnable Sandcastle example, it would be easier for me to debug.
OK. So it turned out that I had a totally messed up Cesium environment. I had to delete it and reinstall it in my project (npm install cesium --save-dev). Then I had to fix a few paths and VOILA! It worked. Thanks to both of you for all your help.

How do I access Chart.js default settings? (& related -- how do I turn the tool tips on?)

I am using a Chart.js doughnut chart. The chart appears fine. However, it is missing tool tips (as have all other charts I have ever made using Chart.js). Why is this, and how do I turn them on? The online documentation claims that I can access global defaults (in which the tool tips can be set on/off, although the site claims that they default to be on) at Chart.defaults.global, which doesn't work for me because Chart.defaults doesn't even exist. I am trying to access these defaults so I can turn the tool tips on.
Thanks for any help you can provide.
var context = document.getElementById("scoreChart").getContext("2d");
var chartData = [
{
label: "Number correct",
value: $scope.numRight,
color: "rgb(134, 202,54)",
highlight: "rgb(100,100,100)"
//not sure what highlight does
},
{
label: "Number wrong",
value: $scope.myTest.testQuestions.length - $scope.numRight,
color: '#7c0b10',
highlight: 'rgb(10,10,10)'
}
];
var theChart = new Chart(context);
var theDough = theChart.Doughnut(chartData/*, chartOptions*/);
console.log("Here is the chart object:");
console.log(theChart);
console.log("Chart.Doughnut object:");
console.log(theChart.Doughnut);
console.log("Chart.Doughnut.defaults:");
console.log(theChart.Doughnut.defaults); // <-- This works
console.log("theChart.defaults:");
console.log(theChart.defaults); // <--This is undefined
console.log("Chart.defaults.global:");
console.log(Chart.defaults.global); // throws an error
// because Chart.defaults is undefined
UPDATE: Fixed it. The bower version of Chart.js is extremely old. see my answer below.
I downloaded Chart.js using Bower. The version of Chart.js listed on Bower is old. That is why the documentation was wrong. I had to cut and paste the newest Chart.js from Github into my project. And voila, tooltips and the object behaves as the documentation says it should.
Alternatively, and easier, as JAAulde pointed out, you can just set your bower dependecies to point to:
"chartjs": "master"
and that should automatically pull the right copy.
theChart and theDough should be set in one go, not as separate objects. For example:
var theChart = new Chart(ctx).Doughnut(data);
If this still does not get you tooltips, pass in and modify the following options:
var theChart = new Chart(ctx).Doughnut(data, {
// Boolean - Determines whether to draw tooltips on the canvas or not
showTooltips: true,
});
For further variety in your tooltips styling, check out the documentation for global chart options on this page: http://www.chartjs.org/docs/#getting-started-global-chart-configuration

Categories

Resources