Pie charts clustering on Google Maps [batchgeo-like] - charts

Anybody knows how to remake something similar to what Batchgeo does when clusters/groups markers with dynamic pie charts?
Example: batchgeo map with pie clustering
Thanks,
Regards

I don't have a full how to for you, but do have some pointers which might help you and appear to be used by BatchGeo.
I would study the cluster example on Google maps:
https://developers.google.com/maps/articles/toomanymarkers
Which covers clustering pretty well... then you would need to look at changing the marker image to a call to Google Charts:
https://developers.google.com/chart/image/docs/gallery/pie_charts
Note: this is deprecated and will drop support 2015... but is used by BatchGeo I believe.
There is also an example here that might help get you on your way with the custom cluster marker images, which I can't post (as limited to 2 links) (such as the Hearts, People etc... set in CLUSTER STYLE). If you Google 'google map v3 cluster example' you should find it in the top results.
If you put all that together then I think you should get there.
Regards,
James

I needed a solution to the same problem so I solved it by extending the Google Maps Marker Cluster Library to use Pie charts instead of cluster markers. You can download the solution from my GitHub repository: https://github.com/hassanlatif/chart-marker-clusterer

Quite late, but I needed to replicate BatchGeo map using Google map. So here I present my CustomRendererClass which I used to draw PieChart as Cluster Icon with Size of Cluster as well. Pass dataset as per your custom requirements.
public class TbmClusterRenderer extends DefaultClusterRenderer<VenueItemData> {
private IconGenerator mClusterIconGenerator;
private Context context;
public TbmClusterRenderer(Context context, GoogleMap map,
ClusterManager<VenueItemData> clusterManager) {
super(context, map, clusterManager);
this.context = context;
mClusterIconGenerator = new IconGenerator(context);
}
#Override
protected void onBeforeClusterItemRendered(VenueItemData item,
MarkerOptions markerOptions) {
try {
int markerColor = item.getMarkerColor();
Bitmap icon;
icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.map_marker).copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(markerColor,
PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
Canvas canvas = new Canvas(icon);
canvas.drawBitmap(icon, 0, 0, paint);
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
} catch (Exception ex) {
ex.printStackTrace();
Crashlytics.logException(ex);
}
}
#Override
protected void onClusterItemRendered(VenueItemData clusterItem, Marker marker) {
super.onClusterItemRendered(clusterItem, marker);
}
#Override
protected void onBeforeClusterRendered(Cluster<VenueItemData> cluster, MarkerOptions markerOptions) {
ArrayList<VenueItemData> a = (ArrayList<VenueItemData>) cluster.getItems();
Canvas canvas;
#SuppressLint("UseSparseArrays")
HashMap<Integer, Integer> markerColors = new HashMap<>();
// ConcurrentHashMap<Integer, Integer> markerColors = new ConcurrentHashMap<>();
for (VenueItemData data : a) {
if (data.getMarkerColor() != 0) {
if (!markerColors.containsValue(data.getMarkerColor())) {
markerColors.put(data.getMarkerColor(), 0);
}
}
}
Set set = markerColors.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object aSet = iterator.next();
Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) aSet;
for (VenueItemData data : a) {
if (data.getMarkerColor() == entry.getKey()) {
entry.setValue(entry.getValue() + 1);
}
}
}
Log.e("graph values", new Gson().toJson(markerColors));
Bitmap myBitmap = Bitmap.createBitmap(70, 70, Bitmap.Config.ARGB_8888);
canvas = new Canvas(myBitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1f);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
RectF rectf = new RectF(2, 2, myBitmap.getWidth() - 2, myBitmap.getHeight() - 2);
set = markerColors.entrySet();
float startAngle = 0.0f;
for (Object aSet : set) {
Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) aSet;
float angle = (360.0f / (float) cluster.getSize()) * (float) entry.getValue();
paint.setColor(entry.getKey());
canvas.drawArc(rectf, startAngle, angle, true, paint);
startAngle += angle;
}
BitmapDrawable clusterIcon = new BitmapDrawable(context.getResources(), myBitmap);
if (set.isEmpty()) {
mClusterIconGenerator.setBackground(context.getResources().getDrawable(R.drawable.circle1));
} else {
mClusterIconGenerator.setBackground(clusterIcon);
}
mClusterIconGenerator.setTextAppearance(R.style.ClusterTextAppearance);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
mClusterIconGenerator.setContentPadding(20, 20, 20, 20);
}
}
Here I attach Screenshot for reference:

Related

How do I get the clicked Box in JavaFX 3d

I've got a problem with my JavaFX 3D application. My application creates a grid consisting of different boxes. The data used for the boxes are from the harry potter books, which are transferred to nodes and then to boxes. Every box symbolizes one character. Now I want to add an event, that when a box is clicked application a window should open to show, which character it is and some other data.
"for (Book book : books) {
Node bookNode = new Node();
bookNode.setType(NodeType.BOOK);
bookNode.setName(book.getName());
bookNode.setMetric(getMetricFromPrimaryInt(book.getPages(),overallPages));
for (Chapter chapter : book.chapters) {
Node chapterNode = new Node();
chapterNode.setType(NodeType.CHAPTER);
chapterNode.setName(chapter.getName());
chapterNode.setMetric(getMetricFromPrimaryInt(chapter.getPages(), book.getPages()));
for (String character : chapter.characters) {
Node characterNode = new Node();
characterNode.setType(NodeType.CHARACTER);
characterNode.setName(character);
characterNode.setMetric(getMetricFromPrimaryInt(1, chapter.characters.length));
//Das neue child node dem parent hinzufügen
chapterNode.extendChildren(characterNode);
}
//Das neue child node dem parent hinzufügen
bookNode.extendChildren(chapterNode);
}"
.
.
.
"for (Node chars: chapt.getChildren()) {
double height = rnd.nextDouble() * 500;
Box box = new Box(chars.getHeight(), height, chars.getWidth());
// color
PhongMaterial mat = new PhongMaterial();
mat.setDiffuseColor(randomColor());
box.setMaterial(mat);
// location
box.setLayoutY(-height * 0.5);
box.setTranslateX(xStart-(chars.getHeight()/2));
box.setTranslateZ(yStart-(chars.getWidth()/2));
grid.getChildren().addAll(box);
Boxliste.add(box);
}"
My problem now is:
How do I differentiate which box got clicked, because I need the box to get the characterdata and then display it. Hope it's clear what I mean.
Casting Intersected Node with mouse event
In this approach getIntersectedNode() method from PickResult class will return a Node object . That object is casted to CustomSphere which extends Sphere and , like any other node in javafx , extends Node class .
This is a single javafx app you can try .
App.java
public class App extends Application {
#Override
public void start(Stage stage) {
Label label = new Label("name");
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setTranslateZ(-10);
Group group3d = new Group(camera, new CustomSphere("violet sphere ", Color.BLUEVIOLET, 0.8, 0),
new CustomSphere("coral sphere ", Color.CORAL, 0.7, 2),
new CustomSphere("yellow-green sphere ", Color.YELLOWGREEN, 0.9, -2));
SubScene subScene = new SubScene(group3d, 480, 320, true, SceneAntialiasing.DISABLED);
subScene.setOnMouseClicked(t -> {
PickResult result = t.getPickResult();
Node intersectedNode = result.getIntersectedNode();
if (intersectedNode instanceof CustomSphere) {
CustomSphere clickedSphere = (CustomSphere) intersectedNode;
label.setText(clickedSphere.getName());
}
});
subScene.setCamera(camera);
StackPane stackPane = new StackPane(subScene, label);
StackPane.setAlignment(label, Pos.TOP_CENTER);
Scene scene = new Scene(stackPane, 480, 320, true, SceneAntialiasing.BALANCED);
stage.setTitle("pickresult");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
class CustomSphere extends Sphere {
private String name;
PhongMaterial material = new PhongMaterial();
public CustomSphere(String name, Color color, double d, double x) {
super(d);
this.name = name;
material.setDiffuseColor(color);
this.setMaterial(material);
this.setTranslateX(x);
}
public String getName() {
return name;
}
}
}

add Marker not working

This is crazy, add marker doesn't seem to do what it suppose to do. Adding marker does nothing:
{
if(!isVisible())
return;
mPinBitmapUtils.retrievePinBitmapAsync(getContext(), recommendation, new OnPinBitmapProcessed()
{
#Override
public void onBitmapProcess(final Pin reco, PinType pinType, Map<String, String> directories)
{
if(!isVisible())
return;
recommendation.setName(pinType.getName());
new AsyncTask<String, Void, PinMarkerOptions>()
{
#Override
protected PinMarkerOptions doInBackground(String... strings)
{
IconFactory iconFactory = IconFactory.getInstance(getContext());
Bitmap bitmap = Utils.getBitmapFromFile(getContext()
, new File(strings[0])
, (int) Utils.convertDpToPixel(48, getContext())
, (int) Utils.convertDpToPixel(48, getContext()));
Icon icon = iconFactory.fromBitmap(bitmap);
LatLng position = new LatLng();
position.setLatitude(recommendation.getLatitude());
position.setLongitude(recommendation.getLongitude());
PinMarkerOptions markerOption = new PinMarkerOptions();
markerOption.setPosition(position);
markerOption.setMetaData(recommendation.getJSON().toString());
if(icon != null)
markerOption.setIcon(icon);
return markerOption;
}
#Override
public void onPostExecute(PinMarkerOptions marker)
{
mMapboxMap.addMarker(marker);
}
}.execute(directories.get(Constants.BLUE_PIN));
}
});
}
Every time I called addMarkers or addMarker its not being shown. I checked the size of the MapBox map instance and it indeed show it increased in size. This happens especially when I remove a marker, or called MapBoxMap#clear(). Nothing happens afterwards.
I am using MapBox API v4.2.2.
There is one problem with markers - you can't add them on top of your layers.
If that is a case, then you should use SymbolLayer for that purpose.
Info about markers from documentation.
Example of how use SympolLayer with BubbleLayout to create a marker with text inside.

Marker and Overlay not displayed at the same place

I use the branflake2267 google maps API for GWT (https://github.com/branflake2267/GWT-Maps-V3-Api).
I would like to display a title below a marker.
My location:
final LatLng latlng = LatLng.newInstance(47.4125, -0.861944);
The icon marker (it is the correct location on the map)
MarkerImage icon = MarkerImage.newInstance("/images/maps/pin_workshop.png", Size.newInstance(21, 34), Point.newInstance(0, 0), Point.newInstance(10, 34));
MarkerImage shadow = MarkerImage.newInstance("/images/maps/shadow.png", Size.newInstance(40, 37), Point.newInstance(0, 0), Point.newInstance(12, 35));
MarkerOptions options = MarkerOptions.newInstance();
options.setPosition(latlng);
options.setMap(map);
options.setTitle("Factory");
options.setIcon(icon);
options.setShadow(shadow);
Marker marker = Marker.newInstance(options);
The overlay with the title (Incorrect position in the map...):
final DivElement div = Document.get().createDivElement();
OverlayView.newInstance(map, new OverlayViewOnDrawHandler() {
#Override
public void onDraw(OverlayViewMethods methods) {
Point position = methods.getProjection().fromLatLngToDivPixel(latlng);
div.getStyle().setPosition(Position.ABSOLUTE);
div.getStyle().setLeft(position.getX(), Unit.PX);
div.getStyle().setRight(position.getY(), Unit.PX);
div.setInnerText("Factory");
}
},
new OverlayViewOnAddHandler() {
#Override
public void onAdd(OverlayViewMethods methods) {
methods.getPanes().getOverlayLayer().appendChild(div);
}
},
new OverlayViewOnRemoveHandler() {
#Override
public void onRemove(OverlayViewMethods methods) {
div.removeFromParent();
}
});
I try different version of the library (3.09 build 17, 3.10.0-alpha-6), and also different panes (getMapPane(), getFloatPane()) without success...
Ok, just using setLeft and setRight instead of setLeft and setTop...

SWT: remove the invisible component space in composite

I put three composite(1,2,3) inside one composite0, so they all set their layout based on the composite0.setLayout(new FormLayout()). The problem I have now is, I make the composite3 invisible: composite3.setVisible(false); (I dont want to delete the data, still need that component, but just doesn't want it shows on the UI), and there's a big gap after componite2 now. How to remove the big gap(which use to put the composite2)? thank you in advanced!
Snippet 313 of the official SWT examples should help you with that. You basically set a different FormData on composite3 depending on whether you want to show or hide it.
I have a databinding observable for that, but it assumes the controls to be within a GridLayout. I use it to show and hide composites and widgets within a wizard page, depending on the selection state of a checkbox.
To use it, set it up with something like this:
DataBindingContext dbc = new DataBindingContext();
Button button = new Button(composite, SWT.CHECK);
IObservableValue target = SWTObservables.observeSelection(button);
dbc.bindValue(target, new HideControlObservable(someControl));
Here is the observable:
/**
* Observable to control the presence (visibility and size) of any control
* within a grid layout.
* <p>
* Changing the value of this observable will do two things:
* <ol>
* <li>Set the visibility of the control</li>
* <li>Set the size of the control to zero when the control is invisible.</li>
* </ol>
* So, when using this observable, the control will not only be invisible,
* but it will be gone, completely. Normally, when setting the visibility of
* a control to <code>false</code>, the control will not be displayed but
* will still take all the space on the screen.
* </p>
* <p>
* <strong>Note:</strong> this observable works for controls within a
* <strong>GridLayout only</strong>.
* </p>
*/
public class HideControlObservable extends WritableValue implements IValueChangeListener {
private final DataBindingContext dbc = new DataBindingContext();
private final ISWTObservableValue sizeObservable;
private final Point size = new Point(0, 0);
private final Control control;
public HideControlObservable(Control control) {
super(control.getVisible(), Boolean.class);
this.control = control;
UpdateValueStrategy never = new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER);
dbc.bindValue(SWTObservables.observeVisible(control), this, never, null);
sizeObservable = SWTObservables.observeSize(control);
sizeObservable.addValueChangeListener(this);
if (!control.isVisible()) {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = true;
control.setLayoutData(gd);
control.setSize(new Point(0, 0));
}
}
#Override
public void doSetValue(Object value) {
super.doSetValue(value);
Boolean bool = (Boolean) value;
if (bool) {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = false;
control.setLayoutData(gd);
control.setSize(size);
control.getParent().layout();
} else {
GridData gd = (GridData) control.getLayoutData();
if (gd == null) {
gd = new GridData();
}
gd.exclude = true;
control.setLayoutData(gd);
control.setSize(new Point(0, 0));
control.getParent().layout();
}
}
#Override
public synchronized void dispose() {
sizeObservable.dispose();
super.dispose();
}
#Override
public void handleValueChange(ValueChangeEvent event) {
Point newSize = (Point) event.getObservableValue().getValue();
if (newSize.x > size.x) {
size.x = newSize.x;
}
if (newSize.y > size.y) {
size.y = newSize.y;
}
}
}
FormData data = new FormData();
data.left = new FormAttachment(0, 100, EditorPanel.SPACING);
data.top = new FormAttachment(section1, EditorPanel.SPACING);
data.height = 0;
data.width = 0;
addSectionFormData(a, b, c);
a.setLayoutData(data);
b.setLayoutData(data);
this solve the problem! :)

Determing size of visible area of a ScrollingGraphicalViewer in Eclipse GEF

I am attempting to create a simple application using Eclipse GEF that displays a diagram inside a ScrollingGraphicalViewer. On start-up I want the diagram to be centered inside the viewer (imagine a star layout where the center of the star is in the center of the view).
Here are what I think are the relevant code sections:
My view:
public class View extends ViewPart {
public static final String ID = "GEFProofOfConcept.view";
...
public void createPartControl(Composite parent) {
viewer.createControl(parent);
viewer.setRootEditPart(rootEditPart);
viewer.setEditPartFactory(editPartFactory);
viewer.setContents(DummyModelCreator.generateModel());
}
The edit part code:
#Override
protected void refreshVisuals() {
Project project = (Project) getModel();
// This is where the actual drawing is done,
// Simply a rectangle with text
Rectangle bounds = new Rectangle(50, 50, 75, 50);
getFigure().setBounds(bounds);
Label label = new Label(project.getName());
projectFont = new Font(null, "Arial", 6, SWT.NORMAL);
label.setFont(projectFont);
label.setTextAlignment(PositionConstants.CENTER);
label.setBounds(bounds.crop(IFigure.NO_INSETS));
getFigure().add(label);
setLocation();
}
private void setLocation() {
Project project = (Project) getModel();
if (project.isRoot()) {
// Place in centre of the layout
Point centrePoint = new Point(0, 0); // This is where I need the center of the view
getFigure().setLocation(centrePoint);
} else {
...
}
}
And the parent of the above edit part:
public class ProjectDependencyModelEditPart extends AbstractGraphicalEditPart {
#Override
protected IFigure createFigure() {
Figure f = new FreeformLayer();
f.setLayoutManager(new XYLayout());
return f;
}
...
Alternative solutions to the problem also welcome, I am most certainly a GEF (and Eclipse in general) newbie.
Worked it out, for anyone who's interested:
Dimension viewSize = (((FigureCanvas) getViewer().getControl()).getViewport().getSize());