what I want to do is the following. I have a linechart with some data points on it. I want to allow user to select chunk of the chart and highlight it by dragging a finger.
I tried a few hacky approaches using ChartTransformer and tracking pixels of the UIPanGestureRecognizer and then programmatically highlighting the appropriate xIndexes, but it looks terrible.
I was wondering if there is a better way to do it. Thank you.
I would say your approaches should be right, what you mean it looks terrible?
I would check when the pan gesture ended, I will calculate how many xIndex has been chosen, and highlight every data entry for that Index.
The logic to determine the xIndex - when user start panning, I know the location, and I will translate it into the closest xIndex; same as the ending point, so we know the start xIndex and end xIndex
Related
I have some experience with Metal and quite a bit with Unity and am familiar with setting up meshes, buffers, and the backing data for drawing; but not so much the math/shader side. What I'm struggling with is how to get an endless scrolling world. So if I pan far to the right side I can see the left side and keep going.
The application of this would be a seamless terrain that a player could scroll in any direction forever and have it just wrap.
I don't want to duplicate everything on draw and offset it, that seems horrendously inefficient. I am hoping for a way to either use some magic matrix math or some sort of shader to get things wrapping/drawing where they should when panning the map. I've searched all over for some sort of guide or explanation of how to get this working but haven't come up with anything.
I know a lot of old (dos) games did this somehow, is it still possible? Is there a reason why it seems the industry has migrated away from this type of scrolling (bounding to edges vs wrapping)?
I have created a simple example demonstrating what you're looking for (I think).
The basic idea of it is that you draw the map in a repeating grid, using the drawPrimitives(type:vertexStart:vertexCount:instanceCount:) method on MTLRenderCommandEncoder. As the instance count you want to pass in the number of identical maps you want to draw, extending it as far as needed to not see where it ends. In my example I used a simple 5x5 grid.
To not have the user see the edge of the map, we're gonna calculate their position modulo 1 (or whatever size your map is):
func didDrag(dx: CGFloat, dy: CGFloat) {
// Move user position on drag, adding 1 to not get below 0
x += Float(dx) * draggingSpeed + 1
z += Float(dy) * draggingSpeed + 1
x.formTruncatingRemainder(dividingBy: 1)
z.formTruncatingRemainder(dividingBy: 1)
}
This is how it looks:
Just a follow up on what I have actually implemented. First I essentially have an array of x,y points with altitude, terrain type and all that jazz. Using some simple % and additions/subtractions it is trivial to get the nodes around a point to generate triangles
On a draw I calculate the first showing point and the last showing point and calculate the groups of triangles shown between those points. The first/last point take into account wrapping, it is then pretty trivial to have an endless wrapping world. For each group a translation offset is passed via a uniform matrix for that group which will position that section where it should belong.
I set it via renderEncoder.setVertexBytes(&uniform, length:..., offset:...)
I am using coreplot to draw a scatter plot like that:
I use 4 different plots (as coloured) and create a "bar like" feeling by adding 0-value points at the beginning/end of each "bar".
I want to determine which bar was selected by the user and then change alphas of other plots.
I've tried using
-(BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDownEvent:(id)event atPoint:(CGPoint)point {
//here I translate the selected point to Data points coordinates
//and check which of the plot sources has value >0 (that means bar is visible)
//and is closest to the selected point
}
This method works, but when I want to scroll the data, the method above is called as well.
There must be some easier solution to do that. Thanks.
Return YES from your delegate method to inform the plot space that you've taken action on the event and it does not need to start the scroll. You may need to handle the other events, too, so your app can differentiate between a tap and a drag.
I'm drawing a chart in an iOS app and I want the gridlines to start in the x axis but end in the data point instead of extending all the way up to the top.
Is this possible?
Thanks in advance.
NC
Disclaimer: I work for ShinobiControls
The shinobicharts framework doesn't currently support this as an out-of-the-box feature.
A workaround may exist though. You may be able to add your own gridline subviews by using the SChartAxis method pixelValueForDataValue: to work out where in the plot area coordinate space you should draw your vertical line up to for a given data point.
Once you have your coordinates there are various ways you could draw your gridlines:
Add a canvas view behind or in front of the chart (depending on what effect you want). Then use your coordinates to draw your gridlines using CoreGraphics or some other drawing technique.
Create individual UIViews that each represent a gridline using your coordinates and add these behind or in front of the chart.
One thing to be aware of with this technique is that the gridlines will not automatically update when you pan and zoom. In order to do this you will need to override one of the chart's delegate methods that notify you of range changes and update your drawn gridlines to match the new data point positions.
Another potential workaround could be to use a column series to mimic gridlines. If you create a column series and feed it the same data points as your original series this will result in columns that go up to the y-value of each data point. You could then use the property interSeriesSetPadding on SChartAxisStyle to cause the columns to appear very thin.
I hope that information is useful!
Using Core Plot's CPTScatterPlot, I've made a bubble chart that looks like the above.
I've implemented plotSymbolWasSelectedAtRecordIndex in my delegate so I can detect when the user touches one of the bubbles. Using this screenshot as an example, I want to be able to highlight the yellow bubble and bring it in front of the red one when the user touches it. In graphical terms, I want to set the Z order of the selected CPTPlotSymbol to be higher than the others. How can I accomplish that? I'm able to highlight the selected bubble by drawing it in a different color in my symbolForScatterPlot method, but I can't seem to find a way to make it draw in front of the overlapping symbol.
Core Plot draws the data points in the order they appear in the datasource. You'll need to reorder the data so the top-most bubble is at the last index and call -reloadData on the plot to tell it to refresh its data. If you have the data points in an array, sort it by the desired z-index (back to front) and use the sorted array to feed the datasource.
So I have a simple line XY Graph with integer values on the Y axis and dates on the X axis. What I would be like to be able to do is do a horizontal two-finger pinch and adjust the range dynamically. Eg, pinching in would give you a bigger range (mental model being that you're setting the start and end date shown to be further apart) and then pinching out would give you smaller time window.
Is there some stuff built in for this already? Reasonably new to CorePlot and the default finger stuff just zooms the graph itself, none of the values.
Would I need to put a gesture recgoniser on it? or does coreplot have stuff build into it for this?
Cheers
This is how the built-in zoom features work. Use a plot space delegate to monitor changes to the plot space while zooming and make changes to the axis appearance as needed based on the changes. See my answer to your other question for more info.