362 dataRemoveTimeline.play();
363 }
364 } else {
365 item.setSeries(null);
366 if (symbol != null) getPlotChildren().remove(symbol);
367 removeDataItemFromDisplay(series, item);
368 }
369 //Note: better animation here, point should move from old position to new position at center point between prev and next symbols
370 }
371
372 /** @inheritDoc */
373 @Override protected void dataItemChanged(Data<X, Y> item) {
374 }
375
376 @Override protected void seriesChanged(ListChangeListener.Change<? extends Series> c) {
377 // Update style classes for all series lines and symbols
378 // Note: is there a more efficient way of doing this?
379 for (int i = 0; i < getDataSize(); i++) {
380 final Series<X,Y> s = getData().get(i);
381 Node seriesNode = s.getNode();
382 if(seriesNode != null) seriesNode.getStyleClass().setAll("chart-series-line", "series" + i, s.defaultColorStyleClass);
383 }
384 }
385
386 @Override protected void seriesAdded(Series<X,Y> series, int seriesIndex) {
387 // create new path for series
388 Path seriesLine = new Path();
389 seriesLine.setStrokeLineJoin(StrokeLineJoin.BEVEL);
390 series.setNode(seriesLine);
391 // create series Y multiplier
392 DoubleProperty seriesYAnimMultiplier = new SimpleDoubleProperty(this, "seriesYMultiplier");
393 seriesYMultiplierMap.put(series, seriesYAnimMultiplier);
394 // handle any data already in series
395 if (shouldAnimate()) {
396 seriesLine.setOpacity(0);
397 seriesYAnimMultiplier.setValue(0d);
398 } else {
399 seriesYAnimMultiplier.setValue(1d);
400 }
401 getPlotChildren().add(seriesLine);
402
412 ));
413 keyFrames.add(new KeyFrame(Duration.millis(500),
414 new KeyValue(seriesYAnimMultiplier, 1)
415 ));
416 }
417 for (int j=0; j<series.getData().size(); j++) {
418 Data<X,Y> item = series.getData().get(j);
419 final Node symbol = createSymbol(series, seriesIndex, item, j);
420 if(symbol != null) {
421 if (shouldAnimate()) symbol.setOpacity(0);
422 getPlotChildren().add(symbol);
423 if (shouldAnimate()) {
424 // fade in new symbol
425 keyFrames.add(new KeyFrame(Duration.ZERO, new KeyValue(symbol.opacityProperty(), 0)));
426 keyFrames.add(new KeyFrame(Duration.millis(200), new KeyValue(symbol.opacityProperty(), 1)));
427 }
428 }
429 }
430 if (shouldAnimate()) animate(keyFrames.toArray(new KeyFrame[keyFrames.size()]));
431 }
432 private void updateDefaultColorIndex(final Series<X,Y> series) {
433 int clearIndex = seriesColorMap.get(series);
434 series.getNode().getStyleClass().remove(DEFAULT_COLOR+clearIndex);
435 for (int j=0; j < series.getData().size(); j++) {
436 final Node node = series.getData().get(j).getNode();
437 if(node!=null) {
438 node.getStyleClass().remove(DEFAULT_COLOR+clearIndex);
439 }
440 }
441 }
442
443 @Override protected void seriesRemoved(final Series<X,Y> series) {
444 updateDefaultColorIndex(series);
445 // remove all symbol nodes
446 seriesYMultiplierMap.remove(series);
447 if (shouldAnimate()) {
448 seriesRemoveTimeline = new Timeline(createSeriesRemoveTimeLine(series, 900));
449 seriesRemoveTimeline.play();
450 } else {
451 getPlotChildren().remove(series.getNode());
452 for (Data<X,Y> d:series.getData()) getPlotChildren().remove(d.getNode());
453 removeSeriesFromDisplay(series);
454 }
455 }
456
457 /** @inheritDoc */
458 @Override protected void layoutPlotChildren() {
459 List<LineTo> constructedPath = new ArrayList<>(getDataSize());
460 for (int seriesIndex=0; seriesIndex < getDataSize(); seriesIndex++) {
461 Series<X,Y> series = getData().get(seriesIndex);
462 final DoubleProperty seriesYAnimMultiplier = seriesYMultiplierMap.get(series);
463 if(series.getNode() instanceof Path) {
464 final ObservableList<PathElement> seriesLine = ((Path)series.getNode()).getElements();
|
362 dataRemoveTimeline.play();
363 }
364 } else {
365 item.setSeries(null);
366 if (symbol != null) getPlotChildren().remove(symbol);
367 removeDataItemFromDisplay(series, item);
368 }
369 //Note: better animation here, point should move from old position to new position at center point between prev and next symbols
370 }
371
372 /** @inheritDoc */
373 @Override protected void dataItemChanged(Data<X, Y> item) {
374 }
375
376 @Override protected void seriesChanged(ListChangeListener.Change<? extends Series> c) {
377 // Update style classes for all series lines and symbols
378 // Note: is there a more efficient way of doing this?
379 for (int i = 0; i < getDataSize(); i++) {
380 final Series<X,Y> s = getData().get(i);
381 Node seriesNode = s.getNode();
382 if (seriesNode != null) seriesNode.getStyleClass().setAll("chart-series-line", "series" + i, s.defaultColorStyleClass);
383 for (int j=0; j < s.getData().size(); j++) {
384 final Node symbol = s.getData().get(j).getNode();
385 if (symbol != null) symbol.getStyleClass().setAll("chart-line-symbol", "series" + i, "data" + j, s.defaultColorStyleClass);
386 }
387 }
388 }
389
390 @Override protected void seriesAdded(Series<X,Y> series, int seriesIndex) {
391 // create new path for series
392 Path seriesLine = new Path();
393 seriesLine.setStrokeLineJoin(StrokeLineJoin.BEVEL);
394 series.setNode(seriesLine);
395 // create series Y multiplier
396 DoubleProperty seriesYAnimMultiplier = new SimpleDoubleProperty(this, "seriesYMultiplier");
397 seriesYMultiplierMap.put(series, seriesYAnimMultiplier);
398 // handle any data already in series
399 if (shouldAnimate()) {
400 seriesLine.setOpacity(0);
401 seriesYAnimMultiplier.setValue(0d);
402 } else {
403 seriesYAnimMultiplier.setValue(1d);
404 }
405 getPlotChildren().add(seriesLine);
406
416 ));
417 keyFrames.add(new KeyFrame(Duration.millis(500),
418 new KeyValue(seriesYAnimMultiplier, 1)
419 ));
420 }
421 for (int j=0; j<series.getData().size(); j++) {
422 Data<X,Y> item = series.getData().get(j);
423 final Node symbol = createSymbol(series, seriesIndex, item, j);
424 if(symbol != null) {
425 if (shouldAnimate()) symbol.setOpacity(0);
426 getPlotChildren().add(symbol);
427 if (shouldAnimate()) {
428 // fade in new symbol
429 keyFrames.add(new KeyFrame(Duration.ZERO, new KeyValue(symbol.opacityProperty(), 0)));
430 keyFrames.add(new KeyFrame(Duration.millis(200), new KeyValue(symbol.opacityProperty(), 1)));
431 }
432 }
433 }
434 if (shouldAnimate()) animate(keyFrames.toArray(new KeyFrame[keyFrames.size()]));
435 }
436
437 @Override protected void seriesRemoved(final Series<X,Y> series) {
438 // remove all symbol nodes
439 seriesYMultiplierMap.remove(series);
440 if (shouldAnimate()) {
441 seriesRemoveTimeline = new Timeline(createSeriesRemoveTimeLine(series, 900));
442 seriesRemoveTimeline.play();
443 } else {
444 getPlotChildren().remove(series.getNode());
445 for (Data<X,Y> d:series.getData()) getPlotChildren().remove(d.getNode());
446 removeSeriesFromDisplay(series);
447 }
448 }
449
450 /** @inheritDoc */
451 @Override protected void layoutPlotChildren() {
452 List<LineTo> constructedPath = new ArrayList<>(getDataSize());
453 for (int seriesIndex=0; seriesIndex < getDataSize(); seriesIndex++) {
454 Series<X,Y> series = getData().get(seriesIndex);
455 final DoubleProperty seriesYAnimMultiplier = seriesYMultiplierMap.get(series);
456 if(series.getNode() instanceof Path) {
457 final ObservableList<PathElement> seriesLine = ((Path)series.getNode()).getElements();
|