3d-force-graph node and sprite text - three.js

I'm using the react version of 3d-force-graph and making some default nodes (spheres) and some sprite text nodes. (Return false does the default sphere node)
nodeThreeObject={node => {
if (node.id % 6 == 0){
const sprite = new SpriteText(buzzwords[node.id % buzzwords.length]);
sprite.color = "#8898aa";
sprite.textHeight = 12;
return sprite;
} else {
return false
}
}}
I was wondering how I could add a sphere node behind my text nodes. They look a little off without it.

simply set nodeThreeObjectExtend to true:
<ForceGraph3D
graphData={graphData}
nodeThreeObjectExtend={true}
nodeThreeObject={node => {
if (node.id % 6 == 0){
const sprite = new SpriteText(buzzwords[node.id % buzzwords.length]);
sprite.color = "#8898aa";
sprite.textHeight = 12;
return sprite;
} else {
return false
}
}}

Related

html/css-/js drag and drop for mouse and touch combine with rotate with every click?

I use a script for moving an object both with mouse and touch screen. This works.
I have another script to make the object rotate 90 degrees with each click, this also works.
It just doesn't work together.
When I merge them, the move still works, but with a click the object moves back to the starting position and only rotates there.
I've read that I should merge this but I don't know how. Below both scripts.
Thanks in advance for responses.
var container = document.querySelector("#container");
var activeItem = null;
var active = false;
container.addEventListener("touchstart", dragStart, false);
container.addEventListener("touchend", dragEnd, false);
container.addEventListener("touchmove", drag, false);
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);
function dragStart(e) {
if (e.target !== e.currentTarget) {
active = true;
// this is the item we are interacting with
activeItem = e.target;
if (activeItem !== null) {
if (!activeItem.xOffset) {
activeItem.xOffset = 0;
}
if (!activeItem.yOffset) {
activeItem.yOffset = 0;
}
if (e.type === "touchstart") {
activeItem.initialX = e.touches[0].clientX - activeItem.xOffset;
activeItem.initialY = e.touches[0].clientY - activeItem.yOffset;
} else {
console.log("doing something!");
activeItem.initialX = e.clientX - activeItem.xOffset;
activeItem.initialY = e.clientY - activeItem.yOffset;
}
}
}
}
function dragEnd(e) {
if (activeItem !== null) {
activeItem.initialX = activeItem.currentX;
activeItem.initialY = activeItem.currentY;
}
active = false;
activeItem = null;
}
function drag(e) {
if (active) {
if (e.type === "touchmove") {
e.preventDefault();
activeItem.currentX = e.touches[0].clientX - activeItem.initialX;
activeItem.currentY = e.touches[0].clientY - activeItem.initialY;
} else {
activeItem.currentX = e.clientX - activeItem.initialX;
activeItem.currentY = e.clientY - activeItem.initialY;
}
activeItem.xOffset = activeItem.currentX;
activeItem.yOffset = activeItem.currentY;
setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
}
}
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}
// Make blocks rotate 90 deg on each click
var count=0;
function rot(e){
count++;
var deg=count*90;
e.style.transform = "rotate("+deg+"deg)";
}
So I put them in a file but then it only works as described above.

Is it possible to round the edges of a row in jetpack?

This is what I'm trying to achieve:
So I have created 2 rounded buttons in a row and gave different background colors depending whether they're selected or not. The goal is to create a kind of an illusion of a tab/toggle.
The unselected button will have the same color as the row's background color. Unfortunately, since a row is a rectangle shape there comes a residue space at the corners that still shows the background color .
This is my code for the buttons
val cornerRadius = 20.dp
var selectedIndex by remember { mutableStateOf(0)}
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val items = listOf(
OutlinedButton(onClick = { /*TODO*/ }) {
},
OutlinedButton(onClick = { /*TODO*/ }) {
})
Row(
modifier = Modifier
.padding(top = 8.dp)
.wrapContentHeight()
.width(screenWidth).background(color = Color.Gray).clip(shape = RoundedCornerShape(20.dp))
) {
// Spacer(modifier = Modifier.weight(1f))
items.forEachIndexed { index, item ->
OutlinedButton(modifier = Modifier
.wrapContentHeight()
.width(screenWidth/2),
shape = when (index) {
// left outer button
0 -> (if (selectedIndex == index) {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
} else {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
})
//rightouterbutton
else -> (if (selectedIndex == index) {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
}
else{RoundedCornerShape(
topStart = 0.dp,
topEnd = cornerRadius,
bottomStart = 0.dp,
bottomEnd = cornerRadius
)})
},
border = BorderStroke(
1.dp, if (selectedIndex == index) {
Color.Transparent
} else {
Color.Transparent
}
),
colors = if (selectedIndex == index) {
// colors when selected
ButtonDefaults.outlinedButtonColors(
backgroundColor = Color.Yellow,
contentColor = Color.Black
)
} else {
// colors when not selected
ButtonDefaults.outlinedButtonColors(
backgroundColor = Color.Gray,
contentColor = Color.Black
)
},
onClick = { selectedIndex = index },
) {
if (index == 0) {
Text(
text = "In progress",
color = if (selectedIndex == index) {
Color.Black
} else {
Color.DarkGray.copy(alpha = 0.9f)
},
modifier = Modifier.padding(horizontal = 8.dp)
)
} else {
Text(
text = "Completed",
color = if (selectedIndex == index) {
MaterialTheme.colors.primary
} else {
Color.DarkGray.copy(alpha = 0.9f)
},
modifier = Modifier.padding(horizontal = 8.dp)
)
}
}
}
}
Modifier.clip applied after the Modifier.background has no effect in your case, you need to reverse the order. Read more about why the order of modifiers matters in this answer
.clip(shape = RoundedCornerShape(20.dp))
.background(color = Color.Gray)
Another option in the case of Modifier.background is that you can apply the shape specifically to the background color. Note that this solution will not clip other view content to the shape as Modifier.clip does, but in your case it fits.
.background(color = Color.Gray, shape = RoundedCornerShape(20.dp))

Draw polygon on MapBox map in Xamarin forms

I am using Mapbox for Xamarin.Forms NuGet to implement MapBox on Xamarin forms.
But I am not able to draw polygon on map.
Code:
Naxam.Controls.Mapbox.Forms.PolylineAnnotation polyline = null;
if (polyline == null)
{
polyline = new Naxam.Controls.Mapbox.Forms.PolylineAnnotation
{
HexColor = “#ff1234”,
Width = 100
};
}
// Set coordinates
List<CompanyGeoFenceVM> cordinates = new List<CompanyGeoFenceVM>();
var savedCordinates = Preferences.Get(“cordinates”, “”);
if (!string.IsNullOrEmpty(savedCordinates))
{
cordinates = JsonConvert.DeserializeObject<List<CompanyGeoFenceVM>>(savedCordinates);
}
foreach (var cordinate in cordinates)
{
if (polyline.Coordinates == null)
{
polyline.Coordinates = new ObservableCollection<Naxam.Controls.Mapbox.Forms.Position>
{ new Naxam.Controls.Mapbox.Forms.Position(cordinate.Latitude, cordinate.Longitude) };
}
else
{
(polyline.Coordinates as ObservableCollection<Naxam.Controls.Mapbox.Forms.Position>)
.Add(new Naxam.Controls.Mapbox.Forms.Position(cordinate.Latitude, cordinate.Longitude));
}
}
List<Naxam.Controls.Mapbox.Forms.PolylineAnnotation> polylineAnnotations = new List<Naxam.Controls.Mapbox.Forms.PolylineAnnotation>();
polylineAnnotations.Add(polyline);
//show polygon
map.Polylines = polylineAnnotations;
map.ZoomLevel = Device.RuntimePlatform == Device.Android ? 8 : 10;
Xamarin.Forms.Maps.Position position = await NexgenGeocoder.ReverseGeocode(Preferences.Get(“address”, “”));
map.Center = new Naxam.Controls.Mapbox.Forms.Position(position.Latitude , position.Longitude);
Here i am trying to add the polygon. cordinate is variable which has the coodinates required data to process. kindly help me on this. Thank you.
Included Naxam nuget package and plotted the polygon using Polyline. At last need to add a custom line to complete the Polyline area.
Naxam.Controls.Mapbox.Forms.PolylineAnnotation polyline = null;
ObservableCollection<Naxam.Controls.Mapbox.Forms.Annotation> annotations;
annotations = new ObservableCollection<Naxam.Controls.Mapbox.Forms.Annotation>();
//Add Polygon
if (polyline == null)
{
polyline = new Naxam.Controls.Mapbox.Forms.PolylineAnnotation
{
Id = "my_polyline",
Title = "Polygon",
HexColor = "#ff1234",
Width = 1
};
}
foreach (var cordinate in cordinates)
{
if (polyline.Coordinates == null)
{
polyline.Coordinates = new ObservableCollection<Naxam.Controls.Mapbox.Forms.Position>
{ new Naxam.Controls.Mapbox.Forms.Position(cordinate.Latitude, cordinate.Longitude) };
}
else
{
(polyline.Coordinates as ObservableCollection<Naxam.Controls.Mapbox.Forms.Position>)
.Add(new Naxam.Controls.Mapbox.Forms.Position(cordinate.Latitude, cordinate.Longitude));
}
}
//We are using polylines so we have to add ending point to line.
if (polyline.Coordinates != null)
(polyline.Coordinates as ObservableCollection<Naxam.Controls.Mapbox.Forms.Position>)
.Add(new Naxam.Controls.Mapbox.Forms.Position(cordinates[0].Latitude, cordinates[0].Longitude));
annotations.Add(polyline);
mapview.Annotations = annotations;

Grouping points after cut plane three js

I found all intersection points between the object and plane, as in this great example. But now I want to connect these points between themselves (dividing into separate arrays) where the plane passes and connect them again. I tried to connect them by distance, but this does not give an effective result
//SORT POINTS DISTANCE
var pointsArray = []; //point after intersection
var sortedPoints = [];
var sortedPointsDis = [];
sortedPoints.push( pointsArray.pop() );
while( pointsArray.length ) {
var distance = sortedPoints[sortedPoints.length - 1].distanceTo( pointsArray[0] );
var index = 0;
for(var i = 1; i < pointsArray.length; i++) {
var tempDistance = sortedPoints[sortedPoints.length - 1].distanceTo( pointsArray[i] );
if( tempDistance < distance ) {
distance = tempDistance;
index = i;
}
}
sortedPoints.push( pointsArray.splice(index, 1)[0] );
sortedPointsDis.push( distance );
}
//GROUP POINTS
var result = [[]];
for(var i = 0; i < sortedPoints.length; i++) {
var lastArr = result[result.length - 1];
if( lastArr.length < 3 ) {
lastArr.push( sortedPoints[i] );
} else {
var distance = lastArr[0].distanceTo( sortedPoints[i] );
if( distance < sortedPointsDis[i - 1] ) {
result.push([]);
lastArr = result[result.length - 1];
}
lastArr.push(sortedPoints[i]);
}
}
JSfiddle.
Ideas? Examples? Thank in advance for your replies!
So, yes, this answer based on that one and extends it. The solution is rough and can be optimized.
I've used modified .equals() method of THREE.Vector3() (I hope it (or something similar) will be a part of the core one day as it's a very useful feature), taken from here:
THREE.Vector3.prototype.equals = function(v, tolerance) {
if (tolerance === undefined) {
return ((v.x === this.x) && (v.y === this.y) && (v.z === this.z));
} else {
return ((Math.abs(v.x - this.x) < tolerance) && (Math.abs(v.y - this.y) < tolerance) && (Math.abs(v.z - this.z) < tolerance));
}
}
The idea:
When we're getting points of intersection, to each point we add information about which face a point belongs to. It means that there are always pairs of points with the same face index.
Then, we recursively find all the contours our points form.
Also, all points mark as unchecked (.checked = false).
Find first unchecked point. Add it to the array of the current contour.
Find its pair point (with the same face index). Add it to the array of the current contour.
Find an unchecked point, the closest one to the point found last. Makr it as checked .checked = true.
Find its pair point (with the same face index). Mark it as checked .checked = true.
Check, if the last found point equals (with some tolerance) to the first found point (the beginning of the contour)
5.1. If no, then just add the last found point in the array of the current contour and go to step 3.
5.2. If yes, then clone the first point of the current contour and add it to the array of the current contour, add the contour to the array of contours.
Check, if we have have all points marked as checked.
6.1. If no, then go to step 1.
6.2. If yes, we finished. Return the array of contours.
Modified function of setting a point of intersection:
function setPointOfIntersection(line, plane, faceIdx) {
pointOfIntersection = plane.intersectLine(line);
if (pointOfIntersection) {
let p = pointOfIntersection.clone();
p.faceIndex = faceIdx;
p.checked = false;
pointsOfIntersection.vertices.push(p);
};
}
How to get contours and how to draw them:
var contours = getContours(pointsOfIntersection.vertices, [], true);
contours.forEach(cntr => {
let cntrGeom = new THREE.Geometry();
cntrGeom.vertices = cntr;
let contour = new THREE.Line(cntrGeom, new THREE.LineBasicMaterial({
color: Math.random() * 0xffffff
}));
scene.add(contour);
});
Where
function getContours(points, contours, firstRun) {
console.log("firstRun:", firstRun);
let contour = [];
// find first line for the contour
let firstPointIndex = 0;
let secondPointIndex = 0;
let firsPoint, secondPoint;
for (let i = 0; i < points.length; i++) {
if (points[i].checked == true) continue;
firstPointIndex = i;
firstPoint = points[firstPointIndex];
firstPoint.checked = true;
secondPointIndex = getPairIndex(firstPoint, firstPointIndex, points);
secondPoint = points[secondPointIndex];
secondPoint.checked = true;
contour.push(firstPoint.clone());
contour.push(secondPoint.clone());
break;
}
contour = getContour(secondPoint, points, contour);
contours.push(contour);
let allChecked = 0;
points.forEach(p => { allChecked += p.checked == true ? 1 : 0; });
console.log("allChecked: ", allChecked == points.length);
if (allChecked != points.length) { return getContours(points, contours, false); }
return contours;
}
function getContour(currentPoint, points, contour){
let p1Index = getNearestPointIndex(currentPoint, points);
let p1 = points[p1Index];
p1.checked = true;
let p2Index = getPairIndex(p1, p1Index, points);
let p2 = points[p2Index];
p2.checked = true;
let isClosed = p2.equals(contour[0], tolerance);
if (!isClosed) {
contour.push(p2.clone());
return getContour(p2, points, contour);
} else {
contour.push(contour[0].clone());
return contour;
}
}
function getNearestPointIndex(point, points){
let index = 0;
for (let i = 0; i < points.length; i++){
let p = points[i];
if (p.checked == false && p.equals(point, tolerance)){
index = i;
break;
}
}
return index;
}
function getPairIndex(point, pointIndex, points) {
let index = 0;
for (let i = 0; i < points.length; i++) {
let p = points[i];
if (i != pointIndex && p.checked == false && p.faceIndex == point.faceIndex) {
index = i;
break;
}
}
return index;
}
jsfiddle example r87.

Flash AS2 - grouping enemies

So I have a Flash ActionScript 2 code, which creates a preset amount of enemies, gives enemies stats, and makes them move around randomly. Code:
//Settings
var mapWidth:Number = 550;
var mapHeight:Number = 400;
var enemiesArray:Array = new Array();
var totalEnemies:Number;
var eClip:MovieClip;
//Math functions
function getdistance(x, y, x1, y1)
{
run = x1-x;
rise = y1-y;
return (hyp(run, rise));
}
function hyp(a, b)
{
return (Math.sqrt(a*a+b*b));
}
function resetDirection(mc:MovieClip)
{
mc.roamTime = random(50);
mc.t = mc.roamTime;
mc.roamDistance = random(60)+25;
mc.randomRoamDistanceX = (Math.random()*mc.roamDistance)+mc.xx-(mc.roamDistance/2);
mc.randomRoamDistanceY = (Math.random()*mc.roamDistance)+mc.yy-(mc.roamDistance/2);
mc.newRoamDistance = getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY);
mc.norm = mc.roamSpeed/mc.newRoamDistance;
mc.finalRoamDistanceX = (mc.randomRoamDistanceX-mc.xx)*mc.norm;
mc.finalRoamDistanceY = (mc.randomRoamDistanceY-mc.yy)*mc.norm;
}
//function to move enemies
function moveIt(mc:MovieClip)
{
//reduce roamTime;
mc.t--;
//move enemy to new position
if (getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY)>mc.roamSpeed) {
mc._x += mc.finalRoamDistanceX;
mc._y += mc.finalRoamDistanceY;
}
//rotate enemy
XXXdiff = mc.xx-mc.randomRoamDistanceX;
YYYdiff = -(mc.yy-mc.randomRoamDistanceY);
rrradAngle = Math.atan(YYYdiff/XXXdiff);
if (XXXdiff<0) {
cccorrFactor = 270;
} else {
cccorrFactor = 90;
}
//
mc.ship_mc._rotation = -(rrradAngle*360/(2*Math.PI)+cccorrFactor);
//check if time to reset, based on roamTime
if (mc.t<=0) {
resetDirection(mc);
}
}
//
// Generate Enemies
//
// set and save enemy stats
//
//
// createEnemies(number of enemies you want, movieclip where you want to create the enemies);
//
function createEnemies(amount:Number, targetLocation:MovieClip) {
trace("createEnemies: "+amount);
for (var i = 0; i<amount; i++) {
randomXpos = Math.round(Math.random()*mapWidth);
randomYpos = Math.round(Math.random()*mapHeight);
//add new enemy to map
var newEnemy:MovieClip = targetLocation.attachMovie("enemy1", "enemy1_"+i, targetLocation.getNextHighestDepth());
enemiesArray.push(newEnemy);
//
//set enemy stats
newEnemy.id = i;
newEnemy._x = randomXpos;
newEnemy._y = randomYpos;
//save x and y position
newEnemy.xx = newEnemy._x;
newEnemy.yy = newEnemy._y;
//
newEnemy.roamSpeed = 2
newEnemy.roamTime = random(50);
newEnemy.roamDistance = random(60)+25;
newEnemy.t = 0;
//
newEnemy.myHealth = 10;
newEnemy.myName = "Small Scout";
//
resetDirection(newEnemy);
//target enemy
newEnemy.onPress = function() {
trace("Enemy: "+this.tName+" "+this.id);
target_txt.text = this.myName+": "+this.id+" Health: "+this.myHealth;
};
newEnemy.onEnterFrame = function() {
moveIt(this);
};
}
}
start_btn.onRelease = function() {
if (start_txt.text == "Start") {
//run the create enemies function to start the engine
createEnemies(box_mc.numberOfEnemies.text, map_mc);
//hide start button
start_txt._visible =false;
this._visible = false;
box_mc._visible = false;
}
};
I want program enemies to be grouped (based on fireflies algorithm). My idea is write for loop to define attractiveness, but I don't know how to make my objects move to the most attractiveness. Maybe someone would help me with this problem?
I change this line:
newEnemy.myHealth = 10;
on this
newEnemy.myHealth = Math.round(random(9)+1);
myHealth would be responsible for attractiveness. I try to use code from this site and modificate code to let objects with low attractiveness follow objects with large attractiveness. Also, I want to stop algorith, when they are in the groups.

Resources