I am making a Discord bot and trying to display someone's level, I would like it to basically say "LEVEL 1" for example, but the distance between the word level and the actual level would change depending on the level they are on. So I am trying to offset the word a little, but when I use measureText(), it displays incorrectly. Code:
const levelNumber = '1';
const levelText = 'LEVEL';
ctx.font = '48px Shapirit';
ctx.fillStyle = '#FF1700';
ctx.textAlign = 'right';
ctx.fillText(levelNumber, 880, 96.8);
ctx.font = '22px Shapirit';
ctx.fillStyle = '#FF1700';
ctx.textAlign = 'right';
ctx.fillText(levelText, 880 - ctx.measureText(levelNumber).width - 20, 96.8);
Here is the current output:
Yes #Jay is right. You have to measureText with the right font, if not you get the wrong results.
See sample below
function drawLevel(x, y, txt, num, style) {
ctx.font = '48px Shapirit';
ctx.fillStyle = style;
ctx.textAlign = 'right';
ctx.fillText(num, x, y);
w = ctx.measureText(num).width
ctx.font = '22px Shapirit';
ctx.fillStyle = style;
ctx.textAlign = 'right';
ctx.fillText(txt, x - w - 20, y);
}
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
drawLevel(200, 40, 'LEVEL', '999', '#FF1700');
drawLevel(200, 80, 'LEVEL', '11', '#0000FF');
drawLevel(200, 120, 'LEVEL', '1', '#00FF00');
<canvas id="canvas">
Related
Using the WebGLRenderer, successfully loaded an .obj file created in Cinema4d.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
const material = new THREE.LineBasicMaterial( {
color: 0xffffff,
linewidth: 1,
linecap: 'round', //ignored by WebGLRenderer
linejoin: 'round' //ignored by WebGLRenderer
} );
scene.add(material)
var objLoader = new THREE.OBJLoader();
objLoader.setPath('/examples/3d-obj-loader/assets/');
objLoader.load('Untitled2.obj', function (object) {
object.position.y -= 60;
scene.add(object);
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
Aiming to convert this to vector using the SVGRenderer - tried swapping out the THREE.WebGLRenderer for SVGRenderer but there's clearly more to it than this, and can't find any walkthroughs, or breakdowns on here.
Can see that what I'm looking for is technically possible with three.js!
Linked an image of the 3d file I'm looking to vectorise - a simple mountain style scene - aiming for each edges of the vertices to be stroked, with no texture needed (white shape, black edges).
Tried making a JSON with Bodymovin and proved impossible to join al the paths of the vertices without lots of stray lines appearing.
enter image description here
I have been trying to center an image inside a canvas drawn circle, the circle is centered in the middle of the page but the image that I want to draw inside it can't.
const background = await Canvas.loadImage(`./backgrounds/${UserJSON[message.author.id].background}.png`);
const canvas = Canvas.createCanvas(250, 400);
const context = canvas.getContext('2d');
context.drawImage(background, 0, 0, canvas.width, canvas.height);
context.strokeStyle = '#0099ff';
context.strokeRect(0, 0, canvas.width, canvas.height);
context.font = '28px sans-serif';
context.fillStyle = '#ffffff';
context.fillText(`${message.author.username}`, canvas.width / 4, canvas.height / 1.6);
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, 70, 0, Math.PI * 2, true);
context.closePath();
context.clip();
const avatar = await Canvas.loadImage(message.author.displayAvatarURL({ format: 'jpg', size: 4096 }));
context.drawImage(avatar, 0, 0, 250, 320);
const attachment = new MessageAttachment(canvas.toBuffer(), 'profile-image.png');
I don't know what I'm doing wrong at "drawImage", I can't seem to minimize the image to fit the circle or anything else. Below I put my discord avatar and the way it's drawn on the canvas
You need to make some calculations on your own. drawImage will take a bitmap and project it on whatever rectangle you gave it (will not preserve aspect ratio). So you need to make all the center and cover calculations.
const canvas = Canvas.createCanvas(250, 400);
const context = canvas.getContext('2d');
context.fillStyle = '#6f6f6f';
context.fillRect(0, 0, canvas.width, canvas.height);
const circle = {
x: canvas.width / 2,
y: canvas.height / 2,
radius: 70,
}
context.beginPath();
context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2, true);
context.closePath();
context.clip();
const avatar = await Canvas.loadImage('./image.jpg');
console.log(avatar.height, avatar.width);
// Compute aspectration
const aspect = avatar.height / avatar.width;
// Math.max is ued to have cover effect use Math.min for contain
const hsx = circle.radius * Math.max(1.0 / aspect, 1.0);
const hsy = circle.radius * Math.max(aspect, 1.0);
// x - hsl and y - hsy centers the image
context.drawImage(avatar,circle.x - hsx,circle.y - hsy,hsx * 2,hsy * 2);
I recreated the scrolling text box tutorial in my game. However, it is running a bit glitchy on mobile. For example, if I swipe up, the text first goes down for a second and then follows my finger up. You’ll see the problem if you open the tutorial on mobile. Any thoughts? I copied my code below.
var graphics = scene.make.graphics();
graphics.fillRect(x, y + 10, width, height - 20);
var mask = new Phaser.Display.Masks.GeometryMask(scene, graphics);
var text = scene.add.text(x + 20, y + 20, content, {
fontFamily: 'Assistant',
fontSize: '28px',
color: '#000000',
wordWrap: { width: width - 20 }
}).setOrigin(0);
text.setMask(mask);
var minY = height - text.height - 20;
if (text.height <= height - 20) {
minY = y + 20;
}
// The rectangle they can 'drag' within
var zone = scene.add.zone(x, y - 3, width, height + 6).setOrigin(0).setInteractive({useHandCursor: true});
zone.on('pointermove', function (pointer) {
if (pointer.isDown) {
text.y += (pointer.velocity.y / 10);
text.y = Phaser.Math.Clamp(text.y, minY, y + 20);
}
});
I had the same issue. My solution is using "pointer.y" instead of "pointer.velocity.y".
Here is my code:
var previousPointerPositionY;
var currentPointerPositionY;
zone.on('pointerdown', function (pointer) {
previousPointerPositionY = pointer.y;
});
zone.on('pointermove', function (pointer) {
if (pointer.isDown) {
currentPointerPositionY = pointer.y;
if(currentPointerPositionY > previousPointerPositionY){
text.y += 5;
} else if(currentPointerPositionY < previousPointerPositionY){
text.y -= 5;
}
previousPointerPositionY = currentPointerPositionY;
text.y = Phaser.Math.Clamp(text.y, -360, 150);
}
});
When I set up text as a link, set a bounds shape, and set the hit area to the bounds shape, my hit area is off if the textAlign = 'center'. Any ideas?
var linkColor = "#0000ff";
var linkFont = "bold 14px Times";
var presentationLink = new createjs.Text("View Presentation", linkFont, linkColor);
presentationLink.textAlign = "left";
presentationLink.maxWidth = 170;
presentationLink.x = 300;
presentationLink.y = 125;
stage.addChild(presentationLink);
var plBounds = presentationLink.getTransformedBounds();
var s = new createjs.Shape().set({ x: plBounds.x, y: plBounds.y + plBounds.height });
s.graphics.s(linkColor).moveTo(0, 0).lineTo(plBounds.width, 0);
stage.addChild(s);
var hitAreaForPLink = new createjs.Shape(new createjs.Graphics().beginFill("#ffffff").drawRect(-10, -10, plBounds.width + 20, plBounds.height + 10));
presentationLink.hitArea = hitAreaForPLink;
stage.enableMouseOver();
presentationLink.on("mouseover", function () {
presentationLink.cursor = "pointer";
});
The hitArea is positioned according to its owner's coordinate system. That is, all of the owner's transformations are applied to the hitArea. This is so that if you were to animate the owner, the hitArea would track it as expected.
Since the transformation is already applied, you need to use getBounds, not getTransformedBounds. See this example: http://jsfiddle.net/gskinner/uagv5t84/2/
I have problem with canvas fillText function. I have this code :
scene.shapes['shop1'] = new Shape();
var ps1 = scene.shapes['shop1'].points; // for convenience
ps1[0] = new Point(1024, 66, 10); // left bottom
ps1[1] = new Point(694, 66, 10); // right bottom
ps1[2] = new Point(694, 466, 10); // right top
ps1[3] = new Point(1024, 466, 10); // left top
// Background
scene.shapes['shop1'].polygons.push(new Polygon(
[ps1[0], ps1[1], ps1[2], ps1[3] ],
new Point(0, 0, 1),
true /* double-sided */,
Polygon.SOLID,
[177, 216, 249]
));
scene.shapes['shop1Header'] = new Shape();
var ps1h = scene.shapes['shop1Header'].points; // for convenience
ps1h[0] = new Point(1024, 400, 11); // left bottom
ps1h[1] = new Point(694, 400, 11); // right bottom
ps1h[2] = new Point(694, 466, 11); // right top
ps1h[3] = new Point(1024, 466, 11); // left top
// Background
scene.shapes['shop1Header'].polygons.push(new Polygon(
[ps1h[0], ps1h[1], ps1h[2], ps1h[3] ],
new Point(0, 0, 1),
true /* double-sided */,
Polygon.SOLID,
[175, 175, 175]
));
var x = -1024;
var y = -500;
ctx.font = '60pt Calibri';
ctx.lineWidth = 3;
// fill color
ctx.fillStyle = 'blue';
ctx.fillText('Hello World!', x, y);
But it don´t create the text and only display the shop. Do you know, how to solve this problem? Thank you very much.
The value of x and y is negative so you are drawing outside of the canvas. If you set x to 0 and y to 0 + font-size it will draw the text in the top left corner.
EDIT: you need to add the font size to y.
ctx.font = "60px Calibri"; // Use pixels instead of points
ctx.fillText("Hello World", 0, 60);