The legend to my graph only occurs whenever the plotpan event occurs. Here is my updateLegend function found below which I am sure the program goes into of course using tracing messages
However, the only time the legend updates anymore since I included the plotpan functionality, is right after a plotpan occurs. I am unsure as to what is causing this, as such I am unable to address the problem. Here is the JSFiddle that will be more helpful than the following isolated segment of code.
var updateLegendTimeout = null;
var latestPosition = null;
function updateLegend(){
var series = (plot.getData())[0];
legends.eq(0).text(series.label ="x: " + (local_x)+" y: "+ (local_y));
}
placeholder.bind("plothover", function (event, pos, item) {
if (item){
local_x = item.datapoint[0].toFixed(2);
local_y = item.datapoint[1].toFixed(2);
console.log("x:" + local_x + ", " + "y:" + local_y);
}
if (!updateLegendTimeout){
updateLegendTimeout = setTimeout(updateLegend, 50);
updateLegendTimeout = null;
}
});
What exactly is this line of code intended to do?
legends.eq(0).text(series.label ="x: " + (x)+" y: "+ (y));
It seems to be assigning the series.label but I don't believe it's actually modifying the contents of the legend div. It updates when you pan, though, because that forces a redraw of the grid (which redraws the legend).
The easiest fix is to call setupGrid manually after you change the legend.
function updateLegend(x,y){
var series = (plot.getData())[0];
var legends = $(placeholder_id+ ".legendLabel");
series.label ="x: " + (x)+" y: "+ (y);
plot.setupGrid();
clearTimeout(updateLegendTimeout);
}
This is relatively expensive, though (redrawing the grid on every mouse move). Another line of attack would be to manually set the text of the legend div but this might interfere with flots internal legend drawing. If you really want to show the nearest point position, perhaps leave the legend alone and do it in a div of your own.
Finally, I'm not quite sure where you are going with all those setTimeout. Seems like an over complication to me and you could simplify this quite a bit.
Update fiddle.
Related
I currently have a giant table of "auditpoints", some of those points are "automated". If they are automated they receive a gear icon in their row. The gear icon is not the only icon each row receives. Each row, no matter if it's automated or not receives two other icons, a pencil and a toggle button. When an automated point "runs" the gear icon rotates until it is finished "running". I've have implemented some code to ran all of these points at once but I have a small problem. When you click my button to run all these points all three of the icons I have mentioned rotate and this is not the result I am looking for. The line commented out in my code snippet (and it's matching bracket) will prevent the code from running all of the automated points. Commenting out the line is what causes all the icons to rotate. I know this line is required to get the automated points to run properly as it used in the single execution of automated points I just don't know what to change it to. It obviously shouldn't be click because you are no longer clicking the gear icon to get a point to run I just don't know what to change it to but the classes in that click function are related to the gear icon.
Hopefully this is a very easy question to solve and doesn't waste anyone's time. Thank you!
private updateAuto() {
var self = this;
$(".auditPointRow").each(function () {
//self.el.on("click", ".update, .edit", function () {
var row = $(this).closest(".auditPointRow");
var id = row.data("id");
var automated = (<string>row.data("automated")).toLowerCase() == "true";
var running = true;
if (automated && $(this).closest(".edit").length == 0) {
var gear = $(this).find(".fa");
var maxTurns = 120;
gear.css("transition", "transform linear " + maxTurns * 2 + "s");
gear.css("transform", "rotate(" + (maxTurns * 360) + "deg)");
var request = $.ajax(self.root + "api/sites/" + self.site.ID + "/auditpoints/" + id, {
"type": "PATCH", data: JSON.stringify([
{
Op: "Replace"
, Path: "/score"
, Value: "run"
}
])
});
request.done(function () {
gear.css("transition", "").css("transform", "rotate(0deg)");
row.prev().find("td").css("background-color", "");
if (row.prev().qtip("api")) {
row.prev().qtip("api").destroy(true);
}
});
}
//}
});
}
I think I found a solution to my problem. I used .each again to go through all of the "gears" and only rotate them.
private updateAuto() {
var self = this;
//$(".auditPointRow").each(function () {
$(".update, .edit").each(function () {
//Left out the rest of the code so this answer isn't too
//long, none of it changed if that matters.
});
//});
}
For some reason the result runs very slowly (but it runs!) and I'm not sure why so if anyone has any better suggestion/optimizations please feel free to leave those here.
Edit: I realized I didn't to go through .each twice, that's what was slowing to down so I removed that first each that went over auditPoints and just did the ones with gears instead.
I am using PaperJS to make a canvas app that generates balloons with text inside each balloon. However I would like to allow the user to edit the text inside each balloon to whatever they want it to say.
Is it possible to allow a user to edit a PaperJS TextItem just like a HTML text input field?
The short answer is no, unless you implement parallel functionality from scratch. The solution I have used is to let the user draw a rectangle then overlay the rectangle on the canvas with a textbox or textarea at the same location using absolute positioning. It requires an additional level of abstraction but can work quite well.
It's non-trivial, but here's a basic framework that shows a bit about how it works. I may get around to making it available online at some point but it will take a bit so I'm not sure when. I'm also extracting this on-the-fly from a larger system so if you spot any errors let me know.
var rect;
var tool = new paper.Tool();
// create a paper rectangle. it's just a visual indicator of where the
// text will go.
tool.onMouseDown = function(e) {
rect = new paper.Path.Rectangle(
from: e.downPoint,
to: e.downPoint,
strokeColor: 'red',
);
}
tool.onMouseDrag = function(3) {
if (rect) {
rect.remove();
}
rect = new paper.path.Rectangle({
from: e.downPoint,
to: e.point,
strokeColor: 'red'
});
}
tool.onMouseUp = function(e) {
var bounds = rect.bounds;
var textarea = $("<textarea class='dynamic-textarea' " +
"style='position:absolute; left:" + bounds.x +
"px; top:" + bounds.y + "px; width: " + bounds.width +
"px; height: " + bounds.height +
"px; resize;' placeholder='Enter text'></textarea>");
// make the paper rectangle invisible for now. may want to show on
// mouseover or when selected.
rect.visible = false;
// add the text area to the DOM then remember it in the path
$("#parent-div").append(textarea);
rect.data.textarea = textarea;
// you may want to give the textarea focus, assign tab indexes, etc.
};
So Im trying to make something where the user is able to drag planets along their orbits and it will continuously update the other planets. Ideally I would like this to work with ellipses too.
So far I can drag an image node with jquery and check/change the coordinates, but i cannot update the position reliably while the user is dragging the object. I know there is an axis and a rectangle containment for draggable but this doesn't really help me.
I have a site for calculating planetary orbits http://www.stjarnhimlen.se/comp/ppcomp.html and a formula i think should help me if i can figure out how to constrain the draggable object with coordinate checks Calculating point on a circle's circumference from angle in C#?
But it seems like there should be an easier way to have a user drag a sphere along a circular track while it updates coords for other spheres
here's what i have so far. It's not much
http://jsfiddle.net/b3247uc2/2/
Html
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
Js
var $newPosX = 100,
$newPosY = 100;
//create image node
var x = document.createElement("IMG");
x.src = "http://upload.wikimedia.org/wikipedia/commons/a/a4/Sol_de_Mayo_Bandera_Argentina.png";
x.width = 100;
x.height = 100;
x.id = "sun";
x.hspace = 100;
x.vspace = 100;
document.body.appendChild(x);
//coords
var text = document.createTextNode($newPosX + " " + $newPosY);
document.body.appendChild(text);
//make sun draggable and update coords
$("#sun").draggable({
drag: function (event, ui) {
$newPosX = $(this).offset().left;
$newPosY = $(this).offset().top;
}
});
//0 millisecond update for displayed coords
setInterval(check, 0);
function check() {
//tries to constrain movement, doesn't work well
/*
if ($newPosX > 300) {
$("#sun").offset({
left: 200
});
}
*/
text.nodeValue = ($newPosX + " " + $newPosY);
}
Edit:
I found this and am trying to modify it to suit my purposes but have so far not had luck.
http://jsfiddle.net/7Asn6/
Ok so i got it to drag
http://jsfiddle.net/7Asn6/103/
This is pretty close to what I want but can be moved without being clicked on directly
http://jsfiddle.net/7Asn6/104/
Ok final edit on this question. This one seems to work well and have fixed my problems. I would still very much like to hear peoples implementation ideas or ideas to make it work smoother.
http://jsfiddle.net/7Asn6/106/
My javascript code loops through some user data and adds each one as a marker to a container. It then adds that container to a nokia map and uses the Display zoomTo to zoom to the bounding box of the container holding all the markers.
However, right after that happens, the map just zooms itself all the way back out. The zoomTo call is the very last of my code that executes so it seems like something weird is going on.
this.finishMapping = function () {
map.objects.add(multiMapContainer);
var markerHopefully = multiMapContainer.objects.get(0);
$.ajax({
dataType: "jsonp",
url: "https://route.api.here.com/routing/7.2/calculateroute.json?app_id=WgevZ2m4AF8WHx1TY6GS&app_code=G11AO2dbvCRTdCjfTf-mUw&waypoint0=geo!" + markerHopefully.coordinate.latitude + "," + markerHopefully.coordinate.longitude + "&waypoint1=geo!" + markerHopefully.coordinate.latitude + "," + markerHopefully.coordinate.longitude + "&mode=fastest;car;",
success: function (data) {
onRouteCalculated(data)
},
jsonp: "jsoncallback"
});
function onRouteCalculated(data) {
if (data.response) {
var position = data.response.route[0].waypoint[0].mappedPosition;
var coordinate = new nokia.maps.map.StandardMarker([position.latitude, position.longitude]);
var tempContainer = new nokia.maps.map.Container();
tempContainer.objects.add(coordinate);
map.zoomTo(multiMapContainer.getBoundingBox().merge(tempContainer.getBoundingBox()), false);
}
}
}
I debugged through it in Chrome and I can see that zoomTo does actually zoom to the proper bounding box, but then right after I hit the 'continue' button it jumps back to the highest zoom level.
I recently came across a similar issue. The basic issue was that the containing <DIV> for the map was itself being initialized during the map initialization. My problem was compounded because map.zoomTo() doesn't work during map initialization anyway (since 2.5.3 map loading is always asynchronous)
The crux of the issue was that I was trying to use zoomTo() on a 0x0 pixel map since the <DIV> wasn't displayed yet - hence I ended up with a zoomLevel zero map.
The solution is to add listeners to the map as shown:
map.addListener("displayready", function () {
if(bbox){map.zoomTo(bbox, false);}
});
map.addListener("resize", function () {
if(bbox){map.zoomTo(bbox, false);}
});
And set up the bbox parameter as each coordinate is received as shown:
function onCoordinateReceived(coordinate){
if(bbox){
bbox = nokia.maps.geo.BoundingBox.coverAll([
bbox.topLeft, bbox.bottomRight, coordinate]);
} else {
bbox = nokia.maps.geo.BoundingBox.coverAll([coordinate]);
}
map.zoomTo(bbox, false);
}
So that:
If the map is already intialized and displayed the zoomTo() in the onCoordinateReceived() will fire
If the map completes intialization after onCoordinateReceived(), the zoomTo() in the displayready listener will fire.
If the <DIV> update occurs last, the zoomTo() in the resize listener will fire, which will alter from a zoomed Out map to the "right" zoom level.
I was having a hard time trying to figure out how to center labels on a datetime x-axis in Highcharts without using categories and tickPlacement (since tickPlacement only works on categories).
My axis was dynamically created so I could not simply set an x-offset or padding, as this would cause axes of different intervals to look strange.
After messing around with the config options I think I may have found a solution using the x-axis formatter and some css / jquery noodling in the Highcharts callback. See my answer below.
The trick is to use the x-axis labels object like this:
xAxis: {
type: 'datetime',
labels: {
useHTML: true,
align: 'center',
formatter: function () {
//using a specific class for the labels helps to ensure no other labels are moved
return '<span class="timeline_label">' + Highcharts.dateFormat(this.dateTimeLabelFormat, this.value) + '</span>';
}
}
You can see that the formatter will keep whatever dateTimeLabelFormat has been set by the user or default.
Then have a callback that does something like this:
function (chart) {
var $container = $(chart.container);
var $labels = $container.find('.highcharts-axis-labels .timeline_label');
var $thisLabel, $nextLabel, thisXPos, nextXPos, delta, newXPos;
$labels.each(function () {
$thisLabel = $(this).parent('span');
thisXPos = parseInt($thisLabel.css('left'));
$nextLabel = $thisLabel.next();
nextXPos = $nextLabel.length ? parseInt($nextLabel.css('left')) : chart.axes[0].left + chart.axes[0].width;
delta = (nextXPos - thisXPos) / 2.0;
newXPos = thisXPos + delta;
if ($nextLabel.length || $(this).width() + newXPos < nextXPos) {
$thisLabel.css('left', newXPos + 'px');
} else {
$thisLabel.remove();
}
});
});
In short, this will go through each label and determine how much it should be moved over (using css) by calculating the distance between itself and the next label. When it reaches the the last label, it either moves it over using the end of the axis for the calculation or removes it if it won't fit. This last part is just the decision I decided to make, you can probably choose to do something else like word wrap, etc.
You can see the jsfiddle here
Hope this helps some people. Also, if there are any improvements it would be great to see them here.
Based on the existing answer, there is a much simpler solution that also works when resizing the browser window (or otherwise forcing the chart to redraw), even when the tick count changes: http://jsfiddle.net/McNetic/eyyom2qg/3/
It works by attaching the same event handler to both the load and the redraw events:
$('#container').highcharts({
chart: {
events: {
load: fixLabels,
redraw: fixLabels
}
},
[...]
The handler itself looks like this:
var fixLabels = function() {
var labels = $('div.highcharts-xaxis-labels span', this.container).sort(function(a, b) {
return +parseInt($(a).css('left')) - +parseInt($(b).css('left'));
});
labels.css('margin-left',
(parseInt($(labels.get(1)).css('left')) - parseInt($(labels.get(0)).css('left'))) / 2
);
$(labels.get(this.xAxis[0].tickPositions.length - 1)).remove();
};
As you see, the extra wrapping of labels is unnecessary (at least if you do not have more than one xAxis). Basically, it works like this:
Get all existing labels (when redrawn, this includes newly added ones). 2. Sort by css property 'left' (they are not sorted this way after some redrawing)
Calculate offset between the first two labels (the offset is the same for all labels)
Set half of the offset as margin-left of all labels, effectively shifting them half the offset to the right.
Remove the rightmost label (moved outside of chart, by sometimes partly visible).