diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow-demo/src/main/java/com/vaadin/flow/component/charts/examples/other/GlobalOptions.java b/vaadin-charts-flow-parent/vaadin-charts-flow-demo/src/main/java/com/vaadin/flow/component/charts/examples/other/GlobalOptions.java new file mode 100644 index 0000000000..2a4a735d4b --- /dev/null +++ b/vaadin-charts-flow-parent/vaadin-charts-flow-demo/src/main/java/com/vaadin/flow/component/charts/examples/other/GlobalOptions.java @@ -0,0 +1,78 @@ +package com.vaadin.flow.component.charts.examples.other; + +import com.vaadin.flow.component.charts.AbstractChartExample; +import com.vaadin.flow.component.charts.Chart; +import com.vaadin.flow.component.charts.ChartOptions; +import com.vaadin.flow.component.charts.SkipFromDemo; +import com.vaadin.flow.component.charts.model.AxisType; +import com.vaadin.flow.component.charts.model.ChartType; +import com.vaadin.flow.component.charts.model.Configuration; +import com.vaadin.flow.component.charts.model.IntervalUnit; +import com.vaadin.flow.component.charts.model.Lang; +import com.vaadin.flow.component.charts.model.ListSeries; +import com.vaadin.flow.component.charts.model.PlotOptionsSeries; +import com.vaadin.flow.component.charts.model.Tooltip; +import com.vaadin.flow.component.charts.model.XAxis; +import com.vaadin.flow.component.charts.model.YAxis; +import com.vaadin.flow.component.html.NativeButton; + +@SkipFromDemo +public class GlobalOptions extends AbstractChartExample { + + @Override + public void initDemo() { + NativeButton changeTitleButton = new NativeButton(); + changeTitleButton.setId("add_chart"); + changeTitleButton.setText("Add chart"); + changeTitleButton.addClickListener(e -> { + final Chart chart = new Chart(); + + Configuration configuration = chart.getConfiguration(); + configuration.setTitle("First Chart for Flow"); + chart.getConfiguration().getChart().setType(ChartType.AREA); + Tooltip tooltip = configuration.getTooltip(); + tooltip.setEnabled(true); + tooltip.setShared(true); + + PlotOptionsSeries options = new PlotOptionsSeries(); + options.setPointStart(0); + options.setPointIntervalUnit(IntervalUnit.DAY); + configuration.setPlotOptions(options); + configuration.addSeries(new ListSeries("Tokyo", 20, 12, 34, 23, 65, + 8, 4, 7, 76, 19, 20, 8)); + configuration.addSeries(new ListSeries("Miami", 34, 29, 23, 65, 8, + 4, 7, 7, 59, 8, 9, 19)); + + XAxis x = new XAxis(); + x.setType(AxisType.DATETIME); + x.getLabels().setFormat("{value:%a}"); + configuration.addxAxis(x); + YAxis y = new YAxis(); + y.setMin(0); + y.setTitle("Rainfall (mm)"); + configuration.addyAxis(y); + add(chart); + }); + add(changeTitleButton); + + NativeButton changeLangButton = new NativeButton(); + changeLangButton.setId("change_lang"); + changeLangButton.setText("Change lang"); + changeLangButton.addClickListener(e -> { + Lang lang = new Lang(); + lang.setShortMonths(new String[] { "Tammi", "Helmi", "Maalis", + "Huhti", "Touko", "Kesä", "Heinä", "Elo", "Syys", "Loka", + "Marras", "Joulu" }); + lang.setMonths(new String[] { "Tammikuu", "Helmikuu", "Maaliskuu", + "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", + "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu" }); + lang.setWeekdays(new String[] { "Sunnuntai", "Maanantai", "Tiistai", + "Keskiviikko", "Torstai", "Perjantai", "Lauantai" }); + lang.setShortWeekdays( + new String[] { "su", "ma", "ti", "ke", "to", "pe", "la" }); + ChartOptions.get().setLang(lang); + }); + add(changeLangButton); + } + +} diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/main/java/com/vaadin/flow/component/charts/ui/MainView.java b/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/main/java/com/vaadin/flow/component/charts/ui/MainView.java index 3eb2086bb0..f42654e534 100644 --- a/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/main/java/com/vaadin/flow/component/charts/ui/MainView.java +++ b/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/main/java/com/vaadin/flow/component/charts/ui/MainView.java @@ -21,7 +21,6 @@ import com.vaadin.flow.component.Component; import com.vaadin.flow.component.charts.AbstractChartExample; import com.vaadin.flow.component.charts.examples.area.AreaChart; -import com.vaadin.flow.component.charts.examples.dynamic.ServerSideEvents; import com.vaadin.flow.component.dependency.StyleSheet; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.router.BeforeEvent; @@ -39,8 +38,6 @@ public class MainView extends Div implements HasUrlParameter { @Override public void setParameter(BeforeEvent event, @WildcardParameter String parameter) { - // workaround for https://github.com/vaadin/flow/issues/5509 - new ServerSideEvents(); removeAll(); Optional content = getContentFromParameter(parameter); if (content.isPresent()) { diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/test/java/com/vaadin/flow/component/charts/tests/GlobalOptionsIT.java b/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/test/java/com/vaadin/flow/component/charts/tests/GlobalOptionsIT.java new file mode 100644 index 0000000000..d8362ea938 --- /dev/null +++ b/vaadin-charts-flow-parent/vaadin-charts-flow-integration-tests/src/test/java/com/vaadin/flow/component/charts/tests/GlobalOptionsIT.java @@ -0,0 +1,84 @@ +/* + * #%L + * Vaadin Charts + * %% + * Copyright (C) 2014 Vaadin Ltd + * %% + * This program is available under Commercial Vaadin Add-On License 3.0 + * (CVALv3). + * + * See the file licensing.txt distributed with this software for more + * information about licensing. + * + * You should have received a copy of the CVALv3 along with this program. + * If not, see . + * #L% + */ +package com.vaadin.flow.component.charts.tests; + +import java.text.DateFormatSymbols; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.flow.component.charts.AbstractChartExample; +import com.vaadin.flow.component.charts.examples.other.GlobalOptions; +import com.vaadin.flow.component.charts.testbench.ChartElement; + +public class GlobalOptionsIT extends AbstractTBTest { + + @Override + protected Class getTestView() { + return GlobalOptions.class; + } + + @Test + public void addChart_defaultLangUsed() { + addChart(); + final ChartElement chart = getChartElement(); + assertAxisLabels(chart, Locale.ENGLISH); + } + + @Test + public void addChart_setLang_newLangUsed() { + addChart(); + final ChartElement chart = getChartElement(); + assertAxisLabels(chart, Locale.ENGLISH); + setLang(); + assertAxisLabels(chart, new Locale("fi")); + } + + @Test + public void setLang_addChart_newLangUsed() { + setLang(); + addChart(); + final ChartElement chart = getChartElement(); + assertAxisLabels(chart, new Locale("fi")); + } + + private void addChart() { + findElement(By.id("add_chart")).click(); + } + + private void setLang() { + findElement(By.id("change_lang")).click(); + } + + private void assertAxisLabels(ChartElement chart, Locale locale) { + WebElement container = chart.$("div").id("chart"); + List axisLabels = container.findElements( + By.cssSelector(".highcharts-xaxis-labels > text")); + List actual = axisLabels.stream().map(WebElement::getText) + .collect(Collectors.toList()); + List expected = Arrays + .asList(new DateFormatSymbols(locale).getShortWeekdays()); + Assert.assertTrue(expected.containsAll(actual)); + } + +} diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/pom.xml b/vaadin-charts-flow-parent/vaadin-charts-flow/pom.xml index b322eb4a01..45762df57d 100644 --- a/vaadin-charts-flow-parent/vaadin-charts-flow/pom.xml +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/pom.xml @@ -43,6 +43,11 @@ 3.1.0 test + + org.mockito + mockito-all + test + diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/Chart.java b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/Chart.java index 4c37588a64..21d03d9929 100644 --- a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/Chart.java +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/Chart.java @@ -70,7 +70,7 @@ import elemental.json.impl.JreJsonFactory; @Tag("vaadin-chart") -@NpmPackage(value="@vaadin/vaadin-charts", version = "7.0.0-alpha2") +@NpmPackage(value="@vaadin/vaadin-charts", version = "7.0.0-alpha3") @JsModule("@vaadin/vaadin-charts/vaadin-chart.js") public class Chart extends Component implements HasStyle, HasSize { diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/ChartOptions.java b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/ChartOptions.java new file mode 100644 index 0000000000..2152c71b0f --- /dev/null +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/ChartOptions.java @@ -0,0 +1,110 @@ +package com.vaadin.flow.component.charts; + +import java.util.Objects; + +import com.vaadin.flow.component.ComponentUtil; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.charts.model.AbstractConfigurationObject; +import com.vaadin.flow.component.charts.model.Lang; +import com.vaadin.flow.component.charts.util.ChartSerialization; + +import elemental.json.JsonObject; +import elemental.json.impl.JreJsonFactory; + +/** + * The ChartOptions configures a page local global options like localized texts + * for charts. + *

+ * Use {@link ChartOptions#get()} or {@link ChartOptions#get(UI)} to get an + * instance for the current or specified {@link UI}. + */ +public class ChartOptions extends AbstractConfigurationObject { + + private Lang lang; + private transient JreJsonFactory jsonFactory; + + protected ChartOptions() { + } + + private JreJsonFactory getJsonFactory() { + if (jsonFactory == null) { + jsonFactory = new JreJsonFactory(); + } + return jsonFactory; + } + + private void updateOptions() { + UI ui = UI.getCurrent(); + + if (ui == null) { + return; + } + + JsonObject configurationNode = getJsonFactory() + .parse(ChartSerialization.toJSON(this)); + ui.getElement().executeJs( + "customElements.get('vaadin-chart').__callHighchartsFunction('setOptions',$0,$1)", + true, configurationNode); + } + + /** + * Changes the language of all charts. + * + * @param lang + */ + public void setLang(Lang lang) { + this.lang = lang; + updateOptions(); + } + + /** + * Returns the {@link Lang} in use or {@code null} if no lang configuration + * has been set. + * + * @return the {@link Lang} in use or {@code null}. + */ + public Lang getLang() { + return lang; + } + + /** + * Returns a ChartOptions instance for the given UI. If a ChartOptions + * extension has not yet been added, a new one is created and added. + * + * @param ui + * the UI for which the ChartOptions should be returned, not + * null + * @return the ChartOptions instance connected to the given UI + */ + public static ChartOptions get(UI ui) { + Objects.requireNonNull(ui, "Given root items may not be null"); + + ChartOptions options = ComponentUtil.getData(ui, ChartOptions.class); + + // Create new options if not found + if (options == null) { + options = new ChartOptions(); + ComponentUtil.setData(ui, ChartOptions.class, options); + } + + return options; + + } + + /** + * Returns a ChartOptions instance for the current UI. If a ChartOptions extension + * has not yet been added, a new one is created and added. + * + * @return a ChartOptions instance connected to the currently active UI + */ + public static ChartOptions get() { + UI ui = UI.getCurrent(); + + if (ui == null) { + throw new IllegalStateException( + "This method must be used from UI thread"); + } + return get(ui); + } + +} diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Configuration.java b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Configuration.java index 51090d132a..2cd1e6fc4c 100644 --- a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Configuration.java +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Configuration.java @@ -69,6 +69,7 @@ public class Configuration extends AbstractConfigurationObject private Navigation navigation; private NoData noData; private Navigator navigator; + private Time time; @JsonIgnore private final List changeListeners = new ArrayList<>(); @@ -822,6 +823,22 @@ public void setNavigator(Navigator navigator) { this.navigator = navigator; } + /** + * @see #setTime(Time) + */ + public Time getTime() { + return time; + } + + /** + * Set configuration for time options + * + * @param time + */ + public void setTime(Time time) { + this.time = time; + } + /** * Reverses the ListSeries (transposes it such that categories would be * series names and vice versa) to help stacking diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Time.java b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Time.java new file mode 100644 index 0000000000..93e1c0b81a --- /dev/null +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/src/main/java/com/vaadin/flow/component/charts/model/Time.java @@ -0,0 +1,75 @@ +package com.vaadin.flow.component.charts.model; + +/*- + * #%L + * Vaadin Charts for Flow + * %% + * Copyright (C) 2014 - 2019 Vaadin Ltd + * %% + * This program is available under Commercial Vaadin Add-On License 3.0 + * (CVALv3). + * + * See the file licensing.txt distributed with this software for more + * information about licensing. + * + * You should have received a copy of the CVALv3 along with this program. + * If not, see . + * #L% + */ + +import javax.annotation.Generated; + +/** + * These settings affect how datetime axes are laid out, how tooltips are + * formatted, how series pointIntervalUnit works and how the Highstock range + * selector handles time. + */ +@Generated(value = "This class is generated and shouldn't be modified", comments = "Incorrect and missing API should be reported to https://github.com/vaadin/vaadin-charts-flow/issues/new") +public class Time extends AbstractConfigurationObject { + + private Number timezoneOffset; + private Boolean useUTC; + + public Time() { + } + + /** + * @see #setTimezoneOffset(Number) + */ + public Number getTimezoneOffset() { + return timezoneOffset; + } + + /** + * The timezone offset in minutes. Positive values are west, negative values + * are east of UTC, as in the ECMAScript getTimezoneOffset method. Use this to display UTC based data in a + * predefined time zone. + *

+ * Defaults to: 0 + */ + public void setTimezoneOffset(Number timezoneOffset) { + this.timezoneOffset = timezoneOffset; + } + + /** + * @see #setUseUTC(Boolean) + */ + public Boolean getUseUTC() { + return useUTC; + } + + /** + * Whether to use UTC time for axis scaling, tickmark placement and time + * display in Highcharts.dateFormat. Advantages of using UTC is + * that the time displays equally regardless of the user agent's time zone + * settings. Local time can be used when the data is loaded in real time or + * when correct Daylight Saving Time transitions are required. + *

+ * Defaults to: true + */ + public void setUseUTC(Boolean useUTC) { + this.useUTC = useUTC; + } +} diff --git a/vaadin-charts-flow-parent/vaadin-charts-flow/src/test/java/com/vaadin/flow/component/charts/ChartOptionsJSONSerializationTest.java b/vaadin-charts-flow-parent/vaadin-charts-flow/src/test/java/com/vaadin/flow/component/charts/ChartOptionsJSONSerializationTest.java new file mode 100644 index 0000000000..10d32fba91 --- /dev/null +++ b/vaadin-charts-flow-parent/vaadin-charts-flow/src/test/java/com/vaadin/flow/component/charts/ChartOptionsJSONSerializationTest.java @@ -0,0 +1,82 @@ +package com.vaadin.flow.component.charts; + +import static com.vaadin.flow.component.charts.util.ChartSerialization.toJSON; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.charts.model.Lang; +import com.vaadin.flow.component.charts.util.ChartSerialization; + +@RunWith(MockitoJUnitRunner.class) +public class ChartOptionsJSONSerializationTest { + + @Mock + private UI ui; + + private ChartOptions options; + + @Before + public void setup() { + options = ChartOptions.get(ui); + } + + @Test + public void toJSON_NoLang_EmptyJsonSerialized() { + assertEquals("{}", toJSON(options)); + } + + @Test + public void toJSON_LangWithFinnishLocale_LocaleSerialized_Months() throws IOException { + final String[] fiMonths=new String[] {"Tammikuu", "Helmikuu", "Maaliskuu", + "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", + "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu"}; + final Lang fi = new Lang(); + fi.setMonths(fiMonths); + + options.setLang(fi); + String json = toJSON(options); + ObjectMapper om = ChartSerialization.createObjectMapper(); + ChartOptions chartOptions = om.readValue(json, ChartOptions.class); + + Assert.assertArrayEquals(fiMonths, chartOptions.getLang().getMonths()); + } + + @Test + public void toJSON_LangWithFinnishLocale_LocaleSerialized_ShortMonths() throws IOException { + final String[] fiShortMonths=new String[]{"Tammi", "Helmi", "Maalis", "Huhti", + "Touko", "Kesä", "Heinä", "Elo", "Syys", "Loka", "Marras", + "Joulu"}; + final Lang fi = new Lang(); + fi.setShortMonths(fiShortMonths); + options.setLang(fi); + String json = toJSON(options); + ObjectMapper om = ChartSerialization.createObjectMapper(); + ChartOptions fromJson = om.readValue(json, ChartOptions.class); + + Assert.assertArrayEquals(fiShortMonths, fromJson.getLang().getShortMonths()); + } + + @Test + public void toJSON_LangWithFinnishLocale_LocaleSerialized_Days() throws IOException { + final String[] fiDays=new String[]{"Ma", "Ti", "Ke", "To", "Pe", "La", "Su"}; + final Lang fi = new Lang(); + fi.setWeekdays(fiDays); + + options.setLang(fi); + String json = toJSON(options); + ObjectMapper om = ChartSerialization.createObjectMapper(); + ChartOptions chartOptions = om.readValue(json, ChartOptions.class); + + Assert.assertArrayEquals(fiDays, chartOptions.getLang().getWeekdays()); + } +} \ No newline at end of file