I'm trying to catch all the mouse coordinates using 'mousemove'.
import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
export class numbersThrower {
static numbersGo() {
const obs$ = fromEvent(document,'mousemove');
obs$.pipe(
throttleTime(10000)
)
return obs$;
}
}
const obs$ = numbersThrower.numbersGo();
obs$.subscribe(
(data)=>console.log(data)
)
This is what I get: MouseEvent {isTrusted: true, constructor: Object}
Why aren't there the screenX and screenY properties?
I got your issue, console does not shows the complete Event object.I am assuming you are trying your code in any online editor.
It does not happens in local development environment.
I have faced such issue in stackblitz but you can still access the screenX and screenY position by specifying the respective event type.
obs$.subscribe(
(data:MouseEvent)=>console.log(data.screenX, data.screenY)
)
Related
[Hi, I am trying to add texture to 3d modal loaded through useLoader i use primitive that react three fiber provides and when i add map prop and pass img to it, it doesn't work. please help me][1]
import { useLoader, useFrame } from '#react-three/fiber'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { Environment, OrbitControls, OrthographicCamera } from "#react-three/drei";
import { Canvas } from "#react-three/fiber";
import { useState, Suspense } from "react";
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { Texture, TextureLoader } from "three";
import Wrapper from "../assets/wrapper.jpg";
const Scene = () => {
const ref = useRef();
useFrame(() => {
// ref.current.rotation.z += 0;
ref.current.rotation.y += 0.01;
// ref.current.rotation.x = 0.09;
// ref.current.rotation.x += -170;
});
const img = useLoader(TextureLoader, Wrapper);
const obj = useLoader(OBJLoader, 'fibbia_wrap.obj');
return (
<>
<primitive map={img} ref={ref} object={obj} scale={0.6} />
</>
)
}```
[1]: https://i.stack.imgur.com/KixV1.png
In this case, don't use primitive.
1) First, export your modal in.glb form.
2) Then use gltfjsx package, this package will auto-generate JSX code for your modal.
Which then you can use. In order to learn more about this package go to (https://github.com/pmndrs/gltfjsx).
3) After that you are good to go the gltfjsx package provides code consisting of mesh and mesh can take map property which primitive can't.
I am using HostListener to get window close event and try to prevent the event.
I imported HostListener First and Used this code. But, I couldn't prevent the window close event.
import { HostListener } from '#angular/core';
#HostListener('window:beforeunload', ['$event'])
onWindowClose(event: any): void {
this.doSomething();
}
You can prevent window close event for separate component, using HostListener.
First Import HostListener in your component
import { HostListener } from '#angular/core';
And, Use this code to prevent window close.
#HostListener('window:beforeunload', ['$event'])
onWindowClose(event: any): void {
// Do something
event.preventDefault();
event.returnValue = false;
}
Now, Your event was prevented.
What I am trying to accomplish is: having a ScalaFX application with some nice ordered objects called Buttons, Labels, Checkboxes and so on to keep everything nice and in order.
Here a little example to show what I mean:
package ButtonsAndLabel
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.control.{ Button, Label }
import scalafx.event.ActionEvent
object Main extends JFXApp {
stage = new JFXApp.PrimaryStage {
title = "Test-Program"
scene = new Scene(300, 200) {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
content = List(label, button1, button2)
}
}
}
This code shows a window with a label and two buttons, and the buttons change the text of the label.
That works fine.
But when my code grows with a lot more controls, things get messy.
That's why I tried to transfer the controls into other objects (in different files). I've put the label into an object called Labels:
package ButtonsAndLabel
import scalafx.scene.control.Label
import scalafx.event.ActionEvent
object Labels {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
}
when I import this into the main-file with
import Labels.label
everything works fine.
But then I try to put the buttons into a Buttons object:
package ButtonsAndLabel
import scalafx.scene.control.Button
import scalafx.event.ActionEvent
import Labels.label
object Buttons {
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
}
this brings the error message when I try to compile:
[error] found : scalafx.event.ActionEvent => Unit
[error] required: javafx.event.EventHandler[javafx.event.ActionEvent]
[error] onAction = (e: ActionEvent) => {
and now I am stuck, as I don't know any Java.
Does anybody know if it is even possible what I am trying to do?
So far I have not found anything about this on the net. The problem doesn't keep me from writing the program I want, but the last application I wrote was a real mess with all the controls in one file.
Am I overlooking something obvious here?
Any help would be really appreciated.
Firstly, your approach is perfectly OK.
The error you're seeing actually has nothing to do with Java—it's output by the Scala compiler! All it's saying is that it has been supplied one type of element (in this case, a function that takes a scalafx.event.ActionEvent and that returns Unit) when it was expecting another type of element (a javafx.event.EventHandler[javafx.event.ActionEvent] instance, in this case).
ScalaFX is just a set of Scala-friendly wrappers for the JavaFX library; without the implicit conversion functions that convert between the two sets of elements, the Scala compiler will complain about finding ScalaFX elements when it needs JavaFX elements, and vice versa.
The solution is to ensure that the following import is added to each of your ScalaFX source files:
import scalafx.Includes._
(You have this at the top of your main source file, but not the others.)
This will ensure that your ScalaFX ActionEvent handler is converted into the JavaFX equivalent, thereby making your life a little easier.
This is a very common type of error with ScalaFX, which is nearly always fixed by specifying the above import. (If the import doesn't fix your problem, then you will typically have a genuine case of type confusion, in which you just plain used the wrong type of object.)
So, here's what I think your code needs to look like:
Main.scala:
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.scene.Scene
import buttonsandlabel._
object Main extends JFXApp {
stage = new JFXApp.PrimaryStage {
title = "Test-Program"
scene = new Scene(300, 200) {
content = List(Labels.label, Buttons.button1, Buttons.button2)
}
}
}
buttonsandlabel/Labels.scala:
package buttonsandlabel
import scalafx.Includes._
import scalafx.scene.control.Label
object Labels {
val label = new Label("Nothing happened yet") {
layoutX = 20
layoutY = 20
}
}
buttonsandlabel/Buttons.scala:
package buttonsandlabel
import scalafx.Includes._
import scalafx.scene.control.Button
import scalafx.event.ActionEvent
import Labels.label
object Buttons {
val button1 = new Button("Button 1") {
layoutX = 20
layoutY = 50
onAction = (e: ActionEvent) => {
label.text = "B1 klicked"
}
}
val button2 = new Button("Button 2") {
layoutX = 20
layoutY = 80
onAction = (e: ActionEvent) => {
label.text = "B2 klicked"
}
}
}
(Note that package names, by convention, are typically all lowercase.)
One thing that you'll need to be aware of is the JavaFX Application Thread: all of your code that interacts with ScalaFX (or JavaFX) must execute on this thread. If you access ScalaFX/JavaFX from a different thread, you'll get an error exception. (This ensures that all such applications are thread-safe.) If you're unfamiliar with multi-threading, don't worry, ScalaFX initializes your application in such a way that this is fairly trivial. Usually, all that's needed is that your initialization code goes into your main application object's constructor (the object that extends JFXApp).
When you start creating ScalaFX elements in other classes and objects, you need to take extra care. An object is initialized when first referenced. If it is first referenced by code that is not executing on the JavaFX Application Thread, then you'll get thread error exceptions. One possible option is to put such code into def or lazy val members, so that they are only executed when referenced directly.
Alternatively, you may have to invoke your code via scalafx.application.Platform.runLater().
For more information on the JavaFX Application Thread, refer to the JavaFX documentation.
I've pairs of events: add1/add2/etc and remove1/remove2/etc. I'd like the following:
when an add1 is emitted on the stream
if DELAY transpires with no new add* emissions
emit remove1
if add* is emitted
emit remove1 for add1 immediately
emit remove* for add* after DELAY
This should continue for all emissions of add* on the stream.
Here's a test I've written using RxJS marble testing for this case:
import test from 'tape'
import { set, lensPath } from 'ramda'
import { TestScheduler } from 'rxjs/testing'
import hideAfterDelay from '../another/file'
import { actionCreators } from '../another/dir'
const prefix = 'epics -> notifications'
test(`${prefix} -> hideAfterDelay`, t => {
t.plan(1)
const scheduler = new TestScheduler(t.deepEqual)
const actionMap = {
a: createAddAction('hello!'),
b: createAddAction('goodbye!'),
x: actionCreators.notifications.remove('hello!'),
y: actionCreators.notifications.remove('goodbye!')
}
scheduler.run(({ cold, expectObservable }) => {
const actionStream = cold('a-------a-b-a------', actionMap)
const expected = '-----x-----x-y----x'
const actual = hideAfterDelay(5)(actionStream)
expectObservable(actual).toBe(expected, actionMap)
})
})
function createAddAction (name) {
const action = actionCreators.notifications.add(name)
const lens = lensPath(['payload', 'id'])
return set(lens, name, action)
}
I think the test is representative of the behavior I described above and that I want.
How can I write this observable? I've tried using timer and race but I haven't been able to get this working...
This is an epic using redux-observable, btw.
Using RxJS v6
Ok, I think I got a working solution using a closure and slightly modifying my test assertion.
First, the expected marble diagram should look like this
// input: a-------a-b-a------
// - expected: -----x-----x-y----x
// + expected: -----x----x-y----x
//
// Note above that the middle x and y emit at the same time as new
// `add*` actions on the source stream instead of one frame later
With that small change—which still feels consistent with my description in the question—I was able to get my test passing with the following:
import { of, timer, empty } from 'rxjs'
import { switchMap, mapTo, tap, merge } from 'rxjs/operators'
import { ofType } from '../operators'
import actionTypes from '../../actionTypes/notifications'
import { actionCreators } from '../..'
export default (delay = 3000) => actionStream => {
let immediateRemove
return actionStream.pipe(
ofType(actionTypes.ADD),
switchMap(action => {
let obs = empty()
if (immediateRemove) {
obs = of(immediateRemove)
}
const remove = actionCreators.notifications.remove(action.payload.id)
immediateRemove = remove
return obs.pipe(
merge(
timer(delay).pipe(
tap(() => {
immediateRemove = null
}),
mapTo(remove)
)
)
)
})
)
}
I've no idea if this is the best or right way to solve it, but I'm fairly certain it is a way.
I have created a service which checks for changes in parent component and send notifications to the child component.
Below is the simple service.
import { Injectable } from '#angular/core';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { CloudDate } from './cloudDate';
import { Clouding } from './clouding';
#Injectable()
export class CloudingService {
// Observable string sources
private cloudingAnnouncedSource = new ReplaySubject<Clouding>(1);
private cloudingConfirmedSource = new ReplaySubject<Clouding>(1);
// Observable string streams
cloudingAnnounced$ = this.cloudingAnnouncedSource.asObservable();
cloudingConfirmed$ = this.cloudingConfirmedSource.asObservable();
// Service message commands
announceClouding(clouding: Clouding) {
this.cloudingAnnouncedSource.next(clouding);
}
confirmClouding(clouding: Clouding) {
this.cloudingConfirmedSource.next(clouding);
}
}
Clouding class looks like this:
export class Clouding {
cameraName: string;
cloudDate: string;
cameraType: string;
}
Now in the parent component, this class is initialized in the constructor and its variables will change depending on different methods.
Example:
// In constructor
this.clouding = new Clouding();
// A method
getCameras(): void {
this.clouding.cameraName = this.currentCloudName;
}
//Another method
getCloudDates(): void {
this.clouding.cloudDate = this.currentCloudDate.cloudDate;
}
The variables this.currentCloudName and this.currentCloudDate.cloudDate will change dynamically depending on button clicks.
When the buttons are clicked, I do:
this.cloudingService.announceClouding(this.clouding);
In child component, I do this to get the new value of clouding.
import { Component, OnDestroy, Input, OnInit } from '#angular/core';
import { Clouding} from './clouding';
import { CloudingService } from './clouding.service';
import { Subscription } from 'rxjs/Subscription';
#Component({
selector: 'app-images',
templateUrl: './images.component.html',
styleUrls: ['./images.component.css']
})
export class ImagesComponent implements OnDestroy, OnInit {
title = 'Images';
#Input()
clouding: Clouding;
subscription: Subscription;
constructor(
private cloudingService: CloudingService
) {
}
ngOnInit(): void {
this.subscription =
this.cloudingService.cloudingAnnounced$.subscribe(
clouding => {
this.clouding = clouding;
console.log(this.clouding);
},
// The 2nd callback handles errors.
(err) => console.error(err),
// The 3rd callback handles the "complete" event.
() => {
}
);
this.cloudingService.confirmClouding(this.clouding);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}
Now on the console, I get the below when I click on a button in the parent:
Clouding {cameraName: "Benjamin2", cloudDate: "2017-08-26"}
Clouding {cameraName: "Benjamin2", cloudDate: "2017-08-24"}
My question is, is there a way to make console print only the last change i.e.
Clouding {cameraName: "Benjamin2", cloudDate: "2017-08-24"}
and ignore the first change that occurred. I dont want to do execute a method everytime the object changes, just execute after all changes have been subscribed.
Hope the question is clear.
It sounds like you need a third button to trigger the announce, take this off the name-setting button and date-setting button and put it on the new button.
this.cloudingService.announceClouding(this.clouding);