Cesium label blurred - cesiumjs

I created a Cesium label, using the following code:
var label: Cesium.LabelGraphics = new Cesium.LabelGraphics({
text : lab,
verticalOrigin: Cesium.VerticalOrigin.TOP,
horizontalOrigin: Cesium.HorizontalOrigin.RIGHT,
font: '15px Helvetica',
fillColor: Cesium.Color.WHITE,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL,
pixelOffset: new Cesium.Cartesian2(20, 20)
});
But it is blurred...
I would like to have a clearer label. Is this image you can see inside the red rectangle the real label. In the blue rectangle is the label with a zoom In. In the green rectangle is how I would like it to be.
Is there some way to make the label clearer?
Thanks!

In Bllboard.js or Cesium.js change
gl_Position = czm_viewportOrthographic * vec4(positionWC.xy,-positionWC.z, 1.0);
to
gl_Position = czm_viewportOrthographic * vec4(floor(positionWC.xy + 0.5), -positionWC.z, 1.0);
It will makethe billboards snap to a pixel, instead of get blurred.
also disable the FXAA (antialias) in your viewer initialization
viewer.scene.fxaa = false
it will make the billboards and labels much more crispy !
Before
.
After

A trick I sometimes use is to combine a larger font size with a scale setting on the label to scale the large font down using WebGL. This is a slightly different scaling than simply picking a smaller font size, because WebGL's texture scaling system comes into play to scale the rasterized font images. This works because Cesium labels are not anchored to an integer pixel position, they can be placed at coordinates with sub-pixel precision. So, the extra resolution in the label texture comes in handy as the label moves around. Of course this method costs a little bit more texture memory, but is usually worth it to get the cleaner edges.
Here's an example, showing the difference between normal (no scaling), double (0.5 scaling), and triple (roughly, 0.3 scaling).
var viewer = new Cesium.Viewer('cesiumContainer', {
navigationHelpButton: false, animation: false, timeline: false
});
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
label : {
text : 'Label == || normal',
verticalOrigin: Cesium.VerticalOrigin.TOP,
horizontalOrigin: Cesium.HorizontalOrigin.RIGHT,
font: '15px Helvetica', // NOTE: Standard size, no scaling here.
fillColor: Cesium.Color.WHITE,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL,
pixelOffset: new Cesium.Cartesian2(20, -10)
}
});
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
label : {
text : 'Label == || double',
verticalOrigin: Cesium.VerticalOrigin.TOP,
horizontalOrigin: Cesium.HorizontalOrigin.RIGHT,
font: '31px Helvetica',
fillColor: Cesium.Color.WHITE,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL,
pixelOffset: new Cesium.Cartesian2(20, 20),
scale: 0.5
}
});
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
label : {
text : 'Label == || triple',
verticalOrigin: Cesium.VerticalOrigin.TOP,
horizontalOrigin: Cesium.HorizontalOrigin.RIGHT,
font: '57px Helvetica', // NOTE: Large font size here
fillColor: Cesium.Color.WHITE,
outlineWidth: 2,
style: Cesium.LabelStyle.FILL,
pixelOffset: new Cesium.Cartesian2(20, 50),
scale: 0.3 // NOTE: Large font images scaled down via WebGL texturing.
}
});
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
}
<link href="http://cesiumjs.org/Cesium/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"/>
<script src="http://cesiumjs.org/Cesium/Build/Cesium/Cesium.js"></script>
<div id="cesiumContainer"></div>

Related

Cocos Creator Change rotation parent but childrent not move

I rotate a node (with a green image sprite for easy viewing) containing child nodes (called Dot, with red color, collider2D and rigidbody2D). I change the Rotation property and all Dots also change. I want to do so in code, however only the blue part rotates.
I rotated both ways:
tween(new Vec3(0, 0, 0))
.to(3, new Vec3(0, 0, 360), {
easing: "cubicIn",
onUpdate(target?: any) {
wheelDot.eulerAngles = target;
},
})
.start();
and
tween(this.wheelDot)
.to(
3,
{
angle: this.wheelDot.angle + 360,
},
{
easing: "cubicIn",
}
)
.start();
Both of the above codes just rotate the green part and the red dots stay in place.
Edit: I found out if I dropped RigidBody2D, the red dots moved. How can I still use RigidBody2D and still rotate?

OpenLayers 5: stroke width scaling?

Is it possible to make Stroke width dependent on the zoom level?
Basically, I am going to use LineStrings/MultiLineStrings to highlight some roads but I would also like to be able to zoom out and not have massive clutter (there will be about 8 pretty wide lines along each path).
You can use the resolution which is passed to a style function. I've use this code to display contours, setting lines at multiples of 50m wider, and when the resolution is greater than 2.5 both widths are reduced proportionately.
style: function(feature, resolution) {
return new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(224,148,94,1)',
width: (feature.getProperties().value % 50 == 0 ? 3.175 : 1.863) * Math.min(1, 2.5/resolution)
})
});
}

Dimensions in html5 canvas

I have a problem with the HTML5 Canvas. I use jCanvas to add layers to an canvas but I have a problem with the sizes.
I have 2 rectangles a green one and a red one.
Now I want the red box touch the green left top corner.
Using the coordinate system I start green at coordinates 200, 200
then red has to start at 0,0 and the width and height has to be 200 and 200.
But that doesn't work
Check this example
Why doesnt this work??
When I use 100x100 dimensions it does work
All depends on the origin of your layer. By default it is the center of the layer.
So to have the results you expect there are two solutions (exemples with layer 100*100) :
First in your case you have to calculate correct position from top left canvas origin to the middle of your object :
$('canvas')
.addLayer({
type: 'rectangle',
name: 'redBox',
fillStyle: '#c33',
x: 50, y: 50,//canvas origin to center (100/2)
width: 100, height: 100
})
.addLayer({
type: 'rectangle',
name: 'greenBox',
fillStyle: '#585',
x: 150, y: 150,//canvas origin to center (100 of red layer + 100/2)
width: 100, height: 100
})
.drawLayers();
Or you can set origin to top left corner by disable fromCenter property:
$('canvas')
.addLayer({
type: 'rectangle',
name: 'redBox',
fillStyle: '#c33',
fromCenter: false,
x: 0, y: 0,
width: 100, height: 100
})
.addLayer({
type: 'rectangle',
name: 'greenBox',
fillStyle: '#585',
fromCenter: false,
x: 100, y: 100,
width: 100, height: 100
})
.drawLayers();
Hope this help

Write text on canvas with background

Is it possible to write image on canvas and write text with background?
For example like this:
How text works in canvas
Unfortunately no, you can't produce text with background with the text methods - only fill or outline the text itself.
This is because the glyphs from the typeface (font) are converted to individual shapes or paths if you want, where the background of it would be the inner part of the glyph itself (the part you see when using fill). There is no layer for the black-box (the rectangle which the glyph fits within) the glyph is using besides from using its geometric position, so we need to provide a sort-of black-box and bearings ourselves.
On the old computer systems most fonts where binary font which where setting or clearing a pixels. Instead of just clearing the background one could opt to provide a background instead. This is not the case with vector based typefaces by default (a browser has direct access to the glyphs geometry and can therefor provide a background this way).
Creating custom background
In order to create a background you would need to draw it first using other means such as shapes or an image.
Examples:
ctx.fillRect(x, y, width, height);
or
ctx.drawImage(image, x, y [, width, height]);
then draw the text on top:
ctx.fillText('My text', x, y);
You can use measureText to find out the width of the text (in the future also the height: ascend + descend) and use that as a basis:
var width = ctx.measureText('My text').width; /// width in pixels
You can wrap all this in a function. The function here is basic but you can expand it with color and background parameters as well as padding etc.
/// expand with color, background etc.
function drawTextBG(ctx, txt, font, x, y) {
/// lets save current state as we make a lot of changes
ctx.save();
/// set font
ctx.font = font;
/// draw text from top - makes life easier at the moment
ctx.textBaseline = 'top';
/// color for background
ctx.fillStyle = '#f50';
/// get width of text
var width = ctx.measureText(txt).width;
/// draw background rect assuming height of font
ctx.fillRect(x, y, width, parseInt(font, 10));
/// text color
ctx.fillStyle = '#000';
/// draw text on top
ctx.fillText(txt, x, y);
/// restore original state
ctx.restore();
}
ONLINE DEMO HERE
Just note that this way of "measuring" height is not accurate. You can measure height of a font by using a temporary div/span element and get the calculated style from that when font and text is set for it.
I simpler solution is to call fillText twice. First a string of Unicode+2588 █ which is a black rectangle repeated the same length as the text using the background color. And then call fillText as normal with the foreground color.
This function gives you vertically and horizontally centered text with a background. It only works well with monospaced fonts (characters with the same width). The function counts the number of character in the string you which to print and multiplies them with 0.62 (assuming that the width of the font is slightly less than 0.62 times the height). The background is 1.5 times bigger than the font size. Change this to fit your needs.
function centeredText(string, fontSize, color) {
var i = string.length;
i = i*fontSize*0.62;
if (i > canvas.width) {
i = canvas.width;
}
ctx.fillStyle = "RGBA(255, 255, 255, 0.8)";
ctx.fillRect(canvas.width / 2 - i / 2,canvas.height / 2 - (fontSize * 1.5) / 2, i, (fontSize * 1.5) );
ctx.font = fontSize.toString() + "px monospace";
ctx.fillStyle = color;
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText(string, canvas.width / 2, canvas.height / 2);
}
So calling the function would look something like this.
centeredText("Hello World", 30, "red");

Make white background of image transparent in css

I have two images, one of which is a small icon that is superimposed over the first image. My icon has a white background, so when the icon is placed over the other image, we get this effect where a white square appears over the image. Ideally, I do not want to display this white background on top of my other image. Is there is a CSS property I can apply to my icon to make its white background transparent?
Actually there is a way although only currently supported on Chrome, Firefox, and Safari. If the background color is white, you can add the CSS property:
mix-blend-mode: multiply;
You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
Opacitator
mix-blend-mode does work for some browsers, but we've found that it causes performance issues in chrome, I have no idea why.
A designer on my team came up with this genius hack, where you create a layer that is mostly transparent, but when it is laid over a white background, it's color will match the color of the surrounding background.
The way this "magical" color is found; is by calculating how much darker each color axis should be for the amount of opacity removed. The formula for this is 255 - ( 255 - x ) / opacity. The issue is: If the opacity is set too low the formula gives you negative numbers (which can't be used). If the opacity is too high, you'll get some coloring on the non-white portions of your image.
Initially we used a spreadsheet that would do the calculations and through manual trial and error we would find that Goldilox color.
Once we started using sass I realized that this can be accomplished with a binary search. So I created a sass function that does the work for us.
Check out this gist on sassmeister. Pass your background color in-to the opacitator function on line 56 of the sass-code. and use the generated rgba color in a div (or a pseudo element) to overlay the image.
I also created a working example on codepen.
As there is no reliable way to remove background with CSS, sharing a code snippet of how I did it with JS:
public async removeImageBackground(image) {
const backgroundColor = { red: 255, green: 255, blue: 255 };
const threshold = 10;
const imageElement = new Image();
imageElement.src = image;
await new Promise(function(resolve) { imageElement.addEventListener('load', resolve); });
var canvas = document.createElement('canvas');
canvas.width = imageElement.naturalWidth;
canvas.height = imageElement.naturalHeight;
var ctx = canvas.getContext('2d');
ctx.drawImage(imageElement, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (var i = 0; i < imageData.data.length; i += 4) {
const red = imageData.data[i];
const green = imageData.data[i + 1];
const blue = imageData.data[i + 2];
if (Math.abs(red - backgroundColor.red) < threshold &&
Math.abs(green - backgroundColor.green) < threshold &&
Math.abs(blue - backgroundColor.blue) < threshold) {
imageData.data[i + 3] = 0;
}
}
ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL(`image/png`);
}
You can make a container for your image.
Then for the css of the container:
overflow:hidden; height: (depends on your image, then make it a smaller px); width:100%;
Hope it helps. :)
No. Not yet...
It is getting very close to possible, though. Check out this article about CSS Filters, an experiemental css feature, that is doing some things client-side that are neat.
CSS Filters