I have a RelativeLayout, and multiple polygons/labels in it. Now I want to place the labels inside the polygons, in the center of it. However, I don't know the width and height of the label, so placing them in the center results in something like this:
However, this is wrong, as I want the label to be in the exact middle of the polygon (of which the width and height is known), no matter what the text is.
I've looked into methods to try to center it, for example using HorizontalTextAlignment and VerticalTextAlignment, but so far no success. What is the right way to do that? HorizontalOptions doesn't work either, as it's not relative to a parent or something.
Code I'm currently using:
var MainGrid = new RelativeLayout();
var path = new PointCollection();
// add points to path
var coords = new Point(100, 100);
var TILE_WIDTH = 70;
var TILE_HEIGHT = 80;
// Here the real code begins
polygon = new Polygon
{
Points = path,
<other arguments>
};
var text = new Label
{
Text = "5",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
TextColor = Color.Black,
};
MainGrid.Children.Add(
polygon,
Constraint.Constant(coords.X),
Constraint.Constant(coords.Y)
);
MainGrid.Children.Add(
text,
Constraint.Constant(coords.X + TILE_WIDTH / 2),
Constraint.Constant(coords.Y + TILE_HEIGHT / 2)
);
set an arbitrary width and height on the label, as long as it is big enough to fit your text and smaller than the polygon. Also set a background color to help visualize the placement of the label (remove this once you get the alignment right)
var text = new Label
{
Text = "5",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
TextColor = Color.Black,
BackgroundColor = Color.White,
HeightRequest = 50,
WidthRequest = 50
};
then factor in the label width and height when placing it
MainGrid.Children.Add(
text,
Constraint.Constant(coords.X + (TILE_WIDTH / 2) - 25),
Constraint.Constant(coords.Y + (TILE_HEIGHT / 2) - 25)
);
Related
I want to display a babylon image but I can't position it, because a BABYLON.GUI.Image doens't seem to have properties like x, y or position.
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
const image = new BABYLON.GUI.Image("but", "bvtech_logo.jpg");
image.width = "300px";
image.height = "100px";
//The following 2 lines don't work
image.x = 10;
image.y = "10px";
advancedTexture.addControl(image);
You must use the properties left and top. The problem is that you have to remenber that if you say image.left = 0 it means that the center of the image is at the center of the canvas. So if you want the top left corner of the screen to be the origin (0, 0) you must use a utility function
const positionImage = (image, x, y) => {
const canvas = document.getElementById('myCanvas');
image.left = - canvas.width / 2 + image.width / 2 + x;
image.top = - canvas.height / 2 + image.height / 2 + y;
};
positionImage(myImage, 10, 10);
I’m a bit new to working with 3D space and rotation. I have a list of four Vector3 points that represent the corners of a rectangle. What I want to do is use those points to create a box mesh that is rotated to exactly match the angle of rotation of the points.
Here is a babylonjs playground demo showing what I mean. In it you can see I’ve drawn a simple line mesh between the points. That is great and the rectangle drawn is at the expected angle given the data. I’ve also created a box mesh and configured its dimensions to match and placed its center point in the proper center of the points. So far so good, however I cannot figure out how to rotate the box so that it’s top face is parallel with the face of the rectangle.
https://playground.babylonjs.com/#SN5K8L#2
var createScene = function () {
// This creates a basic Babylon Scene object (non-mesh)
var scene = new BABYLON.Scene(engine);
// This creates and positions a free camera (non-mesh)
var target = new BABYLON.Vector3(1.5, 4, 0)
var camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 2 + Math.PI, Math.PI / 4, 10, target, scene)
// This attaches the camera to the canvas
camera.attachControl(canvas, true);
// This creates a light, aiming 0,1,0 - to the sky (non-mesh)
var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount
light.intensity = 0.7;
const axes = new BABYLON.AxesViewer(scene)
const points = [
new BABYLON.Vector3(1, 5, 1),
new BABYLON.Vector3(2, 5, 1),
new BABYLON.Vector3(2, 3, -1),
new BABYLON.Vector3(1, 3, -1)
]
const lines = BABYLON.MeshBuilder.CreateLines("lines", {
points: [...points, points[0]] // add a duplicate of first point to close polygon
}, scene)
const centerPoint = new BABYLON.Vector3(
(points[0].x + points[1].x + points[2].x + points[3].x) / 4,
(points[0].y + points[1].y + points[2].y + points[3].y) / 4,
(points[0].z + points[1].z + points[2].z + points[3].z) / 4
)
const width = Math.sqrt(
Math.pow(points[1].x - points[0].x, 2) +
Math.pow(points[1].y - points[0].y, 2) +
Math.pow(points[1].z - points[0].z, 2)
)
const depth = Math.sqrt(
Math.pow(points[2].x - points[1].x, 2) +
Math.pow(points[2].y - points[1].y, 2) +
Math.pow(points[2].z - points[1].z, 2)
)
const height = 0.15
const box = BABYLON.CreateBox("box", { width, height, depth}, scene)
box.position = centerPoint
//box.rotation = ???
return scene;
};
You can use Vector3.RotationFromAxis to compute the required rotation in Euler angles:
const rotationAxisX = points[1].subtract(points[0])
const rotationAxisZ = points[1].subtract(points[2])
const rotationAxisY = rotationAxisZ.cross(rotationAxisX)
// RotationFromAxis has the side effect of normalising the input vectors
// so retrieve the box dimensions here
const width = rotationAxisX.length()
const depth = rotationAxisZ.length()
const height = 0.15
const rotationEuler = BABYLON.Vector3.RotationFromAxis(
rotationAxisX,
rotationAxisY,
rotationAxisZ
)
const box = BABYLON.CreateBox("box", { width, height, depth}, scene)
box.position = centerPoint
box.rotation = rotationEuler
I need to add a class to a Rect. I can't seem to figure out how to do it.
bar = (new Rect(x, ySegment * 10 + 30 + margin, w, 0)
.attr('opacity', 0.8)
.attr('class', data[i].segments[j].color)
.addTo(stage));
the class attr is ignored.
A DisplayObject like Rect isn't the representation of an HTMLElement. That's why custom attributes like "class" don't work. If your intention is to re-use attributes for different DisplayObjects, then try the following:
var myAttrs = {
fillColor: 'red',
opacity: 0.5
};
new Rect(20, 20, 100, 100).attr(myAttrs).addTo(stage);
new Rect(20, 130, 100, 100).attr(myAttrs).addTo(stage);
Play with it here: Orbit
I am new to Leaflet and I am currently struggling with tutorials. So far I managed to create an interactive clorophet map, like in the example http://leafletjs.com/examples/choropleth.html.
Is it possible to add a title (simple text, not dynamic) to the legged located on the bottomright of the page? Could anyone tell me how, by just referring to the linked example?
You just need to add your title under "THE TITLE"...
var legend = L.control({position: 'topleft'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [50, 100, 150, 200, 250, 300],
labels = ['<strong> THE TITLE </strong>'],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades [i];
to = grades[i+1]-1;
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
from + (to ? '–' + to : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
i need the current distance between the marker and the map bounds to decide: draw the tipbox left, right, over or under the marker.
I set the position of the tipbox with these lines of code:
Label.prototype.draw = function() {
var projection = this.getProjection();
var position = projection.fromLatLngToDivPixel(this.get('position'));
// position of tipbox, depends on margin to map boaunds
var div = this.div_;
var mapWidth = parseInt($('#mapBox').css('width'));
var mapHeight = parseInt($('#mapBox').css('height'));
div.style.left = (position.x-(parseInt(div.style.width)/2)) + 'px';
div.style.top = position.y + 'px';
div.style.display = 'inline';
$('.tipBox-inner').html(''+position.x);
};
But if i drag the page, the position.x or position.y return the same number of pixels. As you can see on the image, the x position is at 300px(!). I would draw the tipbox in top of the marker, if the marker is at the bottom of page and so on.
Ok i found a solution myself. I get the distance(px) to margin in the mouseover-Event of the marker:
google.maps.event.addListener(marker, 'mouseover', function(event) {
label = new Label({
map: map
});
label.bindTo('position', marker, 'position');
var pixel = label.getProjection().fromLatLngToContainerPixel(event.latLng);
label.set('mouseX', pixel.x);
label.set('mouseY', pixel.y);
});
Now i can use mouseX and mouseY in draw-functionf of the Label with this.get('mouseX')