I have this code to perform zoom on a XYChart LineChart < Number, Number >
public class Zoom extends Application {
BorderPane pane;
Rectangle rect;
SimpleDoubleProperty rectinitX = new SimpleDoubleProperty();
SimpleDoubleProperty rectinitY = new SimpleDoubleProperty();
SimpleDoubleProperty rectX = new SimpleDoubleProperty();
SimpleDoubleProperty rectY = new SimpleDoubleProperty();
double initXLowerBound = 0, initXUpperBound = 0, initYLowerBound = 0, initYUpperBound = 0;
#Override
public void start(Stage stage) {
stage.setTitle("Lines plot");
final NumberAxis xAxis = new NumberAxis(1, 12, 1);
final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005);
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
#Override
public String toString(Number object) {
return String.format("%7.5f", object);
}
});
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(false);
lineChart.setAlternativeRowFillVisible(false);
lineChart.setAnimated(true);
XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data(1, 0.53185));
series1.getData().add(new XYChart.Data(2, 0.532235));
series1.getData().add(new XYChart.Data(3, 0.53234));
series1.getData().add(new XYChart.Data(4, 0.538765));
series1.getData().add(new XYChart.Data(5, 0.53442));
series1.getData().add(new XYChart.Data(6, 0.534658));
series1.getData().add(new XYChart.Data(7, 0.53023));
series1.getData().add(new XYChart.Data(8, 0.53001));
series1.getData().add(new XYChart.Data(9, 0.53589));
series1.getData().add(new XYChart.Data(10, 0.53476));
series1.getData().add(new XYChart.Data(11, 0.530123));
series1.getData().add(new XYChart.Data(12, 0.53035));
pane = new BorderPane();
pane.setCenter(lineChart);
Scene scene = new Scene(pane, 800, 600);
lineChart.getData().addAll(series1);
initXLowerBound = ((NumberAxis) lineChart.getXAxis()).getLowerBound();
initXUpperBound = ((NumberAxis) lineChart.getXAxis()).getUpperBound();
initYLowerBound = ((NumberAxis) lineChart.getYAxis()).getLowerBound();
initYUpperBound = ((NumberAxis) lineChart.getYAxis()).getUpperBound();
stage.setScene(scene);
scene.setOnMouseClicked(mouseHandler);
scene.setOnMouseDragged(mouseHandler);
scene.setOnMouseEntered(mouseHandler);
scene.setOnMouseExited(mouseHandler);
scene.setOnMouseMoved(mouseHandler);
scene.setOnMousePressed(mouseHandler);
scene.setOnMouseReleased(mouseHandler);
rect = new Rectangle();
rect.setFill(Color.web("blue", 0.1));
rect.setStroke(Color.BLUE);
rect.setStrokeDashOffset(50);
rect.widthProperty().bind(rectX.subtract(rectinitX));
rect.heightProperty().bind(rectY.subtract(rectinitY));
pane.getChildren().add(rect);
stage.show();
}
EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY)
{
if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
rect.setX(mouseEvent.getX());
rect.setY(mouseEvent.getY());
rectinitX.set(mouseEvent.getX());
rectinitY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
rectX.set(mouseEvent.getX());
rectY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) {
if ((rectinitX.get() >= rectX.get())&&(rectinitY.get() >= rectY.get()))
{
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
((NumberAxis) lineChart.getXAxis()).setLowerBound(initXLowerBound);
((NumberAxis) lineChart.getXAxis()).setUpperBound(initXUpperBound);
((NumberAxis) lineChart.getYAxis()).setLowerBound(initYLowerBound);
((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound);
}
else
{
double Tgap = 0;
double newLowerBound, newUpperBound, axisShift;
double xScaleFactor, yScaleFactor;
double xaxisShift, yaxisShift;
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
// Zoom in Y-axis by changing bound range.
NumberAxis yAxis = (NumberAxis) lineChart.getYAxis();
Tgap = yAxis.getHeight()/(yAxis.getUpperBound() - yAxis.getLowerBound());
axisShift = getSceneShiftY(yAxis);
yaxisShift = axisShift;
newUpperBound = yAxis.getUpperBound() - ((rectinitY.get() - axisShift) / Tgap);
newLowerBound = yAxis.getUpperBound() - (( rectY.get() - axisShift) / Tgap);
if (newUpperBound > yAxis.getUpperBound())
newUpperBound = yAxis.getUpperBound();
yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound())/(newUpperBound - newLowerBound);
yAxis.setLowerBound(newLowerBound);
yAxis.setUpperBound(newUpperBound);
NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();
Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound());
axisShift = getSceneShiftX(xAxis);
xaxisShift = axisShift;
newLowerBound = ((rectinitX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
newUpperBound = ((rectX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
if (newUpperBound > xAxis.getUpperBound())
newUpperBound = xAxis.getUpperBound();
xScaleFactor = (xAxis.getUpperBound() - xAxis.getLowerBound())/(newUpperBound - newLowerBound);
xAxis.setLowerBound( newLowerBound );
xAxis.setUpperBound( newUpperBound );
}
// Hide the rectangle
rectX.set(0);
rectY.set(0);
}
}
}
};
private static double getSceneShiftX(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
private static double getSceneShiftY(Node node) {
double shift = 0;
do {
shift += node.getLayoutY();
node = node.getParent();
} while (node != null);
return shift;
}
public static void main(String[] args) {
launch(args);
}
}
I would like to have the same zoom result by using < String, Number > since I would like to use date and time as String on x axys
OK, so this is the application i used, its not really neat, but it will do the job:
first i used the Date axis class for Javafx from :
https://github.com/dukke/FXCharts/blob/master/DateAxis.java
i then added another class, this one inst necessary, but it's easier for me to use it ,so:
package linechartwithdateaxis;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
/**
*
* #author yschellekens
*/
class HoveredThresholdNode extends StackPane {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
HoveredThresholdNode(Date date, double value) {
setPrefSize(5, 5);
final Label label = createDataThresholdLabel(date, value);
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront();
}
});
setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
}
});
setOnMouseDragEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
toBack();
}
});
}
private Label createDataThresholdLabel(Date date, double value) {
final Label label = new Label( java.lang.Math.round(value)+", On " +df.format(date));
label.setStyle("-fx-font-size: 20; -fx-font-weight: bold; -fx-background-color: transparent; -fx-color:transparent;");
label.setTextFill(Color.BLACK);
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
return label;
}
}
And there is the actual code, its ugly but it works:
package linechartwithdateaxis;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
*
* #author yschellekens
*/
public class LineChartWithDateAxis extends Application {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
final DateAxis dateAxis = new DateAxis(new Date(2014-1900,11,10),new Date(2014-1900,11,25));
final NumberAxis yAxis = new NumberAxis(0,20,1);
Date [] xData ;
ObservableList<XYChart.Data<Date, Number>> series1Data;
ObservableList<XYChart.Series<Date, Number>> series;
private double[] anArray;
final LineChart<Date, Number> lineChart = new LineChart<>(dateAxis, yAxis);
private int i;
#Override
public void start(Stage primaryStage) {
xData = new Date[9];
for (i = 0; i < xData.length ; i++) {xData[i]= new Date(2014-1900,11,i+15); }
dateAxis.setLowerBound(xData[0]);
dateAxis.setUpperBound(xData[xData.length-1]);
anArray = new double[9];
anArray[0] = 2;
anArray[1] = 19;
anArray[2] = 3;
anArray[3] = 5;
anArray[4] = 12;
anArray[5] = 6;
anArray[6] = 2;
anArray[7] = 12;
anArray[8] = 6;
XYChart.Series Dates = new XYChart.Series( "Dates", plotWithVisableLabeles(xData,anArray) );
lineChart.getData().add(Dates);
final BorderPane chartContainer = new BorderPane();
final Button zoomButton = new Button("Zoom");
chartContainer.setCenter(lineChart);
final Button unZoomButton = new Button("Un Zoom");
chartContainer.setBottom(zoomButton);
chartContainer.setRight(unZoomButton);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
chartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, lineChart);
StackPane root = new StackPane();
root.getChildren().add(chartContainer);
Scene scene = new Scene(root, 600, 600);
// final Button resetButton = new Button("Reset");
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect);
}
});
unZoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
dateAxis.setLowerBound(new GregorianCalendar(2014, 11, 10).getTime());
dateAxis.setUpperBound(new GregorianCalendar(2014, 11, 25).getTime());
}
});
primaryStage.setTitle("zoomable Line chart with Date axis");
primaryStage.setScene(scene);
primaryStage.show();
}
private void setUpZooming(final Rectangle rect, final Node zoomingNode) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
rect.setWidth(0);
rect.setHeight(0);
}
});
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double x = event.getX();
double y = event.getY();
rect.setX(Math.min(x, mouseAnchor.get().getX()));
rect.setY(Math.min(y, mouseAnchor.get().getY()));
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
}
});
}
private void doZoom(Rectangle zoomRect) {
Date leftBorder = dateAxis.getValueForDisplay(zoomRect.getX());
Date RightBorder = dateAxis.getValueForDisplay(zoomRect.getX() + zoomRect.getWidth());
dateAxis.setLowerBound(leftBorder);
dateAxis.setUpperBound(RightBorder);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
public ObservableList<XYChart.Data<Date, Double>> plotWithVisableLabeles(Date[] x ,double[] y) {
final ObservableList<XYChart.Data<Date, Double>> dataset = FXCollections.observableArrayList();
i = 0;
while (i < y.length) {
final XYChart.Data< Date, Double> data = new XYChart.Data<>(x[i], y[i]);
final StackPane node = new HoveredThresholdNode(x[i],y[i]);
node.setStyle("-fx-background-color: linear-gradient(black,white);");
data.setNode(node);
dataset.add(data);
i++;
}
return dataset;
}
public static void main(String[] args) {
launch(args);
}
}
ive added the version of Date axis that im using (its old, and i removed all the comments due to SO limitations)
package linechartwithdateaxis;
import com.sun.javafx.charts.ChartLayoutAnimator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.chart.Axis;
import javafx.util.Duration;
import javafx.util.StringConverter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public final class DateAxis extends Axis<Date> {
private final LongProperty currentLowerBound = new SimpleLongProperty(this, "currentLowerBound");
private final LongProperty currentUpperBound = new SimpleLongProperty(this, "currentUpperBound");
private final ObjectProperty<StringConverter<Date>> tickLabelFormatter = new ObjectPropertyBase<StringConverter<Date>>() {
#Override
protected void invalidated() {
if (!isAutoRanging()) {
invalidateRange();
requestAxisLayout();
}
}
#Override
public Object getBean() {
return DateAxis.this;
}
#Override
public String getName() {
return "tickLabelFormatter";
}
};
private Date minDate, maxDate;
private ObjectProperty<Date> lowerBound = new ObjectPropertyBase<Date>() {
#Override
protected void invalidated() {
if (!isAutoRanging()) {
invalidateRange();
requestAxisLayout();
}
}
#Override
public Object getBean() {
return DateAxis.this;
}
#Override
public String getName() {
return "lowerBound";
}
};
private ObjectProperty<Date> upperBound = new ObjectPropertyBase<Date>() {
#Override
protected void invalidated() {
if (!isAutoRanging()) {
invalidateRange();
requestAxisLayout();
}
}
#Override
public Object getBean() {
return DateAxis.this;
}
#Override
public String getName() {
return "upperBound";
}
};
private ChartLayoutAnimator animator = new ChartLayoutAnimator(this);
private Object currentAnimationID;
private DateAxis.Interval actualInterval = DateAxis.Interval.DECADE;
public DateAxis() {
}
public DateAxis(Date lowerBound, Date upperBound) {
this();
setAutoRanging(false);
setLowerBound(lowerBound);
setUpperBound(upperBound);
}
public DateAxis(String axisLabel, Date lowerBound, Date upperBound) {
this(lowerBound, upperBound);
setLabel(axisLabel);
}
#Override
public void invalidateRange(List<Date> list) {
super.invalidateRange(list);
Collections.sort(list);
if (list.isEmpty()) {
minDate = maxDate = new Date();
} else if (list.size() == 1) {
minDate = maxDate = list.get(0);
} else if (list.size() > 1) {
minDate = list.get(0);
maxDate = list.get(list.size() - 1);
}
}
#Override
protected Object autoRange(double length) {
if (isAutoRanging()) {
return new Object[]{minDate, maxDate};
} else {
if (getLowerBound() == null || getUpperBound() == null) {
throw new IllegalArgumentException("If autoRanging is false, a lower and upper bound must be set.");
}
return getRange();
}
}
#Override
protected void setRange(Object range, boolean animating) {
Object[] r = (Object[]) range;
Date oldLowerBound = getLowerBound();
Date oldUpperBound = getUpperBound();
Date lower = (Date) r[0];
Date upper = (Date) r[1];
setLowerBound(lower);
setUpperBound(upper);
if (animating) {
animator.stop(currentAnimationID);
currentAnimationID = animator.animate(
new KeyFrame(Duration.ZERO,
new KeyValue(currentLowerBound, oldLowerBound.getTime()),
new KeyValue(currentUpperBound, oldUpperBound.getTime())
),
new KeyFrame(Duration.millis(700),
new KeyValue(currentLowerBound, lower.getTime()),
new KeyValue(currentUpperBound, upper.getTime())
)
);
} else {
currentLowerBound.set(getLowerBound().getTime());
currentUpperBound.set(getUpperBound().getTime());
}
}
#Override
protected Object getRange() {
return new Object[]{getLowerBound(), getUpperBound()};
}
#Override
public double getZeroPosition() {
return 0;
}
#Override
public double getDisplayPosition(Date date) {
final double length = getSide().isHorizontal() ? getWidth() : getHeight();
double diff = currentUpperBound.get() - currentLowerBound.get();
double range = length - getZeroPosition();
double d = (date.getTime() - currentLowerBound.get()) / diff;
if (getSide().isVertical()) {
return getHeight() - d * range + getZeroPosition();
} else {
return d * range + getZeroPosition();
}
}
#Override
public Date getValueForDisplay(double displayPosition) {
final double length = getSide().isHorizontal() ? getWidth() : getHeight();
double diff = currentUpperBound.get() - currentLowerBound.get();
double range = length - getZeroPosition();
if (getSide().isVertical()) {
return new Date((long) ((displayPosition - getZeroPosition() - getHeight()) / -range * diff + currentLowerBound.get()));
} else {
return new Date((long) ((displayPosition - getZeroPosition()) / range * diff + currentLowerBound.get()));
}
}
#Override
public boolean isValueOnAxis(Date date) {
return date.getTime() > currentLowerBound.get() && date.getTime() < currentUpperBound.get();
}
#Override
public double toNumericValue(Date date) {
return date.getTime();
}
#Override
public Date toRealValue(double v) {
return new Date((long) v);
}
#Override
protected List<Date> calculateTickValues(double v, Object range) {
Object[] r = (Object[]) range;
Date lower = (Date) r[0];
Date upper = (Date) r[1];
List<Date> dateList = new ArrayList<Date>();
Calendar calendar = Calendar.getInstance();
// The preferred gap which should be between two tick marks.
double averageTickGap = 100;
double averageTicks = v / averageTickGap;
List<Date> previousDateList = new ArrayList<Date>();
DateAxis.Interval previousInterval = DateAxis.Interval.values()[0];
// Starting with the greatest interval, add one of each calendar unit.
for (DateAxis.Interval interval : DateAxis.Interval.values()) {
// Reset the calendar.
calendar.setTime(lower);
dateList.clear();
previousDateList.clear();
actualInterval = interval;
while (calendar.getTime().getTime() <= upper.getTime()) {
dateList.add(calendar.getTime());
calendar.add(interval.interval, interval.amount);
}
if (dateList.size() > averageTicks) {
calendar.setTime(lower);
// Recheck if the previous interval is better suited.
while (calendar.getTime().getTime() <= upper.getTime()) {
previousDateList.add(calendar.getTime());
calendar.add(previousInterval.interval, previousInterval.amount);
}
break;
}
previousInterval = interval;
}
if (previousDateList.size() - averageTicks > averageTicks - dateList.size()) {
dateList = previousDateList;
actualInterval = previousInterval;
}
// At last add the upper bound.
dateList.add(upper);
List<Date> evenDateList = makeDatesEven(dateList, calendar);
if (evenDateList.size() > 2) {
Date secondDate = evenDateList.get(1);
Date thirdDate = evenDateList.get(2);
Date lastDate = evenDateList.get(dateList.size() - 2);
Date previousLastDate = evenDateList.get(dateList.size() - 3);
if (secondDate.getTime() - lower.getTime() < (thirdDate.getTime() - secondDate.getTime()) / 2) {
evenDateList.remove(secondDate);
}
if (upper.getTime() - lastDate.getTime() < (lastDate.getTime() - previousLastDate.getTime()) / 2) {
evenDateList.remove(lastDate);
}
}
return evenDateList;
}
#Override
protected void layoutChildren() {
if (!isAutoRanging()) {
currentLowerBound.set(getLowerBound().getTime());
currentUpperBound.set(getUpperBound().getTime());
}
super.layoutChildren();
}
#Override
protected String getTickMarkLabel(Date date) {
StringConverter<Date> converter = getTickLabelFormatter();
if (converter != null) {
return converter.toString(date);
}
DateFormat dateFormat;
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
if (actualInterval.interval == Calendar.YEAR && calendar.get(Calendar.MONTH) == 0 && calendar.get(Calendar.DATE) == 1) {
dateFormat = new SimpleDateFormat("yyyy");
} else if (actualInterval.interval == Calendar.MONTH && calendar.get(Calendar.DATE) == 1) {
dateFormat = new SimpleDateFormat("MMM yy");
} else {
switch (actualInterval.interval) {
case Calendar.DATE:
case Calendar.WEEK_OF_YEAR:
default:
dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
break;
case Calendar.HOUR:
case Calendar.MINUTE:
dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
break;
case Calendar.SECOND:
dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);
break;
case Calendar.MILLISECOND:
dateFormat = DateFormat.getTimeInstance(DateFormat.FULL);
break;
}
}
return dateFormat.format(date);
}
private List<Date> makeDatesEven(List<Date> dates, Calendar calendar) {
if (dates.size() > 2) {
List<Date> evenDates = new ArrayList<Date>();
for (int i = 0; i < dates.size(); i++) {
calendar.setTime(dates.get(i));
switch (actualInterval.interval) {
case Calendar.YEAR:
if (i != 0 && i != dates.size() - 1) {
calendar.set(Calendar.MONTH, 0);
calendar.set(Calendar.DATE, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 6);
break;
case Calendar.MONTH:
if (i != 0 && i != dates.size() - 1) {
calendar.set(Calendar.DATE, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 5);
break;
case Calendar.WEEK_OF_YEAR:
// Make weeks begin with first day of week?
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 4);
break;
case Calendar.DATE:
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 3);
break;
case Calendar.HOUR:
if (i != 0 && i != dates.size() - 1) {
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
}
calendar.set(Calendar.MILLISECOND, 2);
break;
case Calendar.MINUTE:
if (i != 0 && i != dates.size() - 1) {
calendar.set(Calendar.SECOND, 0);
}
calendar.set(Calendar.MILLISECOND, 1);
break;
case Calendar.SECOND:
calendar.set(Calendar.MILLISECOND, 0);
break;
}
evenDates.add(calendar.getTime());
}
return evenDates;
} else {
return dates;
}
}
public final ObjectProperty<Date> lowerBoundProperty() {
return lowerBound;
}
public final Date getLowerBound() {
return lowerBound.get();
}
public final void setLowerBound(Date date) {
lowerBound.set(date);
}
public final ObjectProperty<Date> upperBoundProperty() {
return upperBound;
}
public final Date getUpperBound() {
return upperBound.get();
}
public final void setUpperBound(Date date) {
upperBound.set(date);
}
public final StringConverter<Date> getTickLabelFormatter() {
return tickLabelFormatter.getValue();
}
public final void setTickLabelFormatter(StringConverter<Date> value) {
tickLabelFormatter.setValue(value);
}
public final ObjectProperty<StringConverter<Date>> tickLabelFormatterProperty() {
return tickLabelFormatter;
}
private enum Interval {
DECADE(Calendar.YEAR, 10),
YEAR(Calendar.YEAR, 1),
MONTH_6(Calendar.MONTH, 6),
MONTH_3(Calendar.MONTH, 3),
MONTH_1(Calendar.MONTH, 1),
WEEK(Calendar.WEEK_OF_YEAR, 1),
DAY(Calendar.DATE, 1),
HOUR_12(Calendar.HOUR, 12),
HOUR_6(Calendar.HOUR, 6),
HOUR_3(Calendar.HOUR, 3),
HOUR_1(Calendar.HOUR, 1),
MINUTE_15(Calendar.MINUTE, 15),
MINUTE_5(Calendar.MINUTE, 5),
MINUTE_1(Calendar.MINUTE, 1),
SECOND_15(Calendar.SECOND, 15),
SECOND_5(Calendar.SECOND, 5),
SECOND_1(Calendar.SECOND, 1),
MILLISECOND(Calendar.MILLISECOND, 1);
private final int amount;
private final int interval;
private Interval(int interval, int amount) {
this.interval = interval;
this.amount = amount;
}
}
}
and there it is:
Related
private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final long DELAY = 1000;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
private long startTime = 0L;
int num = 1;
List<VideoModel> videoList;
private Handler customHandler = new Handler();
private static final String TAG = "RecordVideoActivity";
private String videoName;
static {
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_0, 90);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_90, 0);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_180, 270);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
static {
INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);
}
private AutoFitTextureView mTextureView;
private ImageButton mRecordButton;
private ImageView mDots;
private ImageButton mCheckPoint;
private CameraDevice mCameraDevice;
private CameraCaptureSession mPreviewSession;
private TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
int width, int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private Size mPreviewSize;
private Size mVideoSize;
private MediaRecorder mMediaRecorder;
private boolean mIsRecordingVideo;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
startPreview();
mCameraOpenCloseLock.release();
if (null != mTextureView) {
configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
}
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
finish();
}
};
private Integer mSensorOrientation;
private String mNextVideoAbsolutePath;
private CaptureRequest.Builder mPreviewBuilder;
private CameraManager manager;
private String cameraId;
private boolean isFlashSupported;
private ImageButton flashButton;
private ImageButton switchCamera;
private ImageButton revertVideo;
public static final String CAMERA_BACK = "0";
private TextView mChronometer;
private String flashOpt;
private long lastSavedTime;
private String prepend;
private static Size chooseVideoSize(Size[] choices) {
for (Size size : choices) {
if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
return size;
}
}
Log.e(TAG, "Couldn't find any suitable video size");
return choices[choices.length - 1];
}
private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getHeight() == option.getWidth() * h / w &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}
}
// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera2_video_image);
File dir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES) + File.separator + AppConstants.APPDIRRECORDING);
if (dir.isDirectory()) {
deleteDirectory(dir);
}
videoList = new ArrayList<>();
mTextureView = findViewById(R.id.textureView);
mRecordButton = findViewById(R.id.videoOnlineImageButton);
mRecordButton.setImageResource(R.drawable.ic_video);
mCheckPoint = findViewById(R.id.checkPoint);
mCheckPoint.setVisibility(View.GONE);
mDots = findViewById(R.id.dot);
mRecordButton.setOnClickListener(this);
flashButton = findViewById(R.id.flashVideo);
switchCamera = findViewById(R.id.switchVideo);
revertVideo = findViewById(R.id.revertVideo);
revertVideo.setVisibility(View.GONE);
mChronometer = findViewById(R.id.chronometer);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
flashOpt = prefs.getString(getString(R.string.flash_option), getString(R.string.auto));
if (flashOpt.equals(getString(R.string.flash_off)))
flashButton.setImageResource(R.drawable.flash_auto);
else if (flashOpt.equals(getString(R.string.flash_on)))
flashButton.setImageResource(R.drawable.flash_on);
else
flashButton.setImageResource(R.drawable.flash_off);
findViewById(R.id.checkPoint).setOnClickListener(this);
findViewById(R.id.flashVideo).setOnClickListener(this);
findViewById(R.id.switchVideo).setOnClickListener(this);
findViewById(R.id.revertVideo).setOnClickListener(this);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
if(mIsRecordingVideo)
mRecordButton.setImageResource(R.drawable.ic_video_stop);
else
mRecordButton.setImageResource(R.drawable.ic_video);
mCheckPoint.setEnabled(true);
startTime=SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}
#Override
public void onPause() {
closeCamera();
mCheckPoint.setEnabled(false);
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
stopBackgroundThread();
super.onPause();
}
private Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
int mins = secs / 60;
secs = secs % 60;
int hour = mins / 60;
mChronometer.setText("" + hour + ":"
+ String.format("%02d", mins) + ":"
+ String.format("%02d", secs));
customHandler.postDelayed(this, 0);
}
};
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.videoOnlineImageButton: {
if (mIsRecordingVideo) {
mDots.setVisibility(View.GONE);
mChronometer.setVisibility(View.GONE);
switchCamera.setVisibility(View.VISIBLE);
mCheckPoint.setVisibility(View.GONE);
stopRecordingVideo();
Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaStoreUpdateIntent.setData(Uri.fromFile(new File(mNextVideoAbsolutePath)));
sendBroadcast(mediaStoreUpdateIntent);
} else {
mCheckPoint.setVisibility(View.VISIBLE);
switchCamera.setVisibility(View.GONE);
mChronometer.setVisibility(View.VISIBLE);
mDots.setVisibility(View.VISIBLE);
startRecordingVideo();
}
break;
}
case R.id.switchVideo: {
facingCamera = !facingCamera;
closeCamera();
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
break;
}
case R.id.flashVideo: {
if (onFlashCheck()) {
CameraCharacteristics cameraCharacteristics = null;
try {
cameraCharacteristics = manager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Boolean available = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
isFlashSupported = available == null ? false : available;
switchFlash();
}
break;
}
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#SuppressLint("MissingPermission")
private void openCamera(int width, int height) {
final Activity activity = this;
if (null == activity || activity.isFinishing()) {
return;
}
manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
Log.d(TAG, "tryAcquire");
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
cameraId = manager.getCameraIdList()[1];
if (facingCamera) {
cameraId = manager.getCameraIdList()[1];
flashButton.setVisibility(View.GONE);
} else {
cameraId = manager.getCameraIdList()[0];
flashButton.setVisibility(View.VISIBLE);
}
// Choose the sizes for camera preview and video recording
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
if (map == null) {
throw new RuntimeException("Cannot get available preview/video sizes");
}
mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
width, height, mVideoSize);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
configureTransform(width, height);
mMediaRecorder = new MediaRecorder();
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
activity.finish();
} catch (NullPointerException e) {
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.");
}
}
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
closePreviewSession();
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mMediaRecorder) {
mMediaRecorder.release();
mMediaRecorder = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.");
} finally {
mCameraOpenCloseLock.release();
}
}
private void startPreview() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Surface previewSurface = new Surface(texture);
mPreviewBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
mPreviewSession = session;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Toast.makeText(RecordVideoActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if (null == mCameraDevice) {
return;
}
try {
setUpCaptureRequestBuilder(mPreviewBuilder);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
if (onFlashCheck()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
flashButton.setVisibility(View.VISIBLE);
}
});
if (flashOpt.equals(getString(R.string.auto)))
builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
else if (flashOpt.equals(getString(R.string.flash_off)))
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
else
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else
runOnUiThread(new Runnable() {
#Override
public void run() {
flashButton.setVisibility(View.GONE);
}
});
}
private void configureTransform(int viewWidth, int viewHeight) {
if (null == mTextureView || null == mPreviewSize) {
return;
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
mTextureView.setTransform(matrix);
}
private void setUpMediaRecorder() throws IOException {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
File file = getVideoFilePath(this);
mNextVideoAbsolutePath = file.getAbsolutePath();
videoName = file.getName();
mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
mMediaRecorder.setVideoEncodingBitRate(10000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
switch (mSensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
break;
case SENSOR_ORIENTATION_INVERSE_DEGREES:
mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
break;
}
mMediaRecorder.prepare();
}
private File getVideoFilePath(Context context) {
File appDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES) + File.separator + AppConstants.APPDIRRECORDING);
if (!appDir.isDirectory()) {
appDir.mkdirs();
}
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String prepend = "VIDEO_" + timestamp + ".mp4";
File videoFile = null;
try {
videoFile = File.createTempFile(prepend, ".mp4", appDir);
} catch (IOException e) {
e.printStackTrace();
}
return videoFile;
}
private void startRecordingVideo() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
setUpMediaRecorder();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
// Set up Surface for the camera preview
Surface previewSurface = new Surface(texture);
surfaces.add(previewSurface);
mPreviewBuilder.addTarget(previewSurface);
// Set up Surface for the MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull final CameraCaptureSession cameraCaptureSession) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mPreviewSession = cameraCaptureSession;
updatePreview();
mIsRecordingVideo = true;
startTime = SystemClock.uptimeMillis();
mChronometer.setVisibility(View.VISIBLE);
customHandler.postDelayed(updateTimerThread, 0);
mRecordButton.setImageResource(R.drawable.ic_video_stop);
mMediaRecorder.start();
mCheckPoint.setEnabled(true);
}
});
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(RecordVideoActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}, mBackgroundHandler);
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
}
}
private void closePreviewSession() {
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
}
#SuppressLint("ResourceType")
private void stopRecordingVideo() {
mIsRecordingVideo = false;
customHandler.removeCallbacks(updateTimerThread);
mRecordButton.setImageResource(R.drawable.ic_video);
if(mMediaRecorder!=null) {
try {
mMediaRecorder.stop();
} catch (RuntimeException e) {
e.printStackTrace();
}
mMediaRecorder.reset();
}
}
static class CompareSizesByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
#Override
protected void onDestroy() {
customHandler.removeCallbacks(updateTimerThread);
}
I have implemented following coding in my app.i used camera 2 api for video recording.i feel that video streaming is stretched. mainly when i switch camera into front one.pls help me to resolve this problem
I have implemented following coding in my app.i used camera 2 api for video recording.i feel that video streaming is stretched. mainly when i switch camera into front one.pls help me to resolve this problem
Change aspect ratio values in AutoFitTextureView class or use Textureview instead of AutoFitTextureview.
Process:*****.googlemapapp, PID: 2402
java.lang.UnsatisfiedLinkError: Couldn't load rocket from loader bvt[DexPathList[[zip file "/data/data/com.google.android.gms/app_chimera/m/00000003/DynamiteModulesB_GmsCore_prod_alldpi_release.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:358)
at java.lang.System.loadLibrary(System.java:526)
at com.google.maps.api.android.lib6.rocket.a.onSurfaceCreated(:com.google.android.gms.DynamiteModulesB:119)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1501)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
i m Getting an error when i run my mapFragment.getMapAsync(this)
i works very well for first time ...when i start again its giving error like above ...everything works well for first time ....it is like for odd it works for even application crashesh.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = MapsActivity.this;
setContentView(R.layout.activity_maps);
MarkerPoints = new ArrayList<>();
nextBtn = (Button) findViewById(R.id.nextBtn);
txtDistance = (TextView) findViewById(R.id.txtDistance);
txtCheckpoint = (TextView) findViewById(R.id.txtCheckpoint);
txtDistance.setText("Distance Travel : 0 Mtr");
distance = new ArrayList<Float>();
waypoints = new ArrayList<LatLng>();
Intent i = getIntent();
Places place = (Places) i.getParcelableExtra("data");
Log.d("data", place.toString());
startPoint = place.startPoint;
endPoint = place.endPoint;
waypoints=place.waypoints;
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resultCode == ConnectionResult.SUCCESS)
{
if(mapFragment != null) {
mapFragment.getMapAsync(this);
}
}else
Toast.makeText(context, "UnAvailable", Toast.LENGTH_SHORT).show();
}
//here application crashes on alternative run on mapFragment.getMapAsync(this) ,
all code works fine for first time on second time it says
java.lang.UnsatisfiedLinkError: Couldn't load rocket from loader bvt[DexPathList[[zip file "/data/data/com.google.android.gms/app_chimera/m/00000003/DynamiteModulesB_GmsCore_prod_alldpi_release.apk"],
nativeLibraryDirectories=[/vendor/lib, /system/lib]]]:
findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:358)
//i initialize maps and then according to location i change panoroma image, here Fetchurl will save the path data in routes which is List<List<HashMap<String, String>>> it is Asynchronous call
#Override
public void onMapReady(GoogleMap googleMap) {
try {
mMap = googleMap;
MarkerPoints.add(startPoint);
startMarker.position(startPoint);
startMarker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
m = mMap.addMarker(startMarker);
m.setTitle("You");
m.showInfoWindow();
MarkerPoints.add(endPoint);
endMarker.position(endPoint);
endMarker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
Marker e = mMap.addMarker(endMarker);
e.setTitle("Goal");
LatLng origin = MarkerPoints.get(0);
LatLng dest = MarkerPoints.get(1);
String url = getUrl(origin, dest);
FetchUrl FetchUrl = new FetchUrl();
FetchUrl.execute(url);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(startPoint));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
initializeSteatView();
} catch (Exception e) {
}
}`
///here i initialize streatview
` public void initializeSteatView() {
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(R.id.mapPanaroma);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
#Override
public void onStreetViewPanoramaReady(final StreetViewPanorama panorama) {
panorama.setUserNavigationEnabled(false);
panorama.setPosition(startPoint);
nextBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!isRouteLoaded)return;
if (currentPosition == routes.get(0).size() - 1) return;
if (currentPosition == 0) {
String s1 = routes.get(0).get(currentPosition).get("lat");
String s2 = routes.get(0).get(currentPosition).get("lng");
double d1 = Double.parseDouble(s1);
double d2 = Double.parseDouble(s2);
LatLng newPosition = new LatLng(d1, d2);
mMap.moveCamera(CameraUpdateFactory.newLatLng(newPosition));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
panorama.setPosition(newPosition);
m.setPosition(newPosition);
distance.add(totalDistance);
for (int i = 1; i < routes.get(0).size(); i++) {
d1 = Double.parseDouble(routes.get(0).get(i - 1).get("lat"));
d2 = Double.parseDouble(routes.get(0).get(i - 1).get("lng"));
LatLng start = new LatLng(d1, d2);
d1 = Double.parseDouble(routes.get(0).get(i).get("lat"));
d2 = Double.parseDouble(routes.get(0).get(i).get("lng"));
LatLng end = new LatLng(d1, d2);
totalDistance += calculateDistance(start, end);
distance.add(totalDistance);
Log.d("distance", distance.toString());
}
final Handler handler = new Handler();
final TimerTask timertask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
distanceTravel++;
txtDistance.setText("Distance Travel : " + distanceTravel + " Mtr");
checkDistance();
}
});
}
};
Timer timer = new Timer();
timer.schedule(timertask, 0, 500);
}
}
public void checkDistance() {
if (currentPosition == routes.get(0).size() - 1) return;
checkPoint = distance.get(currentPosition + 1);
txtCheckpoint.setText("Checkpoint : " + checkPoint);
if (checkPoint < Float.parseFloat(distanceTravel + "")) {
currentPosition++;
} else {
return;
}
String s1 = routes.get(0).get(currentPosition).get("lat");
String s2 = routes.get(0).get(currentPosition).get("lng");
double d1 = Double.parseDouble(s1);
double d2 = Double.parseDouble(s2);
LatLng newPosition = new LatLng(d1, d2);
mMap.moveCamera(CameraUpdateFactory.newLatLng(newPosition));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
panorama.setPosition(newPosition);
m.setPosition(newPosition);
}
});
panorama.setOnStreetViewPanoramaChangeListener(new StreetViewPanorama.OnStreetViewPanoramaChangeListener() {
#Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation streetViewPanoramaLocation) {
if(!isRouteLoaded)return;
if (routes.size() > 0) {
double lat1 = Double.parseDouble(routes.get(0).get(currentPosition).get("lat"));
double lng1 = Double.parseDouble(routes.get(0).get(currentPosition).get("lng"));
double lat2 = Double.parseDouble(routes.get(0).get
(currentPosition + 1).get("lat"));
double lng2 = Double.parseDouble(routes.get(0).get
(currentPosition + 1).get("lng"));
double dLon = (lng2 - lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
// brng = (360 - ((brng + 360) % 360));
long duration = 1000;
StreetViewPanoramaCamera camera =
new StreetViewPanoramaCamera.Builder()
.zoom(panorama.getPanoramaCamera().zoom)
.tilt(panorama.getPanoramaCamera().tilt)
.bearing(Float.parseFloat(brng + ""))
.build();
panorama.animateTo(camera, duration);
}
}
});
}
});
}
`
I am wondering if it's possible to start the Watchface Service from an activity?
I tried to start the service in the onCreate method of my activity but it does not show the Watchface:
Intent serviceIntent = new Intent(this, CustomWatchFaceService);
startService(serviceIntent);
update
Here is the code for the WatchfaceService
public class CustomWatchFaceService extends CanvasWatchFaceService {
private static final String TAG = "DigitalWatchFaceService";
private static final Typeface BOLD_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
private static final Typeface NORMAL_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
private static final long NORMAL_UPDATE_RATE_MS = 500;
private static final long MUTE_UPDATE_RATE_MS = TimeUnit.MINUTES.toMillis(1);
#Override
public Engine onCreateEngine() {
return new Engine();
}
private class Engine extends CanvasWatchFaceService.Engine {
static final String COLON_STRING = ":";
static final int MUTE_ALPHA = 100;
static final int NORMAL_ALPHA = 255;
static final int MSG_UPDATE_TIME = 0;
long mInteractiveUpdateRateMs = NORMAL_UPDATE_RATE_MS;
final Handler mUpdateTimeHandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "updating time");
}
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs =
mInteractiveUpdateRateMs - (timeMs % mInteractiveUpdateRateMs);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
break;
}
}
};
Paint mBackgroundPaint;
Bitmap mBackgroundBitmap;
Bitmap wifiIconOn;
Bitmap wifiIconOff;
Paint mDatePaint;
Paint mNotificationPaint;
Paint mNotificationMax;
Paint mNotificationHigh;
Paint mHourPaint;
Paint mMinutePaint;
Paint mSecondPaint;
Paint mAmPmPaint;
Paint mColonPaint;
float mColonWidth;
boolean mMute;
Calendar mCalendar;
Date mDate;
SimpleDateFormat mDayOfWeekFormat;
java.text.DateFormat mDateFormat;
boolean mShouldDrawColons;
float mXOffset;
float mYOffset;
float mLineHeight;
int mInteractiveBackgroundColor =
R.color.interactive_bg;
int mInteractiveNotificationMax =
R.color.notification_max;
int mInteractiveNotificationHigh =
R.color.notification_high;
int mInteractiveNotificationColor =
R.color.notification;
int mInteractiveHourDigitsColor =
R.color.interactive_time;
int mInteractiveMinuteDigitsColor =
R.color.interactive_time;
int mInteractiveSecondDigitsColor =
R.color.interactive_time;
boolean mLowBitAmbient;
#Override
public void onCreate(SurfaceHolder holder) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onCreate");
}
super.onCreate(holder);
Locale locale = new Locale("de");
Locale.setDefault(locale);
Configuration config = getResources().getConfiguration();
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
setWatchFaceStyle(new WatchFaceStyle.Builder(CustomWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
Resources resources = CustomWatchFaceService.this.getResources();
mYOffset = resources.getDimension(R.dimen.digital_y_offset);
mLineHeight = resources.getDimension(R.dimen.digital_line_height);
setInteractiveColors();
// Not sure why the text color needs to be set here again ... it should be set in setDefaultColors()!
mDatePaint.setColor(getColor(R.color.digital_date));
mNotificationPaint.setColor(getColor(R.color.notification));
mNotificationMax.setColor(getColor(R.color.notification_max));
mNotificationHigh.setColor(getColor(R.color.notification_high));
mHourPaint.setColor(getColor(R.color.interactive_time));
mMinutePaint.setColor(getColor(R.color.interactive_time));
mSecondPaint.setColor(getColor(R.color.interactive_time));
mColonPaint.setColor(getColor(R.color.interactive_time));
//Images should be loaded here so they can be called during the Draw Method
wifiIconOn = BitmapFactory.decodeResource(CustomWatchFaceService.this.getResources(), R.drawable.wifi_on_small);
wifiIconOff = BitmapFactory.decodeResource(CustomWatchFaceService.this.getResources(), R.drawable.wifi_off_small);
mBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.customcart_logo_240_alpha);
mCalendar = Calendar.getInstance();
mDate = new Date();
initFormats();
}
public void setInteractiveColors() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(mInteractiveBackgroundColor));
mNotificationPaint = createTextPaint(mInteractiveNotificationColor);
mNotificationMax = createTextPaint(mInteractiveNotificationMax);
mNotificationHigh = createTextPaint(mInteractiveNotificationHigh);
mDatePaint = createTextPaint(R.color.digital_date);
mHourPaint = createTextPaint(mInteractiveHourDigitsColor, BOLD_TYPEFACE);
mMinutePaint = createTextPaint(mInteractiveMinuteDigitsColor);
mSecondPaint = createTextPaint(mInteractiveSecondDigitsColor);
mColonPaint = createTextPaint(R.color.digital_colons);
}
#Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
private Paint createTextPaint(int defaultInteractiveColor) {
return createTextPaint(defaultInteractiveColor, NORMAL_TYPEFACE);
}
private Paint createTextPaint(int defaultInteractiveColor, Typeface typeface) {
Paint paint = new Paint();
paint.setColor(defaultInteractiveColor);
paint.setTypeface(typeface);
paint.setAntiAlias(true);
return paint;
}
#Override
public void onVisibilityChanged(boolean visible) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onVisibilityChanged: " + visible);
}
super.onVisibilityChanged(visible);
updateTimer();
}
private void initFormats() {
mDayOfWeekFormat = new SimpleDateFormat("EEEE", Locale.getDefault());
mDayOfWeekFormat.setCalendar(mCalendar);
mDateFormat = DateFormat.getDateFormat(CustomWatchFaceService.this);
mDateFormat.setCalendar(mCalendar);
}
#Override
public void onApplyWindowInsets(WindowInsets insets) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onApplyWindowInsets: " + (insets.isRound() ? "round" : "square"));
}
super.onApplyWindowInsets(insets);
// Load resources that have alternate values for round watches.
Resources resources = CustomWatchFaceService.this.getResources();
boolean isRound = insets.isRound();
mXOffset = resources.getDimension(isRound
? R.dimen.digital_x_offset_round : R.dimen.digital_x_offset);
float textSize = resources.getDimension(isRound
? R.dimen.digital_text_size_round : R.dimen.digital_text_size);
float notificationTextSize = resources.getDimension(isRound
? R.dimen.notification_text_size : R.dimen.notification_text_size);
mDatePaint.setTextSize(resources.getDimension(R.dimen.digital_date_text_size));
mHourPaint.setTextSize(textSize);
mMinutePaint.setTextSize(textSize);
mSecondPaint.setTextSize(textSize);
mColonPaint.setTextSize(textSize);
mNotificationPaint.setTextSize(notificationTextSize);
mColonWidth = mColonPaint.measureText(COLON_STRING);
}
#Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
boolean burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
mHourPaint.setTypeface(burnInProtection ? NORMAL_TYPEFACE : BOLD_TYPEFACE);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onPropertiesChanged: burn-in protection = " + burnInProtection
+ ", low-bit ambient = " + mLowBitAmbient);
}
}
#Override
public void onTimeTick() {
super.onTimeTick();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
}
invalidate();
}
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (!isInAmbientMode()) {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(R.color.interactive_bg));
mDatePaint.setColor(getColor(R.color.digital_date));
mHourPaint.setColor(getColor(R.color.interactive_time));
mMinutePaint.setColor(getColor(R.color.interactive_time));
mSecondPaint.setColor(getColor(R.color.interactive_time));
mColonPaint.setColor(getColor(R.color.interactive_time));
}
else {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(R.color.ambient_bg));
mDatePaint.setColor(getColor(R.color.digital_date));
mHourPaint.setColor(getColor(R.color.ambient_time));
mMinutePaint.setColor(getColor(R.color.ambient_time));
mSecondPaint.setColor(getColor(R.color.ambient_time));
mColonPaint.setColor(getColor(R.color.ambient_time));
}
//Log.d("XXX", "onAmbientModeChanged: " + inAmbientMode);
if (mLowBitAmbient) {
boolean antiAlias = !inAmbientMode;
mDatePaint.setAntiAlias(antiAlias);
mHourPaint.setAntiAlias(antiAlias);
mMinutePaint.setAntiAlias(antiAlias);
mSecondPaint.setAntiAlias(antiAlias);
mAmPmPaint.setAntiAlias(antiAlias);
mColonPaint.setAntiAlias(antiAlias);
}
invalidate();
// Whether the timer should be running depends on whether we're in ambient mode (as well
// as whether we're visible), so we may need to start or stop the timer.
updateTimer();
}
#Override
public void onInterruptionFilterChanged(int interruptionFilter) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onInterruptionFilterChanged: " + interruptionFilter);
}
super.onInterruptionFilterChanged(interruptionFilter);
boolean inMuteMode = interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE;
// We only need to update once a minute in mute mode.
setInteractiveUpdateRateMs(inMuteMode ? MUTE_UPDATE_RATE_MS : NORMAL_UPDATE_RATE_MS);
if (mMute != inMuteMode) {
mMute = inMuteMode;
int alpha = inMuteMode ? MUTE_ALPHA : NORMAL_ALPHA;
mDatePaint.setAlpha(alpha);
mHourPaint.setAlpha(alpha);
mMinutePaint.setAlpha(alpha);
mColonPaint.setAlpha(alpha);
mAmPmPaint.setAlpha(alpha);
invalidate();
}
}
public void setInteractiveUpdateRateMs(long updateRateMs) {
if (updateRateMs == mInteractiveUpdateRateMs) {
return;
}
mInteractiveUpdateRateMs = updateRateMs;
// Stop and restart the timer so the new update rate takes effect immediately.
if (shouldTimerBeRunning()) {
updateTimer();
}
}
private String formatTwoDigitNumber(int hour) {
return String.format("%02d", hour);
}
#Override
public void onDraw(Canvas canvas, Rect bounds) {
long now = System.currentTimeMillis();
int width = bounds.width();
int height = bounds.height();
mCalendar.setTimeInMillis(now);
mDate.setTime(now);
boolean is24Hour = DateFormat.is24HourFormat(CustomWatchFaceService.this);
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
//Draw the background Image
if (mBackgroundBitmap == null
|| mBackgroundBitmap.getWidth() != width
|| mBackgroundBitmap.getHeight() != height) {
mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
width, height, true /* filter */);
}
//Log.d("XXX", "Width: "+ mBackgroundBitmap.getWidth() + "Height: "+mBackgroundBitmap.getHeight() );
if (isInAmbientMode() && (mLowBitAmbient)) {
canvas.drawColor(Color.BLACK);
} else if (isInAmbientMode()) {
canvas.drawColor(Color.BLACK);
} else {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
}
// Show colons for the first half of each second so the colons blink on when the time updates.
mShouldDrawColons = (System.currentTimeMillis() % 1000) < 500;
// Draw the hours.
float x = mXOffset;
String hourString;
if (is24Hour) {
hourString = formatTwoDigitNumber(mCalendar.get(Calendar.HOUR_OF_DAY));
} else {
int hour = mCalendar.get(Calendar.HOUR);
if (hour == 0) {
hour = 12;
}
hourString = String.valueOf(hour);
}
canvas.drawText(hourString, x, mYOffset, mHourPaint);
x += mHourPaint.measureText(hourString);
// In ambient and mute modes, always draw the first colon. Otherwise, draw the
// first colon for the first half of each second.
if (isInAmbientMode() || mMute || mShouldDrawColons) {
canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
}
x += mColonWidth;
// Draw the minutes.
String minuteString = formatTwoDigitNumber(mCalendar.get(Calendar.MINUTE));
canvas.drawText(minuteString, x, mYOffset, mMinutePaint);
x += mMinutePaint.measureText(minuteString);
// In unmuted interactive mode, draw a second blinking colon followed by the seconds.
// Otherwise, if we're in 12-hour mode, draw AM/PM
if (!isInAmbientMode() && !mMute) {
if (mShouldDrawColons) {
canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
}
x += mColonWidth;
canvas.drawText(formatTwoDigitNumber(
mCalendar.get(Calendar.SECOND)), x, mYOffset, mSecondPaint);
} else if (!is24Hour) {
x += mColonWidth;
}
// Only render the day of week and date if there is no peek card, so they do not bleed
// into each other in ambient mode.
if (getPeekCardPosition().isEmpty()) {
// Day of week
canvas.drawText(
mDayOfWeekFormat.format(mDate),
mXOffset, mYOffset + mLineHeight, mDatePaint);
// Date
canvas.drawText(
mDateFormat.format(mDate),
mXOffset, mYOffset + mLineHeight * 2, mDatePaint);
}
}
/**
* Starts the {#link #mUpdateTimeHandler} timer if it should be running and isn't currently
* or stops it if it shouldn't be running but currently is.
*/
private void updateTimer() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "updateTimer");
}
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
/**
* Returns whether the {#link #mUpdateTimeHandler} timer should be running. The timer should
* only run when we're visible and in interactive mode.
*/
private boolean shouldTimerBeRunning() {
return isVisible() && !isInAmbientMode();
}
}
}
I have a JPopUpMenu with several JCheckBoxMenuItem's on it.
Actually what I would like to do is basicly to select an item of the JPopUpMenu with a specific index.
For exemple, a method like myPopUpMenu.setSelected(2), which would select "Algérie" in my JPopUpMenu.
The problem is that I don't know any method which would allow me to check an item manually...
Here's the code of my JPopUpMenu :
MainVue.java:
public class MainVue extends JFrame implements ActionListener {
private static final JScrollPopupMenu menuProduit = new JScrollPopupMenu();
private static final JScrollPopupMenu menuPays = new JScrollPopupMenu();
private static List<String> listeFiltres = new ArrayList<String>();
private String listeDeFiltres;
private String[] tableauFiltrePermanent;
private String listeFiltrePermanent;
private String[] tableauPays = { "Autres", "Afrique du sud", "Algérie", "Allemagne", "Arabie Saoudite", "Argentine",
"Australie", "Bangladesh", "Belgique", "Brésil", "Bulgarie", "Canada", "Chine", "Corée du sud", "Egypte",
"Emirats-Arabes Unis", "Espagne", "Etats-Unis", "Ethiopie", "Europe", "France", "Hongrie", "Inde",
"Indonésie", "Irak", "Iran", "Israél", "Italie", "Japon", "Jordanie", "Kazakhstan", "Koweit", "Liban",
"Libye", "Malaisie", "Maroc", "Mexique", "Monde", "Oman", "Pakistan", "Pays-Bas", "Philippines", "Poligne",
"Portugal", "Qatar", "République tchéque", "Roumanie", "Russie", "Taïwan", "Tunisie", "Turquie",
"Ukraine" };
private String[] tableauProduit = { "Blé", "Colza", "Mais", "Orge", "Orge de Brasserie", "Palme", "Soja",
"Tournesol", "Tourteaux De Colza", "Tourteaux de Soja", "Huile de Soja", "Huile De Colza" };
private List<JCheckBoxMenuItem> listJCBProduit = new ArrayList<JCheckBoxMenuItem>();
private List<JCheckBoxMenuItem> listJCBPays = new ArrayList<JCheckBoxMenuItem>();
public static PropertiesConfiguration prop;
public MainVue(Modele modele, Controleur controleur) throws ClassNotFoundException, SQLException, IOException {
prop = new PropertiesConfiguration("config.properties");
for (int i = 0; i < tableauProduit.length; i++) {
listJCBProduit.add(new JCheckBoxMenuItem(tableauProduit[i]));
}
for (int j = 0; j < listJCBProduit.size(); j++) {
JCheckBoxMenuItem produitActuel = listJCBProduit.get(j);
menuProduit.add(produitActuel);
produitActuel.addActionListener(new OpenAction(menuProduit, boutonProduit));
}
for (int i = 0; i < tableauPays.length; i++) {
listJCBPays.add(new JCheckBoxMenuItem(tableauPays[i]));
}
for (int j = 0; j < listJCBPays.size(); j++) {
JCheckBoxMenuItem paysActuel = listJCBPays.get(j);
menuPays.add(paysActuel);
paysActuel.addActionListener(new OpenAction(menuPays, boutonPays));
}
listeDeFiltres = "";
for (int p = 0; p < listeFiltres.size(); p++) {
String filtreActuel = listeFiltres.get(p);
if (listeDeFiltres == "") {
listeDeFiltres += filtreActuel;
} else {
listeDeFiltres += "," + filtreActuel;
}
}
prop.setProperty("listeFiltres", listeDeFiltres);
}
}
Here's the JScrollPopUpMenu component :
JScrollPopUpMenu.java:
package fr.views;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
public class JScrollPopupMenu extends JPopupMenu {
protected int maximumVisibleRows = 10;
public JScrollPopupMenu() {
this(null);
}
public JScrollPopupMenu(String label) {
super(label);
setLayout(new ScrollPopupMenuLayout());
super.add(getScrollBar());
addMouseWheelListener(new MouseWheelListener() {
#Override public void mouseWheelMoved(MouseWheelEvent event) {
JScrollBar scrollBar = getScrollBar();
int amount = (event.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
? event.getUnitsToScroll() * scrollBar.getUnitIncrement()
: (event.getWheelRotation() < 0 ? -1 : 1) * scrollBar.getBlockIncrement();
scrollBar.setValue(scrollBar.getValue() + amount);
event.consume();
}
});
}
private JScrollBar popupScrollBar;
protected JScrollBar getScrollBar() {
if(popupScrollBar == null) {
popupScrollBar = new JScrollBar(JScrollBar.VERTICAL);
popupScrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override public void adjustmentValueChanged(AdjustmentEvent e) {
doLayout();
repaint();
}
});
popupScrollBar.setVisible(false);
}
return popupScrollBar;
}
public int getMaximumVisibleRows() {
return maximumVisibleRows;
}
public void setMaximumVisibleRows(int maximumVisibleRows) {
this.maximumVisibleRows = maximumVisibleRows;
}
public void paintChildren(Graphics g){
Insets insets = getInsets();
g.clipRect(insets.left, insets.top, getWidth(), getHeight() - insets.top - insets.bottom);
super.paintChildren(g);
}
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if(maximumVisibleRows < getComponentCount()-1) {
getScrollBar().setVisible(true);
}
}
public void remove(int index) {
// can't remove the scrollbar
++index;
super.remove(index);
if(maximumVisibleRows >= getComponentCount()-1) {
getScrollBar().setVisible(false);
}
}
public void show(Component invoker, int x, int y){
JScrollBar scrollBar = getScrollBar();
if(scrollBar.isVisible()){
int extent = 0;
int max = 0;
int i = 0;
int unit = -1;
int width = 0;
for(Component comp : getComponents()) {
if(!(comp instanceof JScrollBar)) {
Dimension preferredSize = comp.getPreferredSize();
width = Math.max(width, preferredSize.width);
if(unit < 0){
unit = preferredSize.height;
}
if(i++ < maximumVisibleRows) {
extent += preferredSize.height;
}
max += preferredSize.height;
}
}
Insets insets = getInsets();
int widthMargin = insets.left + insets.right;
int heightMargin = insets.top + insets.bottom;
scrollBar.setUnitIncrement(unit);
scrollBar.setBlockIncrement(extent);
scrollBar.setValues(0, heightMargin + extent, 0, heightMargin + max);
width += scrollBar.getPreferredSize().width + widthMargin;
int height = heightMargin + extent;
setPopupSize(new Dimension(width, height));
}
super.show(invoker, x, y);
}
protected static class ScrollPopupMenuLayout implements LayoutManager{
#Override public void addLayoutComponent(String name, Component comp) {}
#Override public void removeLayoutComponent(Component comp) {}
#Override public Dimension preferredLayoutSize(Container parent) {
int visibleAmount = Integer.MAX_VALUE;
Dimension dim = new Dimension();
for(Component comp :parent.getComponents()){
if(comp.isVisible()) {
if(comp instanceof JScrollBar){
JScrollBar scrollBar = (JScrollBar) comp;
visibleAmount = scrollBar.getVisibleAmount();
}
else {
Dimension pref = comp.getPreferredSize();
dim.width = Math.max(dim.width, pref.width);
dim.height += pref.height;
}
}
}
Insets insets = parent.getInsets();
dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
return dim;
}
#Override public Dimension minimumLayoutSize(Container parent) {
int visibleAmount = Integer.MAX_VALUE;
Dimension dim = new Dimension();
for(Component comp : parent.getComponents()) {
if(comp.isVisible()){
if(comp instanceof JScrollBar) {
JScrollBar scrollBar = (JScrollBar) comp;
visibleAmount = scrollBar.getVisibleAmount();
}
else {
Dimension min = comp.getMinimumSize();
dim.width = Math.max(dim.width, min.width);
dim.height += min.height;
}
}
}
Insets insets = parent.getInsets();
dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
return dim;
}
#Override public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int width = parent.getWidth() - insets.left - insets.right;
int height = parent.getHeight() - insets.top - insets.bottom;
int x = insets.left;
int y = insets.top;
int position = 0;
for(Component comp : parent.getComponents()) {
if((comp instanceof JScrollBar) && comp.isVisible()) {
JScrollBar scrollBar = (JScrollBar) comp;
Dimension dim = scrollBar.getPreferredSize();
scrollBar.setBounds(x + width-dim.width, y, dim.width, height);
width -= dim.width;
position = scrollBar.getValue();
}
}
y -= position;
for(Component comp : parent.getComponents()) {
if(!(comp instanceof JScrollBar) && comp.isVisible()) {
Dimension pref = comp.getPreferredSize();
comp.setBounds(x, y, width, pref.height);
y += pref.height;
}
}
}
}
}
Thanks in advance for any help !
The index which you get from getIndex() method use as follows. You are adding ScrollBar in your JScrollPopupMenu at 0 index. So to remove casting error update your code as follow.
int index = getIndex("name");
((JCheckBoxMenuItem)menuProduit.getComponentAtIndex(index+1)).setState(true);
I have a problem again with the JavaFX Chart : D
Context :
I had Popup/Label on my chart to display the value on hover : JavaFX LineChart Hover Values (Jewelsea answer)
Problem :
But when the point are near the edges of chart, the popup is hidden by them.
The chart with problem, I highlighted the edges of chart.
This is a problem, because my popup is bigger and display more informations (x value, y value and the data serie)
Possible solutions :
May I can check where the edges are, and if the popup is hide. In this case, I should shift the popup. But when I look doc, I didn't found the right method :
XYChart
XYChart.Data#nodeProperty
May I can put the popup above the chart. Like z-index in CSS.
The code :
import javafx.application.Application;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Displays a LineChart which displays the value of a plotted Node when you hover over the Node.
* #author original, jewelsea https://gist.github.com/jewelsea
*/
public class LineChartWithHover extends Application {
#SuppressWarnings("unchecked")
#Override public void start(Stage stage) {
final LineChart lineChart = new LineChart(
new NumberAxis(), new NumberAxis(),
FXCollections.observableArrayList(
new XYChart.Series(
"My portfolio",
FXCollections.observableArrayList(
plot(0, 14, 15, 24, 34, 36, 22, 55, 43, 17, 29, 25)
)
)
)
);
lineChart.setCursor(Cursor.CROSSHAIR);
lineChart.setTitle("Stock Monitoring, 2013");
stage.setScene(new Scene(lineChart, 500, 400));
stage.show();
System.out.println("test 1 = "+lineChart.getProperties());
}
/** #return plotted y values for monotonically increasing integer x values, starting from x=1 */
public ObservableList<XYChart.Data<Integer, Integer>> plot(int... y) {
final ObservableList<XYChart.Data<Integer, Integer>> dataset = FXCollections.observableArrayList();
int i = 0;
while (i < y.length) {
final XYChart.Data<Integer, Integer> data = new XYChart.Data<>(i + 1, y[i]);
data.setNode(
new HoveredThresholdNode(
(i == 0) ? 0 : y[i-1],
y[i]
)
);
dataset.add(data);
i++;
}
return dataset;
}
/** a node which displays a value on hover, but is otherwise empty */
class HoveredThresholdNode extends StackPane {
HoveredThresholdNode(int priorValue, int value) {
setPrefSize(15, 15);
final Label label = createDataThresholdLabel(priorValue, value);
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
private Label createDataThresholdLabel(int priorValue, int value) {
final Label label = new Label(value + "");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");
if (priorValue == 0) {
label.setTextFill(Color.DARKGRAY);
} else if (value > priorValue) {
label.setTextFill(Color.FORESTGREEN);
} else {
label.setTextFill(Color.FIREBRICK);
}
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
return label;
}
}
public static void main(String[] args) { launch(args); }
}
Thank you in advance ! And my apologies about my english, still learning !
I have been looking on the JavaFX CSS reference guide and I could'nt find anything to simply solve your problem.
A possible solution is to translate your symbol depending on how near it is to the max or min value.
I wrote something like this, based on your code :
/**
* Displays a LineChart which displays the value of a plotted Node when you hover over the Node.
* #author original, jewelsea https://gist.github.com/jewelsea
*/
public class LineChartWithHover extends Application {
#SuppressWarnings("unchecked")
#Override public void start(Stage stage) {
final LineChart lineChart = new LineChart(
new NumberAxis(), new NumberAxis(),
FXCollections.observableArrayList(
new XYChart.Series(
"My portfolio",
FXCollections.observableArrayList(
plot(0, 14, 15, 24, 34, 36, 22, 55, 43, 17, 29, 25)
)
)
)
);
lineChart.setCursor(Cursor.CROSSHAIR);
lineChart.setTitle("Stock Monitoring, 2013");
stage.setScene(new Scene(lineChart, 500, 400));
stage.show();
System.out.println("test 1 = "+lineChart.getProperties());
}
/** #return plotted y values for monotonically increasing integer x values, starting from x=1 */
public ObservableList<XYChart.Data<Integer, Integer>> plot(Integer... y) {
final ObservableList<XYChart.Data<Integer, Integer>> dataset = FXCollections.observableArrayList();
int i = 0;
List<Integer> list = Arrays.asList(y);
int min = Collections.min(list);
int max = Collections.max(list);
int minThreshold = 5;
int maxThreshold = 5;
while (i < y.length) {
final XYChart.Data<Integer, Integer> data = new XYChart.Data<>(i + 1, y[i]);
int topMargin = 0;
if(y[i] <= min + minThreshold) {
topMargin = -50;
} else if (y[i] >= max - maxThreshold) {
topMargin = 50;
}
StackPane stackPane = new HoveredThresholdNode(
(i == 0) ? 0 : y[i-1],
y[i],
topMargin
);
data.setNode(stackPane);
dataset.add(data);
i++;
}
return dataset;
}
/** a node which displays a value on hover, but is otherwise empty */
class HoveredThresholdNode extends StackPane {
HoveredThresholdNode(int priorValue, int value, int topMargin) {
setPrefSize(15, 15);
final Label label = createDataThresholdLabel(priorValue, value);
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront();
setMargin(label, new Insets(topMargin,0,0,0));
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
private Label createDataThresholdLabel(int priorValue, int value) {
final Label label = new Label(value + "");
label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");
if (priorValue == 0) {
label.setTextFill(Color.DARKGRAY);
} else if (value > priorValue) {
label.setTextFill(Color.FORESTGREEN);
} else {
label.setTextFill(Color.FIREBRICK);
}
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
return label;
}
}
public static void main(String[] args) { launch(args); }
}
Basically, I am just saying that all values <= min+5 and >= max-5 must be translated.
The +/- 5 is arbitrary and should be calculated from the ticks gap and plot scale to have a perfect repositioning. Anyway, without performing any maths, it is still quite satisfying.
Based on Mr Kwoinkwoin solution, I wrote my own.
Im not sure if its possible to optimize it or improve it. But seems to be working for me so far.
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.NumberAxis.DefaultFormatter;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import static javafx.scene.layout.StackPane.setMargin;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class StockLineChartApp extends Application {
private LineChart<Number, Number> chart;
private Series<Number, Number> series;
private NumberAxis xAxis;
private ZonedDateTime time;
public StockLineChartApp() {
time = ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2000, Month.JANUARY, 1), LocalTime.NOON), ZoneId.systemDefault());
}
public Parent createContent() {
xAxis = new NumberAxis();
xAxis.setLabel("Date/Time");
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(true);
xAxis.setTickLabelFormatter(new StringConverter<Number>() {
#Override
public String toString(Number t) {
long longValue = t.longValue();
ZonedDateTime zd = convertLongToZonedDateTime(longValue);
String formatDate = formatDate(zd, "dd/MM/yyyy");
return formatDate;
}
#Override
public Number fromString(String string) {
ZonedDateTime dl = ZonedDateTime.parse(string, DateTimeFormatter.ofPattern("dd/MM/yyyy"));
long toEpochMilli = dl.toEpochSecond();
//DateTimeFormatter.ofPattern(string).p
return toEpochMilli;
}
});
final NumberAxis yAxis = new NumberAxis();
yAxis.setAutoRanging(true);
chart = new LineChart<>(xAxis, yAxis);
chart.setCursor(Cursor.CROSSHAIR);
chart.setAlternativeRowFillVisible(true);
chart.setAlternativeColumnFillVisible(true);
// setup chart
//final String stockLineChartCss= getClass().getResource("StockLineChart.css").toExternalForm();
//chart.getStylesheets().add(stockLineChartCss);
chart.setCreateSymbols(true);
chart.setAnimated(true);
chart.setLegendVisible(true);
chart.setTitle("ACME Company Stock");
yAxis.setLabel("Share Price");
yAxis.setTickLabelFormatter(new DefaultFormatter(yAxis, "$", null));
// add starting data
series = new Series<>();
series.setName("Data por Peça");
for (double m = 0; m < (10); m++) {
long data = nextTime();
addData(data, (long) (Math.random() * 10));
System.out.println(data);
}
//chart.
chart.getData().add(series);
//chart.getData().add(hourDataSeries);
return chart;
}
private void addData(long x, long y) {
Data<Number, Number> data = new Data<Number, Number>(x, y);
series.getData().add(data);
ZonedDateTime zd = convertLongToZonedDateTime(x);
String formatDate = formatDate(zd, "dd/MM/yyyy");
//String text = "(" + formatDate + ";" + y + ")";
String text = y + "";
if (text.length() > 4) {
text = text.substring(0, 4);
}
String t = formatDate + "\nValor: " + text;
data.setNode(new HoveredThresholdNode(t, data));
}
public static long convertZonedDateTimeToLong(ZonedDateTime zonedDateTime) {
long e = zonedDateTime.toInstant().toEpochMilli();
return e;
}
private long nextTime() {
time = time.plusYears(10);
return convertZonedDateTimeToLong(time);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent createContent = createContent();
//
final StackPane pane = new StackPane();
pane.getChildren().add(createContent);
final Scene scene = new Scene(pane, 500, 400);
//new ZoomManager(pane, chart, series);
//
primaryStage.setScene(scene);
primaryStage.show();
}
public static String formatDate(ZonedDateTime ts, String format) {
try {
if (ts == null) {
return "";
}
String format1 = ts.format(DateTimeFormatter.ofPattern(format));
return format1;
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
public static ZonedDateTime convertLongToZonedDateTime(long e) {
Instant i = Instant.ofEpochMilli(e);
ZonedDateTime ofInstant = ZonedDateTime.ofInstant(i, ZoneId.systemDefault());
return ofInstant;
}
/**
* Java main for when running without JavaFX launcher
*/
public static void main(String[] args) {
launch(args);
}
public class HoveredThresholdNode extends StackPane {
//Reference
private Data<Number, Number> data;
private Label label;
private String value;
public HoveredThresholdNode(String value, Data<Number, Number> data) {
this.data = data;
this.value = value;
this.label = new Label(value);
this.label.getStyleClass().clear();
this.getStyleClass().clear();
this.label.setStyle("-fx-font-size: 12; fx-text-fill: black;");
this.label.getStyleClass().addAll("default-color0", "chart-line-symbol", "chart-series-line");
this.label.setWrapText(true);
this.label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
toFront();
boolean close_top = false, close_right = false, close_bottom = false, close_left = false;
long min_x = Long.MAX_VALUE;
long max_x = Long.MIN_VALUE;
long min_y = Long.MAX_VALUE;
long max_y = Long.MIN_VALUE;
ObservableList<Series<Number, Number>> chartSeries = chart.getData();
for (Series<Number, Number> s : chartSeries) {
ObservableList<Data<Number, Number>> chartData = s.getData();
for (Data<Number, Number> d : chartData) {
Number xValue = d.getXValue();
Number yValue = d.getYValue();
long kx = xValue.longValue();
long ky = yValue.longValue();
if (kx < min_x) {
min_x = kx;
}
if (kx > max_x) {
max_x = kx;
}
if (ky < min_y) {
min_y = ky;
}
if (ky > max_y) {
max_y = ky;
}
}
}
if (data.getXValue().longValue() - max_x == 0) {
close_right = true;
}
if (data.getXValue().longValue() - min_x == 0) {
close_left = true;
}
if (data.getYValue().longValue() - min_y == 0) {
close_bottom = true;
}
if (data.getYValue().longValue() - max_y == 0) {
close_top = true;
}
// System.out.println("\n");
// System.out.println(" close_right " + close_right);
// System.out.println(" close_left " + close_left);
// System.out.println(" close_bottom " + close_bottom);
// System.out.println(" close_top " + close_top);
double top = 0;
double right = 0;
double bottom = 0;
double left = 0;
if (close_top) {
top = 50;
}
if (close_bottom) {
bottom = 50;
}
if (close_right) {
right = 50;
}
if (close_left) {
left = 50;
}
setMargin(label, new Insets(top, right, bottom, left));
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
}
});
}
public HoveredThresholdNode copy() {
HoveredThresholdNode copy = new HoveredThresholdNode(value, data);
return copy;
}
}
}