threeJS Raycaster.set() not detecting intersections ( plane ) - threejs-editor

const origin = new THREE.Vector3(...point, -100),
direction = new THREE.Vector3(0, 0, 1) // is a normalized vector
const raycaster = new THREE.Raycaster( origin, direction );
const intersects = raycaster.intersectObject( dem ); // is a planeGeometry (mesh)
const length = 2000;
const hex = 0xff0000;
const arrowHelper = new THREE.ArrowHelper( direction, origin, length, hex );
cx3d.addObject( arrowHelper );
if( intersects.length ){
console.log( intersects[0] )
}
now intersects = [], but point is in the plane mesh, so I need help, thank everyone
like this https://jsfiddle.net/Hoshua/obm8ke0q/2/

You need to update your mesh matrix world with mesh.updateMatrixWorld();. See below.
function seta(){
const origin = new THREE.Vector3(0.5, 0, 0),
direction = new THREE.Vector3(-1, 0, 0)
const raycaster = new THREE.Raycaster( origin, direction );
mesh.updateMatrixWorld(); // here
const intersects = raycaster.intersectObject( mesh );
const length = 1.5;
const hex = 0xff0000;
const arrowHelper = new THREE.ArrowHelper( direction, origin, length, hex );
scene.add( arrowHelper );
console.log(intersects)
}
Not sure if link will work. In case: https://jsfiddle.net/4n0tgwuo/
Output:
[{
distance: 0.5,
face: {
a: 0,
b: 2,
c: 1,
materialIndex: 0,
normal: { ... }
},
faceIndex: 0,
object: {
animations: [],
castShadow: false,
children: [],
frustumCulled: true,
geometry: { ... },
isMesh: true,
isObject3D: true,
layers: { ... },
material: { ... },
matrix: { ... },
matrixAutoUpdate: true,
matrixWorld: { ... },
matrixWorldNeedsUpdate: false,
name: "",
parent: { ... },
position: { ... },
quaternion: { ... },
receiveShadow: false,
renderOrder: 0,
rotation: { ... },
scale: { ... },
type: "Mesh",
up: { ... },
userData: { ... },
uuid: "cb14eb31-b325-4252-8fb6-0d4417cbf39d",
visible: true
},
point: {
isVector3: true,
x: 0,
y: 0,
z: 0
},
uv: {
isVector2: true,
x: 0.5,
y: 0.5
}
}, {
distance: 0.5,
face: {
a: 2,
b: 3,
c: 1,
materialIndex: 0,
normal: { ... }
},
faceIndex: 1,
object: [circular object Object],
point: {
isVector3: true,
x: 0,
y: 0,
z: 0
},
uv: {
isVector2: true,
x: 0.5,
y: 0.5
}
}]

Related

Apex Line Area chart is not getting displayed on the page in Vuejs

I am stuck on a page where i am not able to display the charts on the page.
To make it simplify what I have done is, here is the code sandbox:
I see there an error in console about the data, I am not sure about it.
https://codesandbox.io/s/compassionate-snyder-bckoq
I want to display the chart like this (as an example), but I am not able to display on the code sandbox
Please help.
The format of series is not aligned with ApexCharts.
You need to transform the data to match with ApexChart format.
Please see the changes in the codesandbox.
https://codesandbox.io/s/small-dew-eztod?file=/src/components/HelloWorld.vue
options: {
// X axis labels
xaxis: {
type: 'date',
categories: ["2021-05-04", "2021-05-05", "2021-05-07"]
},
},
series: [
{
name: "total",
data: [2, 2, 1],
},
{
name: "pending",
data: [0, 1, 0],
},
{
name: "approved",
data: [2, 1, 1],
},
{
name: "rejected",
data: [0, 0, 0],
},
],
Transform data to fit ApexChart
const data = {
"2021-05-04": {
total: 2,
pending: 0,
approved: 2,
rejected: 0,
},
"2021-05-05": {
total: 2,
pending: 1,
approved: 1,
rejected: 0,
},
"2021-05-07": {
total: 1,
pending: 0,
approved: 1,
rejected: 0,
},
};
const xaxis = {
type: "date",
categories: Object.keys(data).map((key) => key), // ['2021-05-04', '2021-05-05', '2021-05-07']
};
let statusObj = [];
for (const dataValue of Object.values(data)) { // get the values from keys '2021-05-04', '2021-05-05' ...
// loop the values, e.g. 1st loop: { total: 2, pending: 0, approved: 2, rejected: 0, }
for (const [key, value] of Object.entries(dataValue)) {
// take 'total' as example, find if statusObj already has { name: 'total', data: [x] }, e.g. statusObj = { name: 'total', data: [1] }
const existingStatusIndex = Object.keys(statusObj).find(
(sKey) => statusObj[sKey].name === key
);
// if yes, return the index of it
if (existingStatusIndex) {
// add new data value to existing data object. e.g. { name: 'total', data: [1, 2] }
statusObj[existingStatusIndex].data.push(value);
continue;
}
// if no, create a new object and add it to statusObj
statusObj.push({
name: key,
data: [value],
});
}
}
Output:
xaxis {
type: 'date',
categories: [ '2021-05-04', '2021-05-05', '2021-05-07' ]
}
statusObj [
{ name: 'total', data: [ 2, 2, 1 ] },
{ name: 'pending', data: [ 0, 1, 0 ] },
{ name: 'approved', data: [ 2, 1, 1 ] },
{ name: 'rejected', data: [ 0, 0, 0 ] }
]

Trying to do slow scrolling, but it seems gsap can't handle as many events per scroll

I need to slow down scroll speed on the page to animate elements better (For example one wheel event on mine laptop makes deltaY = 378 and it's too hard to calculate correct offset to start animations). I decided to disable scroll with e.preventDefault() and e.returnValue = false. It works well, but sometimes page starts 'jumping', when u try to scroll.
import { gsap } from 'gsap'
import { ScrollToPlugin } from 'gsap/src/ScrollToPlugin.js'
gsap.registerPlugin(ScrollToPlugin);
export default {
data: () => {
return {
currentSlide: 0,
offsetTop: 0,
pageHeight: 0,
wheelCounter: 0,
scrollCounter: 0,
slides: [
{
id: 'ad1',
bg: '/hall.jpg'
},
{
id: 'ad2',
bg: '/home.jpg'
},
{
id: 'ad3',
bg: '/hall.jpg'
},
{
id: 'ad4',
bg: '/home.jpg'
}]
}
},
methods: {
checkScroll (event) {
event.returnValue = false
event.preventDefault()
let sliderGap = 300
let current, next
let tl = gsap.timeline()
this.wheelCounter += parseInt(event.deltaY / 5)
if (this.wheelCounter < 0) this.wheelCounter = 0
gsap.to(window, {scrollTo: this.wheelCounter, duration: 0.2})
current = parseInt(this.wheelCounter / sliderGap)
if (current > 4) current = 4
if ((current != this.currentSlide) && (current < 4)) {
document.getElementById('main').style.backgroundImage = 'url("' + this.slides[current].bg + '")'
tl.to('#' + this.slides[this.currentSlide].id, {x: 20, opacity: 0, duration: 0.3})
tl.to('#' + this.slides[current].id, {x: -20, opacity: 1, duration: 0.7})
this.currentSlide = current
}
if (window.scrollY > 300) {
tl.to('#about_header', {x: 0, opacity: 1, duration: 0.7})
tl.to('#about_description', {y: 0, opacity: 1, duration: 0.7}, 0.5)
tl.to('#about_picture', {x: 0, opacity: 1, duration: 1}, 0.5)
}
if (window.scrollY > 500) {
tl.to('#left_offer', {y: 0, opacity: 1, duration: 1}, 0)
tl.to('#right_offer', {y: 0, opacity: 1, duration: 1}, 0.5)
tl.to('#offers_description', {x: 0, opacity: 1, duration: 0.5}, 1.5)
}
}
}
}
I thought about adding vue-observe-visibility package and perform animation via it. But scroll should be smooth too and idk how can I do it.

How to calculate array of numbers in vuejs

I have array. in that array there is a field name debit. I want to add all the debit on this array and find the total. I am trying to do this with reduce function. but it's adding number as character not calculating the sum of the array number. here is the code
export default {
data() {
return {
fields: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
dataRemove(index) {
Vue.delete(this.fields, index);
},
calculate() {
this.allDebit = this.fields.reduce((acc, item) => acc + item.debit, 0);
}
}
}
output:
{
"fields": [
{
"debit": "4",
"credit": "2",
"type": ""
},
{
"debit": "4",
"credit": "2",
"type": ""
}
],
"allDebit": "044",
"allCredit": 0
}
fields: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
You specify object fields and array in the data. You cannot have an object with two identical keys in the object literal. That is not a valid JS. I wouldn't be surprised if that was the reason.
Also, your values in output seem to all be strings. Try parseInt function in the reduce function.
convert string to number and then sum them
calculate() {
this.allDebit = this.fields.reduce((acc, item) => Number(acc) + Number(item.debit), 0);
}
Rename first fields to field, or remove it completely, I do not see where do you use it.
Parse to integer item.debit either in the accumulator or in the place where do you set it.
The possible fix:
export default {
data() {
return {
field: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
dataRemove(index) {
Vue.delete(this.fields, index);
},
calculate() {
this.allDebit = this.fields.reduce((acc, item) => acc + parseInt(item.debit), 0);
}
}
}
export default {
data() {
return {
fields: { // this is identical to the fields: [] array
// you need to rename it to something like field (Singular)
debit: 0,
credit: 0,
type: '',
},
// maybe you ment
field: { // field (Singular)
debit: 0,
credit: 0,
type: '',
},
//
fields: [], // THIS !!!
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
calculate() {
const { debit } = this.fields.reduce((acc, item) => {
return { debit: acc.debit + item.debit };
}, { debit: 0 })
this.allDebit = debit;
}
}
}
You can't have 2 identical keys in the data function property.
I would do this in a computed property instead, so that the value is calculated again if fields changes.
computed: {
allDebit() {
return this.fields.reduce((acc, item) => acc + parseInt(item.debit), 0);
}
}
EDIT: You can't have two properties with the same key in your data function. You have fields two times.

Chartist Pie Char Custom Label

I am trying to customize the label of Chartist Pie Chart so that it will show both the label and value.
So in the example below, I would want the label to show "Bananas - 20", "Apples - 15", "Grapes - 40". I know I can just change the labels:, but is there a way to do that with the labelInterpolationFnc?
https://jsfiddle.net/ckmz7L1p/
var data = {
labels: ['Bananas', 'Apples', 'Grapes'],
series: [20, 15, 40]
};
var options = {
labelInterpolationFnc: function(value) {
return value[0]
}
};
var responsiveOptions = [
['screen and (min-width: 640px)', {
chartPadding: 30,
labelOffset: 100,
labelDirection: 'explode',
labelInterpolationFnc: function(value) {
return value;
}
}],
['screen and (min-width: 1024px)', {
labelOffset: 80,
chartPadding: 20
}]
];
new Chartist.Pie('.ct-chart', data, options, responsiveOptions);
Got it figured out. Didn't realize labelInterpolationFnc can take function with both value and index parameters.
var data = {
labels: ['Bananas', 'Apples', 'Grapes'],
series: [20, 15, 40]
};
var options = {
width: "400px",
height: "400px",
labelInterpolationFnc: function(value, idx) {
return value + " - " + data.series[idx];
}
};
var responsiveOptions = [
['screen and (min-width: 640px)', {
chartPadding: 0,
labelOffset: 0,
labelDirection: 'explode',
labelInterpolationFnc: function(value, idx) {
return value + " - " + data.series[idx];
}
}],
['screen and (min-width: 1024px)', {
labelOffset: 30,
chartPadding: 0
}]
];
new Chartist.Pie('.ct-chart', data, options, responsiveOptions);

How to customize czml datasource?

I have a CZML data that I extracted via python.
I have buildings, with their geometry, height, building ID, and intervals. each interval has a value.
After loading the czml data to Cesium, I'd like to access the attributes and then customize the color of the buildings according to the value given.
Here is a sample of my CZML:
[{
"id": "document",
"version": "1.0"
}, {
"id": 32,
"availability": "2014-01-01T00:00:00Z/2014-12-31T00:00:00Z",
"polygon": {
"positions": {
"cartographicDegrees": [54.7162360431897, 24.4519912715277, 0, 54.716219612921, 24.4519754832587, 0, 54.7162501395131, 24.4519488635358, 0, 54.7162465684811, 24.4519454316688, 0, 54.7162670831639, 24.4519275432238, 0, 54.7162707308589, 24.4519310439514, 0, 54.7163022563025, 24.4519035537608, 0, 54.7161962974502, 24.4518018819532, 0, 54.7161647729823, 24.4518293730395, 0, 54.7162035538772, 24.4520196028966, 0, 54.7162360431897, 24.4519912715277, 0]
},
"someProperty": [{
"interval": "2014-00-01T00:00:00Z/2014-01-01T00:00:00Z",
"En_C_need": 0.7
}, {
"interval": "2014-01-01T00:00:00Z/2014-02-01T00:00:00Z",
"En_C_need": 1.0
}, {
"interval": "2014-02-01T00:00:00Z/2014-03-01T00:00:00Z",
"En_C_need": 2.6
}, {
"interval": "2014-03-01T00:00:00Z/2014-04-01T00:00:00Z",
"En_C_need": 12.1
}, {
"interval": "2014-04-01T00:00:00Z/2014-05-01T00:00:00Z",
"En_C_need": 30.2
}, {
"interval": "2014-05-01T00:00:00Z/2014-06-01T00:00:00Z",
"En_C_need": 37.8
}],
"extrudedHeight": 6.0
}
}]
I have other GeoJSON data that I customized, I tried the same method but it didn't work.
Here is what I'm trying to do (this does not work):
var test2 = Cesium.CzmlDataSource.load ('Data/czml/TESTING/example_8.czml');
test2.then(function (dataSource) {
viewer.dataSources.add(test2);
viewer.zoomTo (test2);
var entities = dataSource.entities.values;
var colorHash = {};
var Energy = [];
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
Energy = entity.someProperty.En_C_need;
var color = colorHash [Energy];
if(!color ) {
if (Energy < 5 ) {
color = Cesium.Color.DARKSALMON.withAlpha (0.95);
} else if (Energy < 10) {
color = Cesium.Color.BURLYWOOD.withAlpha (0.95);
} else if (Energy < 20) {
color = Cesium.Color.RED.withAlpha (0.95);
} else {
color = Cesium.Color.PINK.withAlpha (0.95);
};
colorHash[Energy] = color;
};
entity.polygon.fill = true;
entity.polygon.material = color;
entity.polygon.outline = false;
};
});
To start with the solution - here's the working plnkr:
https://plnkr.co/edit/P1Cg4DNJYtK9r9XrLzxK?p=preview
I've changed several things in your code:
1) viewer.dataSources.add(test2); should be outside your promise (it doesn't really matter, but it's cleaner code - using the promise inside the promise feels strange).
2) According to the CZML properties spec, you need to place the properties in the right location in the CZML. It should not be inside the polygon, but in the "root":
var czml = [{"id": "document", "version": "1.0"},
{
"id": 32, "availability": "2014-01-01T00:00:00Z/2014-12-31T00:00:00Z", "properties": {
"someProperty": [
{"interval": "2014-00-01T00:00:00Z/2014-01-01T00:00:00Z", "En_C_need": 0.7},
{"interval": "2014-01-01T00:00:00Z/2014-02-01T00:00:00Z", "En_C_need": 1.0},
{"interval": "2014-02-01T00:00:00Z/2014-03-01T00:00:00Z", "En_C_need": 2.6},
{"interval": "2014-03-01T00:00:00Z/2014-04-01T00:00:00Z", "En_C_need": 12.1},
{"interval": "2014-04-01T00:00:00Z/2014-05-01T00:00:00Z", "En_C_need": 30.2},
{"interval": "2014-05-01T00:00:00Z/2014-06-01T00:00:00Z", "En_C_need": 37.8}
],
},
"polygon": {
"positions": {
"cartographicDegrees":
[54.7162360431897, 24.4519912715277, 0, 54.716219612921, 24.4519754832587, 0, 54.7162501395131, 24.4519488635358, 0, 54.7162465684811, 24.4519454316688, 0, 54.7162670831639, 24.4519275432238, 0, 54.7162707308589, 24.4519310439514, 0, 54.7163022563025, 24.4519035537608, 0, 54.7161962974502, 24.4518018819532, 0, 54.7161647729823, 24.4518293730395, 0, 54.7162035538772, 24.4520196028966, 0, 54.7162360431897, 24.4519912715277, 0]
},
"extrudedHeight": 6.0
}
}];
Then you can ask for the properties according to the interval (Energy = entity.properties.getValue(viewer.clock.currentTime).someProperty.En_C_need;) and get the Energy at viewer's current time.
Update after commentchatting:
Your code was not meant to change dynamically. You need to set the value either by callbackProperty as in this example: plnkr.co/edit/lm290uaQewEvfIOgXbDP?p=preview or by using timeIntervalCollection