I am using ProgressBar.js to create a circle with a percentage in the center. The circle creates properly but when I run it again, I want it to update the text (the percentage) with the new passed in value.
How can I do this? Currently, the code does not update the inner text.
Use circle.animate(value) or circle.set(value):
let circle = null
/**
* #param percentage - decimal from 0 to 1 (0.7 => 70%)
*/
function refreshCircle(percentage) {
if (!circle) {
circle = /* initialize */
}
circle.animate(percentage)
// or without animation:
circle.set(percentage)
}
demo
Related
When you use lightningchart to set the scale to be displayed, the default size is 5 or 10 increments.
Is it possible to change this to an arbitrary increments (2 increments, 3 increments, etc.)?
Please let me know.
The Axis automatically calculates the increment size depending on the level of zooming for the Axis and space available for each tick label. We're looking towards improving our Axis behavior with the next Major release this Summer.
In the meanwhile, it is possible to create this behavior manually by using customTicks.
/*
* LightningChartJS example that showcases a simple XY line series.
*/
// Import LightningChartJS
const lcjs = require('#arction/lcjs')
// Extract required parts from LightningChartJS.
const {
lightningChart,
ColorRGBA,
UIElementBuilders,
emptyFill,
emptyLine,
emptyTick,
SolidLine,
SolidFill
} = lcjs
// Create a XY Chart.
const chart = lightningChart().ChartXY()
.setTitle('XY Chart with custom tick interval')
// Get the default X Axis and cache it
const defXAxis = chart.getDefaultAxisX()
// Set the default Axis style as emptyTick, hiding the default Ticks created
// by the AxisTickStrategy
defXAxis.setTickStyle(emptyTick)
// Iterate an arbitrary amount of ticks, creating a new customTick with interval of 2
for ( let i = 10; i <= 90; i += 2 ) {
// Add a new custom tick to the X Axis
defXAxis.addCustomTick(
// Modify the textBox to hide its background and border
UIElementBuilders.PointableTextBox.addStyler(
(styler) => {
styler.setBackground(
(bg)=>
bg
.setFillStyle(emptyFill)
.setStrokeStyle(emptyLine)
) }
))
// Set the tick position
.setValue( i )
// Make the Grid stroke less visible
.setGridStrokeStyle(
new SolidLine( {
thickness: 1,
fillStyle: new SolidFill( { color: ColorRGBA(200, 200, 200, 50)})
})
)
}
I'm not sure how to do this. I'm developing a heatmap dc.js. I want to set a range of colors manually. For example,
var chart = dc.heatMap('#heatmapID');
chart
.width(690) //850
.height(400)
.margins({top: 10, right: 0, bottom: 50, left: 70})
.dimension(dimension)
.group(group)
.keyAccessor(function(d) { return d.key[0]; })
.valueAccessor(function(d) { return d.key[1]; })
.colorAccessor(function(d) {return d.value.rate;});
chart.data(grouphelper.dataAccessor(dimension));
chart.colors(['#30d074', '#f3cb2c', '#ffa85c', '#ff604e'])
.calculateColorDomain();
The code above works but its automatically setting the colors base on the min and the max data (I'm assuming). For the chart.colors(....) i want to set a range manually but when I tried to apply a return function, for example,
//Outside of the chart function
var colors = ['#30d074', '#f3cb2c', '#ffa85c', '#ff604e'];
function colorHeatMap() {
return d3.scale.threshold().domain([0.02,0.06,0.23]).range(colors); }
//now apply colorHeatMap function into the .color function.
chart.colors(colorHeatMap()) .calculateColorDomain();
I received a _colors.domain is not a function error. When I remove the .calculateColorDomain(), the heatmap display all black boxes. My goal is to set the range manually for the 4 colors. Please help. This approach works well with dc row charts but I cannot figure out how to do that for the heatmap.
You cannot pass an array colors to the chart.colors() function; you must pass a d3 color scale object. That's why your heatmap shows all black boxes when you remove calculateColorDomain().
I've run into a similar issue, and my solution was to create a colorDomain array and use it to access the colors. If you know which values you want to assign to each color, it's simple: just put the values in an array in that order.
var colorsDomain = [0.02, 0.06, 0.23];
var colors = ['#30d074', '#f3cb2c', '#ffa85c', '#ff604e'];
chart.colors(d3.scaleQuantize().domain([0, colors.length - 1]).range(colors))
.colorAccessor(d => colorsDomain.indexOf(d.value.rate))
It looks like you might be using d3 v3 or lower, in which case you would want to use d3.scale.quanitze() instead of d3.scaleQuantize() in the colors function. Hope this helps!
I my fabric application, I want to align the selected objects, for example, to the left. Because objects might be rotated (and or scaled), thus, aligning objects actually mean align the bounding boxes of the objects to some edge.
For non-rotated objects, that's quite trivial to implement.
See sample code below:
// find the minimum 'left' value
// function 'min' is used to find the minimum value of a
// given array of objects by comparing the property value
// which is returned by a given callback function
const { minValue } = min(objects, object => {
const left = object.get('left');
const originX = object.get('originX');
if (originX === 'center') {
return left - (object.get('width') * object.get('scaleX')) / 2;
}
return left;
});
objects.forEach(object => {
if (object.get('originX') === 'center') {
object.set('left', minValue + (
object.get('width') * object.get('scaleX')
) / 2);
} else {
object.set('left', minValue);
}
});
canvas.renderAll();
However, it's quite complicated for rotated objects. I have to translate the rotated objects either horizontally or vertically to some calculated offset/distance.
Can anybody give some advise on this? thanks.
After a small research, I found this demo on the official fabricjs website.
Basically you can do:
var bound = obj.getBoundingRect();
Then use bound.top, bound.left, bound.width, bound.height as the bounding rectangle coordinates.
I have objects which each have a separate parent for each rotation axis (1 for X-rotation, 1 for Y-rotation, and 1 for Z-rotation. They are all related to each other in that order as well: X-rotation object is a child of the Y-rotation object. Y-rotation object is a child of the Z-rotation object).
I'm trying to make a feature which allows users to rotate all objects in the scene together (they are all contained in a single Object3D). When that Object3D is rotated, the program must find all of the objects' absolute positions and rotations relative to the world so that the program can output the new values for each object.
To do this, I currently have it setup to move the object so that its position inside the "scene-rotator", which is an Object3D, is set to its absolute position relative to the world. Now, I'm trying to make the rotation of the object become the absolute rotation of the object relative to the world, so that it changes accordingly when the "scene-rotator"'s rotation is changed. Also, the setFromRotationMatrix method was not working correctly when I tried just running it once on the child object, so instead, I had to run it again for each parent object and get each separate rotation from them accordingly
This is the code that I currently have which is supposed to get the absolute rotation of the object relative to the world:
var beforeRotForX = new THREE.Euler();
beforeRotForX.setFromRotationMatrix(objects[i].parent.matrixWorld, "ZYX");
var beforeRotForY = new THREE.Euler(); // Had to be a separate one for some reason...
beforeRotForY.setFromRotationMatrix(objects[i].parent.parent.matrixWorld, "ZYX");
var beforeRotForZ = new THREE.Euler(); // And apparently this one has to be separate too
beforeRotForZ.setFromRotationMatrix(objects[i].parent.parent.parent.matrixWorld, "ZYX");
// Absolute before rotation
objects[i].userData.sceneBeforeRotAbs = {
x: beforeRotForX.x,
y: beforeRotForY.y,
z: beforeRotForZ.z
};
Then, it must apply that absolute rotation to the relative rotation of the object
objects[i].parent.rotation.x = objects[i].userData.sceneBeforeRotAbs.x;
objects[i].parent.parent.rotation.y = objects[i].userData.sceneBeforeRotAbs.y;
objects[i].parent.parent.parent.rotation.z = objects[i].userData.sceneBeforeRotAbs.z;
This all works fine when the Y-rotation of the second parent is within -90 through 90
// Results of absolute world rotation when the Y-rotation of the
// second parent is set to 90 degrees (1.5707... as euler)
objects[i].userData.sceneBeforeRotAbs.x === 0
objects[i].userData.sceneBeforeRotAbs.y === 1.5707963267948966
objects[i].userData.sceneBeforeRotAbs.z === 0
but when the Y-rotation of the second parent is below -90 or greater than 90, then it gives the wrong value for the absolute world X-rotation and Y-rotation as a result
// Results of absolute world rotation when the Y-rotation of the
// second parent is set to 91 degrees (1.5882... as euler)
objects[i].userData.sceneBeforeRotAbs.x === 3.141592653589793
objects[i].userData.sceneBeforeRotAbs.y === 1.5533438924131038
objects[i].userData.sceneBeforeRotAbs.z === 0
You're running into gimbal lock. When using euler angles you'll always run into gimbal lock issues, and you'll encounter unexpected behavior when applying multiple rotations.
For example, in 2D space, a 30° rotation is the same as a -330° rotation. In 3D space, you can get the same problem: rotating an object 180° in the X-axis is the same as giving it a 180° Y-axis + 180° Z-axis rotation.
You should declare your rotations using quaternions, and then multiply them together to get the desired result without gimbal lock issues.
// Declare angles
var angleX = 45;
var angleY = 120;
var angleZ = 78;
// Declare X and Y axes
var axisX = new THREE.Vector3(1, 0, 0);
var axisY = new THREE.Vector3(0, 1, 0);
var axisZ = new THREE.Vector3(0, 0, 1);
// Init quaternions that will rotate along each axis
var quatX = new THREE.Quaternion();
var quatY = new THREE.Quaternion();
var quatZ = new THREE.Quaternion();
// Set quaternions from each axis (in radians)...
quatX.setFromAxisAngle(axisX, THREE.Math.degToRad(angleX));
quatY.setFromAxisAngle(axisY, THREE.Math.degToRad(angleY));
quatZ.setFromAxisAngle(axisZ, THREE.Math.degToRad(angleZ));
// ...then multiply them to get final rotation
quatY.multiply(quatX);
quatZ.multiply(quatY);
// Apply multiplied rotation to your mesh
mesh.quaternion.copy(quatZ);
I need to add a vertical line and a text on my Line chart near to a specified point on chart (specified by data, not coordinates). I tried to use CompositeSprites, but it doesn't show on screen completely. I'm new to ExtJS drawing.
You should put the logic that adds the vertical line inside of the chart's refresh event listener, that way, if the data changes the line position will be updated to reflect the new data.
Here's an example of how you could do it, assuming you can get a reference to the chart container (e.g. "myPanel"):
var myChart = myPanel.down('chart'),
myChart.on('refresh', function(myChart) {
// First, get a reference to the record that you want to position your
// vertical line at. I used a "findRecord" call below but you can use
// any of the datastore query methods to locate the record based on
// some logic: findBy (returns index #), getAt, getById, query, queryBy
var myRecord = myChart.store.findRecord(/*[someField]*/, /*[someValue]*/),
// a reference to the series (line) on the chart that shows the record
mySeries = myChart.series.first(),
// get the chart point that represents the data
myPoint = Ext.each(mySeries.items, function(point) {
return myRecord.id === point.storeItem.id;
}),
// the horizontal position of the point
xCoord = point.point[0],
// check for any previously drawn vertical line
myLine = myChart.surface.items.findBy(function(item) {
item.id === 'vert'
});
// if there is no previously drawn line add it to the "surface"
if (!myLine) {
myChart.surface.add({
id: 'vert', // an id so that we can find it again later
type: 'rect',
width: 4,
height: myChart.surface.height, // the same height as the chart
fill: 'black',
opacity: 0.5, // some transparency might be good
x: xCoord,
y: 0 // start the line at the top of the chart
});
// if we already had a line just reposition it's x coordinate
} else {
myLine.setAttributes({
translate: {
x: xCoord,
y: 0
}
// I think the chart gets drawn right after the refresh event so
// this can be false, I haven't tested it though
}, false);
}
});
If you are using the MVC pattern your event handler would look a little different (you wouldn't use myChart.on()).