How to get offset between last point of series and left corner of chart - lightningchart

I have a chart that is filled with content from HTTP requests. And data always come with this code
chartComponent.chartInstance
.getDefaultAxisX()
.onAxisInteractionAreaMouseDragStop((axis: Axis, event: MouseEvent, button: number, startLocation: Point): void => {
if (axis.getInterval().start / 2 < 10000) {
this.chartService.loadHistorySeriesData(chartComponent.selectedTimeRangeMinutes).subscribe((data: SeriesMapResponse) => {
this.chartService.addNewDataToTheSeriesInstances(chartComponent.chartId, chartComponent.seriesInstances);
})
}
})
So I have to implement conditions like if the offset is less than some number load me new data... Like pagination on the Instagram feed but with carts. How can I get this offset, I tried a lot of approaches and nothing works.

You can get the "left side of chart" information by referencing the X Axis interval start, like follows:
Axis.getInterval().start
You can probably get the needed information of "last old point" by LineSeries.getXMin() method.

Related

get custom value from point series data

I am adding data to scatter series like below , how do we receive the custom parameter value I add here
series.add({
x: 0,
y: 22,
color: ColorRGBA(255, 0, 0),
size: 10,
rotation: 45,
value: "custom message",
});
From the above series how do I extract the value "custom message" .. basically is there anyway to get it ? so I can to use it in table formatter like below .
series.setCursorResultTableFormatter((builder, series, xValue, yValue,value) => {
return builder.addRow(value).addRow(series.getValue());
});
Also another doubt is can we change shape of series dynamically like we change color and size ?
With v.3.1 this kind of logic is not supplied out of the box.
To implement it you'd need to add some kind of custom logic which finds your custom data based on the X and Y information.
In next release, v.3.2 we'll add an extra parameter to cursor result table formatters, so you can use it like follows:
series.setCursorResultTableFormatter((builder, series, x, y, dataPoint) => {
// `dataPoint` has all same information as user supplied, size, rotation, value or anything.
return builder.addRow(x).addRow(y).addRow(dataPoint.value);
});
Please note that these custom properties (size, rotation, value, etc.) will only be included when cursor interpolation is disabled.
At this time v.3.2 is scheduled for late September, but this could change.
2nd question about changing shape of point series, we currently don't have active plans to change this, but when there is enough motivation it will be improved on.

Given many rectangles, whats the best approach to group by line

TLDR: How to find boxes that are lined up horizontally
Given I have the data from an image like this:
We can visually see that we have two lines:
Tare: 11700 kg 10:40:58 am 16-May
Gross: 21300 kg 12:49:34 pm 9-Aug
The data I have for each blue box shown in the image is:
Top
Left
Width
Height
Coordinates for each corner of the box (X, Y)
My main thought is to start from the top of my "grid" and loop through each value of y, and then group boxes where they share the largest amount of matching "y" values, but it seems very over the top for something that seems simple.
Unsure really where to go from here
Example data set
I was able to get boxes lined up using this bit of code (in JavaScript), it essentially finds the first "most top left" box, and then finds any boxes that "intersect" with a line that starts from the middle of that first box
We don't care what order we get the boxes in, so as long as we start with the most left on any line we are golden.
function getMostTopLeftBox(boxes) {
const sorted = boxes.slice()
.sort(
(a, b) => {
if (a.Left === b.Left) {
return a.Top < b.Top ? -1 : 1;
}
return a.Left < b.Left ? -1 : 1;
}
);
return sorted[0];
}
function getAlignedBoxesFromSet(boxes) {
const mostTopLeftBox = getMostTopLeftBox(boxes);
const line = mostTopLeftBox.Top + (mostTopLeftBox.Height / 2);
return boxes
.filter(({ Top, Height }) => Top < line && (Top + Height) > line)
.sort(({ Left: a }, { Left: b }) => a < b ? -1 : 1)
}
function getAlignedBoxes(boxes) {
let remaining = boxes;
const lines = [];
const next = () => {
const line = getAlignedBoxesFromSet(remaining);
lines.push(line);
remaining = remaining.filter(box => line.indexOf(box) === -1);
if (!remaining.length) {
return;
}
return next();
};
next();
return lines;
}
The above code with the data set provided above gives us this result
However, it doesn't account for slight angles on the boxes, for example this image:
Another example of different boxes, with senstive information removed:
You can see from the above that the values below should be considered to be on the same line:
Product: [type]
Num Of [type]: 0
[value]: [value]
I may make a new question for this, but part of the answer to this is to figure out the actual curve of a line, and not just assume that the median angle of all lines is the actual "curve" of the line, so if I was to start with the most left box, then progress to the second box, now I have two distinct lines that I would want to find the smoothed curve for, which I would then use to find the next box, as I find each box I would want to adjust this curve to find the complete line, I will investigate this one further, if anyone has any hints, please do mention it.
I've managed to solve this, with a variant of the code posted in the question.
Here is a code sandbox of the solution, I will do a full write up of this, but here it is for now: https://codesandbox.io/s/102xnl7on3
Here is an example of grouped boxes based on angled lines calculated from the angle of all horizontal lines, if all the boxes were to be straight, then the result would be the lines being straight as well, so it should work in all scenarios.
Here is also an example where the lines are straight:
You can see the lines from the box before intersecting with the next box, it does this each time until it can find a complete line of boxes (till no more line up), this works out better than using an average angle from the entire data set.
I would like to be able to generate a mathematical curve for the already found boxes and apply that to find the next box, but for now, using the previous box as the anchor works pretty well.

Determining what direction to face over a network with an omnidirectional camera

I have a rather difficult problem. I am making a topdown 2D game. And I have decided to make an omnidirectional character control like realm of the mad god (Video shows at second 16 what that means). I have it all working fine and have managed to work out almost all the kinks of this sort of camera but one thing remains.
(if you dont know what effect im looking create you can see and example hee at 16 seconds mark: https://youtu.be/N2q6aXkvIiI?t=12s)
When the Camera of the the main client gets rotated more that 180 degrees Left becomes right and right becomes left and my messages to the server about flipping the given character when he is supposed to get inverted. I somewhat fixed this by making an if statement that sends an opposite flip request when your world is completely flipped.
However up and down also become a factor as they dont send requests to flip the character.
What im trying to get to is that I have overcomplicted this script I beleive when trying to get the correct messages accross all clients.
I am wondering if anyone has a logical solution to making sure all chracters on the network are always facing the correct direction at all times.
I am using socket.io and Node.js for speaking to the server.
Any input would be appeciated.
TL;DR
How would you go about making realm of the mad gods camera rotation style when all clients need to know what way everyone is facing. (see video 0:16)
thanks.
I have somewhat fixed this problem with a bit of a rewrite of my logic and managed to make all the magic happen on the client and keep the server out of it entirely. I do not know if what I have done is super effecient as I am rather new to coding.
The logic is that I have created a circle collider2D that represents the players field of view. so things slightly outside the camera view are included. Any collision with an object tagged "otherPlayer" will add them to a list.
I then iterate through the list, if its not empty, and I determine if the object is moving away or coming towards me. (thank you to HigherScriptingAuthority for part of the code for this :: https://forum.unity3d.com/threads/left-right-test-function.31420/).
once I know that, all I have to do is grab the transform of that object and flip it accordingly. Boom it now rotates the object or player correctly no matter what rotation the main client is in.
Hope this makes sense and it helps someone:
private float lastDist = 0;
public float dirNum;
void CheckArea()
{
if (listOfPlayers.Count != 0)
{
foreach(var otherPlayer in listOfPlayers)
{
float distance = (transform.position - otherPlayer.transform.position).magnitude;
if (distance < lastDist)
{
Vector3 heading = otherPlayer.transform.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
var objectDirection = AngleDir(transform.forward, heading, transform.up);
if (objectDirection > 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Left();
}
if (objectDirection < 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Right();
}
}
if (distance > lastDist)
{
Vector3 heading = otherPlayer.transform.position - transform.position;
dirNum = AngleDir(transform.forward, heading, transform.up);
var objectDirection = AngleDir(transform.forward, heading, transform.up);
if (objectDirection > 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Right();
}
if (objectDirection < 0)
{
var nav = otherPlayer.GetComponent<Navigator>();
nav.Left();
}
}
lastDist = distance;
}
}
}

Selectively removing node labels in D3 force directed diagram

Overall context: I have a db of cross-references among pages in a wiki space, and want an incrementally-growing visualization of links.
I have working code that shows clusters of labels as you mouseover. But when you move away, rather than hiding all the labels, I want to keep certain key labels (e.g. the centers of clusters).
I forked an existing example and got it roughly working.
info is at http://webseitz.fluxent.com/wiki/WikiGraphBrowser
near the bottom of that or any other page in that space, in the block that starts with "BackLinks:", at the end you'll find "Click here for WikiGraphBrowser" which will launch a window with the interface
equivalent static subset example visible at http://www.wikigraph.net/static/d3/cgmartin/WikiGraphBrowser/:
code for that example is at https://github.com/BillSeitz/WikiGraphBrowser/blob/master/js/wiki_graph.js
Code that works at removing all labels:
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return !(o.name in clicked_names);
})
.text(function(o) { return ""; });
j++;
}
Code attempting to leave behind some labels, which does not work:
labels.forEach(function(o) {
if (!(d.name in clicked_names)) {
d.text.label.remove();
}
I know I'm just not grokking the d3 model at all....
thx
The problem comes down to your use of in to search for a name in an array. The Javascript in keyword searches object keys not object values. For an array, the keys are the index values. So testing (d.name in clicked_names) will always return false.
Try
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return (clicked_names.indexOf(o.name) < 0);
})
.text(function(o) { return ""; });
j++;
}
The array .indexOf(object) method returns -1 if none of the elements in the array are equal (by triple-equals standards) to the parameter. Alternatively, if you are trying to support IE8 (I'm assuming not, since you're using SVG), you could use a .some(function) test.
By the way, there's a difference between removing a label and just setting it's text content to the empty string. Which one to use will depend on whether you want to show the text again later. Either way, just be sure you don't end up with a proliferation of empty labels clogging up your browser.

Flex Charts: Can you use a minimum/maximum point from an IAxis for Cartesian Data Canvas to draw the entire width of the chart?

I have a chart with a DateTime axis as my horizontal and a Linear Axis for my vertical inside a Adobe Flex Line Chart. I want to use a Cartesian Data Canvas as a background element and draw custom set of background graphics mostly rectangles. When I have more than a single data point, the graphics work perfectly since they are supposed to span the width of the entire chart.
When I have only a single data point, however, I can't seem to get the rectangles to draw. Since I want my rectangles to span the entire width of the chart, I was thinking that I could get the x-coordinates from my axis, but this isn't working.
var canvasWidth:Number = chtCanvas.width;
var canvasHeight:Number = chtCanvas.height;
var minPt:Array;
var maxPt:Array;
var minPtDate:Date;
var maxPtDate:Date;
var minPtComplete:Point;
var maxPtComplete:Point;
// This works fine when there is more than 1 data point
minPt = chtCanvas.localToData(new Point(0, 0));
maxPt = chtCanvas.localToData(new Point(canvasWidth,canvasHeight));
//This does return a date object, but wont draw below
minPtDate = axisDate.minimum;
maxPtDate = axisDate.maximum;
//This returns NaN for the x
minPtComplete = chtCanvas.dataToLocal(minPtDate, axisSalary.minimum);
maxPtComplete = chtCanvas.dataToLocal(maxPtDate, axisSalary.maximum);
// Also tried this. Also returns NaN for the x value
//minPtComplete = chtCanvas.dataToLocal(axisDate.minimum, axisSalary.minumum);
//maxPtComplete = chtCanvas.dataToLocal(axisDate.maximum, axisSalary.maximum);
My actual drawing method is as follows:
// Tried this, works with points >2, does not draw with single data point
chtCanvas.drawRect(minPt[0], detail[i].MaxValue, maxPt[0], detail[i].MinValue);
//tried this, no effect with single point
//chtCanvas.drawRect(minPtDate, detail[i].MaxValue, maxPtDate, detail[i].MinValue);
// Tried this, no effect with single point
//chtCanvas.drawRect(minPtDate, minPt[1], maxPtDate, detail[i].MinValue);
// Tried this also
//chtCanvas.drawRect(minPtComplete.x, detail[i].MaxValue, maxPtComplete.x, detail[i].MinValue);
In this example, detail is an array collection of salary values and Im using the data value in the array to determine the vertical bounds of my rectangles.
I need to draw the rectangles the entire width of the chart (even when there is only a single data point). Thanks
Thanks to Heikki for his help. The following code works to use the axis values to draw on your Cartesian Data Canvas:
chtCanvas.drawRect(axisDate.minimum as Date, axisSalary.maximum, axisDate.maximum as Date, axisSalary.minimum);
Casting the values as Date really helped. The rest of the code used above is unecessary.
One thing to note, I was using a DateFormatter to format the date values from my data. What I didn't consider was that when using a DateTimeAxis, Flex will automatically add in extra dates to display on the axis. In my case, I was using a custom parse function to create MY points, but wasnt considering the points Flex was creating and also passing to my parse function (Therefore, they were not getting parsed correctly). Once I corrected this, the values laid out correctly in the case of multiple data points. I'm still having a bit of an issue with single data points and them not filling the chart entirely, but they are now drawing.
UPDATE:
Although there are signs of life, the minimum and maximum are still not drawing the entire width of the chart in some cases depending on the dataUnits and labelUnits combination.
UPDATE #2: SOLVED
Ok, so the axis does work as minimum/maximum values for the Cartesian Data Canvas but there is something important to remember. For a single point (and probably for multiple points as well, I just couldnt visually see the difference), when using a custom DateTimeAxis parse function such as what was in the Adobe Flex ASDoc tutorials:
private function axisDateParseFunction(item:String):Date
{
var inputDate:String = item;
inputDate = fmtDate.format(inputDate);
var newDate:Date = new Date();
if(inputDate)
{
var a:Array = inputDate.split('/');
newDate.fullYear = a[2];
newDate.month = a[0] - 1;
newDate.date = a[1];
newDate.hours = 0;
newDate.hoursUTC = 0;
newDate.minutes = 0;
newDate.minutesUTC = 0;
newDate.seconds = 0;
newDate.secondsUTC = 0;
newDate.milliseconds = 0;
newDate.millisecondsUTC = 0;
}
return newDate;
}
You MUST remember to set the UTC values as shown above also. Since the DateTimeAxis uses date AND time, when you create new Date objects, their time values also get set to the local system time. Remember to set those values to zero also or you will get points that dont exactly line up with your axis labels.

Resources