what's wrong with this code ? I got undefined - javascript-objects

Code:
const john = { fullName: 'johny Rodes', mass: 92, height: 1.95, calcBMI: ()=>{ this.bmi = this.mass / this.height ** 2; return this.bmi; } };
john.calcBMI();
console.log(john.bmi);

Arrow functions in javascript inherit from that calling scope, so this actually refers to the global this in your case, not the john object.
const john = {
fullName: 'johny Rodes',
mass: 92,
height: 1.95,
// calcBMI is an arrow function, so "this" is bound to the calling state
calcBMI: () => {
this.bmi = this.mass / this.height ** 2;
return this.bmi;
},
// "this" in calcBMI2 refers to this object
calcBMI2() {
this.bmi = this.mass / this.height ** 2;
return this.bmi;
},
};
As mass and height do not exist in the calling scope, the arrow function results in undefined. However, the regular function inherits the scope of the class it belongs to.
john.calcBMI();
console.log(john.bmi); // => undefined
john.calcBMI2();
console.log(john.bmi); // => 24.194608809993426
If you were to set mass and height outside of the function call, it would now work.
const this.mass = 92;
const this.height = 1.95;
// the "this" in the current scope is not the "john" object
john.calcBMI();
console.log(john.bmi); // => 24.194608809993426
See this question which touches on the same subject

Related

React js, Raphael: canvas throw an Error: <path> attribute d: Expected number, "….68028259277344CNaN,NaN,NaN,NaN,…"

Framwork: React js.
Library: "raphael": "^2.2.8",
Description: canvas throw an Error: attribute d: Expected number, "….68028259277344CNaN,NaN,NaN,NaN,…".
console errors screenshot
http://jsfiddle.net/fzjc81ym/
this.canvas = Raphael('grid', '100%', '100%');
drawLine(this.canvas, path1, duration, arrowAtrr, color, strokeDasharray, strokeWidth, arrowend).then(() => this.resolve(item, callback))
const drawLine = (canvas, pathStr, duration = 1000, attr = arrowAtrr, color = Color.GREEN, strokeDasharray = '-', strokeWidth = 4, arrowend = "block-wide-long") => {
return new Promise((resolve) => {
attr.stroke = color;
attr['stroke-dasharray'] = strokeDasharray;
attr['stroke-width'] = strokeWidth;
attr['arrow-end'] = arrowend
var guidePath = canvas.path(pathStr).attr({ stroke: 'none', fill: 'none' });
var path = canvas.path(pathStr).attr({ stroke: 'none', fill: 'none' });
var totalLength = guidePath.getTotalLength(guidePath);
var startTime = new Date().getTime();
var intervalLength = 25;
var intervalId = setInterval(function () {
var elapsedTime = new Date().getTime() - startTime;
var thisLength = elapsedTime / duration * totalLength;
var subPathStr = guidePath.getSubpath(0, thisLength);
attr.path = subPathStr;
path.attr(attr)
path.animate(attr, intervalLength);
if (elapsedTime >= duration) {
clearInterval(intervalId);
resolve();
}
}, intervalLength);
});
}
it seems to happen when I use the arrow-end attribute
I didn't find an answer in other places
Maybe someone has any idea how to solve that error?
A solutions:
in my case, the arrow line was smaller than the arrow-end triangle,
so I set the min size of the path to be 11 (the length of the arrow-end).
var subPathStr = guidePath.getSubpath(0, Math.max(11, thisLength));
here the around code:
var subPathStr = guidePath.getSubpath(0, Math.max(11, thisLength));
attr.path = subPathStr;
path.attr(attr)
path.animate(attr, intervalLength);
You didnt really include enough Information for your problem but this may help.
https://www.npmjs.com/package/react-raphael
It looks like you need to call Raphael.Paper(width={300} height={300}) in order to set the width of a canvas.

Update texture of mesh using ThreeJS & Dat.Gui

I would like the texture of my Mesh to update when clicked on function.
When you click on the 'UpdateMateria' function i'd like the mesh to dispose its current texture and add a new one.
Animation Loop
startAnimationLoop = () => {
const tableBoard = this.scene.getObjectByName('tableSurface');
tableBoard.material.map = this.updateMateria;
this.renderer.render(this.scene, this.camera);
this.requestID = window.requestAnimationFrame(this.startAnimationLoop);
};
Dat.Gui
userGUI = () => {
const update = {
updateMateria: function() {
alert('Changing');
this.material.dispose();
this.material.map = texture1();
}
}
this.gui = new dat.GUI();
const controls = function() {
this.title = new controls();
this.gui.add(update, 'updateMateria')
}
}
When i put the function straight into the 'Animation Loop' this actually updates the texture to the desired one, but the current version gives me 'TypeError: Cannot read property 'dispose' of undefined'
First, you can not use the this reference in updateMateria (probably updateMaterial???). Consider to safe the this reference in a variable outside of this function and use this variable instead. Besides, it's not necessary to dispose the material if you just want to change the texture.
userGUI = () => {
const scope = this;
const update = {
updateMateria: function() {
alert('Changing');
// scope.material.dispose();
scope.material.map = texture1();
}
}
this.gui = new dat.GUI();
const controls = function() {
this.title = new controls();
this.gui.add(update, 'updateMateria')
}
three.js R108

Camera streaming service works only with localhost but not with IP address

I have implemented a service which streams camera output on html5. But it works only if I use localhost:8080 localhost if I use IP address or machine name then it does not even detect the camera.
/*global logger*/
/*
VisualInspection
========================
#file : VisualInspection.js
#version : 1.0.0
#author :
#date : 7/28/2019
#copyright :
#license : Apache 2
Documentation
========================
Describe your widget here.
*/
// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate.
define([
"dojo/_base/declare",
"mxui/widget/_WidgetBase",
"dijit/_TemplatedMixin",
"mxui/dom",
"dojo/dom",
"dojo/dom-prop",
"dojo/dom-geometry",
"dojo/dom-class",
"dojo/dom-style",
"dojo/dom-construct",
"dojo/_base/array",
"dojo/_base/lang",
"dojo/text",
"dojo/html",
"dojo/_base/event",
"VisualInspection/lib/jquery-1.11.2",
"dojo/text!VisualInspection/widget/template/VisualInspection.html",
"VisualInspection/widget/template/tf.min",
// "dojo/text!VisualInspection/widget/template/labels.json",
// "dojo/text!VisualInspection/widget/template/model.json"
], function (declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, dojoProp, dojoGeometry, dojoClass, dojoStyle, dojoConstruct, dojoArray, lang, dojoText, dojoHtml, dojoEvent, _jQuery, widgetTemplate, tf) {
"use strict";
var $ = _jQuery.noConflict(true);
var LABELS_URL = "http://pni6w2465:7777/EasyPlan/model_web/labels.json"
var MODEL_JSON = "http://pni6w2465:7777/EasyPlan/model_web/model.json"
// var tf = require(['../../VisualInspection/node_modules/#tensorflow/tfjs']);
//////////////
const TFWrapper = model => {
const calculateMaxScores = (scores, numBoxes, numClasses) => {
const maxes = []
const classes = []
for (let i = 0; i < numBoxes; i++) {
let max = Number.MIN_VALUE
let index = -1
for (let j = 0; j < numClasses; j++) {
if (scores[i * numClasses + j] > max) {
max = scores[i * numClasses + j]
index = j
}
}
maxes[i] = max
classes[i] = index
}
return [maxes, classes]
}
const buildDetectedObjects = (
width,
height,
boxes,
scores,
indexes,
classes
) => {
const count = indexes.length
const objects = []
for (let i = 0; i < count; i++) {
const bbox = []
for (let j = 0; j < 4; j++) {
bbox[j] = boxes[indexes[i] * 4 + j]
}
const minY = bbox[0] * height
const minX = bbox[1] * width
const maxY = bbox[2] * height
const maxX = bbox[3] * width
bbox[0] = minX
bbox[1] = minY
bbox[2] = maxX - minX
bbox[3] = maxY - minY
objects.push({
bbox: bbox,
class: classes[indexes[i]],
score: scores[indexes[i]]
})
}
return objects
}
var img = null;
const detect = input => {
const batched = tf.tidy(() => {
const img = tf.browser.fromPixels(input)
// Reshape to a single-element batch so we can pass it to executeAsync.
// var img = null;
// //sid
// var canvas = document.querySelector("#canvasElement");
// if (canvas.getContext) {
// var ctx = canvas.getContext("2d");
// img = canvas.toDataURL("image/png");
// }
return img.expandDims(0)
})
const height = batched.shape[1]
const width = batched.shape[2]
// const height = img.height
// const width = img.width
return model.executeAsync(batched).then(result => {
const scores = result[0].dataSync()
const boxes = result[1].dataSync()
// clean the webgl tensors
batched.dispose()
tf.dispose(result)
const [maxScores, classes] = calculateMaxScores(
scores,
result[0].shape[1],
result[0].shape[2]
)
const prevBackend = tf.getBackend()
// run post process in cpu
tf.setBackend('cpu')
const indexTensor = tf.tidy(() => {
const boxes2 = tf.tensor2d(boxes, [
result[1].shape[1],
result[1].shape[3]
])
return tf.image.nonMaxSuppression(
boxes2,
maxScores,
20, // maxNumBoxes
0.5, // iou_threshold
0.5 // score_threshold
)
})
const indexes = indexTensor.dataSync()
indexTensor.dispose()
// restore previous backend
tf.setBackend(prevBackend)
return buildDetectedObjects(
width,
height,
boxes,
maxScores,
indexes,
classes
)
})
}
return {
detect: detect
}
}
//////////////////////
// Declare widget's prototype.
return declare("VisualInspection.widget.VisualInspection", [_WidgetBase, _TemplatedMixin], {
// _TemplatedMixin will create our dom node using this HTML template.
templateString: widgetTemplate,
// DOM elements
inputNodes: null,
colorSelectNode: null,
colorInputNode: null,
infoTextNode: null,
// Parameters configured in the Modeler.
mfToExecute: "",
messageString: "",
backgroundColor: "",
// Internal variables. Non-primitives created in the prototype are shared between all widget instances.
_handles: null,
_contextObj: null,
_alertDiv: null,
_readOnly: false,
// dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties.
constructor: function () {
logger.debug(this.id + ".constructor");
this._handles = [];
},
// dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work.
postCreate: function () {
logger.debug(this.id + ".postCreate");
if (this.readOnly || this.get("disabled") || this.readonly) {
this._readOnly = true;
}
this._updateRendering();
this._setupEvents();
var video = document.querySelector("#videoElement");
var canvas = document.querySelector("#canvasElement");
// if (navigator.mediaDevices.getUserMedia) {
// navigator.mediaDevices.getUserMedia({ video: true })
// .then(function (stream) {
// video.srcObject = stream;
// })
// .catch(function (err0r) {
// console.log("Something went wrong!");
// });
// }
this.componentDidMount();
},
////////////////////////////////////////////////////////
componentDidMount: function () {
var video = document.querySelector("#videoElement");
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
const webCamPromise = navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
facingMode: 'user'
}
})
.then(stream => {
window.stream = stream
video.srcObject = stream
return new Promise((resolve, _) => {
video.onloadedmetadata = () => {
resolve()
}
})
})
const modelPromise = tf.loadGraphModel(MODEL_JSON)
const labelsPromise = fetch(LABELS_URL).then(data => data.json())
Promise.all([modelPromise, labelsPromise, webCamPromise])
.then(values => {
const [model, labels] = values
this.detectFrame(video, model, labels)
})
.catch(error => {
console.error(error)
})
}
},
detectFrame: function (video, model, labels) {
TFWrapper(model)
.detect(video)
.then(predictions => {
this.renderPredictions(predictions, labels)
requestAnimationFrame(() => {
this.detectFrame(video, model, labels)
})
})
},
renderPredictions: function (predictions, labels) {
var canvas = document.querySelector("#canvasElement");
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
// Font options.
const font = '16px sans-serif'
ctx.font = font
ctx.textBaseline = 'top'
predictions.forEach(prediction => {
const x = prediction.bbox[0]
const y = prediction.bbox[1]
const width = prediction.bbox[2]
const height = prediction.bbox[3]
const label = labels[parseInt(prediction.class)]
// Draw the bounding box.
ctx.strokeStyle = '#00FFFF'
ctx.lineWidth = 4
ctx.strokeRect(x, y, width, height)
// Draw the label background.
ctx.fillStyle = '#00FFFF'
const textWidth = ctx.measureText(label).width
const textHeight = parseInt(font, 10) // base 10
ctx.fillRect(x, y, textWidth + 4, textHeight + 4)
})
predictions.forEach(prediction => {
const x = prediction.bbox[0]
const y = prediction.bbox[1]
const label = labels[parseInt(prediction.class)]
// Draw the text last to ensure it's on top.
ctx.fillStyle = '#000000'
ctx.fillText(label, x, y)
})
},
///////////////////////////////////////////////////////////
// mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data.
update: function (obj, callback) {
logger.debug(this.id + ".update");
this._contextObj = obj;
this._resetSubscriptions();
this._updateRendering(callback); // We're passing the callback to updateRendering to be called after DOM-manipulation
},
// mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget.
enable: function () {
logger.debug(this.id + ".enable");
},
// mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget.
disable: function () {
logger.debug(this.id + ".disable");
},
// mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead.
resize: function (box) {
logger.debug(this.id + ".resize");
},
// mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work.
uninitialize: function () {
logger.debug(this.id + ".uninitialize");
// Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own.
},
// We want to stop events on a mobile device
_stopBubblingEventOnMobile: function (e) {
logger.debug(this.id + "._stopBubblingEventOnMobile");
if (typeof document.ontouchstart !== "undefined") {
dojoEvent.stop(e);
}
},
// Attach events to HTML dom elements
_setupEvents: function () {
logger.debug(this.id + "._setupEvents");
this.connect(this.colorSelectNode, "change", function (e) {
// Function from mendix object to set an attribute.
this._contextObj.set(this.backgroundColor, this.colorSelectNode.value);
});
this.connect(this.infoTextNode, "click", function (e) {
// Only on mobile stop event bubbling!
this._stopBubblingEventOnMobile(e);
// If a microflow has been set execute the microflow on a click.
if (this.mfToExecute !== "") {
this._execMf(this.mfToExecute, this._contextObj.getGuid());
}
});
},
_execMf: function (mf, guid, cb) {
logger.debug(this.id + "._execMf");
if (mf && guid) {
mx.ui.action(mf, {
params: {
applyto: "selection",
guids: [guid]
},
callback: lang.hitch(this, function (objs) {
if (cb && typeof cb === "function") {
cb(objs);
}
}),
error: function (error) {
console.debug(error.description);
}
}, this);
}
},
// Rerender the interface.
_updateRendering: function (callback) {
logger.debug(this.id + "._updateRendering");
// Important to clear all validations!
this._clearValidations();
// The callback, coming from update, needs to be executed, to let the page know it finished rendering
this._executeCallback(callback, "_updateRendering");
},
// Handle validations.
_handleValidation: function (validations) {
logger.debug(this.id + "._handleValidation");
this._clearValidations();
var validation = validations[0],
message = validation.getReasonByAttribute(this.backgroundColor);
if (this._readOnly) {
validation.removeAttribute(this.backgroundColor);
} else if (message) {
this._addValidation(message);
validation.removeAttribute(this.backgroundColor);
}
},
// Clear validations.
_clearValidations: function () {
logger.debug(this.id + "._clearValidations");
dojoConstruct.destroy(this._alertDiv);
this._alertDiv = null;
},
// Show an error message.
_showError: function (message) {
logger.debug(this.id + "._showError");
if (this._alertDiv !== null) {
dojoHtml.set(this._alertDiv, message);
return true;
}
this._alertDiv = dojoConstruct.create("div", {
"class": "alert alert-danger",
"innerHTML": message
});
dojoConstruct.place(this._alertDiv, this.domNode);
},
// Add a validation.
_addValidation: function (message) {
logger.debug(this.id + "._addValidation");
this._showError(message);
},
// Reset subscriptions.
_resetSubscriptions: function () {
logger.debug(this.id + "._resetSubscriptions");
// Release handles on previous object, if any.
this.unsubscribeAll();
// When a mendix object exists create subscribtions.
if (this._contextObj) {
this.subscribe({
guid: this._contextObj.getGuid(),
callback: lang.hitch(this, function (guid) {
this._updateRendering();
})
});
this.subscribe({
guid: this._contextObj.getGuid(),
attr: this.backgroundColor,
callback: lang.hitch(this, function (guid, attr, attrValue) {
this._updateRendering();
})
});
this.subscribe({
guid: this._contextObj.getGuid(),
val: true,
callback: lang.hitch(this, this._handleValidation)
});
}
},
_executeCallback: function (cb, from) {
logger.debug(this.id + "._executeCallback" + (from ? " from " + from : ""));
if (cb && typeof cb === "function") {
cb();
}
}
});
});
require(["VisualInspection/widget/VisualInspection"]);
<div id="container">
<video autoplay="true" playsInline="true" width="600" height="500" id="videoElement" style="position: fixed;" >
</video>
<canvas id= "canvasElement" width="600" height="500" style="position: absolute;">
</canvas>
</div>
From Above code, When I run using localhost this code will execute :
<!-- begin snippet: js hide: false console: true babel: false -->
When I run using machine name or IP name :
This code is not considered in developer tool of chrome due to security or some reason

Context issues with React and requestAnimationFrame

I'm currently playing around with React and Three.js. I'm trying to call an update function that is passed as a prop to another component as below. The problem is I get an error sayign this.cube is undefined.
public renderer : THREE.WebGLRenderer;
public scene : THREE.Scene = new THREE.Scene();
public camera : THREE.PerspectiveCamera = new THREE.PerspectiveCamera(70, 400 / 300, 0.1, 0.1);
public cube : THREE.Mesh;
public componentDidMount() {
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
}
public update = () => {
console.log(this);
console.log(this.cube);
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
}
public render() {
const sceneArr : THREE.Scene[] = [];
sceneArr.push(this.scene);
return (
<React.Fragment>
<Three mainCamera={this.camera} width={400} height={300} update={this.update} scenes={sceneArr} />
</React.Fragment>
);
}
Here is the render function inside the `Three` component calling `requestAnimationFrame`.
public threeRender = () => {
this.props.update();
requestAnimationFrame(this.threeRender);
this.props.scenes.forEach(scene => {
this.renderer.render(scene, this.props.mainCamera);
});
}
I assumed that the context of this inside update was incorrectly referring to the Three component, but it turns out that the print statements inside update showed contradicting evidence.
console.log(this) returns the correct object context, and the cube member shows up in the log, but console.log(this.cube) returns undefined. This makes no sense to me. Any ideas?
Inside of your constructor initialize cube and then you should be able to refer to it without getting that error.
constructor(props){
this.cube = {}
}
Now you can give this.cube a value and refer to it from within update()

how to resize dynamically markers on a map

My exercise with Leaflet.js : resize the icon of a marker when zooming in or out by modifying the iconSize option (ie not by changing the icon source).
I tried this :
function resize(e) {
for (const marker of markers) {
const newY = marker.options.icon.options.iconSize.y * (mymap.getZoom() / parameterInitZoom);
const newX = marker.options.icon.options.iconSize.x * (mymap.getZoom() / parameterInitZoom);
marker.setIcon(marker.options.icon.options.iconsize = [newX, newY]);
}
}
mymap.on('zoomend', resize)
but I ended up with :
t.icon.createIcon is not a function
I saw also the method muliplyBy but couldn't find out the way to make it work.
How to do it ?
What I did finally, and it's working well :
let factor;
let markers = [];
//New class of icons
const MyIcon = L.Icon.extend({
options: {
iconSize: new L.Point(iconInitWidth, iconInitHeight) //Define your iconInitWidth and iconInitHeight before
},
});
/*------------ Functions - Callbacks ----------------*/
//Small function to keep the factor up to date with the current zoom
function updateFactor() {
let currentZoom = mymap.getZoom();
factor = Math.pow(currentZoom / mymap.options.zoom, 5);
};
updateFactor();
//Create a new marker
function makeMarker(e) {
const newX = Math.round(iconInitWidth * factor);
const newY = newX * iconInitHeight / iconInitWidth;
const newMarker = new L.Marker(new L.LatLng(e.latlng.lat, e.latlng.lng), {
icon: new MyIcon({ iconSize: new L.Point(newX, newY) })
}).addTo(mymap);
markers[markers.length] = newMarker;
}
//Update the marker
function resize(e) {
updateFactor();
for (const marker of markers) {
const newX = Math.round(iconInitWidth * factor);
const newY = newX * iconInitHeight / iconInitWidth;
marker.setIcon(new MyIcon({ iconSize: new L.Point(newX, newY) }));
}
}
/*------------ Event listeners ----------------*/
mymap.addEventListener('click', makeMarker);
mymap.on('zoom', resize);

Resources