Failed import using amCharts5 and Nuxt 3 - amcharts5

I am trying to implement amCharts3 in Nuxt 3 and am getting the following error in the console:
"Uncaught SyntaxError: The requested module '/_nuxt/#fs/Users/[...]/ui/client/node_modules/regression/dist/regression.js?v=7015616a' does not provide an export named 'default' (at RegressionSeries.ts:5:8)".
Snapshot of RegressionSeries.ts file
The RegressionSeries.ts is imbedded in the amCharts module...amcharts5>.internal.charts.stock.drawing>RegressionSeries.js. Here the file which is the source of the error:
import { SimpleLineSeries } from "./SimpleLineSeries";
import regression from "regression";
export class RegressionSeries extends SimpleLineSeries {
constructor() {
super(...arguments);
Object.defineProperty(this, "_tag", {
enumerable: true,
configurable: true,
writable: true,
value: "regression"
});
}
_updateSegment(index) {
const diP1 = this._di[index]["p1"];
const diP2 = this._di[index]["p2"];
const series = this.get("series");
if (series && diP1 && diP2) {
const xAxis = series.get("xAxis");
let x1 = this._getXValue(diP1.get("valueX"));
let x2 = this._getXValue(diP2.get("valueX"));
const di1 = xAxis.getSeriesItem(series, xAxis.valueToPosition(x1));
const di2 = xAxis.getSeriesItem(series, xAxis.valueToPosition(x2));
const field = this.get("field") + "Y";
if (di1 && di2) {
const dataItems = series.dataItems;
let startIndex = dataItems.indexOf(di1);
let endIndex = dataItems.indexOf(di2);
let inversed = false;
if (startIndex > endIndex) {
inversed = true;
[startIndex, endIndex] = [endIndex, startIndex];
}
const points = [];
let ii = 0;
for (let i = startIndex; i <= endIndex; i++) {
const dataItem = dataItems[i];
points.push([ii, dataItem.get(field)]);
ii++;
}
const result = regression.linear(points);
const resultPoints = result.points;
const len = resultPoints.length;
if (len > 1) {
const p1 = resultPoints[0];
const p2 = resultPoints[resultPoints.length - 1];
if (p1 && p2) {
let y1 = p1[1];
let y2 = p2[1];
if (inversed) {
[y1, y2] = [y2, y1];
}
this._setContext(diP1, "valueY", y1, true);
this._setContext(diP2, "valueY", y2, true);
this._setContext(diP1, "valueX", x1);
this._setContext(diP2, "valueX", x2);
this._positionBullets(diP1);
this._positionBullets(diP2);
}
}
}
}
}
// need to override so that location would not be set
_setXLocation() {
}
}
Object.defineProperty(RegressionSeries, "className", {
enumerable: true,
configurable: true,
writable: true,
value: "RegressionSeries"
});
Object.defineProperty(RegressionSeries, "classNames", {
enumerable: true,
configurable: true,
writable: true,
value: SimpleLineSeries.classNames.concat([RegressionSeries.className])
});
//# sourceMappingURL=RegressionSeries.js.map
added the amcharts.client.ts plugin like this:
import * as am5 from '#amcharts/amcharts5'
import * as am5xy from '#amcharts/amcharts5/xy'
import * as am5radar from '#amcharts/amcharts5/radar'
import * as am5stock from '#amcharts/amcharts5/stock'
import am5themes_Animated from '#amcharts/amcharts5/themes/Animated'
export default defineNuxtPlugin(() => {
return {
provide: {
am5,
am5xy,
am5radar,
am5stock,
am5themes_Animated,
},
}
})
and other charts have worked, so I am fairly certain that the setup is correct.

For those interested:
I had amCharts5 set set up for transpiling in the NuxtConfig file. Removing it resolved the error.

Related

Overwrite cypress commands to include a wait before they are run

I am trying to overwrite Cypress commands such as click, type and should to include some waiting time before they are executed. My motivation for this is that I want to highlight the areas the test interacts with in the produced video, so in click I would like to say for example: "Display circle where the click will happen, wait 500ms, click, wait 250ms, remove circle".
The wait-part of this of this is what causes me trouble.
Google suggests I do something like this:
Cypress.Commands.overwrite('click', function (originalFN) {
const originalParams = [...arguments].slice(1);
cy.wait(500).then(() => originalFN.apply(originalFN, originalParams));
});
And I think this works for normal clicks(), but it causes the type command to fail entirely saying this: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
It seems type() internally calls click in a way that prevents me from using wait() inside click.
Is there any way around this?
I've found a solution in the code of a library to slow down cypress, the key is to overwrite the internal runCommand cypress function. This allows me to do what I want on click and type. Should is still an open question, but not as important. Code below is my function to patch cypress, which I call right before my tests.
export function patchCypressForVideoRecording(cy: any, Cypress: any, speedFactor = 1) {
const colorClick = 'rgba(255, 50, 50, 0.8)';
const colorType = 'rgba(50, 255, 50, 0.8)';
const colorShould = 'rgba(50, 50, 255, 0.8)';
const waitTime = 600;
const highlightArea = (rect: any, clr: string, scale: boolean) => {
const x = Math.round(rect.x);
const y = Math.round(rect.y);
const w = Math.round(rect.width);
const h = Math.round(rect.height);
// cy.window() breaks in commands like click due to promise-inside promises stuff
// this window reference is just there and allows to run synchronous side-effects js without cypress noticing it
const hackWindow = (cy as any).state('window');
hackWindow.eval(`
const time = ${waitTime / speedFactor};
const x = ${x};
const y = ${y};
const highlightElement = document.createElement('div');
highlightElement.style.backgroundColor = '${clr}';
highlightElement.style.position = 'fixed';
highlightElement.style.zIndex = '999';
highlightElement.style['pointer-events'] = 'none';
document.body.appendChild(highlightElement);
const scaleElement = (p) => {
if (${scale}) {
const psq = p;
const scale = (0.1 + ((psq < 0.5 ? (1 - psq) : psq)));
const w = scale * ${w};
const h = scale * ${h};
const wLoss = ${w} - w;
const hLoss = ${h} - h;
const x = ${x} + wLoss / 2;
const y = ${y} + hLoss / 2;
return {x, y, w, h};
} else {
const w = ${w};
const h = ${h};
const x = ${x};
const y = ${y};
return {x, y, w, h};
}
};
const newSize = scaleElement(0);
highlightElement.style.top = newSize.y + 'px';
highlightElement.style.left = newSize.x + 'px';
highlightElement.style.width = newSize.w + "px";
highlightElement.style.height = newSize.h + "px";
const tickSize = 30;
let op = 1;
let prog = 0;
const fadeIv = setInterval(() => {
prog += tickSize;
const p = Math.min(1, prog / time);
let op = 1-(p*0.5);
highlightElement.style.opacity = op + '';
const newSize = scaleElement(p);
highlightElement.style.top = newSize.y + 'px';
highlightElement.style.left = newSize.x + 'px';
highlightElement.style.width = newSize.w + "px";
highlightElement.style.height = newSize.h + "px";
}, tickSize);
setTimeout(() => {
clearInterval(fadeIv);
document.body.removeChild(highlightElement);
}, time);
`);
};
const highlightInteractedElements = (firstParam: any, clr: string, scale: boolean) => {
if (firstParam != null && firstParam.length != null && firstParam.length > 0 && typeof firstParam !== 'string') {
for (let i = 0; i < firstParam.length; i++) {
const elem = firstParam[i];
if (elem != null && 'getBoundingClientRect' in elem && typeof elem['getBoundingClientRect'] === 'function') {
highlightArea(elem.getBoundingClientRect(), clr, scale);
}
}
}
};
// To figure out the element that is clicked/typed in need to wait until
// the selector right before click/type has a subject element
const waitAndDisplay = (x: any, clr: string) => {
if (x.state === 'passed') {
highlightInteractedElements(x.attributes.subject, clr, true);
} else {
if (x.attributes.prev.state === 'queued') {
setTimeout(() => {
waitAndDisplay(x, clr);
}, 15);
} else {
highlightInteractedElements(x.attributes.prev.attributes.subject, clr, true);
}
}
};
const cqueue = (cy as any).queue;
const rc = cqueue.runCommand.bind(cqueue);
cqueue.runCommand = (cmd: any) => {
let delay = 50;
if (cmd.attributes.name === 'click') {
waitAndDisplay(cmd, colorClick);
delay = waitTime / 2;
}
if (cmd.attributes.name === 'type') {
waitAndDisplay(cmd, colorType);
delay = waitTime;
}
return Cypress.Promise.delay(delay / speedFactor)
.then(() => rc(cmd))
.then(() => Cypress.Promise.delay(delay / speedFactor));
};
Cypress.Commands.overwrite('should', function (originalFN: any) {
const originalParams = [...arguments].slice(1);
highlightInteractedElements(originalParams[0], colorShould, false);
return originalFN.apply(originalFN, originalParams);
});
}

React Redux Toolkit TS - Can't access class methods from my state objects

I have set up my redux store and I am able to edit my state objects and get their values. But for some reason I can't call methods on the state objects. It's as if they are stored as javascript objects.
When I call getSequence() the first console.log correctly logs the sequence structure. But the second log call gives me an error
sequence.dump is not a function
Here is my store, including getSequence():
import {configureStore} from '#reduxjs/toolkit'
import sequenceReducer, {selectSequence} from '../feature/sequence-slice'
import midiMapsReducer from '../feature/midimaps-slice'
import {Sequence} from "../player/sequence";
export function getSequence() : Sequence {
const sequence: Sequence = selectSequence(store.getState())
console.log(`getCurrentSequence: ${JSON.stringify(sequence)}`)
console.log(`getCurrentSequence: ${sequence.dump()}`)
return sequence
}
const store = configureStore({
reducer: {
sequence: sequenceReducer,
midiMaps: midiMapsReducer,
}
})
export default store
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
I set up my slice state like this:
interface SequenceSliceState {
value: Sequence;
}
const initialState : SequenceSliceState = {
value: new Sequence({})
}
export const sequenceSlice = createSlice({
name: 'sequence',
// type is inferred. now the contained sequence is state.value
initialState,
reducers: {
and here is my Sequence module:
export class SequenceStep {
time: number = 0;
note: number = 64;
velocity: number = 100;
gateLength: number = 0.8;
}
export class MidiSettings {
midiInputDeviceId: string = "";
midiInputDeviceName: string = "";
midiInputChannelNum: number = -1;
midiOutputDeviceId: string = "";
midiOutputDeviceName: string = "";
midiOutputChannelNum: number = 0;
}
export class EnvelopePoint {
time: number = 0;
value: number = 0;
}
export class Envelope {
id: string = "";
controller: string = "";
points: Array<EnvelopePoint> = [];
locked: boolean = true;
mode: string = "loop";
trigger: string = "first";
type: string = "envelope";
// cacheMinValue: number = 0;
// cacheMaxValue: number = 127;
constructor(fake: any) {
this.id = fake.id;
this.controller = fake.controller;
this.points = fake.points;
this.locked = fake.locked;
this.mode = fake.mode;
this.trigger = fake.trigger;
this.type = fake.type;
}
dump() : string {
return "I am an envelope"
}
getValue(time: number) : number {
const numpoints = this.points.length
const length: number = this.points[numpoints - 1].time;
const loop: boolean = true;
const position: number = time % length;
var index = 0
while (index < numpoints && this.points[index].time < position) {
++index
}
if (index == 0) {
return this.points[0].value
} else if (index >= numpoints) {
return this.points[numpoints - 1].value
} else {
const p0: EnvelopePoint = this.points[index - 1];
const p1: EnvelopePoint = this.points[index];
if (p0.time == p1.time) {
return p0.value
} else {
return p0.value + (position - p0.time) / (p1.time - p0.time) * (p1.value - p0.value)
}
}
}
}
export class Sequence {
_id: string = "";
name: string = "";
text: string = "";
user_name: string = "";
user_id: string = "";
steps: Array<SequenceStep> = []
tempo: number = 120.0;
length: number = 8;
numSteps: number = 8;
division: number = 8;
midiSettings: MidiSettings = new MidiSettings();
currentEnvelopeId: string = "";
envelopes: Array<Envelope> = []
constructor(fakeSequence: any) {
this._id = fakeSequence._id;
this.name = fakeSequence.name;
this.text = fakeSequence.text;
this.user_id = fakeSequence.user_id;
this.steps = fakeSequence.steps;
this.tempo = fakeSequence.tempo;
this.length = fakeSequence.length;
this.numSteps = fakeSequence.numSteps;
this.division = fakeSequence.division;
this.midiSettings = fakeSequence.midiSettings;
this.currentEnvelopeId = fakeSequence.currentEnvelopeId;
this.envelopes = new Array<Envelope>();
if (fakeSequence.envelopes) {
for (const fakeEnvelope in fakeSequence.envelopes) {
this.envelopes.push(new Envelope(fakeEnvelope));
}
}
}
dump() : string {
return "I am a Sequence"
}
}
Here is the rest of my sequence slice:
import { createSlice } from '#reduxjs/toolkit'
import { v4 as uuidv4 } from "uuid";
import {Envelope, Sequence} from "../player/sequence"
import {RootState} from "../app/store";
interface SequenceSliceState {
value: Sequence;
}
const initialState : SequenceSliceState = {
value: new Sequence({})
}
export const sequenceSlice = createSlice({
name: 'sequence',
// type is inferred. now the contained sequence is state.value
initialState,
reducers: {
sequenceLoad: (state, payloadAction) => {
console.log(`🍕sequencerSlice.sequenceLoad ${JSON.stringify(payloadAction)}`)
state.value = JSON.parse(JSON.stringify(payloadAction.payload.sequence));
return state;
},
sequenceName: (state, payloadAction) => {
console.log(`🍕sequencerSlice.sequenceName ${JSON.stringify(payloadAction)}`)
state.value.name = payloadAction.payload;
return state
},
numSteps: (state, payloadAction) => {
var sequence: Sequence = state.value
sequence.numSteps = payloadAction.payload;
console.log(`🍕hi from numsteps ${sequence.numSteps} ${sequence.steps.length}`);
if (sequence.numSteps > sequence.steps.length) {
console.log(`🍕extend sequence`);
var newSteps: any = [];
for (var n = sequence.steps.length + 1; n <= sequence.numSteps; n++) {
newSteps = newSteps.concat({ note: 60, velocity: 100, gateLength: 0.9, });
console.log(`added step - now ${newSteps.length} steps`)
}
console.log(`🍕handleNumStepsChange: ${newSteps.length} steps -> ${newSteps}`)
const newStepsArray = sequence.steps.concat(newSteps);
sequence.steps = newStepsArray;
// console.log(`🍕handleNumStepsChange: ${stepsEdits.length} steps -> ${stepsEdits}`)
}
return state
},
midiSettings: (state, payloadAction) => {
console.log(`🍕sequence-slice - payloadAction ${JSON.stringify(payloadAction)}`)
console.log(`🍕sequence-slice - midiSettings ${JSON.stringify(payloadAction.payload)}`)
state.value.midiSettings = payloadAction.payload;
return state
},
division: (state, payloadAction) => {
state.value.division = payloadAction.payload;
return state
},
length: (state, payloadAction) => {
state.value.length = payloadAction.payload;
return state
},
sequenceText: (state, payloadAction) => {
state.value.text = payloadAction.payload;
return state
},
tempo: (state, payloadAction) => {
console.log(`🍕Edit tempo payloadaction ${JSON.stringify(payloadAction)}`)
state.value.tempo = payloadAction.payload
// return { ...state, tempo: parseInt(payloadAction.payload) }
// state.tempo = payloadAction.payload
return state
},
stepControllerValue: (state: any, payloadAction) => {
var sequence: Sequence = state.value
console.log(`🍕Edit stepControllerValue ${JSON.stringify(payloadAction)}`)
const stepNum: number = payloadAction.payload.stepNum
const controllerNum: number = payloadAction.payload.controllerNum
const controllerValue: number = payloadAction.payload.controllerNum
// sequence.steps[stepNum][controllerNum] = controllerValue;
// sequence.steps = steps
return state
},
stepNote: (state, action) => {
const stepnum = action.payload.stepNum
const notenum = action.payload.note
console.log(`🍕sequence-slice.stepNote ${JSON.stringify(action.payload)} ${stepnum} ${notenum}`)
var sequence: Sequence = state.value
// var steps: Array<SequenceStep> = [...sequence.steps];
sequence.steps[stepnum].note = notenum
// sequence.steps = steps;
return state
},
stepGateLength: (state, action) => {
const stepnum = action.payload.stepNum
const gateLength = action.payload.gateLength
// console.log(`🍕sequence-slice.stepNote ${JSON.stringify(action.payload)} ${stepnum} ${notenum}`)
// var steps = [...state.steps];
var sequence: Sequence = state.value
sequence.steps[stepnum].gateLength = gateLength
// state.steps = steps;
return state
},
stepVelocity: (state, action) => {
const stepnum = action.payload.stepNum
const velocity = action.payload.velocity
// console.log(`🍕sequence-slice.stepNote ${JSON.stringify(action.payload)} ${stepnum} ${notenum}`)
var sequence: Sequence = state.value
// var steps = [...state.steps];
sequence.steps[stepnum].velocity = velocity
// state.steps = steps;
return state
},
decrement: state => {
var sequence: Sequence = state.value
sequence.numSteps -= 1;
return state
},
// incrementByAmount: (state, action) => {
// var sequence: Sequence = state.value
// sequence.numSteps += action.payload;
// return state
// },
createEnvelope: (state, action) => {
console.log(`🍕sequenceSlice - createEnvelope: action should be controller ${JSON.stringify(action)}`)
const controller = action.payload.controller
console.log(`🍕sequenceSlice - createEnvelope: controller ${JSON.stringify(controller)}`)
var sequence: Sequence = state.value
var newEnvelopeId = uuidv4()
var newEnvelope = new Envelope({
id: newEnvelopeId,
controller: controller.name,
points: [{ time: 0, value: 0}, ],
locked: true,
mode: "loop",
trigger: "first",
type: "envelope"
})
if (sequence.envelopes == null) {
sequence.envelopes = new Array<Envelope>();
}
sequence.envelopes = [...sequence.envelopes, newEnvelope];
sequence.currentEnvelopeId = newEnvelopeId;
// console.log(`🍕state.envelopes <${state.envelopes}> (added ${newEnvelopeId}`);
return state
},
envelopeValue: (state, action) => {
console.log(`🍕sequenceSlice - envelopeValue: action ${JSON.stringify(action)}`)
const ccValue = action.payload.value
const controller = action.payload.controller
const envelopeId = action.payload.envelopeId
var sequence: Sequence = state.value
var envelope = sequence.envelopes.find((envelope: any) => envelope.id === envelopeId);
if (envelope) {
console.log(`🍕envelope ${envelopeId} ${JSON.stringify(envelope)}`)
const ccid = action.payload.ccid
// const currentValue = envelope.points[0].value
// const currentLsb = currentValue % ((controller.max + 1) / 128)
// const currentMsb = currentValue - currentLsb
// const value = action.payload.value * ((controller.max + 1) / 128)
envelope.points[0] = {time: 0, value: action.payload.value}
}
return state
},
currentEnvelopeId: (state, action) => {
console.log(`🍕sequence-slice: action ${JSON.stringify(action)}`)
var sequence: Sequence = state.value
console.log(`🍕sequence-slice: currentEnvelopeId - was ${sequence.currentEnvelopeId}`);
sequence.currentEnvelopeId = action.payload.envelopeId;
console.log(`🍕sequence-slice: currentEnvelopeId - now ${sequence.currentEnvelopeId}`);
return state
},
addEnvelopePoint(state, action) {
console.log(`addEnvelopePoint: action ${JSON.stringify(action)}`)
const envelopeId = action.payload.envelopeId
var sequence: Sequence = state.value
var envelope = sequence.envelopes.find((envelope: any) => envelope.id === envelopeId);
if (envelope) {
envelope.points.push({time: action.payload.time, value: action.payload.value})
envelope.points = envelope.points.sort((a,b) => { return a.time - b.time })
console.log(`addEnvelopePoint: found envelope. Points are now ${JSON.stringify(envelope.points)}`)
}
return state
},
deleteEnvelopePoint(state, action) {
console.log(`deleteEnvelopePoint: point ${JSON.stringify(action.payload)} ${action.payload.envelopeId}`)
const envelopeId = action.payload.envelopeId
var sequence: Sequence = state.value
var envelope = sequence.envelopes.find((envelope: any) => envelope.id === envelopeId);
if (envelope) {
console.log(`deleteEnvelopePoint: envelope ${JSON.stringify(envelope)} ${envelope.points.length}`)
for (var n = 0; n < envelope.points.length; n++) {
console.log(`envelope.points[n] ${JSON.stringify(envelope.points[n])} == action.payload.point ${JSON.stringify(action.payload.point)}`)
if (envelope.points[n].time == action.payload.point.time && envelope.points[n].value == action.payload.point.value) {
envelope.points.splice(n, 1)
console.log('deleteEnvelopePoint: found it')
console.log(`deleteEnvelopePoint: envelope ${JSON.stringify(envelope)} ${envelope.points.length}`)
break;
}
}
}
return state
},
moveEnvelopePoint(state, action) {
console.log(`moveEnvelopePoint: point ${JSON.stringify(action.payload)} ${action.payload.envelopeId}`)
console.log(`moveEnvelopePoint: point ${JSON.stringify(action)}`)
const envelopeId = action.payload.envelopeId
const pointNum : number = action.payload.pointNum
const time : number = action.payload.time
const value : number = action.payload.value
var sequence: Sequence = state.value
var envelope = sequence.envelopes.find((envelope: any) => envelope.id === envelopeId);
if (envelope) {
console.log(`moveEnvelopePoint: envelope ${JSON.stringify(envelope)} point ${pointNum} -> ${time},${value}`)
envelope.points[pointNum].time = time
envelope.points[pointNum].value = value
}
return state
}
}
})
export const {
sequenceLoad,
sequenceName,
numSteps,
midiSettings,
division,
sequenceText,
length,
tempo,
stepControllerValue,
stepNote,
stepGateLength,
stepVelocity,
decrement,
envelopeValue,
addEnvelopePoint,
deleteEnvelopePoint,
currentEnvelopeId,
moveEnvelopePoint,
} = sequenceSlice.actions
export const selectSequence = (state: RootState) => state.sequence.value
export default sequenceSlice.reducer
The moment you call JSON.parse(JSON.stringify(payloadAction.payload.sequence)), you create a normal JavaScript object that just has the properties of the class instance, but not the functionality.
Generally, you should not be storing things like class instances in a Redux store - classes cannot be serialized (as you just saw here), which causes problems with the devtools and libraries like redux-persist. Also, they tend to modify themselves, which collides with the core tenets of Redux.
Store pure data instead, use reducers to do modifications and selectors to derive further data from it.

Camera rotation and OrbitControls in react-three/fiber

I am trying to create a scene with react-three/fiber and react-three/drei. I want to use a PerspectiveCamera and be able to pan/zoom/rotate with the mouse, but I am also trying to add some buttons that can update the camera position and target in order to have different views (eg. top view, bottom view, side view, etc). I have achieved the latter part and my buttons seem to be working as I update the target x,y,z and position x,y,z using props.
The only problem is that the camera is not responding to the mouse so I only get a fixed camera position and target.
I have included all the scene codes below.
import React,{ useRef, useState, useEffect} from 'react'
import * as THREE from 'three';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { PerspectiveCamera, Icosahedron, OrbitControls } from '#react-three/drei'
import { Canvas, useThree } from "#react-three/fiber";
function VisualizationComponent(props) {
const width = window.innerWidth;
const height = window.innerHeight;
const [controls, setControls] = useState(null);
const [threeState, setThreeState] = useState(null);
const [treeStateInitialized, setThreeStateInitialized] = useState(false);
useEffect(()=>{
if(threeState){
_.forOwn(props.objects, (value, key) => {
threeState.scene.current.add(value);
});
}
return () => {
if(controls) controls.dispose();
}
},[])
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const { objects } = props
const prevState = usePrevious({objects});
const mainCamera = useRef();
useEffect(() => {
if(!threeState) return;
if (
!treeStateInitialized ||
shouldUpdateObjects(props.objects, prevState.objects)
) {
setThreeStateInitialized(true);
garbageCollectOldObjects();
addDefaultObjects();
_.forOwn(props.objects, (value, key) => {
threeState.scene.add(value);
});
}
})
const addDefaultObjects = () => {
if (threeState) {
var hemiLight = new THREE.HemisphereLight( 0xffffbb, 0x080820, 0.2 );
hemiLight.position.set( 0, 0, 1 );
threeState.scene.add( hemiLight );
}
}
const garbageCollectOldObjects = () => {
while (threeState && threeState.scene.children.length) {
const oldObject = threeState.scene.children[0];
oldObject.traverse((child) => {
if (child.geometry) {
child.geometry?.dispose();
if(child.material && Array.isArray(child.material)){
child.material.forEach(d => d.dispose());
}else{
child.material?.dispose();
}
}
});
threeState.scene.remove(oldObject);
}
}
const shouldUpdateObjects = (currentObjects,nextObjects) => {
const result = false;
let currentDigest = 1;
let nextDigest = 1;
_.forIn(currentObjects, (value, key) => {
currentDigest *= value.id;
});
_.forIn(nextObjects, (value, key) => {
nextDigest *= value.id;
});
return currentDigest !== nextDigest;
}
const hasAncestorWhichDisablesThreeJs = (element) => {
if (!element) return false;
let isEditable = false;
for (let i = 0; i < element.classList.length; i++) {
if (element.classList[i] === 'disable-threejs-controls') {
isEditable = true;
}
}
return isEditable ||
hasAncestorWhichDisablesThreeJs(element.parentElement);
}
const initializeScene = (state) => {
setThreeState(state);
addDefaultObjects();
}
return (
<div
id="threejs-controllers-div"
className='threejs-container'
onMouseOver={ (e) => {
const target = e.target;
if (!target || !controls) return true;
if (hasAncestorWhichDisablesThreeJs(target)) {
controls.enabled = false;
} else {
controls.enabled = true;
}
} }
>
<Canvas
className='threejs'
onCreated={ (state) => {initializeScene(state)}}
shadows={true}
gl={
{
'shadowMap.enabled' : true,
'alpha' : true
}
}
>
<PerspectiveCamera
makeDefault
ref={mainCamera}
position-x={props.cameraX || 0}
position-y={props.cameraY || -20}
position-z={props.cameraZ || 20}
up={[0, 0, 1]}
fov={ 15 }
aspect={ width / height }
near={ 1 }
far={ 10000 }
visible={false}
controls={controls}
/>
<OrbitControls
ref={controls}
camera={mainCamera.current}
domElement={document.getElementById("threejs-controllers-div")}
enabled={true}
enablePan={true}
enableZoom={true}
enableRotate={true}
target-x={props.targetX || 0}
target-y={props.targetY || 0}
target-z={props.targetZ || 0}
/>
</Canvas>
<div className='threejs-react-container'>
{ props.children }
</div>
</div>
)
}
VisualizationComponent.propTypes = {
children: PropTypes.node.isRequired,
objects: PropTypes.object.isRequired,
cameraX: PropTypes.number,
cameraY: PropTypes.number,
cameraZ: PropTypes.number,
targetX: PropTypes.number,
targetY: PropTypes.number,
targetZ: PropTypes.number,
};
export default withRouter(VisualizationComponent);

How to make Compass in nativescript when i am unable to find north direction?

I am working on nativescript , but There are serious lack of libraries in it. I am not able to find north direction.
i have tried plugin
import * as geolocation from "nativescript-geolocation";
import { Accuracy } from "tns-core-modules/ui/enums";
test:function() {
var a = geolocation.getCurrentLocation({ desiredAccuracy: Accuracy.high, maximumAge: 5000, timeout: 20000 })
;
a.then( return_a => {
console.log("this------------------------------->",return_a);
//distance(return_a,);
var degree = angleFromCoordinate(return_a.latitude,return_a.longitude , 21.4225,39.8262);
console.log(degree);
this.gaugeValue = degree;//return_a.verticalAccuracy
});
}
});
function angleFromCoordinate( lat1, long1, lat2, long2) {
var dLon = (long2 - long1);
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
var brng = Math.atan2(y, x);
brng = brng * 180 / Math.PI;
brng = (brng + 360) % 360;
brng = 360 - brng; // count degrees counter-clockwise - remove to make clockwise
return brng;
}
There is direction property also available.but it is always -1 .
i am using Typescript , javascript as template language.
Here I found the solution. You need to do it manually.
import * as app from "tns-core-modules/application";
import { isAndroid, isIOS } from "tns-core-modules/platform";
declare const android: any;
declare const CLLocationManager: any;
export class MyClass {
private sensorUpdate: any;
private sensorManager: any;
startHeadingUpdates() {
if (this.sensorManager || this.sensorUpdate) {
return;
}
if (isIOS) {
this.sensorManager = CLLocationManager.alloc().init();
if (this.sensorManager.headingAvailable) {
this.sensorManager.startUpdatingHeading();
this.sensorUpdate = setInterval(() => {
console.log(this.sensorManager.heading.trueHeading);
}, 100);
} else {
console.log("Heading not available.");
}
return;
}
if (isAndroid) {
this.sensorManager = app.android.foregroundActivity.getSystemService(
android.content.Context.SENSOR_SERVICE
);
this.sensorUpdate = new android.hardware.SensorEventListener({
onAccuracyChanged: (sensor: any, accuracy: any) => {
// console.log(accuracy)
},
onSensorChanged: (event: any) => {
console.log(event.values[0]);
}
});
const orientationSensor = this.sensorManager.getDefaultSensor(
android.hardware.Sensor.TYPE_ORIENTATION
);
this.sensorManager.registerListener(
this.sensorUpdate,
orientationSensor,
android.hardware.SensorManager.SENSOR_DELAY_UI
);
}
}
stopUpdatingHeading() {
if (!this.sensorManager || !this.sensorUpdate) {
return;
}
if (isIOS) {
this.sensorManager.stopUpdatingHeading();
clearInterval(this.sensorUpdate);
this.sensorManager = null;
return;
}
if (isAndroid) {
this.sensorManager.unregisterListener(this.sensorUpdate);
this.sensorManager = null;
}
}
}

Nunjucks setup for koa v2

I have a Koa v2 app with koa-views#next as a renderer and nunjucks templating engine. Here is my working setup, which don't have any problem, I just confused with the double declaration of the views folder:
const Koa = require('koa');
const nunjucks = require('nunjucks');
const path = require('path');
const router = require('koa-router')();
const views = require('koa-views');
const app = new Koa();
const index = require('./routes/index');
app.use(views(path.join(__dirname, 'views'), {
extension: 'njk',
map: { njk: 'nunjucks' },
}));
nunjucks.configure(path.join(__dirname, 'views'), {
autoescape: true,
});
router.use('/', index.routes(), index.allowedMethods());
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000);
But if I don't do this, the rendering doesn't work. If I uncommenting the nunjucks.configure block, I'm getting the following error:
Template render error: (unknown path)
Error: template not found: layout.njk
Is there any problem with my setup?
I come up a solution to use nunjucks without any other renderer library in koa v2:
/*
USAGE:
import njk from './nunjucks';
// Templating - Must be used before any router
app.use(njk(path.join(__dirname, 'views'), {
extname: '.njk',
noCache: process.env.NODE_ENV !== 'production',
throwOnUndefined: true,
filters: {
json: function (str) {
return JSON.stringify(str, null, 2);
},
upperCase: str => str.toUpperCase(),
},
globals: {
version: 'v3.0.0',
},
}));
*/
// Inspired by:
// https://github.com/ohomer/koa-nunjucks-render/blob/master/index.js
// https://github.com/beliefgp/koa-nunjucks-next/blob/master/index.js
const Promise = require('bluebird');
const nunjucks = require('nunjucks');
function njk(path, opts) {
const env = nunjucks.configure(path, opts);
const extname = opts.extname || '';
const filters = opts.filters || {};
//console.time('benchmark');
const f = Object.keys(filters).length;
let i = 0;
while (i < f) {
env.addFilter(Object.keys(filters)[i], Object.values(filters)[i]);
i += 1;
}
//console.timeEnd('benchmark');
const globals = opts.globals || {};
const g = Object.keys(globals).length;
let j = 0;
while (j < g) {
env.addFilter(Object.keys(globals)[j], Object.values(globals)[j]);
j += 1;
}
return (ctx, next) => {
ctx.render = (view, context = {}) => {
context = Object.assign({}, ctx.state, context);
return new Promise((resolve, reject) => {
env.render(`${view}${extname}`, context, (err, res) => {
if (err) {
return reject(err);
}
ctx.body = res;
return resolve();
});
});
};
return next();
};
}
module.exports = njk;
Gist

Resources