How to enable react state to update a chartjs label? - react-chartjs-2

Trying to update the text in the center of a doughnut chart when the prop month changes.
Screenshot of chart, as you can see January did not update, but price did.
However chartJS never updates past the initial month, January, even though it will update when the data changes.
const plugins = [{
beforeDraw: (chart: any) => {
var width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
var price = chart.config.data.datasets[0].data[0];
var item = month;
//Price
var fontSize = (height / 200).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "top";
var text = `$${price.toFixed(2)}`,
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
// Item Type
fontSize = (height / 400).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "top";
text = `${item}`;
textX = Math.round((width - ctx.measureText(text).width) / 2);
textY = height / 2 + 50;
ctx.fillText(text, textX, textY);
ctx.save();
}
}];
const chartRef = useRef<Chart>(null);
return <Doughnut
// #ts-ignore
ref={chartRef}
options={options}
data={data}
// #ts-ignore
plugins={plugins}
/>;
How are we supposed to properly pass information to a chartjs component?

I had the same issue and the problem seems to be the beforeDraw() function won't see any change in variables contained outside of it including any data you pass through the parent component. My workaround was to pass the required data you want into the options object that gets passed into the chart. You will then be able to access it in the beforeDraw() function through the automatic chart parameter like so chart.config.options.nameOfUpdatedData
const options = {
...
price,
month,
}
const plugins = [
{
...
beforeDraw: (chart: any) => {
...
const updatedPrice = chart.config.options.price;
const updatedMonth = chart.config.options.month;
}
},
];
return (
<Chart type="doughnut" data={data} options={options} plugins={plugins} />
)

Related

PixiJs mask filter with background image

How can I create effect like on this site (work links)
https://monopo.london/work/
I was trying implement this example, but can't change black background with another image.
https://pixijs.io/examples/#/masks/filter.js
Please, HELP!
const app = new PIXI.Application();
document.body.appendChild(app.view);
// Inner radius of the circle
const radius = 100;
// The blur amount
const blurSize = 12;
app.loader.add('grass', 'https://images.prismic.io/monopolondon/abb53b73-caae-41d2-9031-f889aa27780d_onefinestay_thumb.jpeg?auto=compress,format&rect=0,0,1200,1436&w=600&h=718');
app.loader.load(setup);
function setup(loader, resources) {
const background = new PIXI.Sprite(resources.grass.texture);
app.stage.addChild(background);
background.width = app.screen.width;
background.height = app.screen.height;
const circle = new PIXI.Graphics()
.beginFill(0xFF0000)
.drawCircle(radius + blurSize, radius + blurSize, radius)
.endFill();
circle.filters = [new PIXI.filters.BlurFilter(blurSize)];
const bounds = new PIXI.Rectangle(0, 0, (radius + blurSize) * 2, (radius + blurSize) * 2);
const texture = app.renderer.generateTexture(circle, PIXI.SCALE_MODES.NEAREST, 1, bounds);
const focus = new PIXI.Sprite(texture);
console.log(texture);
app.stage.addChild(focus);
background.mask = focus;
app.stage.interactive = true;
app.stage.on('mousemove', pointerMove);
function pointerMove(event) {
focus.position.x = event.data.global.x - focus.width / 2;
focus.position.y = event.data.global.y - focus.height / 2;
}
}
Try simply adding some other Sprite to stage - before grass is added - like this:
look at usage of some_bg
const app = new PIXI.Application();
document.body.appendChild(app.view);
// Inner radius of the circle
const radius = 100;
// The blur amount
const blurSize = 32;
app.loader.add('grass', 'examples/assets/bg_grass.jpg');
app.loader.add('some_bg', 'examples/assets/bg_plane.jpg');
app.loader.load(setup);
function setup(loader, resources) {
const some_bg = new PIXI.Sprite(resources.some_bg.texture);
some_bg.width = app.screen.width;
some_bg.height = app.screen.height;
app.stage.addChild(some_bg);
console.log(some_bg);
const background = new PIXI.Sprite(resources.grass.texture);
app.stage.addChild(background);
background.width = app.screen.width;
background.height = app.screen.height;
const circle = new PIXI.Graphics()
.beginFill(0xFFFFFF)
.drawCircle(radius + blurSize, radius + blurSize, radius)
.endFill();
circle.filters = [new PIXI.filters.BlurFilter(blurSize)];
const bounds = new PIXI.Rectangle(0, 0, (radius + blurSize) * 2, (radius + blurSize) * 2);
const texture = app.renderer.generateTexture(circle, PIXI.SCALE_MODES.NEAREST, 1, bounds);
const focus = new PIXI.Sprite(texture);
app.stage.addChild(focus);
background.mask = focus;
app.stage.interactive = true;
app.stage.on('mousemove', pointerMove);
function pointerMove(event) {
focus.position.x = event.data.global.x - focus.width / 2;
focus.position.y = event.data.global.y - focus.height / 2;
}
}

Make zoom images slideshow on canvas

i am trying to making zoomin images slideshow using pixijs on canvas from three images like this
I tried but not succeed. My question in how to add zoomin or zoomout image in pixijs for specific width and height, then second image and so on.
I am writing this code
var pixiapp;
var pixiloader = PIXI.Loader.shared;
initpixiapp();
function initpixiapp() {
pixiapp = new PIXI.Application({ width: 1280, height: 720 });
document.getElementById('canvas-container').appendChild(pixiapp.view);
pixiloader.add('images/img1.png').add('images/img2.png').add('images/img3.png').load(handleimagesload);
}
function handleimagesload() {
var imagessprites=[]
var img1 = new PIXI.Sprite(pixiloader.resources['images/img1.png'].texture);
var img2 = new PIXI.Sprite(pixiloader.resources['images/img2.png'].texture);
var img3 = new PIXI.Sprite(pixiloader.resources['images/img3.png'].texture);
imagessprites.push(img1)
imagessprites.push(img2)
imagessprites.push(img3);
for (let index = 0; index < imagessprites.length; index++) {
const element = imagessprites[index];
pixiapp.stage.addChild(element);
// here will the the code to run zoom image to specific width and heigth and then move to next image,
// here is my code, its only display zooming third image
var ticker = new PIXI.Ticker();
ticker.add(() => {
console.log('ticker called')
element.width += 1;
element.height += 1;
if(element.width==1500)
{
ticker.stop()
}
})
ticker.start()
}
}
One more things, how to display a box with text for three seconds before slideshow start.
Try something like this:
var pixiapp;
var pixiloader = PIXI.Loader.shared;
initpixiapp();
function initpixiapp() {
pixiapp = new PIXI.Application({ width: 1280, height: 720 });
document.getElementById('canvas-container').appendChild(pixiapp.view);
pixiloader
.add('images/img1.png')
.add('images/img2.png')
.add('images/img3.png')
.load(handleimagesload);
}
function handleimagesload() {
var imagessprites = [];
var img1 = new PIXI.Sprite(pixiloader.resources['images/img1.png'].texture);
var img2 = new PIXI.Sprite(pixiloader.resources['images/img2.png'].texture);
var img3 = new PIXI.Sprite(pixiloader.resources['images/img3.png'].texture);
imagessprites.push(img1);
imagessprites.push(img2);
imagessprites.push(img3);
// Put first image on stage:
var currentImageIndex = 0;
var currentImage = imagessprites[currentImageIndex];
pixiapp.stage.addChild(currentImage);
var ticker = new PIXI.Ticker();
// Start "main animation loop":
ticker.add(() => {
currentImage.width += 1;
currentImage.height += 1;
if (currentImage.width >= 1500) {
// remove current image from stage:
pixiapp.stage.removeChild(currentImage);
// Move to next image:
// Increase index - but if it reached maximum then go back to 0 (to first image)
currentImageIndex++;
if (currentImageIndex >= imagessprites.length) {
currentImageIndex = 0;
}
currentImage = imagessprites[currentImageIndex];
// Set initial width and height of image (TODO: adjust this)
currentImage.width = 1000;
currentImage.height = 1000;
// put image on stage:
pixiapp.stage.addChild(currentImage);
}
});
ticker.start()
}

How to assign variables in loop For NodeJS

I have an array called req.body.items, which contains always one or more items. And I have to assign some variables according to the quantity of items that it has, like this:
for (x in req.body.items.length) {
var width = req.body.items[x].dimensions.width * 100;
var height = req.body.items[x].dimensions.height * 100;
var weight = req.body.items[x].dimensions.weight;
var depth = req.body.items[x].dimensions.depth * 100;
var quantity = req.body.items[x].quantity;
var sku = req.body.items[x].sku;
};
The problem is that I will have as many "widthes" as items, so if I have 3 items, I must have 3 widthes. And I don't know how to do so. I have searched this, but I only found in Javascript for frontend, I need it to create an API.
It could be just like var width0, var width1, var width2, etc.
let req={
body: {
items: [
{
dimensions: {
width: 1,
height:3,
weight:4,
quantity:7
}
},
{
dimensions: {
width: 5,
height:2,
weight:6,
quantity:8
}
}
]
}
}
let dimensions = req.body.items.reduce((result,item)=>{
Object.entries(item.dimensions).map(([key,value])=>(!!result[key] ? result[key]=[...result[key], value*100]: result[key]=[value*100]));
return result;
},{});
console.log(dimensions);
I believe you need something like this:
var width = [];
var height = [];
var weight = [];
var depth = [];
var quantity = [];
var sku = [];
for (let x in req.body.items.length) {
width.push(req.body.items[x].dimensions.width * 100);
height.push(req.body.items[x].dimensions.height * 100);
weight.push(req.body.items[x].dimensions.weight);
depth.push(req.body.items[x].dimensions.depth * 100);
quantity.push(req.body.items[x].quantity);
sku.push(req.body.items[x].sku);
};
Now, width, height ... are arrays conaining your data.

Fabric.js: Issue with discard active group and object presented in the canvas.

Working on fabricjs here i am trying to discard active object and groups on click event of Calculate Price button.When i add some text or image into the canvas and if i select that object and press Calulate Price button(#chk-price) selected object is going centering off-screen.On calculate price button i am making a group of all object to calculate the price of design according to group height and width after calculate price i have deselect the all object or group in the canvas.
Site Link:- click here
Bellow is the code which i am using for discard the object
$('#chk-price').click(function(e) {
canvas.discardActiveGroup();
canvas.discardActiveObject();
canvas.renderAll();
});
Bellow is the code which i am using to calculate price on same button click(#chk-price)
document.getElementById('chk-price').addEventListener('click', function (e) {
//function calculate_final_design_price()
//{
var objs = canvas.getObjects().map(function(o) {
return o.set('active', true);
});
//alert("logo" + globl_id_logo + "text" + globl_Text_id + "svg" + globl_id );
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center',
//id: globl_Text_id
});
//globl_Text_id++;
canvas.activeObject = null;
var grup_width=group.getWidth();
var grup_height=group.getHeight();
var txt_width=$('#input-value').val();
grup_width=grup_width.toFixed(2);
grup_height=grup_height.toFixed(2);
parseFloat(txt_width);
// alert(txt_width);
var width= txt_width*price_unit;
var inchweight=width; //1.042/100*width;
inchweight=inchweight.toFixed(2);
var get_left = function_getheight(grup_width,grup_height,txt_width);
//alert(get_left);
var left= get_left*price_unit;
var inchieght=left;//1.042/100*left;
inchieght=inchieght.toFixed(2);
//alert(inchweight);
//alert(inchieght);
var total= inchieght * inchweight;
var x=total/144;
//Calculate price if text only
if(globl_Text_id>1 && globl_id==1){
var type="Text Only";
var sf="$40";
var ftotal = x * SF_A;
ftotal=ftotal.toFixed(2);
}
//Calculate price if svg image only
if(globl_Text_id==1 && globl_id>1){
var type="Svg Only";
var sf="$50";
var ftotal = x * SF;
ftotal=ftotal.toFixed(2);
}
//Calculate price if text + svg image
if(globl_Text_id>1 && globl_id>1){
var type="Both Text and Svg";
var sf="$60";
var ftotal = x * SF_TS;
ftotal=ftotal.toFixed(2);
}
//Calculate price if custom logo only
if(globl_Text_id==1 && globl_id==1 && globl_id_logo>1){
var type="Custom Logo";
var sf="$55";
var ftotal = x * SF_C;
ftotal=ftotal.toFixed(2);
}
//Calculate price if text + svg image + custom logo only
if(globl_Text_id>1 && globl_id>1 && globl_id_logo>1 ){
var type=" text ,svg image,custom logo";
var sf="$75";
var ftotal = x * SF_SCT;
ftotal=ftotal.toFixed(2);
}
//Calculate price if text + custom logo only
if(globl_Text_id>1 && globl_id_logo>1 && globl_id==1){
var type=" Text ,Custom Logo";
var sf="$65";
var ftotal = x * SF_TC;
ftotal=ftotal.toFixed(2);
}
//Calculate price if svg image + cutom logo only
if(globl_id>1 && globl_id_logo>1 && globl_Text_id==1 ){
var type=" Svg ,Custom Logo";
var sf="$70";
var ftotal = x * SF_SC;
ftotal=ftotal.toFixed(2);
}
if(ftotal<50)
{
ftotal=50;
}
$('#toatl_price').html(ftotal);
$('#finl_price').html(ftotal);
$('#design_size_height').html(inchieght);
$('#design_size_width').html(inchweight);
//if(globl_Text_id==1 && globl_id==1 && globl_id_logo==1 ){
//alert("Can not calculate price with blank canvas");
//}
//else{
alert("Final Product contains "+ type +" And Finale product total width "+ grup_width+" PX And Height "+ grup_height+" PX So Total square foot Height = "+inchieght + " Width = "+ txt_width+ "So Total price is : (HxW of area)/144 x S.F. price) = $"+ftotal) ;
canvas.setActiveGroup(group.setCoords()).renderAll();
canvas.discardActiveGroup();
canvas.renderAll();
// }
});
Not sure what's causing you problems, but your code answered what I was googling, so I'll take a shot.
You're using version 1.4.0 of fabric, so my guess is that this is a bug in fabric. I'm using similar code with 1.4.7 with no problems.
If you can't upgrade, try changing your Group object creation to:
var group = new fabric.Group(objs);
Fabric no longer uses center origin by default, so maybe this is confusing it when you discard the active group? Is it shifting by group.width / 2?
===
Here's my fabric 1.4.7 code that's working. I'm using it to scale an entire design on load.
var objs = canvas.getObjects()
, group = new fabric.Group(objs);
canvas._activeObject = null;
canvas.setActiveGroup(group.scale(1.4).setCoords()).renderAll();
canvas.discardActiveGroup();
Also note: I override the origin defaults to put them back to center (and not top/left) with:
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

Anyway to make the uBaseColor value transparent? Three.js && ShaderToon.js

don't know if this is possible, but using the ShaderToon.js in three.js, is there anyway to make the uBaseColor value transparent??? and leave the uLineColor value opaque?
function createShaderMaterial( id, light, ambientLight ) {
var shader = THREE.ShaderToon[ id ];
var u = THREE.UniformsUtils.clone( shader.uniforms );
var vs = shader.vertexShader;
var fs = shader.fragmentShader;
var material = new THREE.ShaderMaterial( { uniforms: u, vertexShader: vs, fragmentShader: fs } );
material.uniforms.uDirLightPos.value = light.position;
material.uniforms.uDirLightColor.value = light.color;
material.uniforms.uAmbientLightColor.value = ambientLight.color;
return material;
}
geometry = new THREE.TorusKnotGeometry(106.68, 200, 12, 2, 8.44, 5.4, 1);
material = createShaderMaterial( "dotted", directionalLight, ambientLight );
material.uniforms.uBaseColor.value.setHex( 0xffffff ); // want this to be transparent
material.uniforms.uLineColor1.value.setHex( 0x0000 );
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
ShaderToon is part of the examples, so you are free to modify it to your liking.
For example, you could do this:
"gl_FragColor = vec4( uBaseColor, 0.5 );",
In your createShaderMaterial() function, you will also have to set
material.transparent = true;
three.js r.59

Resources