I'm testing Gwt Highcharts but I have a big problem: I need to draw a scatter chart with symbol and rotate the symbol.
For example:
Point p1 = new Point(5, 5);
Marker m = new Marker();
m.setEnabled(true);
m.setRadius(4);
String myUrl = "url(" + GWT.getModuleBaseURL()+"images/snow.png" + ")";
m.setOption("symbol", myUrl);
p1.setMarker(m);
This all works fine
The problem is that I need to rotate the symbol by a degree value. I've tried the following code but it doesn't work:
String myRotate = "rotate(45)";
m.setOption("transform", myRotate);
What's wrong?
Thanks a Lot.
Maurizio
This is what we've came up with in our case:
private static native void rotateMarkers(double angle)/*-{
//Accessing the series we'll rotate
var points = $wnd.Highcharts.charts[0].series[3].points;
//rotating
var str = parseFloat(points[i].graphic.attr('x')) +
parseFloat(points[i].graphic.attr('width'))/2 +
","+ (parseFloat(points[i].graphic.attr("y")))+
")";
points[i].graphic.attr("transform","rotate("+angle+","+str);
}-*/;
It didn't work for us in non-jsni way, same way it didn't for you.
Related
I am using Adobe Captivate to produce an online learning activity, We are using the drag and drop which works well. Only issue is that it is not dynamic, therefore once a student has got it correct they can just follow position to get correct again.
Is it possible to shuffle the position of drag or drop objects so as to show that the sudent has understanding of the question and not just following a remembered pattern.
Not out of the box. There's no like "Shuffle Drag Sources" checkbox like there is for say multiple choice answers. It would be possible to achieve something like you are asking by putting this script into your OnEnter action and selecting "Execute Javascript":
$(function () {
var dss = cp.DD.CurrInteractionManager.m_ActiveInteraction.m_dsList;
var ypos = dss.map((i) => {
return $("div[id='" + i.n + "']").css("top");
});
ypos = shuffle(ypos);
dss.forEach((o, i) => {
$("div[id='re-" + o.n + "c']").css("top", ypos[i]);
$("div[id='" + o.n + "']").css("top", ypos[i]);
});
function shuffle(arr) {
for (var i = 0; i < arr.length; i++) {
var randId = Math.floor(Math.random() * arr.length);
var tmp = arr[i];
arr[i] = arr[randId];
arr[randId] = tmp;
}
return arr;
}
});
I didn't put comments in here for copy/paste purposes because that awful Captivate JavaScript window is very flaky with whitespace, so a statement by statement walkthrough is here:
var dss = cp.DD.CurrInteractionManager.m_ActiveInteraction.m_dsList;
Collects all of the drag sources into an array.
var ypos = dss.map((i) => {return $("div[id='" + i.n + "']").css("top")});
Extracts the Y position of each object.
ypos = shuffle(ypos);
Calls the function (defined below) to shuffle the order of the array of Y positions randomly.
dss.forEach((o, i) => {$("div[id='re-" + o.n + "c']").css("top", ypos[i]);
$("div[id='" + o.n + "']").css("top", ypos[i]);});
Cycles through the drag sources and places each into its new position, bringing the canvas along with it.
Couple of caveats here.
If more than one attempt is allowed, the "Reset button will place the
drag sources back to their original locations.
This assumes the drag sources are all lined up with the same
horizontal position. If they are scattered about, the X position
would also need to be accounted for.
I didn't test this on a responsive or flex project, I'm not sure how Adobe does the positioning for object in those cases, this will work on fixed-sized projects.
Arrow functions might not be supported in IE11, if you need to support that, you might need to re-write the callback functions using traditional syntax.
I know how to move the zoomable map to a specific lat/long, and that point will be centered in the screen. If the user moves the map (drags it sideways), how do I get the coordinates at the point of the map that is now centered?
Thanks!
I would recommend to use the Camera.ScreenToWorldPoint method from Unity:
https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html?_ga=2.95757022.39200391.1587116665-1246420375.1587116665
Please also have a look at this similar thread:
https://forum.unity.com/threads/how-to-get-a-world-position-from-the-center-of-the-screen.524573/
Thanks!
Based on the similar thread you pointed me to, I added a function to my QuadTreeCameraMovement...
public Vector2d GeoCoordsAtCenter() {
var centerScreen = _referenceCamera.ViewportToScreenPoint(new Vector3(.5f, .5f, _referenceCamera.transform.localPosition.y));
var pos = _referenceCamera.ScreenToWorldPoint(centerScreen);
var latlongDelta = _mapManager.WorldToGeoPosition(pos);
Debug.Log("CENTER: Latitude: " + latlongDelta.x + " Longitude: " + latlongDelta.y);
return latlongDelta;
}
I have a level in which I have placed many instances of a prefab Gameobject (targets). I need to use the coordinates of those targets in a script. Is there a way to obtain the xyz vector coordinates of all those objects and export them to a text file? Right now I need to manually copy-past each individual target from the Unity inspector to MonoDevelop, which is a PITA...
To get the coordinates of an object use item.transform.Position where item is a reference to the object you want to get coordinates for. The result is a Vector3 from which you can do .x, .y or .z to get individual coordinates/
Writing to a text file is well-documented.
Alternatively, you may want to look into Serialization
EDIT: To do this for all objects in the scene:
string filePath = "D:/mycoords.txt";
string coordinates = "";
var objects = GameObject.FindObjectsOfType(Transform) as Transform[];
foreach(Transform trans in objects)
{
coordinates+= "x: " + trans.position.x.ToString() + ", y: " + trans.position.y.ToString() + ", z: " + trans.position.z.ToString() + System.Environment.NewLine;
}
//Write the coords to a file
System.IO.File.WriteAllText(filePath,coordinates);
NOTE: FindObjectsOfType will not return any assets (meshes, textures, prefabs, ...) or inactive objects.
EDIT3: If you want to only get your Targets, add a script to you Target prefab called "SaveMeToFile" and use this code:
string filePath = "D:/mycoords.txt";
string coordinates = "";
var objects = GameObject.FindObjectsOfType(SaveMeToFile) as SaveMeToFile[];
foreach(SaveMeToFile smtf in objects)
{
Transform trans = smtf.transform;
coordinates+= "x: " + trans.position.x.ToString() + ", y: " + trans.position.y.ToString() + ", z: " + trans.position.z.ToString() + System.Environment.NewLine;
}
//Write the coords to a file
System.IO.File.WriteAllText(filePath,coordinates);
EDIT 4: Or if you have any component specific to your target you can use that instead of SaveMeToFile in the code above, saving you from having to create a new, worthless Monobehaviour
I have a flex plotchart and I need an animation that would enable me to move datapoints from 1 location to another. The actual movement must also be shown.
I have tried move control but the call to play() does not work.
Any hints would also help greatly..
Thanks in advance
After much effort, I found that one way to move the point from 1 point to another is by making it move along the equation of the line and rendering the intermediate points on the graph after some delay...
I'll share the code...
Place the following line where you want to start the movement:
setTimeout(showLabel,singleDuration,oldLocation,newLocation,
Constants.TOTAL_STEPS,1,oldLocation.x, oldLocation.y, singleDuration);
And this is the function definition:
private function showLabel(oldLoc:Object newLoc: Object, totalSteps: Number,
count:Number, currentX: Number, currentY: Number, singleDuration: Number): void{
tempArrColl = new ArrayCollection();
var tempObj: Object= new Object();
xDelta = 0.25;
yDelta = 0.25;
tempObj.x = currentX + (xDelta * count);
tempObj.y = currentY + (yDelta * count);
if ((tempObj.x >= newLoc.x) || (tempObj.y >= newLoc.y)){
tempObj.x = newLoc.x;
tempObj.y = newLoc.y;
callLater(showPoint,[tempObj]);
tempArrColl = new ArrayCollection();
plotGraphArrayColl.addItem(newLoc);
return;
}
callLater(showPoint,[tempObj]);
count++;
setTimeout(showLabel, singleDuration, oldLoc, newLoc,
totalSteps, count, tempObj.x, tempObj.y, singleDuration);
}
private function showPoint(loc: Object): void {
tempArrColl.addItem(loc);
plotChart.validateNow();
}
Here, tempArrColl will hold the intermediate point along the line equation. Put it as a dataProvider in a series on the graph and then once all the points are moved, remove it. plotGraphArrayColl is the dataProvider that would hold the newly moved points..
There may be better ways possible but it worked for me... Do tell if anyone finds something easier.. Thanks
I'm using mapbox-gl-draw to add move-able features to my map. In addition to movability functionality, I am needing rotate/transform -ability functionality for the features akin to Leaflet.Path.Transform.
At current, would my only option to achieve be to create a custom mode?
e.g. something like:
map.on('load', function() {
Draw.changeMode('transform');
});
I am not able to convert my map and it's features to mapbox-gl-leaflet in order to implement Leaflet.Path.Transform as losing rotation / bearing / pitch support is not an option.
Long answer incoming. (see http://mapster.me/mapbox-gl-draw-rotate-mode and http://npmjs.com/package/mapbox-gl-draw-rotate-mode for some final products, https://github.com/mapstertech/mapbox-gl-draw-rotate-mode)
I've been working on something similar for a custom project, and not using a draw library. My project involves some pretty regularly sized objects, not very complex polygons, so the solution might be too simple for you but it may be the right path. I just have rotate and move.
Doing movement isn't too hard geographically. Here's some help to get you started. A basic JSBin is up at https://jsbin.com/yoropolewo/edit?html,output with some drag functionality (too tired to do rotate too).
First, register the necessary click events to have a dragging event. You can listen on the specific Mapbox layers for a mousedown, then on the whole document for a mousemove and mouseup.
To do individual shape rotation, you need to ensure that you are referring to the right feature. In this example I assume there's just one feature in the source data, but that's probably too simple for most uses, so you have to extrapolate. The source data is what we affect when we setData() later on. There are obviously numerous ways to do what I'm doing here, but I'm trying to be clear.
var currentDragging = false;
var currentDraggingFeature = false;
var currentDraggingType = false;
var firstDragEvent = false;
map.on('mousedown','my-layer-id',function(e) {
currentDragging = 'my-source-id'; // this must correspond to the source-id of the layer
currentDraggingFeature = e.features[0]; // you may have to filter this to make sure it's the right feature
currentDraggingType = 'move'; // rotation or move
firstDragEvent = map.unproject([e.originalEvent.layerX,e.originalEvent.layerY]);
});
window.addEventListener('mousemove',dragEvent);
window.addEventListener('mouseup',mouseUpEvent);
You will need a function, then, that takes an initial point, a distance, and a rotation, and returns a point back to you. Like this:
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
function getPoint(point, brng, dist) {
dist = dist / 63.78137; // this number depends on how you calculate the distance
brng = brng.toRad();
var lat1 = point.lat.toRad(), lon1 = point.lng.toRad();
var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) *
Math.sin(lat2));
if (isNaN(lat2) || isNaN(lon2)) return null;
return [lon2.toDeg(),lat2.toDeg()];
}
Now, the key is the unproject method in Mapbox GL JS, so you can move between x/y coordinates on the mouse and lng/lat on your map. Then, using the map.getSource().setData() function to set a new geoJSON.
I am turning the x/y into coordinates immediately here but you can do it at any point. Something like the following for moving:
function moveEvent(e) {
// In the case of move, you are just translating the points based on distance and angle of the drag
// Exactly how your translate your points here can depend on the shape
var geoPoint = map.unproject([e.layerX,e.layerY]);
var xDrag = firstDragEvent.lng - geoPoint.lng;
var yDrag = firstDragEvent.lat - geoPoint.lat;
var distanceDrag = Math.sqrt( xDrag*xDrag + yDrag*yDrag );
var angle = Math.atan2(xDrag, yDrag) * 180 / Math.PI;
// Once you have this information, you loop over the coordinate points you have and use a function to find a new point for each
var newFeature = JSON.parse(JSON.stringify(currentDraggingFeature));
if(newFeature.geometry.type==='Polygon') {
var newCoordinates = [];
newFeature.geometry.coordinates.forEach(function(coords) {
newCoordinates.push(getPoint(coords,distanceDrag,angle));
});
newFeature.geometry.coordinates = newCoordinates;
}
map.getSource(currentDragging).setData(newFeature);
}
Rotating is a little harder because you want the shape to rotate around a central point, and you need to know the distance of each point to that central point in order to do that. If you have a simple square polygon this calculation would be easy. If not, then using something like this would be helpful (Finding the center of Leaflet polygon?):
var getCentroid2 = function (arr) {
var twoTimesSignedArea = 0;
var cxTimes6SignedArea = 0;
var cyTimes6SignedArea = 0;
var length = arr.length
var x = function (i) { return arr[i % length][0] };
var y = function (i) { return arr[i % length][1] };
for ( var i = 0; i < arr.length; i++) {
var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
twoTimesSignedArea += twoSA;
cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
}
var sixSignedArea = 3 * twoTimesSignedArea;
return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];
}
Once you have the ability to know the polygon's center, you're golden:
function rotateEvent(e) {
// In the case of rotate, we are keeping the same distance from the center but changing the angle
var findPolygonCenter = findCenter(currentDraggingFeature);
var geoPoint = map.unproject([e.layerX,e.layerY]);
var xDistanceFromCenter = findPolygonCenter.lng - geoPoint.lng;
var yDistanceFromCenter = findPolygonCenter.lat - geoPoint.lat;
var angle = Math.atan2(xDistanceFromCenter, yDistanceFromCenter) * 180 / Math.PI;
var newFeature = JSON.parse(JSON.stringify(currentDraggingFeature));
if(newFeature.geometry.type==='Polygon') {
var newCoordinates = [];
newFeature.geometry.coordinates.forEach(function(coords) {
var xDist = findPolygonCenter.lng - coords[0];
var yDist = findPolygonCenter.lat - coords[1];
var distanceFromCenter = Math.sqrt( xDist*xDist + yDist*yDist );
var rotationFromCenter = Math.atan2(xDist, yDist) * 180 / Math.PI;
newCoordinates.push(
getPoint(coords,distanceFromCenter,rotationFromCenter+angle)
);
});
newFeature.geometry.coordinates = newCoordinates;
}
}
Of course, throughout, ensure that your coordinates are being passed and returned correctly from functions. Some of this code may have incorrect levels of arrays in it. It's very easy to run into bugs with the lat/lng object versus the geoJSON arrays.
I hope the explanation is brief but clear enough, and that you understand logically what we are doing to reorient these points. That's the main point, the exact code is details.
Maybe I should just make a module or fork GL Draw...