How to prevent the suggestedResult from collapsing after clicking result using SearchWidget? - reactjs

How to prevent the suggestedResult from collapsing after clicking result using SearchWidget?
CodePen, copied below
// An open data address search API for France
const url = "https://api-adresse.data.gouv.fr/";
const map = new Map({
basemap: "streets-vector"
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [2.21, 46.22], // lon, lat
scale: 3000000
});
const customSearchSource = new SearchSource({
placeholder: "example: 8 Boulevard du Port",
// Provide a getSuggestions method
// to provide suggestions to the Search widget
getSuggestions: (params) => {
// You can request data from a
// third-party source to find some
// suggestions with provided suggestTerm
// the user types in the Search widget
return esriRequest(url + "search/", {
query: {
q: params.suggestTerm.replace(/ /g, "+"),
limit: 6,
lat: view.center.latitude,
lon: view.center.longitude
},
responseType: "json"
}).then((results) => {
// Return Suggestion results to display
// in the Search widget
return results.data.features.map((feature) => {
return {
key: "name",
text: feature.properties.label,
sourceIndex: params.sourceIndex
};
});
});
},
// Provide a getResults method to find
// results from the suggestions
getResults: (params) => {
// If the Search widget passes the current location,
// you can use this in your own custom source
const operation = params.location ? "reverse/" : "search/";
let query = {};
// You can perform a different query if a location
// is provided
if (params.location) {
query.lat = params.location.latitude;
query.lon = params.location.longitude;
} else {
query.q = params.suggestResult.text.replace(/ /g, "+");
query.limit = 6;
}
return esriRequest(url + operation, {
query: query,
responseType: "json"
}).then((results) => {
// Parse the results of your custom search
const searchResults = results.data.features.map((feature) => {
// Create a Graphic the Search widget can display
const graphic = new Graphic({
geometry: new Point({
x: feature.geometry.coordinates[0],
y: feature.geometry.coordinates[1]
}),
attributes: feature.properties
});
// Optionally, you can provide an extent for
// a point result, so the view can zoom to it
const buffer = geometryEngine.geodesicBuffer(
graphic.geometry,
100,
"meters"
);
// Return a Search Result
const searchResult = {
extent: buffer.extent,
feature: graphic,
name: feature.properties.label
};
return searchResult;
});
// Return an array of Search Results
return searchResults;
});
}
});
// Create Search widget using custom SearchSource
const searchWidget = new Search({
view: view,
sources: [customSearchSource],
includeDefaultSources: false
});
// Add the search widget to the top left corner of the view
view.ui.add(searchWidget, {
position: "top-right"
});
3d version of code sample above

There is no documented way to do this through the API, as far as I can tell. But by adding the esri-search--show-suggestions to the SearchWidget, the suggestions will reappear:
const searchWidget = new Search({
view: view,
sources: [customSearchSource],
includeDefaultSources: false,
//autoSelect: false,
goToOverride: function(view, { target, options }) {
view.goTo(target, options);
const widget = document.querySelector('.esri-search__container')
widget.className += ' esri-search--show-suggestions'
},
});
Working CodePen here

Related

leaflet-draw delete problem "Cannot read properties of undefined "

I'm trying to work with leaflet and leaflet-draw on my react project but i keep getting an error message when I click on delete in the draw pannel even thaugh the edit button and event work fine
here is the code `
const script = document.createElement("script");
script.src =
"https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.js";
script.async = true;
document.body.appendChild(script);
var map = L.map("map").setView([36.8299552, 10.3194016], 14);
L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© OpenStreetMap contributors',
}).addTo(map);
// FeatureGroup is to store editable layers
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
var drawControl = new L.Control.Draw({
draw: {
marker: false,
rectangle: false,
circle: false,
polyline: false,
circlemarker: false,
},
edit: {
featureGroup: drawnItems,
},
});
map.addControl(drawControl);
//draw event
map.on(L.Draw.Event.CREATED, (e) => {
var type = e.layerType,
layer = e.layer;
// Do whatever else you need to. (save to db; add to map etc)
map.addLayer(layer);
drawnItems.addLayer(layer);
if (type == "polygon") {
add_microzone_service({ _latlngs: layer._latlngs });
}
});
map.on("draw:edited", function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
console.log(layer.options._id);
});
});
map.on("draw:deleted", function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
console.log("deleted");
});
});
and here is the error I'm getting:
Can someone help?

Nativescript Class constructor Observable cannot be invoked without 'new'

I'm trying to upload a multipart form in nativescript and I'm using http-background. I keep getting the error Class constructor Observable cannot be invoked without 'new'. I've tried changing the compilerOptions target to es5 and es2017, but nothing changed.
Here's all my code from the component.
onSave(){
console.log("clicked")
this.proccessImageUpload(this.file);
}
public onSelectSingleTap() {
this.isSingleMode = true;
let context = imagepicker.create({
mode: "single"
});
this.startSelection(context);
}
private startSelection(context) {
let that = this;
context
.authorize()
.then(() => {
that.imageAssets = [];
that.imageSrc = null;
return context.present();
})
.then((selection) => {
console.log("Selection done: " + JSON.stringify(selection));
this.file = selection[0]._android;
that.imageSrc = that.isSingleMode && selection.length > 0 ? selection[0] : null;
// set the images to be loaded from the assets with optimal sizes (optimize memory usage)
selection.forEach(function (element) {
element.options.width = that.isSingleMode ? that.previewSize : that.thumbSize;
element.options.height = that.isSingleMode ? that.previewSize : that.thumbSize;
});
that.imageAssets = selection;
}).catch(function (e) {
console.log(e);
});
}
// proccess image function
proccessImageUpload(fileUri) {
var backgroundHttp = require("nativescript-background-http");
return new Promise((resolve, reject) => {
// body...
var request = {
url: 'http://192.168.0.2:4000/api/posts',
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
"user_id": "<user_id>"
},
description: 'Uploading profile image..',
androidAutoDeleteAfterUpload: false,
androidNotificationTitle: 'Profile image'
}
var params = [
{ name: "title", value: "test" },
{ name: "content", value: "test" },
{ name: "fileToUpload", filename: fileUri, mimeType: "image/jpeg" }
];
var backgroundSession = backgroundHttp.session('image-upload');
var task = backgroundSession.uploadFile(fileUri, request);
task.on("progress", (e) => {
// console log data
console.log(`uploading... ${e.currentBytes} / ${e.totalBytes}`);
});
task.on("error", (e) => {
// console log data
console.log(`Error processing upload ${e.responseCode} code.`);
reject(`Error uploading image!`);
});
task.on("responded", (e) => {
// console log data
console.log(`received ${e.responseCode} code. Server sent: ${e.data}`);
// var uploaded_response = JSON.parse(e.data);
});
task.on("complete", (e) => {
// console log data
console.log(`upload complete!`);
console.log(`received ${e.responseCode} code`);
// console.log(e.data);
})
resolve(task);
});
}
I know the issue is coming from this line.
var task = backgroundSession.uploadFile(fileUri, request);
Any help would be greatly appreciated!
You use old version if nativescript-background-http plugin
You have to install latest version
tns plugin add #nativescript/background-http
I was able to get this working by installing tns version 6.
I had exactly the same problem. I got this from slack.com, compliments Chris Vietor
"tns plugin add nativescript-background-http" works with nativescript 6.
"tns plugin add #nativescript/background-http" works with nativescript 7.

Test scrolling in a react-window list with react-testing-library

I am stuck here with a test where I want to verify that after scrolling through a list component, imported by react-window, different items are being rendered. The list is inside a table component that saves the scrolling position in React context, which is why I need to test the whole table component.
Unfortunately, the scrolling event seems to have no effect and the list still shows the same items.
The test looks something like this:
render(
<SomeProvider>
<Table />
</SomeProvider>
)
describe('Table', () => {
it('scrolls and renders different items', () => {
const table = screen.getByTestId('table')
expect(table.textContent?.includes('item_A')).toBeTruthy() // --> true
expect(table.textContent?.includes('item_Z')).toBeFalsy() // --> true
// getting the list which is a child component of table
const list = table.children[0]
fireEvent.scroll(list, {target: {scrollY: 100}})
expect(table.textContent?.includes('item_A')).toBeFalsy() // --> false
expect(table.textContent?.includes('item_Z')).toBeTruthy() // --> false
})
})
Any help would be much appreciated.
react-testing-library by default renders your components in a jsdom environment, not in a browser. Basically, it just generates the html markup, but doesn't know where components are positioned, what are their scroll offsets, etc.
See for example this issue.
Possible solutions are :
use Cypress
or override whatever native attribute react-window is using to measure scroll offset in your container (hacky). For example, let's say react-window is using container.scrollHeight :
// artificially setting container scroll height to 200
Object.defineProprerty(containerRef, 'scrollHeight', { value: 200 })
I had a scenario where certain presentation aspects depended on the scroll position. To make tests clearer, I defined the following mocks in test setup:
1. Mocks that ensure programmatic scrolls trigger the appropriate events:
const scrollMock = (leftOrOptions, top) => {
let left;
if (typeof (leftOrOptions) === 'function') {
// eslint-disable-next-line no-param-reassign
({ top, left } = leftOrOptions);
} else {
left = leftOrOptions;
}
Object.assign(document.body, {
scrollLeft: left,
scrollTop: top,
});
Object.assign(window, {
scrollX: left,
scrollY: top,
scrollLeft: left,
scrollTop: top,
}).dispatchEvent(new window.Event('scroll'));
};
const scrollByMock = function scrollByMock(left, top) { scrollMock(window.screenX + left, window.screenY + top); };
const resizeMock = (width, height) => {
Object.defineProperties(document.body, {
scrollHeight: { value: 1000, writable: false },
scrollWidth: { value: 1000, writable: false },
});
Object.assign(window, {
innerWidth: width,
innerHeight: height,
outerWidth: width,
outerHeight: height,
}).dispatchEvent(new window.Event('resize'));
};
const scrollIntoViewMock = function scrollIntoViewMock() {
const [left, top] = this.getBoundingClientRect();
window.scrollTo(left, top);
};
const getBoundingClientRectMock = function getBoundingClientRectMock() {
let offsetParent = this;
const result = new DOMRect(0, 0, this.offsetWidth, this.offsetHeight);
while (offsetParent) {
result.x += offsetParent.offsetX;
result.y += offsetParent.offsetY;
offsetParent = offsetParent.offsetParent;
}
return result;
};
function mockGlobal(key, value) {
mockedGlobals[key] = global[key]; // this is just to be able to reset the mocks after the tests
global[key] = value;
}
beforeAll(async () => {
mockGlobal('scroll', scrollMock);
mockGlobal('scrollTo', scrollMock);
mockGlobal('scrollBy', scrollByMock);
mockGlobal('resizeTo', resizeMock);
Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', { value: scrollIntoViewMock, writable: false });
Object.defineProperty(HTMLElement.prototype, 'getBoundingClientRect', { value: getBoundingClientRectMock, writable: false });
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { value: 250, writable: false });
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { value: 250, writable: false });
});
The above ensures that, after a programmatic scroll takes place, the appropriate ScrollEvent will be published, and the window properties are updated accordingly.
2. Mocks that setup a basic layout for a collection of siblings
export function getPosition(element) {
return element?.getClientRects()[0];
}
export function scrollToElement(element, [extraX = 0, extraY = 0]) {
const { x, y } = getPosition(element);
window.scrollTo(x + extraX, y + extraY);
}
export const layoutTypes = {
column: 'column',
row: 'row',
};
function* getLayoutBoxIterator(type, { defaultElementSize }) {
const [width, height] = defaultElementSize;
let offset = 0;
while (true) {
let left = 0;
let top = 0;
if (type === layoutTypes.column) {
top += offset;
offset += height;
} else if (type === layoutTypes.row) {
left += offset;
offset += width;
}
yield new DOMRect(left, top, width, height);
}
}
function getLayoutProps(element, layoutBox) {
return {
offsetX: layoutBox.x,
offsetY: layoutBox.y,
offsetWidth: layoutBox.width,
offsetHeight: layoutBox.height,
scrollWidth: layoutBox.width,
scrollHeight: layoutBox.height,
};
}
function defineReadonlyProperties(child, props) {
let readonlyProps = Object.entries(props).reduce((accumulator, [key, value]) => {
accumulator[key] = {
value,
writable: false,
}; return accumulator;
}, {});
Object.defineProperties(child, readonlyProps);
}
export function mockLayout(parent, type, options = { defaultElementSize: [250, 250] }) {
const layoutBoxIterator = getLayoutBoxIterator(type, options);
const parentLayoutBox = new DOMRect(parent.offsetX, parent.offsetY, parent.offsetWidth, parent.offsetHeight);
let maxBottom = 0;
let maxRight = 0;
Array.prototype.slice.call(parent.children).forEach((child) => {
let layoutBox = layoutBoxIterator.next().value;
// eslint-disable-next-line no-return-assign
defineReadonlyProperties(child, getLayoutProps(child, layoutBox));
maxBottom = Math.max(maxBottom, layoutBox.bottom);
maxRight = Math.max(maxRight, layoutBox.right);
});
parentLayoutBox.width = Math.max(parentLayoutBox.width, maxRight);
parentLayoutBox.height = Math.max(parentLayoutBox.height, maxBottom);
defineReadonlyProperties(parent, getLayoutProps(parent, parentLayoutBox));
}
With those two in place, I would write my tests like this:
// given
mockLayout(/* put the common, direct parent of the siblings here */, layoutTypes.column);
// when
Simulate.click(document.querySelector('#nextStepButton')); // trigger the event that causes programmatic scroll
const scrolledElementPosition = ...; // get offsetX of the component that was scrolled programmatically
// then
expect(window.scrollX).toEqual(scrolledElementPosition.x); // verify that the programmatically scrolled element is now at the top of the page, or some other desired outcome
The idea here is that you give all siblings at a given level sensible, uniform widths and heights, as if they were rendered as a column / row, thus imposing a simple layout structure that the table component will 'see' when calculating which children to show / hide.
Note that in your scenario, the common parent of the sibling elements might not be the root HTML element rendered by table, but some element nested inside. Check the generated HTML to see how to best obtain a handle.
Your use case is a little different, in that you're triggering the event yourself, rather than having it bound to a specific action (a button click, for instance). Therefore, you might not need the first part in its entirety.

How to get old and new value of dynamically generated checkbox column in agGrid

I am using agGrid where the columns are dynamically created. My objective is to get the old value and new value after checking the checkboxes. I try to use "onCellValueChanged" but it didnt work. If I use "onCellClicked" then I am not getting Old Value and New Value.
For your understanding I want to mean by Old Value and New Value that if user checked then Old Value is false and New Value is true.
HTML
<ag-grid-angular class="ag-theme-balham" [gridOptions]="siteJobDeptGridOptions"
[rowData]="siteJobDeptRowData" [columnDefs]="siteJobDeptColDef" [paginationPageSize]=10 [domLayout]="domLayout"
(gridReady)="onGridReady($event)">
</ag-grid-angular>
TS File
export class SiteJobDeptConfigComponent implements OnInit {
ngOnInit() {
this.domLayout = "autoHeight";
this.getAllSiteJobConfig();
this.generateColumns();
}
onGridReady(params: any) {
params.api.sizeColumnsToFit();
params.api.resetRowHeights();
}
generateColumns()
{
let deptColDef = [];
let colSiteJob = {
field: 'SiteJobName', headerName: 'Site Job Name',resizable: true,
sortable: true, filter: true, editable: false,
}
this.siteJobDeptCommonService.getEntityData('getpublisheddepts')
.subscribe((rowData) => {
deptColDef.push(colSiteJob);
for(let dept of rowData)
{
deptColDef.push({
field: dept.DeptName, headerName: dept.DeptName, width:100,resizable: true,
cellClass: 'no-border',
cellRenderer : params => {
var input = document.createElement('input');
input.type="checkbox";
input.checked=params.data[dept.DeptName];
return input;
},
onCellValueChanged: this.siteDeptCellValueChanged.bind(this),
})
}
this.siteJobDeptColDef = deptColDef;
},
(error) => { alert(error) });
}
siteDeptCellValueChanged(dataCol: any) {
let checkedOldValue = "Old Check Value - " + dataCol.oldValue;
let checkedNewValue = "New Check Value - " + dataCol.newValue;
}
getAllSiteJobConfig()
{
let siteJobRowData = [];
this.siteJobDeptCommonService.getEntityData('getallsitedeptjob')
.subscribe((rowData) => {
for(let siteJobDetail of rowData)
{
for(let deptAllow of siteJobDetail.DeptAllow)
{
tempArray[deptAllow["DeptName"]] = deptAllow["IsAllow"];
}
siteJobRowData.push(tempArray);
}
this.siteJobDeptRowData = siteJobRowData;
},
(error) => { alert(error) });
}
}
The grid looks like below:-
Can you please help me how to get Old Data and New Data value from checkbox that is dynamically generated?
It should be "cellValueChanged" not "onCellValueChanged" in the column definition creation.
You can find here.
When you declare your method in the params object, there are oldValue and newValue properties that give the result that you are looking for:
onCellValueChanged: function(params) {
console.log(params.oldValue);
console.log(params.newValue)
}

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

Resources