Drawing rectangle underneath PIXI.Text - pixi.js

In a word game I am trying to draw score as white numbers above a blue (or red) rectangle:
For example, in the above screenshot it is the number "13".
Here is my entire class Score.js (with currently hardcoded WIDTH and HEIGHT):
"use strict";
function Score(color) {
PIXI.Container.call(this);
this.interactive = false;
this.buttonMode = false;
this.visible = false;
this.bgGraphics = new PIXI.Graphics();
this.bgGraphics.beginFill(color, 1);
this.bgGraphics.drawRect(0, 0, Score.WIDTH, Score.HEIGHT);
this.bgGraphics.endFill();
this.addChild(this.bgGraphics);
this.text = new PIXI.Text('XXX', {font: '20px Arial', fill: 0xFFFFFF});
this.text.x = 1;
this.text.y = 1;
this.addChild(this.text);
}
Score.prototype = Object.create(PIXI.Container.prototype);
Score.prototype.constructor = Score;
Score.WIDTH = 36;
Score.HEIGHT = 24;
Score.prototype.setText = function(str) {
this.text.text = str;
}
I wonder, how to modify my setText() function, so that a new rectangle is drawn on each call - as a bounding rectangle for the str argument?
I have looked at the PIXI.Text.getBounds() method, but it returns a Matrix and not a Rectangle...

I think you can just use this.text.width. This has historically had some bugs associated with it, but it should be working right in the latest version.

Related

html canvas clip but with an image

I have been working with html canvas compositing trying to clip a pattern with a mask.
The main issue that I have is that the mask I have comes from an svg with transparencies within the outer most border. I want the entire inside from the outer most border to be filled with the pattern.
Take this SVG for example you can see that there is a single pixel border, then some transparency, and then an opaque red inner blob. The compositing I have done works as the documentation says it should, the single pixel border and the red inner portion pick up the pattern that I want to mask into this shape. The problem is that I want to mask the entire innards starting from the single pixel border.
This is where I think clip might help. But it seems clip only works with manually drawn paths, not paths from an svg (at least that I am aware of).
Is there a way to accomplish what I am trying to do?
Regards,
James
The Path2D constructor accepts an SVG path data argument, that it will parse as the d attribute of an SVG <path> element.
You can then use this Path2D object with the clip() method:
(async () => {
// fetch the svg's path-data
const markup = await fetch("https://upload.wikimedia.org/wikipedia/commons/7/76/Autism_spectrum_infinity_awareness_symbol.svg").then(resp => resp.ok && resp.text());
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
const pathData = doc.querySelector("[d]").getAttribute("d");
// build our Path2D object and use it
const path = new Path2D(pathData);
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.clip(path);
// draw something that will get clipped
const rad = 30;
for(let y = 0; y < canvas.height; y += rad * 2 ) {
for(let x = 0; x < canvas.width; x += rad * 2 ) {
ctx.moveTo(x+rad, y);
ctx.arc(x, y, rad, 0, Math.PI*2);
}
}
ctx.fillStyle = "red";
ctx.fill();
})().catch(console.error);
<canvas width="792" height="612"></canvas>
If you need to transform this path-data (e.g scale, or rotate), then you can create a second Path2D object, and use its .addPath(path, matrix) method to do so:
// same as above, but smaller
(async () => {
const markup = await fetch("https://upload.wikimedia.org/wikipedia/commons/7/76/Autism_spectrum_infinity_awareness_symbol.svg").then(resp => resp.ok && resp.text());
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
const pathData = doc.querySelector("[d]").getAttribute("d");
const originalPath = new Path2D(pathData);
const path = new Path2D();
// scale by 0.5
path.addPath(originalPath, { a: 0.5, d: 0.5 });
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.clip(path);
// draw something that will get clipped
const rad = 15;
for(let y = 0; y < canvas.height; y += rad * 2 ) {
for(let x = 0; x < canvas.width; x += rad * 2 ) {
ctx.moveTo(x+rad, y);
ctx.arc(x, y, rad, 0, Math.PI*2);
}
}
ctx.fillStyle = "red";
ctx.fill();
})().catch(console.error);
<canvas width="396" height="306"></canvas>

Frame rate drops / efficiency problem in three.js [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
Upon running there is a slow but consistent drop in fps. I have tried to identify the responsible function and it seems to be that:
updatepoints() and rotateTriangle() seem to be the main culprits but it's clear I have misunderstood something or used an inefficient means of calculating something somewhere
Upon further inspection using browser tools it seems to be an array and an object that are filling up the memory which I'm guessing is what is causing the frame drops.
I have also noticed that the buffer in the performance tab for the browser tools is filling up
I know bufferGeometry is the more efficient means of creating objects but I'd still like to know the cause the performance issues
Sorry to just dump code but I feel as though it'll be something obvious.
Any advice or ways of going about finding the problem and solution would be greatly appreciated
//every scene needs these
var scene, camera, renderer, controls;
//links div with canvas
var canvas = document.getElementById('canvas');
// What I need are number of particles and the length the curve goes to be uncoupled
// Each part of degree array serves one particles
// If I added a factor so:
// factor * coord *
//creating particles
var particleCount = 360;
var particles = [];
var particles2 = [];
var particles3 = [];
var SPEED = 0.01;
var radians, y, x;
var centerX = 0;
var centerY = 0;
var radius = 231.84;
var pointPositions=[];
var vupdateXvertices, updateYvertices, updateXvertices2, updateYvertices2,
updateXvertices3, updateYvertices3;
var pivot1;
var parent;
var pointsX = [];
var pointsY = [];
var particleMaterial = new THREE.MeshBasicMaterial({
color: 0x7a7a7a,
transparent: true,
opacity: 0.8
});
init();
animate();
function init() {
scene = new THREE.Scene();
//setup camera for scene
//PerspectiveCamera(fov, aspect, near, far [In terms of camera frustum plane])
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
//setup renderer for scene (generation of whatever you've made)
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x31AED1, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
//OrbitControls(Camera, HTMLDOMElement)
controls = new THREE.OrbitControls( camera, renderer.domElement );
// Set to true to enable damping (inertia), which can be used to give a sense
//of weight to the controls. Default is false.
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
console.log("Called");
fillSceneWithParticles();
fillSceneWithShapes();
canvas.appendChild( renderer.domElement );
renderer.render( scene, camera );
}
function fillSceneWithParticles() {
var particleGeometry = new THREE.SphereGeometry(3, 32, 32);
parent = new THREE.Object3D();
scene.add(parent);
for (var i = 0; i < particleCount; i++) {
particles[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles[i].position.x = 0;
particles[i].position.y = 0;
particles[i].position.z = (0);
particles2[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles2[i].position.x = (200);
particles2[i].position.y = (-115.57);
particles2[i].position.z = (0);
particles3[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles3[i].position.x = (0);
particles3[i].position.y = (231.84);
particles3[i].position.z = (0);
scene.add(particles[i]);
scene.add(particles2[i]);
scene.add(particles3[i]);
}
}
function fillSceneWithShapes() {
//Add a 2d Triangle W centre = 200, 115.57
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-200, -115.57, 0));
geometry.vertices.push( new THREE.Vector3( 200, -115.57, 0 ));
geometry.vertices.push( new THREE.Vector3( 0, 231.84, 0 ));
geometry.vertices.push( new THREE.Vector3( -200, -115.57, 0 ));
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
line = new THREE.Line( geometry, material );
scene.add(line);
}
function rotateTriangle() {
var geom = line.geometry.clone();
geom.applyMatrix(line.matrix);
updateXvertices = geom.vertices[0].x;
//The circle that we use to place our points
var centerX = 0;
var centerY = 0;
var radius = 231.84;
for(var degree = 90; degree < 450; degree++){
var radians = degree * Math.PI/180;
var x = centerX + radius * Math.cos(radians);
var y = centerY + radius * Math.sin(radians);
pointsX[degree - 90] = x;
pointsY[degree - 90] = y;
}
}
function updatePoints() {
//link counter with number of degrees initially created
//These are intialised because V1 = 120 degrees from V0 and V2 = 240 degrees
var counter = 120;
var counter2 = 240;
var zCounter = 0;
var curveFactor = 1;
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
var secondTriangle = new THREE.Geometry();
for (var i = 0; i < particleCount; i++) {
parent.add(particles[i]);
//Plot points around the circle relative to vertices of triangle
particles[i].position.x = (pointsX[i]);
particles[i].position.y = (pointsY[i]);
particles[i].position.z = zCounter * curveFactor;
//If array index out of bounds then loop back to the start of array
//i.e. Go back around the circle relative to the triangle vertices
parent.add(particles2[i]);
if (counter == 360) {
counter = 0;
}
particles2[i].position.x = (pointsX[counter]);
particles2[i].position.y = (pointsY[counter]);
particles2[i].position.z = zCounter * curveFactor;
counter++;
if (counter2 == 360) {
counter2 = 0;
}
parent.add(particles3[i]);
particles3[i].position.x = (pointsX[counter2]);
particles3[i].position.y = (pointsY[counter2]);
particles3[i].position.z = zCounter * curveFactor;
counter2++;
zCounter++;
}
//Give the second triangle the position of the last particles in array
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles2[particleCount-1].position.x, particles2[particleCount-1].position.y, particles2[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles3[particleCount-1].position.x, particles3[particleCount-1].position.y, particles3[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
line1 = new THREE.Line( secondTriangle, material );
scene.add(line1);
parent.add(line1);
}
function animate() {
requestAnimationFrame( animate );
controls.update();
rotateTriangle();
updatePoints();
line1.rotation.z -= SPEED *2;
line.rotation.z -= SPEED *2;
parent.rotation.z -= SPEED *2;
renderer.render( scene, camera );
}
In retrospect it seems obvious what the problem was.
Since I had geometry.vertices.push inside my animate loop it was continuously pushing new Vectors to a buffer.
I just had to move the pushing of those vertices and that solved any frame rate and memory problems I was having

Phaser BitmapData Sprite Immovable on Drag

I am a noob with Phaser games in general but I am trying to make a scrabble like game.
I made my tiles as BitmapData and added to sprite. I want to be able to drag and drop them on my scrabble board but not be able to place one tile in a spot where another tile is.
For debugging purposes Ive been just trying to get the individual tiles to respect each other's physics when you drag and drop. The behavior I want is, when dragging, to bump into another tile with that tile "holding its ground" and the dragging tile unable to cross on top of the other tile. Currently the dragged tile just goes on top of other tiles. I've looked at a lot of examples and feel that my issue may be either because my sprite is made with bitmapData or something around the drag event...
function makeTile (tileIndex, tile) {
var bmd = game.add.bitmapData(canvasZoom, canvasZoom);
// draw to the canvas context
bmd.ctx.beginPath();
bmd.ctx.rect(0, 0, canvasZoom, canvasZoom);
bmd.ctx.fillStyle = '#efefef';
bmd.ctx.fill();
bmd.ctx.fillStyle = '#234234';
bmd.ctx.font="20px Georgia";
bmd.ctx.fillText(tile.tileName, 7,23);
// use the bitmap data as the texture for the sprite
var tileSprite = game.make.sprite((tileIndex * canvasZoom) + canvasZoom, canvasZoom, bmd);
game.physics.arcade.enable([tileSprite]);
tileHandGroup.add(tileSprite);
tileSprite.inputEnabled = true;
var bounds = new Phaser.Rectangle(canvasZoom, canvasZoom, spriteWidth * canvasZoom, (spriteHeight * canvasZoom) + (canvasZoom * 2));
tileSprite.input.boundsRect = bounds;
tileSprite.name = 'tileSpriteName' + tileIndex;
tileSprite.input.enableDrag(true);
tileSprite.input.enableSnap(canvasZoom, canvasZoom, true, false);
tileSprite.immovable = true;
tileSprite.body.moves = false;
tileSprite.events.onDragStart.add(onDragStart, this);
tileSprite.events.onDragStop.add(onDragStop, this);
}
function firstTileHand() {
tileHandGroup = game.add.physicsGroup(Phaser.Physics.ARCADE);
game.physics.enable(tileHandGroup, Phaser.Physics.ARCADE);
tileHandGroup.enableBody = true;
tileHandGroup.name = 'tileHandGroup';
for (var i = 0; i < tiles.length; i++)
{
makeTile(i, tiles[i]);
}
}

In createjs textAlign Center Causing hit area misalignment

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/

how to apply gradient effect on Image GDI

How can I apply gradient effect on image like this image in c#. I have a transparent image with black drawing I want to apply 2 color gradient on the image is this possible in gdi?
Here is the effect i want to achieve
http://postimg.org/image/ikz1ie7ip/
You create a PathGradientBrush and then you draw your texts with that brush.
To create a bitmap filled with a gradient brush you could do something like:
public Bitmap GradientImage(int width, int height, Color color1, Color color2, float angle)
{
var r = new Rectangle(0, 0, width, height);
var bmp = new Bitmap(width, height);
using (var brush = new LinearGradientBrush(r, color1, color2, angle, true))
using (var g = Graphics.FromImage(bmp))
g.FillRectangle(brush, r);
return bmp;
}
So now that you have an image with the gradient in it, all you have to do is to bring over the alpha channel from your original image into the newly created image. We can take the transferOneARGBChannelFromOneBitmapToAnother function from a blog post I once wrote:
public enum ChannelARGB
{
Blue = 0,
Green = 1,
Red = 2,
Alpha = 3
}
public static void transferOneARGBChannelFromOneBitmapToAnother(
Bitmap source,
Bitmap dest,
ChannelARGB sourceChannel,
ChannelARGB destChannel )
{
if ( source.Size!=dest.Size )
throw new ArgumentException();
Rectangle r = new Rectangle( Point.Empty, source.Size );
BitmapData bdSrc = source.LockBits( r, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );
BitmapData bdDst = dest.LockBits( r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb );
unsafe
{
byte* bpSrc = (byte*)bdSrc.Scan0.ToPointer();
byte* bpDst = (byte*)bdDst.Scan0.ToPointer();
bpSrc += (int)sourceChannel;
bpDst += (int)destChannel;
for ( int i = r.Height * r.Width; i > 0; i-- )
{
*bpDst = *bpSrc;
bpSrc += 4;
bpDst += 4;
}
}
source.UnlockBits( bdSrc );
dest.UnlockBits( bdDst );
}
Now you could do something like:
var newImage = GradientImage( original.Width, original.Height, Color.Yellow, Color.Blue, 45 );
transferOneARGBChannelFromOneBitmapToAnother( original, newImage, ChannelARGB.Alpha, ChannelARGB.Alpha );
And there you are. :-)

Resources