/* * Copyright (c) 2013 by Gerrit Grunwald * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package eu.hansolo.enzo.charts; import com.sun.javafx.css.converters.PaintConverter; import eu.hansolo.enzo.charts.skin.SimpleLineChartSkin; import eu.hansolo.enzo.common.Section; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.css.CssMetaData; import javafx.css.Styleable; import javafx.css.StyleableObjectProperty; import javafx.css.StyleableProperty; import javafx.scene.chart.XYChart; import javafx.scene.control.Control; import javafx.scene.control.Skin; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Created by * User: hansolo * Date: 19.08.13 * Time: 13:26 */ public class SimpleLineChart extends Control { public static final String STYLE_CLASS_BLUE_TO_RED_5 = "blue-to-red-5"; public static final String STYLE_CLASS_GREEN_TO_DARKGREEN_6 = "green-to-darkgreen-6"; public static final String STYLE_CLASS_GREEN_TO_RED_6 = "green-to-red-6"; public static final String STYLE_CLASS_RED_TO_GREEN_6 = "red-to-green-6"; public static final String STYLE_CLASS_BLUE_TO_RED_6 = "blue-to-red-6"; public static final String STYLE_CLASS_PURPLE_TO_RED_6 = "purple-to-red-6"; public static final String STYLE_CLASS_GREEN_TO_RED_7 = "green-to-red-7"; public static final String STYLE_CLASS_RED_TO_GREEN_7 = "red-to-green-7"; public static final String STYLE_CLASS_GREEN_TO_RED_10 = "green-to-red-10"; public static final String STYLE_CLASS_RED_TO_GREEN_10 = "red-to-green-10"; public static final String STYLE_CLASS_PURPLE_TO_CYAN_10 = "purple-to-cyan-10"; private static final double PREFERRED_WIDTH = 200; private static final double PREFERRED_HEIGHT = 100; private static final double MINIMUM_WIDTH = 25; private static final double MINIMUM_HEIGHT = 25; private static final double MAXIMUM_WIDTH = 1024; private static final double MAXIMUM_HEIGHT = 1024; // CSS styleable properties private static final Color DEFAULT_BULLET_FILL = Color.web("#5a615f"); private static final Color DEFAULT_SERIES_STROKE = Color.web("#ffffff"); private static final Color DEFAULT_SECTION_FILL_0 = Color.web("#f3622d"); private static final Color DEFAULT_SECTION_FILL_1 = Color.web("#fba71b"); private static final Color DEFAULT_SECTION_FILL_2 = Color.web("#57b757"); private static final Color DEFAULT_SECTION_FILL_3 = Color.web("#f5982b"); private static final Color DEFAULT_SECTION_FILL_4 = Color.web("#41a9c9"); private static final Color DEFAULT_SECTION_FILL_5 = Color.web("#4258c9"); private static final Color DEFAULT_SECTION_FILL_6 = Color.web("#9a42c8"); private static final Color DEFAULT_SECTION_FILL_7 = Color.web("#c84164"); private static final Color DEFAULT_SECTION_FILL_8 = Color.web("#888888"); private static final Color DEFAULT_SECTION_FILL_9 = Color.web("#aaaaaa"); private ObjectProperty<Paint> bulletFill; private ObjectProperty<Paint> seriesStroke; private ObjectProperty<Paint> sectionFill0; private ObjectProperty<Paint> sectionFill1; private ObjectProperty<Paint> sectionFill2; private ObjectProperty<Paint> sectionFill3; private ObjectProperty<Paint> sectionFill4; private ObjectProperty<Paint> sectionFill5; private ObjectProperty<Paint> sectionFill6; private ObjectProperty<Paint> sectionFill7; private ObjectProperty<Paint> sectionFill8; private ObjectProperty<Paint> sectionFill9; private ObservableList<Section> sections; private XYChart.Series<?,?> series; private BooleanProperty sectionRangeVisible; private StringProperty unit; private StringProperty from; private StringProperty to; private BooleanProperty titleVisible; // ******************** Constructors ************************************** public SimpleLineChart() { sections = FXCollections.observableArrayList(); series = new XYChart.Series(); getStyleClass().setAll("canvas-chart"); } // ******************** Methods ******************************************* public final ObservableList<Section> getSections() { return sections; } public final void setSections(final List<Section> SECTIONS) { sections.setAll(SECTIONS); } public final void setSections(final Section... SECTIONS) { setSections(Arrays.asList(SECTIONS)); } public final void addSection(final Section SECTION) { if (!sections.contains(SECTION)) sections.add(SECTION); } public final void removeSection(final Section SECTION) { if (sections.contains(SECTION)) sections.remove(SECTION); } public final XYChart.Series<?, ?> getSeries() { return series; } public final void setSeries(final XYChart.Series<?, ?> SERIES) { series = SERIES; } public final boolean isSectionRangeVisible() { return null == sectionRangeVisible ? false : sectionRangeVisible.get(); } public final void setSectionRangeVisible(final boolean SECTION_RANGE_VISIBLE) { sectionRangeVisibleProperty().set(SECTION_RANGE_VISIBLE); } public final BooleanProperty sectionRangeVisibleProperty() { if (null == sectionRangeVisible) { sectionRangeVisible = new SimpleBooleanProperty(this, "sectionRangeVisible", false); } return sectionRangeVisible; } public final String getUnit() { return null == unit ? "" : unit.get(); } public void setUnit(final String UNIT) { unitProperty().set(UNIT); } public final StringProperty unitProperty() { if (null == unit) { unit = new SimpleStringProperty(this, "unit", ""); } return unit; } public final String getFrom() { return null == from ? "" : from.get(); } public final void setFrom(final String FROM) { fromProperty().set(FROM); } public final StringProperty fromProperty() { if (null == from) { from = new SimpleStringProperty(this, "from", ""); } return from; } public final String getTo() { return null == to ? "" : to.get(); } public final void setTo(final String TO) { toProperty().set(TO); } public final StringProperty toProperty() { if (null == to) { to = new SimpleStringProperty(this, "to", ""); } return to; } public final boolean isTitleVisible() { return null == titleVisible ? true : titleVisible.get(); } public final void setTitleVisible(final boolean TITLE_VISIBLE) { titleVisibleProperty().set(TITLE_VISIBLE); } public final BooleanProperty titleVisibleProperty() { if (null == titleVisible) { titleVisible = new SimpleBooleanProperty(this, "titleVisible", true); } return titleVisible; } // ******************** CSS Stylable Properties *************************** public final Paint getBulletFill() { return null == bulletFill ? DEFAULT_BULLET_FILL : bulletFill.get(); } public final void setBulletFill(Paint value) { bulletFillProperty().set(value); } public final ObjectProperty<Paint> bulletFillProperty() { if (null == bulletFill) { bulletFill = new StyleableObjectProperty<Paint>(DEFAULT_BULLET_FILL) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.BULLET_FILL; } @Override public Object getBean() { return this; } @Override public String getName() { return "bulletFill"; } }; } return bulletFill; } public final Paint getSeriesStroke() { return null == seriesStroke ? DEFAULT_SERIES_STROKE : seriesStroke.get(); } public final void setSeriesStroke(Paint value) { seriesStrokeProperty().set(value); } public final ObjectProperty<Paint> seriesStrokeProperty() { if (null == seriesStroke) { seriesStroke = new StyleableObjectProperty<Paint>(DEFAULT_SERIES_STROKE) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SERIES_STROKE; } @Override public Object getBean() { return this; } @Override public String getName() { return "seriesStroke"; } }; } return seriesStroke; } public final Paint getSectionFill0() { return null == sectionFill0 ? DEFAULT_SECTION_FILL_0 : sectionFill0.get(); } public final void setSectionFill0(Paint value) { sectionFill0Property().set(value); } public final ObjectProperty<Paint> sectionFill0Property() { if (null == sectionFill0) { sectionFill0 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_0) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_0; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill0"; } }; } return sectionFill0; } public final Paint getSectionFill1() { return null == sectionFill1 ? DEFAULT_SECTION_FILL_1 : sectionFill1.get(); } public final void setSectionFill1(Paint value) { sectionFill1Property().set(value); } public final ObjectProperty<Paint> sectionFill1Property() { if (null == sectionFill1) { sectionFill1 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_1) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_1; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill1"; } }; } return sectionFill1; } public final Paint getSectionFill2() { return null == sectionFill2 ? DEFAULT_SECTION_FILL_2 : sectionFill2.get(); } public final void setSectionFill2(Paint value) { sectionFill2Property().set(value); } public final ObjectProperty<Paint> sectionFill2Property() { if (null == sectionFill2) { sectionFill2 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_2) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_2; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill2"; } }; } return sectionFill2; } public final Paint getSectionFill3() { return null == sectionFill3 ? DEFAULT_SECTION_FILL_3 : sectionFill3.get(); } public final void setSectionFill3(Paint value) { sectionFill3Property().set(value); } public final ObjectProperty<Paint> sectionFill3Property() { if (null == sectionFill3) { sectionFill3 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_3) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_3; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill3"; } }; } return sectionFill3; } public final Paint getSectionFill4() { return null == sectionFill4 ? DEFAULT_SECTION_FILL_4 : sectionFill4.get(); } public final void setSectionFill4(Paint value) { sectionFill4Property().set(value); } public final ObjectProperty<Paint> sectionFill4Property() { if (null == sectionFill4) { sectionFill4 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_4) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_4; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill4"; } }; } return sectionFill4; } public final Paint getSectionFill5() { return null == sectionFill5 ? DEFAULT_SECTION_FILL_5 : sectionFill5.get(); } public final void setSectionFill5(Paint value) { sectionFill5Property().set(value); } public final ObjectProperty<Paint> sectionFill5Property() { if (null == sectionFill5) { sectionFill5 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_5) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_5; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill5"; } }; } return sectionFill5; } public final Paint getSectionFill6() { return null == sectionFill6 ? DEFAULT_SECTION_FILL_6 : sectionFill6.get(); } public final void setSectionFill6(Paint value) { sectionFill6Property().set(value); } public final ObjectProperty<Paint> sectionFill6Property() { if (null == sectionFill6) { sectionFill6 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_6) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_6; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill6"; } }; } return sectionFill6; } public final Paint getSectionFill7() { return null == sectionFill7 ? DEFAULT_SECTION_FILL_7 : sectionFill7.get(); } public final void setSectionFill7(Paint value) { sectionFill7Property().set(value); } public final ObjectProperty<Paint> sectionFill7Property() { if (null == sectionFill7) { sectionFill7 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_7) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_7; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill7"; } }; } return sectionFill7; } public final Paint getSectionFill8() { return null == sectionFill8 ? DEFAULT_SECTION_FILL_8 : sectionFill8.get(); } public final void setSectionFill8(Paint value) { sectionFill8Property().set(value); } public final ObjectProperty<Paint> sectionFill8Property() { if (null == sectionFill8) { sectionFill8 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_8) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_8; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill8"; } }; } return sectionFill8; } public final Paint getSectionFill9() { return null == sectionFill9 ? DEFAULT_SECTION_FILL_9 : sectionFill9.get(); } public final void setSectionFill9(Paint value) { sectionFill9Property().set(value); } public final ObjectProperty<Paint> sectionFill9Property() { if (null == sectionFill9) { sectionFill9 = new StyleableObjectProperty<Paint>(DEFAULT_SECTION_FILL_9) { @Override public CssMetaData getCssMetaData() { return StyleableProperties.SECTION_FILL_9; } @Override public Object getBean() { return this; } @Override public String getName() { return "sectionFill9"; } }; } return sectionFill9; } // ******************** Style related ************************************* @Override protected Skin createDefaultSkin() { return new SimpleLineChartSkin(this); } @Override protected String getUserAgentStylesheet() { return getClass().getResource("simplelinechart.css").toExternalForm(); } private static class StyleableProperties { private static final CssMetaData<SimpleLineChart, Paint> BULLET_FILL = new CssMetaData<SimpleLineChart, Paint>("-bullet-fill", PaintConverter.getInstance(), DEFAULT_BULLET_FILL) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.bulletFill || !chart.bulletFill.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.bulletFillProperty(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getBulletFill(); } }; private static final CssMetaData<SimpleLineChart, Paint> SERIES_STROKE = new CssMetaData<SimpleLineChart, Paint>("-series-stroke", PaintConverter.getInstance(), DEFAULT_SERIES_STROKE) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.seriesStroke || !chart.seriesStroke.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.seriesStrokeProperty(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSeriesStroke(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_0 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-0", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_0) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill0 || !chart.sectionFill0.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill0Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill0(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_1 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-1", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_1) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill1 || !chart.sectionFill1.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill1Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill1(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_2 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-2", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_2) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill2 || !chart.sectionFill2.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill2Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill2(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_3 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-3", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_3) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill3 || !chart.sectionFill3.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill3Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill3(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_4 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-4", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_4) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill4 || !chart.sectionFill4.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill4Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill4(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_5 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-5", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_5) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill5 || !chart.sectionFill5.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill5Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill5(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_6 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-6", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_6) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill6 || !chart.sectionFill6.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill6Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill6(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_7 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-7", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_7) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill7 || !chart.sectionFill7.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill7Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill7(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_8 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-8", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_8) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill8 || !chart.sectionFill8.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill8Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill8(); } }; private static final CssMetaData<SimpleLineChart, Paint> SECTION_FILL_9 = new CssMetaData<SimpleLineChart, Paint>("-section-fill-9", PaintConverter.getInstance(), DEFAULT_SECTION_FILL_9) { @Override public boolean isSettable(SimpleLineChart chart) { return null == chart.sectionFill9 || !chart.sectionFill9.isBound(); } @Override public StyleableProperty<Paint> getStyleableProperty(SimpleLineChart chart) { return (StyleableProperty) chart.sectionFill9Property(); } @Override public Paint getInitialValue(SimpleLineChart chart) { return chart.getSectionFill9(); } }; private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; static { final List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<>(Control.getClassCssMetaData()); Collections.addAll(styleables, BULLET_FILL, SERIES_STROKE, SECTION_FILL_0, SECTION_FILL_1, SECTION_FILL_2, SECTION_FILL_3, SECTION_FILL_4, SECTION_FILL_5, SECTION_FILL_6, SECTION_FILL_7, SECTION_FILL_8, SECTION_FILL_9); STYLEABLES = Collections.unmodifiableList(styleables); } } public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { return StyleableProperties.STYLEABLES; } @Override public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { return getClassCssMetaData(); } }