How do I make the closest four points on a graph glow? - javascript

As my cursor moves, I grab the two closest points IF it is not already on a plotted point.
I want to be able to make these two closest points light up (i.e. change colour to something orange or something), and then go back to normal once the cursor leaves the scope of the graph. How do I go about implementing this?
placeholder.bind("plothover", function (event, pos, item) {
if (item){
local_x = item.datapoint[0].toFixed(2);
local_y = item.datapoint[1].toFixed(2);
if (!updateLegendTimeout){
updateLegendTimeout = setTimeout(updateLegend(local_x,local_y), 1000);
updateLegendTimeout = null;
}
}
else{
var closest_points_container = interpolate(plot,pos.x,pos.y);
//Code to make points glow goes here, they are contained in closest_points[0]
and closest_points[1].
}

Flot provides highlight and unhighlight methods on the plot object, as described in the Plot Methods section of the docs. Unfortunately that has the restriction that only one point may be highlighted at a time. That is baked-in; you can't change it without altering the source.
The work-around I would use is to add a second series showing only points, no lines, and set the point style to appear as a highlight, i.e. with translucency. This highlight series will start out empty; then when you want to highlight a point on your main series you can copy it to the highlight series and redraw.

Related

javascript picture.js - Moving grouped items around the canvas

I basically have a rectangle with a PointText item overlayed on top of it. I currently have a working sample where I can move items around on the canvas by using sample code from the paperjs-v0.9.23\examples\Paperjs.org\HitTesting.html which has been really useful. However, I want to treat the rectangle and the text as one logical grouping to be moved around.
Please see the link below to see what I mean:
http://jsfiddle.net/svt9wa9f/6/
In the HitTesting.html example it has this within the onMouseDown event: `
if (hitResult)
{
path = hitResult.item;
if (hitResult.type == 'segment')
{
segment = hitResult.segment;
} else if (hitResult.type == 'stroke')
{
var location = hitResult.location;
segment = path.insert(location.index + 1, event.point);
path.smooth();
}
}
`
I was hoping I could modify this to work with the groups, but it seems this type of hitesting doesn't work. Everytime I click within any object I just get the 'fill' type. So I was then thinking I would have to do a linear search through the array of groups performing a hittest just to see which item is within the group. Or a hashmap keyd on items, and the value as the group. But there must be an easier way?
Within the fiddle example, the group code is commented out because. When you first execute it you can't see the items, you have to hover the mouse pointer of the canvas to get them to appear. Any help on this would be appreciated.
Ideally, I just need to be able to move these groups around through drag events, and extend the code to be able to determine whilst dragging if I am over another grouping. But that is further down the line.
Thank you for your time.

how to make doughnut chart portions, buttons

I have a doughnut chart made by Chart.js. When my mouse comes over a portion, the portion label appears such as RED: 300.
What I want is to show this label in the middle when I click it.
I have the code to write in the middle, but I need to know how to make portions to behave as buttons.
I think you're looking for the getSegmentsAtEvent(evt) method.
canvas.onclick = function(evt){
var activePoints = myDoughnutChart.getSegmentsAtEvent(evt);
// => activePoints is an array of segments on the canvas that are at the same position as the click event.
};
If activePoints is empty, that means you can just return because no segment was clicked. Otherwise, go ahead and draw your tooltip.

KineticJS: Draw Arrow between two shapes

So, I want to create a finite state machine-visualizer/editor with the help of kineticjs and i'm stumbling with the following scenario:
I have two "nodes", let's say circle-objects (grouped with a label) which are draggable on my stage. Now I wan't to click on one circle, hold the mouse and move it and add a connection (an arrow, for simplicities sake) between the two shapes.
So it would be great to have any hints on how to accomplish this for I haven't found a solution yet.
To specify it: The nodes themselves should stay draggable. My thought was: Add a black circle and a white circle with a slightly smaller radius, group them. then on dragstart white circle -> drag node, on dragstart black circle -> draw arrow.
The Problem is how to draw an arrow starting from one shape and following the mouse to it's target (which can be another nodegroup => connection to this group or a blank point of the stage => an overlay opens which lets the user choose another node to draw or cancel the drawing).
I hope this is somewhat clear to understand. For more information please feel free to ask me.
Best regards,
Dominik
p.s.: The behaviour seems to be exactly like the behaviour lucidchart (dot com) uses when creating diagrams, so maybe you understand what I want to achieve better looking at their demo here: https://www.lucidchart.com/demo .
First off, for simplicity's sake here is a fiddle on how to draw a basic Line with your mouse and KineticJS: http://jsfiddle.net/projeqht/fF3hh/
Let's say you already have two circles on the stage, and you need to draw a line to connect them.
We can use e.targetNode to select the nodes on each event (mousedown, mouseup), for example:
layer.on("mousedown", function (e) {
var nodeDown = e.targetNode;
}
layer.on("mouseup", function (e) {
var nodeUp = e.targetNode;
}
We need to check if the parent of nodeDown is a Kinetic.Group or something else.
If the target node nodeDown has a Kinetic.Group for a parent, we can use this Group to store the new line, and the 2nd target node nodeUp.
If the target node nodeUp does not have a Kinetic.Group for a parent, we need to see if nodeUp has a Group for a parent. If nodeUp has a Kinetic.Group for a parent, then we can use that Group to store the new line, and the first target node nodeDown.
If neither nodeDown or nodeUp have a group for a parent, then we will need to create a new group for them and add all 3 shapes (2 circles and a line) to that new group.
Use this tutorial to learn how to move shapes from 1 group to another: http://www.html5canvastutorials.com/kineticjs/html5-canvas-move-shape-to-another-container-with-kineticjs/
Also, if you move a shape from one group to another, you may want to remove() or destroy() the extra group if it is no longer needed.
While drawing a Line, you will have to disable dragging the shapes, so that you can drag and draw with a mouse. You can do that by doing something similar to this:
function stopDrag() {
for (var i=0; i<layer.children.length; i++) {
layer.children[i].setDraggable(false);
}
}
function startDrag() {
for (var i=0; i<layer.children.length; i++) {
layer.children[i].setDraggable(true);
}
}
This will make all the children of layer draggable and undraggable, but you might want to limit that by being more specific than select layer.children. A nice trick I liked to use here was to name all groups that were draggable as "draggable_shapes" and then use var draggableArray = stage.get('.draggable_shapes') to select all the groups that are allowed to be dragged, then you could loop through that array and setDraggable().
Another point to note is that the X and Y coordinates of the Line will be a bit tricky to calculate, depending on if it has a Group as a parent or a Layer. If the Line is grouped, line's coordinates will be relative to the Group position, or else the Line's coordinates will be relative to the Stage (top left corner).
This will get you started on connecting a line with two different circles. It's up to you to do the coordinate logic if you want the lines to only connect on the outer rim of the circles.
Maybe you might want to add a transparent rectangle (attribute opacity: 0) behind each circle, so that on mousedown with the rectangle, you will call drawLine() to start drawing a line. Or else if the user clicks the circle, it will drag the group. At least that has similar functionality to the lucid charts application.
Custom Hit Function (http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-custom-hit-function-tutorial/) would probably be a cleaner way to do this but I'm not 100% on using Custom Hit Functions, someone else might know better.
Let me know if you need further help. Good luck!

How can this object be appended to a specific tile on an isometric map?

I have an isometric map that has selectable tiles. The map is formed by a matrix such as $('div').gameMap({map:[[{"tile":"tile_0","object":"anObjectOnTile"},{"tile":"tile_3","object":""}], [{...}]],mapsize:3}); If the tile has something within the object:"", then that tile has that object (in my case, an image of an oil derrick) on top of that tile.
There is a Place button which when clicked should place an oil derrick object on top of the currently selected tile.
However, I have run into two problems:
Knowing which tile is currently selected
Adding a single oil derrick
At first I wanted to figure a way to modify the map's matrix to insert the object's name (oilDerrick) into the tile's object parameter, but now I think the better solution would be to append the oilDerrick to the tile. I can't figure out how to append to the particular tile and not every tile.
I've got the code set up to look at and play with: http://jsfiddle.net/briz/jdhPW/13/
There's an oilDerrick object set up in the map's matrix for you to view, which can be removed by deleting the word oilDerrick in the matrix
I played with $(".tile").append($('.oilDerrick')); though I knew that would append to every tile. But I simply do not know enough about appending yet to figure out how to limit it to a single instance.
Each tile has a unique ID. I also tried this in order to add an oilDerrick to a certain tile:
$("#placeButton").click(function()
{
for (var y in config.map)
{
for (var x in config.map[y])
{
document.getElementById(obj.attr('id') + '_tile_' + x + '_' +y).appendChild(".oilDerrick");
}
}
}
But this came to no avail as well. I think I'm heading in the right direction though? Can anyone help?
I did some modifications.
There a little mess in your code. For example, your using jquery but there is a lot of direct DOM manipulation.
.style.background = ...
// should be
.css("background",...)
And the most important:
document.getElementById(...)
// should be
$("#...")
Easier, don't you think? Then, the problem is simple solved by creating a var currentTile and when the user select one tile, it save it. When click in 'place', $(currentTile).append($('.oilDerrick')); And the oil derrick move to where to selected tile.
Anyway, more details you can see in the link.

Mouseover preview for bar instead of datapoint in StackedColumn chart

I have a StackedColumn chart which I'd like to add a mouseover preview. Currently I'm looping through the points of a series to add the the functionality to do this.
This makes each series in the column will do a mouseover/mouseout. I'd like it to do a single mouseover/mouseout for the column. Suggestions?
Ok, not a popular question.
I stumbled across the CustomizeMapAreas event. In there I looped through the e.MapAreaItems and adjusted the size of the areas so that there was just one area for the entire column. Then I removed the areas I didn't need anymore. It's probably not the most efficient way to do it, but here it is...
protected void FixStackedColumnAreas(object sender, CustomizeMapAreasEventArgs e)
{
Dictionary<float, MapArea> newAreas = new Dictionary<float, MapArea>();
//loop through all areas and collect the Min and Max Y values for each X
foreach (MapArea area in e.MapAreaItems)
{
if (!newAreas.ContainsKey(area.Coordinates[0]))
{
newAreas.Add(area.Coordinates[0], area);
}
else
{
//get the lowest and highest Y for this X column area
newAreas[area.Coordinates[0]].Coordinates[1] = Math.Min(newAreas[area.Coordinates[0]].Coordinates[1], area.Coordinates[1]);
newAreas[area.Coordinates[0]].Coordinates[3] = Math.Max(newAreas[area.Coordinates[0]].Coordinates[3], area.Coordinates[3]);
}
}
//clear out existing areas
e.MapAreaItems.Clear();
//put in our new areas that define the whole column area instead of the individual pieces of the column
foreach (MapArea area in newAreas.Values)
{
e.MapAreaItems.Add(area);
}
}

Categories