commit 2f97305223c38183574c34b42c1dc582477e18c4 Author: zhongjin Date: Fri Sep 14 13:57:28 2018 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa2e80b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.idea +node_modules +src/i18n/flat.txt +src/i18n/*/flat.txt +www +package-lock.json +iob_npm.done +tmp + diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..323ba42 --- /dev/null +++ b/.npmignore @@ -0,0 +1,9 @@ +gulpfile.js +src +.idea +node_modules +.git +test +.travis.yml +iob_npm.done +appveyor.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c05adf9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +os: + - linux +language: node_js +node_js: + - '4' + - '8' + - '10' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0b7336a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 bluefox + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e811ea --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +![Logo](admin/flot.png) +# yunkong2.flot +================= + +[![NPM version](http://img.shields.io/npm/v/yunkong2.flot.svg)](https://www.npmjs.com/package/yunkong2.flot) +[![Downloads](https://img.shields.io/npm/dm/yunkong2.flot.svg)](https://www.npmjs.com/package/yunkong2.flot) + +[![NPM](https://nodei.co/npm/yunkong2.flot.png?downloads=true)](https://nodei.co/npm/yunkong2.flot/) + +Draw charts with [flot](http://www.flotcharts.org/) + +![Example](img/example.png) +![Example](img/screen1.jpg) +![Example](img/screen2.jpg) +![Example](img/screen3.jpg) +![Example](img/screen4.jpg) +![Example](img/screen5.jpg) +![Example](img/screen6.jpg) +![Example](img/screen7.jpg) + +To use the charts one of the history adapters is required: history, sql or InfluxDB + +To **edit** created chart again, you should replace index.html with edit.html and call this link in browser, e.g: + +http://localhost:8082/flot/**index**.html?l%5B0%5D%5Bid%5D=system.adapter.admin.0.memRss + +to + +http://localhost:8082/flot/**edit**.html?l%5B0%5D%5Bid%5D=system.adapter.admin.0.memRss + +## How to use +- install "web"-adapter and create one instance if not installed. +- Select in settings of "web"-adapter the instance of installed "socket.io"-instance. +- install "flot"-adapter and call +- Go to http://ip:8082/flot/edit.html + +## Changelog + +### 1.9.2 (2018-08-18) +* (Seqway) Translations + +### 1.9.1 (2018-06-04) +* (bluefox) Added dashed lines +* (bluefox) All JS files together are concatenated +* (bluefox) Show days of week (dow) in time axis. + +### 1.8.0 (2018-05-04) +* (bluefox) Optimize communication + +### 1.7.9 (2018-05-01) +* (bluefox) Added support of multi-languages in names + +### 1.7.7 (2018-03-04) +* (Apollon77) fix month range + +### 1.7.6 (2018-02-16) +* (Apollon77) remove alert windows from errors, log instead + +### 1.7.5 (2018-01-13) +* (bluefox) try to fix small error + +### 1.7.4 (2018-01-05) +* (bluefox) The loading via cloud is fixed + +### 1.7.1 (2017-12-14) +* (bluefox) Fixed the loading of presets +* (bluefox) Added new date formats for X axis + +### 1.7.0 (2017-10-17) +* (bluefox) Add presets + +### 1.6.2 (2017-08-12) +* (bluefox) Show chart at start + +### 1.6.1 (2017-03-25) +* (bluefox) Change edit layout + +### 1.5.9 (2017-02-27) +* (bluefox) New color picker +* (bluefox) If 'none' for title selected => do not show any title +* (bluefox) add date format 'dd.mm.' + +### 1.5.8 (2017-02-01) +* (bluefox) Add series as X ticks + +### 1.5.7 (2017-01-26) +* (bluefox) Small fix in smoothing algorithm + +### 1.5.6 (2016-11-04) +* (bluefox) fix marking line + +### 1.5.4 (2016-10-13) +* (bluefox) remove area, line plot +* (bluefox) add fill value, points option + +### 1.5.3 (2016-10-08) +* (bluefox) Allow using of IDs in the marking +* (bluefox) Support of filled markings + +### 1.5.2 (2016-09-30) +* (bluefox) fix range and offset if month or year +* (bluefox) fix after comma settings + +### 1.5.1 (2016-09-15) +* (bluefox) Filter IDs depends on storage instance + +### 1.5.0 (2016-09-10) +* (bluefox) Support of marking lines + +### 1.4.0 (2016-08-30) +* (bluefox) support bar chart (only one bar chart possible) + +### 1.3.5 (2016-08-14) +* (bluefox) support of web-sockets force + +### 1.3.4 (2016-07-23) +* (nobodyMO) Add app support +* (nobodyMO) Fix for jquery to the current version in vis + +### 1.3.3 (2016-06-16) +* (bluefox) remove RTL direction in id field + +### 1.3.2 (2016-06-13) +* (bluefox) add settings for border color and border width +* (bluefox) make splines work + +### 1.3.1 (2016-06-07) +* (bluefox) add spline file + +### 1.3.0 (2016-05-29) +* (bluefox) add animation +* (bluefox) remove smoothing, because does not work +* (bluefox) try to add splines, but it does not work always + +### 1.2.5 (2016-05-28) +* (bluefox) do not include nulls by smoothing + +### 1.2.4 (2016-05-27) +* (bluefox) show edit button + +### 1.2.3 (2016-05-25) +* (bluefox) fix digits after comma +* (bluefox) fix start and finish points + +### 1.2.2 (2016-05-22) +* (bluefox) change default aggregation name +* (bluefox) add units in tooltip + +### 1.2.1 (2016-05-13) +* (bluefox) implement loading indicator + +### 1.2.0 (2016-05-05) +* (bluefox) implement zoom and pan +* (bluefox) support ms +* (bluefox) support m4 +* (bluefox) support of pan and zoom on touchable devices +* (bluefox) support of 3 types of "null" handling: use nulls, use last value instead of null, use 0 instead of 0 +* (bluefox) update interval in seconds +* (bluefox) smoothing and "after comma" per variable + +### 1.1.0 (2016-04-09) +* (bluefox) change splash screen +* (bluefox) ignoreNull per variable +* (bluefox) fix x axis + +### 1.0.0 (2016-04-09) +* (bluefox) enable editing of created charts +* (bluefox) enable set of label colors +* (bluefox) enable set of window background + +### 0.2.6 (2016-02-24) +* (Pmant) remove ignore null per state + +### 0.2.5 (2016-02-14) +* (Pmant) add ignore null per state +* (Pmant) change commonYAxis per state + +### 0.2.4 (2016-01-31) +* (ldsign) Title/help attribute for lineWidth and ShadowSize table head +* (ldsign) option for shadowSize +* (nobodyMO) Add option commonYAxis +* (bluefox) add favicon and title + +### 0.2.3 (2016-01-26) +* (ldsign) user selectable time (hours/minutes) for static timeArt + +### 0.2.2 (2015-12-17) +* (bluefox) fix SelectID for safary + +### 0.2.1 (2015-12-14) +* (Smiling_Jack) support of new History concept +* (Smiling_Jack) new editor & working on axis +* (bluefox) add onchange aggregation +* (Smiling_Jack) add ignoreNull +* (Smiling_Jack) working on flot nav +* (bluefox) import old settings + +### 0.1.1 (2015-07-13) +* (bluefox) fix time format + +### 0.1.0 (2015-07-10) +* (bluefox) lines are implemented + +### 0.0.2 (2015-07-09) +* (bluefox) implement title and sort points + +### 0.0.1 (2015-03-27) +* (bluefox) initial commit + + +## License +The MIT License (MIT) + +Copyright (c) 2014-2018 bluefox \ No newline at end of file diff --git a/admin/flot.png b/admin/flot.png new file mode 100644 index 0000000..42987bd Binary files /dev/null and b/admin/flot.png differ diff --git a/docs/de/flot.md b/docs/de/flot.md new file mode 100644 index 0000000..ffe596b --- /dev/null +++ b/docs/de/flot.md @@ -0,0 +1,456 @@ +# flot + +Der Adapter dient der grafischen Darstellung von Messwerten. Mit ihm kann man die mit einem History-Adapter geloggten Daten visualisieren. Zum einen direkt beim Aufruf eines geloggten Datenpunktes über das History Icon im Reiter Objects, er kann jedoch auch als eigenständige Applikation zur gleichzeitigen Darstellung mehrerer Datenpunkte benutzt werden. + +[![](img/flot-2_yunkong2_Adapter_Flot_001.jpg)](img/flot-2_yunkong2_Adapter_Flot_001.jpg)Ein so generierter Chart kann in einem iFrame-Widget in .vis dargestellt werden + + + + +* * * + +# [](https://github.com/yunkong2/yunkong2/wiki/yunkong2-Adapter-rickshaw#konfiguration)**Konfiguration** + +[![](img/flot-2_yunkong2_Adapter_Flot_000.jpg)](img/flot-2_yunkong2_Adapter_Flot_000.jpg) Eine Konfiguration ist nicht nötig. Hier wird deswegen auch das Konfigurationsmenü nicht angeboten. + +* * * + +# [](https://github.com/yunkong2/yunkong2/wiki/yunkong2-Adapter-rickshaw#bedienung)**Bedienung** + +Der Editor des Flot-Adapters wird über `:8082/flot/edit.html/` oder über den Hyperlink im Reiter Instanzen des admin-Adapter aufgerufen. + +Die Eingabefelder gliedern sich in 4 Blöcke: + +####  [![](img/flot-2_yunkong2_Adapter_Flot_Groups.jpg)](img/flot-2_yunkong2_Adapter_Flot_Groups.jpg) + +## [](https://github.com/yunkong2/yunkong2/wiki/yunkong2-Adapter-rickshaw#input-data)**Input data (1)** + +Die aktuell installierte Version wird oben rechts angezeigt. + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data.jpg) + +### Einstellungen löschen (Mülleimer) + +Löscht alle Eingaben in diesem Chart. Wenn man /flot/edit.html/ aufruft wird üblicherweise das zuletzt bearbeitete Projekt in dem Editor aufgerufen. Will man jedoch einen ganz anderen Chart erstellen, kann man mit diesem Button alle Einstellungen auf Standardwerte zurücksetzen. + +### Linie hinzufügen + +Eine weitere Zeile wird in der darunterliegenden Tabelle am Ende eingefügt. Diese bekommt eine weitere Farbe zugewiesen. + +### Auto update + +Wenn das Vorschaubild in der unteren Hälfte der Seite bei jeder Änderung aktualisiert werden soll, muss diese Checkbox aktiviert werden. Bei sehr komplexen Charts kann dies einige Zeit dauern. Standardmäßig ist diese Checkbox nicht aktiviert. + +Wenn die Checkbox aktiviert ist, verschwindet der Button **_Update Preview_** rechts über dem Vorschaufenster, über den ansonsten die Vorschau aktualisiert werden würde. + +### Platziere Booleans + +Mit diesem Button wird der Graph in mehrere vertikal übereinanderliegende Abschnitte unterteilt, in denen jeweils der Zustand eines Datenpunktes dargestellt wird. Dies dient der besseren Übersicht bei bool'schen Datenpunkten (on/off; true/false) + +### Datenpunktparameter + +In der folgenden Tabelle werden die Parameter festgelegt mit der die jeweiligen Datenpunkte dargestellt werden sollen + +#### Instanz + +Hier wird festgelegt aus welcher History-Instanz die geloggten Daten für den Graph entnommen werden sollen. + + +![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Instanz.jpg) + + +default bezieht sich auf die in den Systemeinstellungen festgelegte Default-Instanz zur Datensammlung. Die weiteren Punkte entsprechen den installierten Instanzen. + +#### ID + +Hier wird der darzustellende Datenpunkt ausgewählt. Der Datenpunkt muss im Reiter _**Objekte**_ des Adapter _**Admin**_ mit der unter _**Instanz**_ ausgewählten History-Instanz geloggt werden. + +#### Art + +Hier findet die Auswahl der Art und Weise der Darstellung der Datenpunkte in der Linie statt + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Art.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Art.jpg) + +**-minmax (default):** Es werden sowohl der höchste, als auch der niedrigste Wert innerhalb des Aggregationsintervalls angezeigt + +**-mittel:**  Es wird der Mittelwert innerhalb des Aggregationsintervalls angezeigt + +**-min:**  Es wird sowohl der niedrigste Wert innerhalb des Aggregationsintervalls angezeigt + +**-max:**  Es wird der höchste Wert innerhalb des Aggregationsintervalls angezeigt + +**-total:**  Es wird der ??? Wert innerhalb des Aggregationsintervalls angezeigt + + **-bei Änderung:** Es werden nur Werte angezeigt, wenn sich der Wert ändert + +#### Chart Type + +Hier wird festgelegt in welcher Form die Daten dargestellt werden sollen. + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Chart_Type.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Chart_Type.jpg) + +**Linie:** Die Daten werden als Linien dargestellt. Die einzelnen Punkte werden als Gerade miteinander verbunden. + +**Bar:** Jeder einzelne Messpunkt der Daten wird als vertikaler Balken dargestellt. Diese Darstellung empfiehlt sich nur bei wenigen Messpunkten. + +**Scatter plot:** Die Daten werden als isolierte Punkte dargestellt. Die einzelnen Punkte werden nicht miteinander verbunden. + +**Schritte:** Die Daten werden als Linien dargestellt. Die einzelnen Punkte werden bis zur nächsten Änderung horizontal als Gerade miteinander verbunden. Zum Zeitpunkt der Änderung wird eine Stufe eingelegt. + +**Spline:** Die Daten werden als Linien dargestellt. Die einzelnen Punkte werden als gebogene Kurve miteinander verbunden. + +#### Füllen (0-1) + +Hier kann festgelegt werden, ob zwischen der gezeichneten Linie und der X-Achse (oder der Linie durch 0) eine Fläche gezeichent werden soll. Mit einem Wert zwischen 0 und 1 (z.B. 0.4) wird die Deckung der Farbe angegeben (0=transparent; 1= deckend). + +#### Punkte + +Sollen zusätzlich zur Linie auch noch die Messpunkte hervorgehoben werden, kann man diese Checkbox anhaken. + +#### Farbe + +Die Farbe mit der die Daten für diesen Datenpunkt angezeigt werden sollen kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Min + +Hier kann der Mindestwert für die Y-Achse eingegeben werden. Wird kein Wert eingegeben wird die Achse dynamisch skaliert. + +#### Max + +Hier kann der Höchstwert für die Y-Achse eingegeben werden. Wird kein Wert eingegeben wird die Achse dynamisch skaliert. + +#### Einheiten + +Hier kann eine Einheit für die Skalierung der Y-Achse angegeben werden + +#### Y-Achse + +Es gibt mehrere Möglichkeiten, wie die Y-Achse jedes Datenpunktes dargestellt werden kann. Standardmäßig wird für jeden Datenpunkt eine eigene Y-Achse gezeichnet. Dies kann jedoch leicht unübersichtlich werden. Daher gibt es die folgenden Optionen. + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Y_Achse.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data_Y_Achse.jpg) + +**-nichts:** für diesen Datenpunkt soll keine eigene Y-Achse gezeichnet werden. + +**-links:** die Y-Achse für diesen Datenpunkt soll links von dem Chart gezeichnet werden + +**-rechts:** die Y-Achse für diesen Datenpunkt soll rechts von dem Chart gezeichnet werden + +**-links farblich:** die Y-Achse für diesen Datenpunkt soll links von dem Chart in der Farbe des Datenpunktes gezeichnet werden + +**-rechts farblich:** die Y-Achse für diesen Datenpunkt soll rechts von dem Chart in der Farbe des Datenpunktes gezeichnet werden + +#### X-Achse + +Es gibt mehrere Möglichkeiten, wie die X-Achse jedes Datenpunktes dargestellt werden kann. Standardmäßig wird für jeden Datenpunkt eine eigene X-Achse gezeichnet. Dies kann jedoch leicht unübersichtlich werden. Daher gibt es die folgenden Optionen. + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_X_Achse.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data_X_Achse.jpg) + +**-nichts:** für diesen Datenpunkt soll keine eigene Y-Achse gezeichnet werden. + +**-oben:** die X-Achse für diesen Datenpunkt soll über dem Chart gezeichnet werden + +**-unten:** die X-Achse für diesen Datenpunkt soll unter dem Chart gezeichnet werden + +**-oben farblich:** die X-Achse für diesen Datenpunkt soll über dem Chart in der Farbe des Datenpunktes gezeichnet werden + +**-unten farblich:** die X-Achse für diesen Datenpunkt soll unter dem Chart in der Farbe des Datenpunktes gezeichnet werden + +#### Name + +Hier kann eine Bezeichnung für den Datenpunkt festgelegt werden, die auch in der Legende angezeigt wird. Wird hier nichts eingegeben wird die vollständige Datenpunktbezeichnung verwendet. + +#### mehr + +Hinter diesem Icon verbergen sich weitere Einstellungen + +[![](img/flot-2_yunkong2_Adapter_Flot_Input_Data_more.jpg)](img/flot-2_yunkong2_Adapter_Flot_Input_Data_more.jpg) + +**X-Offset:** Um die Kurve von der Y-Achse abzusetzen, kann hier ein Wert eingegeben werden um welchen Betrag diese Absetzung durchgeführt werden soll. + +**Y-Offset:** Um die Kurve von der X-Achse abzusetzen, kann hier ein Wert eingegeben werden um welchen Betrag diese Absetzung durchgeführt werden soll. Dadurch wird u.a. verhindert, dass die Linienstärke die X-Achse überlagert + +**X-Achse Ticks:** Anzahl der Markierungen der X-Achse + +**Y-Achse Ticks: **Anzahl der Markierungen der Y-Achse + +**ØL:** Dicke der Linie in Pixeln + +**ØS:** Dicke des Schattens in Pixeln + +**Gemeinsame Y-Achse:** default = jede Linie eine eigene Achse, jede Ziffer steht für die entsprechende Linie + +**NULL als:** Hier wird festgelegt wie die Linie gezeichnet werden soll, wenn keine Daten vorliegen. + +default: keine Linie; + +null-Werte ignorieren: Linie wird horizontal weitergeführt + +0 statt null benutzen: die Linie wird auf den Wert 0 gezogen. + +**Smoothing:** Glättung der Kurve. Im Prinzip wird ein gleitender Mittelwert über die eingestellte Anzahl Punkte gezogen. + +**Nach Komma:** Anzahl der Nachkommastellen. + +#### Datenpunkt löschen (Mülleimer) + +Mit einem Klick auf dieses Icon wird die gesamte Zeile der Tabelle mit allen Einstellungen gelöscht. + +## Markierungen (2) + +Mit dieser Option können horizontale Linien in einen Chart eingetragen werden um Schwellwerte darzustellen. Die Markierungen können auch Bereiche (z.B. Wohlfühlbereich bei Temperatur oder Luftfeuchte) anzeigen. Dann muss ein obererer und unterer Trigger angegeben werden. +![](img/flot-2_yunkong2_Adapter_Flot_Markierungen.jpg) + + +### Neue Markierung hinzufügen + +Mit einem Klick auf diese Schaltfläche wird in der darunterliegenden Tabelle eine weitere Reihe eingefügt, um eine weitere Markierung zu definieren. + +### Markierungsparameter + +Die Eigenschaften einer ausgewählten Markierung werden in je einer Zeile festgelegt: + +#### Linie ID + +Hier wird eine Datenreihe aus dem Chart ausgewählt. Dies ist nötig, damit die Markierung sich an den Werten der zugehörigen Y-Achse orientiert. + +#### Oberer Wert oder ID + +Hier wird wahlweise ein absoluter Wert oder ein Datenpunkt, der als Trigger für die obere Grenze des Bereichs gelten soll, eingegeben. Der Datenpunkt kann über den Objekt-Explorer gesucht werden. + +#### Unterer Wert oder ID + +Hier wird wahlweise ein absoluter Wert oder ein Datenpunkt, der als Trigger für die untere Grenze des Bereichs gelten soll, eingegeben. Der Datenpunkt kann über den Objekt-Explorer gesucht werden. + +#### Farbe + +Die Farbe mit der die Linien für diese Markierung angezeigt werden sollen kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Füllen + +Hier kann festgelegt werden, ob zwischen den gezeichneten Linie, bzw. zwischen der Linie und der X-Achse (oder der Linie durch 0) eine Fläche gezeichnet werden soll. + +#### ØL + +Dicke der Linie in Pixeln + +#### ØS + +Dicke des Schattens in Pixeln + +#### Text + +Hier kann eine Information zu der Markierung eingegeben werden, die im Chart erscheint. + +#### Textposition + +Man kann festlegen, ob diese Information an der rechten oder linken Y-Achse angezeigt werden soll. + +#### Textoffset + +Dies ist der Abstand zur Markierungslinie. Der Wert kann positiv oder negativ angegeben werden. + +#### Textgröße + +Textgröße in px. Auch eine Angabe in pt ist möglich + +#### Textfarbe + +Die Farbe mit der die Information zu dieser Markierung angezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +## Zeit (3) + + +![](img/flot-2_yunkong2_Adapter_Flot_Zeit-e1484938214253.jpg) + + +### Zeitspanne + +#### Art + +Hier kann man zwischen statisch und relativ auswählen. + +[![](img/flot-2_yunkong2_Adapter_Flot_Zeit_statisch.jpg)](img/flot-2_yunkong2_Adapter_Flot_Zeit_statisch.jpg) + +Bei statisch werden fixe Zeitpunkte definiert, bei relativ die Zeitbereiche zu einem variablen Zeitpunkt, wie z.B. _**heute**_. + +#### Ende + +Dieser Punkt kann je nach Einstellung in dem darüber liegenden Punkt _**Art**_ ein fester Zeitpunkt oder im Falle dass relativ ausgewählt wurde ein variabler wiederholender Zeitpunkt sein. + + +![](img/flot-2_yunkong2_Adapter_Flot_Zeit_relativ_Ende.jpg) + + +#### Range + +Hier wird der Zeitbereich (die Dauer) eingegeben, über die die X-Achse die Daten anzeigen soll. + +[![](img/flot-2_yunkong2_Adapter_Flot_Zeit_relativ_Range.jpg)](img/flot-2_yunkong2_Adapter_Flot_Zeit_relativ_Range.jpg) + +#### Autoupdate alle: + +Mit diesem Wert wird festgelegt, wie oft sich die Darstellung der Datenpunkte in dem Chart automatisch updaten soll: + +[![](img/flot-2_yunkong2_Adapter_Flot_Zeit_autoupdate.jpg)](img/flot-2_yunkong2_Adapter_Flot_Zeit_autoupdate.jpg) + +Wenn z.B. bei Homematic Funksensoren sich die Daten sowieso nur alle 3 Minuten ändern ist ein häufigerer Refresh nicht nötig. + +### Aggregation + +Dieser Punkt dient der Verringerung der Datenmenge in dem Chart. Es kann die Anzahl der geloggten Punkte pro Datenpunkt festgelegt werden (Anzahl) oder der zeitliche Abstand der einzelnen Punkte in Sekunden. + +## Options (4) + +Der vierte Block enthält jede Menge Zusatzoptionen um ein Chart ansehnlich zu gestalten [![](img/flot-2_yunkong2_Adapter_Flot_Options_all.jpg)](img/flot-2_yunkong2_Adapter_Flot_Options_all.jpg) + +### Erscheinung + +#### Breite + +Gibt an wie breit der Chart dargestellt werden soll. Angabe in px. + +#### Höhe + +Gibt an wie hoch der Chart dargestellt werden soll. Angabe in px. + +#### kein Rahmen + +Auswahl, ob ein Rahmen um die gesamte Fläche von Chart, Achsen und deren Beschriftung gezeichnet werden soll + +#### Fenster-Hintergrund + +Die Farbe mit der dieses Fenster gefüllt werden sollen kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. Dieser Parameter bezieht sich auf die gesamte Fläche inkl. der Achsen mit ihren Beschriftungen. + +#### Anwender Chart-Hintergrund + +Wird diese Checkbox aktiviert, verschwindet die darunter liegende Pulldownmenü und statt dessen erscheint ein Eingabefeld. + +#### Chart-Hintergrund + +Dieser Parameter bezieht sich nur auf den Hintergrund des eigentlichen Charts. Ist die Checkbox darüber aktiviert kann hiereine eigene Beschreibung oder rgb(a) Farbe eingegeben werden. Wenn nicht, kann in dem Pulldownmenü unter verschiedenen vorgefertigten Hintergründen gewählt werden. + +#### Y-Beschriftungsfarbe + +Die Farbe mit der die Beschriftung der Y-Achse gezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +Diese Farbe gilt nicht, wenn in der Datenpunktbeschreibung _**Y-Achse rechts/links farblich**_ gewählt wurde. + +#### X-Beschriftungsfarbe + +Die Farbe mit der die Beschriftung der X-Achse gezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +Diese Farbe gilt nicht, wenn in der Datenpunktbeschreibung **_X-Achse rechts/links farblich_** gewählt wurde. + +#### Rahmenfarbe + +Die Farbe mit der der Rahmen um den eigentlichen Chart gezeichnet werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Gitterfarbe + +Die Farbe mit der das Gitter auf dem Chart-Hintergrund gezeichnet werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Rahmenbreite + +Angabe der Rahmenbreite, die um den Chart-Hintergrund gezeichnet werden soll. Angabe in px. + +### Bar-Einstellungen + +Die hier eingegeben Werte gelten nur, wenn der Chart Typ auf Bar gestellt ist. + +#### Füllfarbe + +Die Farbe mit der eine Füllung der Balken gezeichnet werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Zeige Labels + +Soll die Bezeichnung der Datenpunkte an den Balken angezeigt werden kann man hier die Position dieser Bezeichnung bestimmen. + +**nichts:** keine Bezeichnung + +**oben über:** oberhalb des Balkens + +**oben unten:** oben innerhalb des Balkens unter der Oberkante + +**unten:** unten im Balken + +**mittig:** auf halber Höhe im Balken + +#### Barbreite + +Angabe der Balkenbreite in px + +#### Labelschriftgröße + +Angabe der Schriftgröße in px + +#### Labelfarbe + +Die Farbe mit der die Bezeichnung der Balken gezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +### Beschriftung + +In dieser Kategorie geht es um die mögliche Beschriftung des Charts + +#### Beschriftung + +Hier wird eine Beschriftung festgelegt, die im oder am Chart erscheinen soll eingegeben. In den meisten Fällen wird dies der Titel des Charts sein. + +#### Beschriftungsposition + +Der Titel kann an verschiedenen Stellen des Charts platziert werden. Diese sind über das Pulldownmenü verfügbar. + +#### Titelfarbe + +Die Farbe mit der Titel des Charts gezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Titelgröße + +Die Schriftgröße der Beschriftung kann in % einer Standardgröße, in px oder in pt angegeben werden. Soll der Chart später in einem skalierbaren Fenster dargestellt werden empfiehlt sich die Größenangabe in %. + +### Options + +In dieser Kategorie werden zusätzliche Items und Features konfiguriert um dem Chart den letzten Schliff zu geben. + +#### Zeige Legende + +Hier wird ausgewählt ob eine Legende angezeigt werden soll und wenn ja, wo diese platziert wird. Damit die Legende nicht die Kurven verdeckt, ist die Position sinnvollerweise davon abhängig wie der Chart aufgebaut ist. + +#### Spalten in Legende + +Bei sehr vielen Datenpunkten bietet es sich an, die Datenpunkte in der Legende in mehreren Spalten anzuzeigen. + +#### Legende Opacity (0-1) + +Die Farbdichte der Legende wirde mit Werten von 0 bis 1 angegeben (0=transparent; 1= dicht) + +#### Legende Hintergrund + +Die Farbe mit derder Hintergrund der Legende gezeigt werden soll kann als Hex (#FF0000), rgb (rgb(21, 120, 210)) oder als rgba (rgba(0, 0, 255, 0.6)) eingegeben werden. Klickt man auf das Feld, öffnet sich ein rgba Colorpicker in dem der Wert graphisch ermittelt werden kann. + +#### Hover Details + +Ist diese Checkbox angehakt, werden die Daten zu der Kurve angezeigt, wenn man mit der Maus die Linie abfährt. + +#### Time Format + +Standardmäßig wird das Zeitformat verwendet wie es in den Systemeinstellungen vorgegeben wurde. Alternativ können viele andere Frormate für den Chart verwendet werden. + +#### Benutze Komma + +Ist diese Checkbox angehakt wird als Dezimaltrennzeichen ein Komma benutz. Ansonsten wird der Dezimalpunkt verwendet + +#### Aktiviere Zoom und Schieben + +Die Aktivierung dieser Checkbox ermöglicht die Charts in der Live-Darstellung durch Mausbewegungen in der Zeitachse zu zoomen und zu verschieben. + +#### Kein 'Edit'-Knopf + +Ist diese Checkbox aktiviert wird das "Bleistift-Icon" in der rechten oberen Ecke des Chart-Fensters nicht angezeigt. Dieses Icon öffnet ansonsten diesen Chart im edit-Modus + +#### Animation + +Hier kann angegeben werden ob bei dem Öffnen des Charts dieser sofort zur Verfügung stehen soll, oder durch eine Animation aufgebaut wird. Hier wird die Dauer dieser Animation festgelegt. + +## Link + +In diesem Feld werden sämtliche Daten, die in den vorausgegangenen Menüs konfiguriert wurden in Textform zusammengefasst. Wenn man diesen Link bei vis in ein iFrame-Widget kopiert wird dort der Chart komplett angezeigt. Der Button _**zeige im Fenster**_ öffnet einen weiteren Tab im Browser und zeigt dort den Chart an. Diese Seite kann man zum Speichern des Charts bookmarken. Die Schaltfläche _**Update preview**_ zeigt in dem Vorschaufenster die letzten Änderungen. Wenn unter _**input data**_ die Checkbox autoupdate angehakt ist, steht diese Schaltfläche nicht zur Verfügung. Das Vorschaufenster aktualisiert dann bei jeder Änderung automatisch \ No newline at end of file diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_000.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_000.jpg new file mode 100644 index 0000000..57a91f1 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_000.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_001.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_001.jpg new file mode 100644 index 0000000..93bcb81 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_001.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Groups.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Groups.jpg new file mode 100644 index 0000000..219d0ed Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Groups.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data.jpg new file mode 100644 index 0000000..6d9d3c9 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Art.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Art.jpg new file mode 100644 index 0000000..854e3d6 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Art.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Chart_Type.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Chart_Type.jpg new file mode 100644 index 0000000..8c6b0c2 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Chart_Type.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Instanz.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Instanz.jpg new file mode 100644 index 0000000..9f83170 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Instanz.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_X_Achse.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_X_Achse.jpg new file mode 100644 index 0000000..38ab48a Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_X_Achse.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Y_Achse.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Y_Achse.jpg new file mode 100644 index 0000000..7c620e8 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_Y_Achse.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_more.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_more.jpg new file mode 100644 index 0000000..4421090 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Input_Data_more.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Markierungen.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Markierungen.jpg new file mode 100644 index 0000000..4ab16cf Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Markierungen.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Options_all.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Options_all.jpg new file mode 100644 index 0000000..746c744 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Options_all.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit-e1484938214253.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit-e1484938214253.jpg new file mode 100644 index 0000000..106f447 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit-e1484938214253.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_autoupdate.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_autoupdate.jpg new file mode 100644 index 0000000..3f503b7 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_autoupdate.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Ende.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Ende.jpg new file mode 100644 index 0000000..738dead Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Ende.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Range.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Range.jpg new file mode 100644 index 0000000..9d2de23 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_relativ_Range.jpg differ diff --git a/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_statisch.jpg b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_statisch.jpg new file mode 100644 index 0000000..3a5dc84 Binary files /dev/null and b/docs/de/img/flot-2_ioBroker_Adapter_Flot_Zeit_statisch.jpg differ diff --git a/docs/en/flot.md b/docs/en/flot.md new file mode 100644 index 0000000..96f31e2 --- /dev/null +++ b/docs/en/flot.md @@ -0,0 +1,105 @@ +# Flot - Charts + +## Desctiption + +[Flot](http://www.flotcharts.org/) is JavaScript JQuery library for plotting, with a focus on the simple use, attractive appearance and +interactive opportunities. yunkong2 driver with the same name allows you to plot archived data (for access to historical data in +the system should be installed driver History, SQL History or History with InfluxDB). It can be used as a standalone application +for simultaneous display of several charts to analyze the different states of the system in time. + +## Installation + +Installation is on the **Driver** tab page of the [administration](http://www.yunkong2.net/?page_id=4179&lang=en) system. + +In the driver group Visualization find a line called **Flot Charts**, and press the button with the plus icon in the right side of the line. +You will see a pop-up window driver installation, after installation, it will automatically close. + +If all goes well, +on the Setup driver tab appears **flot.0** installed instance of the driver. Please note that **Flot** driver must have access to +historical data (DB), so the system must be installed and configured at +least one driver from the **Storage** groups (History, SQL History or History with InfluxDB). + +For Flot also required driver Web, but it is usually installed automatically. + +![](img/flot_Adapter-Flot-EN-Pic1.png) + +## Setting + +The driver does not require special settings. It runs as a separate WEB-service on the web yunkong2 system driver port (usually 8082). +To get started with the driver, you must click on the button **Open the application** on the **Settings driver** tab in the line of the selected instance. + +## Using + +Flot charts window you can open the **Open app** button or type the link into your browser: `http://IP-адрес:8082/flot/edit.html` +The window can be divided into three zones (top to bottom): Settings, URL page to display graphics and preview charts. + +![](img/flot_Flot_en_pic2.png) + +In order to display the graph in another application, or simply call again in a browser, you need to copy the generated URL, +and it will again plot a graph with the specified parameters. If you want to change the graphics settings, insert the resulting +URL in the browser string path, replacing ```index.html``` on ```edit.html```: + +```http://IP:8082/flot/**index**.html?params.... => http://IP:8082/flot/**edit**.html?params....``` + +### Input data + +Setting the source data to draw a graph/graphs. + + ![](img/flot_Flot_en_pic3.png) + + +* You can add / delete the data series, +* The checkmark **Update once** allows you to apply the setting changes immediately after it (if not set, lower the Refresh button **updates** the preview charts in accordance with the settings), +* **ID** - you must use the buttons to select the variable to construct a time series (graphics) in the window only those variables that are configured to keep a history, +* **Driver** - You can choose from the list of driver instances, which is tied to a particular database, consequently data for construction will be requested from that database, +* **The shift in the X-axis** (shift on the Y axis) - You can specify a time period for which you need to move the chart to the right (deeper in the archive) or the absolute value of the shift on the Y axis, +* **Type** - points output mode on the chart (in the time group has a **Data Merge** (by time or number)setting - is taken a segment of the data and only rendered maximum, minimum, average, all values or special algorithms MinMax), +* **The type of graph** – drawing mode (Line, Area, Line with points,etc.), +* **Min**, **Max**, **Unit** - the interval on the Y axis (values) and units of measurements if not specified, the interval is automatically selected, units are taken from the yunkong2 system, +* **Y Axis, X Axis** - position of the axes X and Y, +* **ØL**, **ØS** - the thickness of lines and size of the shadow graph, +* **Name** – value to show the name of the time series in the legend (if enabled), if not specified, take the value from the yunkong2 (object name), +* **Coaxis Y** – the union of the Y-axis (values) for two or more time series, +* **NULL** as – interpretation of empty records the values of a variable (do not use, use a value of 0 or to take the previous), +* Settings **Smoothing and after the decimal point** – smoothing peaks graph and rounding values of the time series. + +### Time + +Setting time interval graph display data. + +![](img/flot_Flot_en_pic4.png) + +* Time interval **type** - relative (starting point is tied to the current time slot, and the ability to update automatically) and permanent (precise indication of the time frame), +* **Data Merge** - combine the values of time (in seconds), or a certain amount. + +### Options + +Here you can customize the appearance of the graphs, grids, axes and legends and captions. All settings are intuitive. + +![](img/flot_Flot_en_pic5.png) + +For example, you can add a few variables to records in the database (host variables work yunkong2 - CPU load, memory and so on.). +To do this, **objects** in the upper left corner of the tab, click the **Show system objects**, +the table looking for a group **system.host.host’s_name**, drop-down list and insist to keep a history of selected variables (extreme right button at the prompt): + +* put a check **active** in the group **sql.o** (pre-configure an instance of the driver to work with the database), +* other settings can be left default, +* click the **Save** button. + + +![](img/flot_Flot_en_pic6.png) +     +![](img/flot_Flot_en_pic7.png) + + After a while, when the database will accumulate records to display on the chart, you can try to build a time series: + +![](img/flot_Flot_en_pic8.png) +   +## System integration + +For example, consider the integration of graphics in the driver VIS visualization system yunkong2. +There are several options you can place on the desktop object static-iFrame iframe group. +In the settings you can specify the update interval (in ms), and then the graph will update and +display the current data (if the timeline is set to the current time). + +![](img/flot_Flot_en_pic9.png) diff --git a/docs/en/img/flot_Adapter-Flot-EN-Pic1.png b/docs/en/img/flot_Adapter-Flot-EN-Pic1.png new file mode 100644 index 0000000..c8d6b90 Binary files /dev/null and b/docs/en/img/flot_Adapter-Flot-EN-Pic1.png differ diff --git a/docs/en/img/flot_Flot_en_pic2.png b/docs/en/img/flot_Flot_en_pic2.png new file mode 100644 index 0000000..93ae0d0 Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic2.png differ diff --git a/docs/en/img/flot_Flot_en_pic3.png b/docs/en/img/flot_Flot_en_pic3.png new file mode 100644 index 0000000..028013c Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic3.png differ diff --git a/docs/en/img/flot_Flot_en_pic4.png b/docs/en/img/flot_Flot_en_pic4.png new file mode 100644 index 0000000..8d1a3bf Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic4.png differ diff --git a/docs/en/img/flot_Flot_en_pic5.png b/docs/en/img/flot_Flot_en_pic5.png new file mode 100644 index 0000000..d69684e Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic5.png differ diff --git a/docs/en/img/flot_Flot_en_pic6.png b/docs/en/img/flot_Flot_en_pic6.png new file mode 100644 index 0000000..10a63e1 Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic6.png differ diff --git a/docs/en/img/flot_Flot_en_pic7.png b/docs/en/img/flot_Flot_en_pic7.png new file mode 100644 index 0000000..4c1ac3d Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic7.png differ diff --git a/docs/en/img/flot_Flot_en_pic8.png b/docs/en/img/flot_Flot_en_pic8.png new file mode 100644 index 0000000..ec35153 Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic8.png differ diff --git a/docs/en/img/flot_Flot_en_pic9.png b/docs/en/img/flot_Flot_en_pic9.png new file mode 100644 index 0000000..78bd86b Binary files /dev/null and b/docs/en/img/flot_Flot_en_pic9.png differ diff --git a/docs/ru/flot.md b/docs/ru/flot.md new file mode 100644 index 0000000..38f028e --- /dev/null +++ b/docs/ru/flot.md @@ -0,0 +1,106 @@ +# Flot - Графики + +## Описание + +[Flot](http://www.flotcharts.org/) является JavaScript библиотекой JQuery для построения графиков, с акцентом на +простом использовании, привлекательном внешнем виде и интерактивных возможностях. Драйвер yunkong2 с одноименным +названием позволяет строить графики архивных данных (для доступа к историческим данным в системе должен быть установлен +драйвер [History](http://www.yunkong2.net/?page_id=3636&lang=ru), [SQL History](http://www.yunkong2.net/?page_id=4044&lang=ru) или +History with InfluxDB). Он может быть использован как отдельное приложение для одновременного отображения нескольких графиков +для анализа различных состояний системы во времени. + +## Установка + +Установка осуществляется на вкладке **Драйвера** странички [администрирования](http://www.yunkong2.net/?page_id=3800&lang=ru) системы. +В группе драйверов **Визуализация** находим строчку с названием **Flot Charts** и нажимаем кнопку со значком плюса в этой строке справа. +На экране появится всплывающее окно установки драйвера, в конце установки оно автоматически закроется. Если все прошло удачно, +на вкладке **Настройка драйверов** появится строка **flot.0** с установленным экземпляром драйвера. Обращаем ваше внимание на то, +что драйвер **Flot** должен иметь доступ к историческим данным (БД), поэтому в системе должен быть установлен и настроен как минимум +один драйвер из группы **Хранилище** ([History](http://www.yunkong2.net/?page_id=3636&lang=ru), +[SQL History](http://www.yunkong2.net/?page_id=4044&lang=ru) или History with InfluxDB). + +Так же для работы flot необходим драйвер web, но он устанавливается обычно автоматически. + +![](img/Flot-setting1.jpg) + +## Настройка + +Определенных настроек драйвер не требует. Он работает как отдельный WEB-сервис на порту драйвера web системы yunkong2 (обычно 8082). +Чтобы начать работу с драйвером, необходимо нажать на кнопку **Открыть приложение** на вкладке **Настройка драйверов** в строчке выбранного экземпляра. + +## Использование + +Окно графиков Flot можно открыть кнопкой **Открыть приложение** или в строке браузер набрать адрес: `http://IP-адрес:8082/flot/edit.html` + +Окно можно условно поделить на три зоны (сверху вниз): +Настройки, URL странички для вывода графика и предварительный просмотр графиков. + +![](img/Flot-setting6.jpg) + +Для того, что бы отобразить график в другой программе или просто вызвать ещё раз в браузере, надо скопировать сгенерированный URL и +по нему график построится снова с заданными параметрами. Если необходимо изменить настройки графика, вставьте получившийся URL в +строку пути браузера, заменив ```index.html``` на ```edit.html```: + +```http://IP:8082/flot/**index**.html?params.... => http://IP:8082/flot/**edit**.html?params....``` + +## Входные данные + +Настройка исходных данных для построения графика/графиков. + +![](img/Flot-setting7.jpg) + +* Можно добавить/удалить ряд данных, +* Галочка **Обновлять сразу** позволяет применять настройку сразу после её изменения (если не установлена, ниже будет кнопка **Обновить**, которая обновляет превью графиков в соответствии с настройками), +* **ID** - необходимо с помощью кнопки выбрать переменную для построения временного ряда (графика), в окне будут только те переменные, для которых настроено хранение истории, +* **Драйвер** - можно выбрать из списка экземпляр драйвера, который привязан к конкретной БД, соответственно данные для построения будут запрошены из этой БД, +* **Сдвиг по оси Х** (Сдвиг по оси Y) - можно указать промежуток времени, на который необходимо сдвинуть график вправо (глубже в архиве) или абсолютное значение для сдвига по оси Y, +* **Тип** - режим вывода точек на график (в группе время есть настройка **Объединение данных** (по времени или количеству) - берется отрезок этих данных и отрисовывается только максимум, минимум, среднее, все значения или специальный алгоритм MinMax), +* **Тип графика** - режим отрисовки (Линия, Область, Линия с точками и пр.), +* **Min**, **Max**, **Unit** - интервал по оси Y (значений) и единицы измерений, если не указано, то интервал выбирается автоматически, юниты берутся из системы yunkong2, +* **Y Axis, X Axis** - положение осей X и Y, +* **ØL**, **ØS** - толщина линий и размер тени графика, +* **Имя** - значение для отображения названия временного ряда в легенде (если она включена), если не указано, то берется значение из yunkong2 (имя объекта), +* **Общая ось Y** - объединение оси Y (значений) для двух и более временных рядов, +* **NULL как** - интерпретация пустых записей значения переменной (не использовать, использовать значение 0 или брать предыдущее), +* Настройки **Сглаживание** и **После запятой** - сглаживание пиков графика и округление значений временного ряда. + +## Время + +Настройка временного интервала отображения данных графика. + +![](img/Flot-setting8.jpg) + +* Временной интервал **тип** - относительный (начальная точка привязана к текущему времени, интервал, и возможность обновлять автоматически) и постоянный (точное указание временных рамок), +* Объединение данных - объединять значения по времени (в секундах) или определенное количество. + +## Опции + +Здесь можно настроить внешний вид графиков, сетки, осей и легенды и подписи. Все настройки интуитивно-понятны. + +![](img/Flot-setting9.jpg) + +Для примера можно добавить несколько переменных для записи в БД (переменные работы хоста yunkong2 - нагрузку ЦП, память и пр.). +Для этого на вкладке **Объекты** в верхнем левом углу нажимаем кнопку **Показать системные объекты**, +в таблице ищем группу **system.host.имя_хоста**, раскрываем список и настаиваем хранение истории для выбранных +переменных (кнопка в строке крайняя справа): + +* ставим галочку **активно** в группе **sql.o** (предварительно должен быть настроен экземпляр этого драйвера на работу с БД), +* остальные настройки можно оставить по-умолчанию, +* нажимаем кнопку **Сохранить**. + +![](img/Flot-setting3.jpg) + +![](img/Flot-setting4.jpg) + +Через некоторое время, когда в БД накопятся записи для отображения на графике, можно попробовать построить временные ряды: + +![](img/Flot-use2.jpg) + +## Интеграция в систему + +Для примера, рассмотрим интеграцию графиков в драйвер **VIS** системы визуализации yunkong2. +Есть несколько вариантов, можно на рабочем поле разместить объект static-iFrame группы iframe. +В настройках можно указать интервал обновления (в ms) и тогда график будет обновляться и отображать +текущие данные (если временная шкала настроена относительно текущего времени). + +![](img/Flot-use1.jpg) \ No newline at end of file diff --git a/docs/ru/img/Flot-setting1.jpg b/docs/ru/img/Flot-setting1.jpg new file mode 100644 index 0000000..9ea44d7 Binary files /dev/null and b/docs/ru/img/Flot-setting1.jpg differ diff --git a/docs/ru/img/Flot-setting3.jpg b/docs/ru/img/Flot-setting3.jpg new file mode 100644 index 0000000..b2dca7e Binary files /dev/null and b/docs/ru/img/Flot-setting3.jpg differ diff --git a/docs/ru/img/Flot-setting4.jpg b/docs/ru/img/Flot-setting4.jpg new file mode 100644 index 0000000..df7abd6 Binary files /dev/null and b/docs/ru/img/Flot-setting4.jpg differ diff --git a/docs/ru/img/Flot-setting6.jpg b/docs/ru/img/Flot-setting6.jpg new file mode 100644 index 0000000..3303563 Binary files /dev/null and b/docs/ru/img/Flot-setting6.jpg differ diff --git a/docs/ru/img/Flot-setting7.jpg b/docs/ru/img/Flot-setting7.jpg new file mode 100644 index 0000000..c285033 Binary files /dev/null and b/docs/ru/img/Flot-setting7.jpg differ diff --git a/docs/ru/img/Flot-setting8.jpg b/docs/ru/img/Flot-setting8.jpg new file mode 100644 index 0000000..8e14946 Binary files /dev/null and b/docs/ru/img/Flot-setting8.jpg differ diff --git a/docs/ru/img/Flot-setting9.jpg b/docs/ru/img/Flot-setting9.jpg new file mode 100644 index 0000000..ad1a19e Binary files /dev/null and b/docs/ru/img/Flot-setting9.jpg differ diff --git a/docs/ru/img/Flot-use1.jpg b/docs/ru/img/Flot-use1.jpg new file mode 100644 index 0000000..8486095 Binary files /dev/null and b/docs/ru/img/Flot-use1.jpg differ diff --git a/docs/ru/img/Flot-use2.jpg b/docs/ru/img/Flot-use2.jpg new file mode 100644 index 0000000..48d2e48 Binary files /dev/null and b/docs/ru/img/Flot-use2.jpg differ diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..61ebf72 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,501 @@ +'use strict'; + +const gulp = require('gulp'); +const fs = require('fs'); +const pkg = require('./package.json'); +const iopackage = require('./io-package.json'); +const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version; +const uglify = require('gulp-uglify'); +const concat = require('gulp-concat'); +const sourcemaps = require('gulp-sourcemaps'); +const gutil = require('gulp-util'); +const htmlmin = require('gulp-htmlmin'); +const del = require('del'); + +/*var appName = getAppName(); + +function getAppName() { + var parts = __dirname.replace(/\\/g, '/').split('/'); + return parts[parts.length - 1].split('.')[0].toLowerCase(); +} +*/ +const fileName = 'words.js'; +let languages = { + en: {}, + de: {}, + ru: {}, + pt: {}, + nl: {}, + fr: {}, + it: {}, + es: {}, + pl: {} +}; + +function lang2data(lang, isFlat) { + let str = isFlat ? '' : '{\n'; + let count = 0; + for (const w in lang) { + if (lang.hasOwnProperty(w)) { + count++; + if (isFlat) { + str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n'; + } else { + const key = ' "' + w.replace(/"/g, '\\"') + '": '; + str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n'; + } + } + } + if (!count) return isFlat ? '' : '{\n}'; + if (isFlat) { + return str; + } else { + return str.substring(0, str.length - 2) + '\n}'; + } +} + +function readWordJs(src) { + try { + let words; + if (fs.existsSync(src + 'js/' + fileName)) { + words = fs.readFileSync(src + 'js/' + fileName).toString(); + } else { + words = fs.readFileSync(src + fileName).toString(); + } + + const lines = words.split(/\r\n|\r|\n/g); + let i = 0; + while (!lines[i].match(/^systemDictionary = {/)) { + i++; + } + lines.splice(0, i); + + // remove last empty lines + i = lines.length - 1; + while (!lines[i]) { + i--; + } + if (i < lines.length - 1) { + lines.splice(i + 1); + } + + lines[0] = lines[0].replace('systemDictionary = ', ''); + lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}'); + words = lines.join('\n'); + const resultFunc = new Function('return ' + words + ';'); + + return resultFunc(); + } catch (e) { + return null; + } +} +function padRight(text, totalLength) { + return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : ''); +} +function writeWordJs(data, src) { + let text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n'; + text += '/*global systemDictionary:true */\n'; + text += '\'use strict\';\n\n'; + + text += 'systemDictionary = {\n'; + for (const word in data) { + if (data.hasOwnProperty(word)) { + text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50); + let line = ''; + for (const lang in data[word]) { + if (data[word].hasOwnProperty(lang)) { + line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' '; + } + } + if (line) { + line = line.trim(); + line = line.substring(0, line.length - 1); + } + text += line + '},\n'; + } + } + text += '};'; + + if (fs.existsSync(src + 'js/')) { + fs.writeFileSync(src + 'js/' + fileName, text); + } else { + fs.writeFileSync(src + '' + fileName, text); + } +} + +const EMPTY = ''; + +function words2languages(src) { + const langs = Object.assign({}, languages); + const data = readWordJs(src); + if (data) { + for (const word in data) { + if (data.hasOwnProperty(word)) { + for (const lang in data[word]) { + if (data[word].hasOwnProperty(lang)) { + langs[lang][word] = data[word][lang]; + // pre-fill all other languages + for (const j in langs) { + if (langs.hasOwnProperty(j)) { + langs[j][word] = langs[j][word] || EMPTY; + } + } + } + } + } + } + if (!fs.existsSync(src + 'i18n/')) { + fs.mkdirSync(src + 'i18n/'); + } + for (const l in langs) { + if (!langs.hasOwnProperty(l)) continue; + const keys = Object.keys(langs[l]); + //keys.sort(); + let obj = {}; + for (let k = 0; k < keys.length; k++) { + obj[keys[k]] = langs[l][keys[k]]; + } + if (!fs.existsSync(src + 'i18n/' + l)) { + fs.mkdirSync(src + 'i18n/' + l); + } + + fs.writeFileSync(src + 'i18n/' + l + '/translations.json', lang2data(obj)); + } + } else { + console.error('Cannot read or parse ' + fileName); + } +} +function words2languagesFlat(src) { + const langs = Object.assign({}, languages); + const data = readWordJs(src); + if (data) { + for (const word in data) { + if (data.hasOwnProperty(word)) { + for (const lang in data[word]) { + if (data[word].hasOwnProperty(lang)) { + langs[lang][word] = data[word][lang]; + // pre-fill all other languages + for (const j in langs) { + if (langs.hasOwnProperty(j)) { + langs[j][word] = langs[j][word] || EMPTY; + } + } + } + } + } + } + const keys = Object.keys(langs.en); + //keys.sort(); + for (const l in langs) { + if (!langs.hasOwnProperty(l)) continue; + let obj = {}; + for (let k = 0; k < keys.length; k++) { + obj[keys[k]] = langs[l][keys[k]]; + } + langs[l] = obj; + } + if (!fs.existsSync(src + 'i18n/')) { + fs.mkdirSync(src + 'i18n/'); + } + for (const ll in langs) { + if (!langs.hasOwnProperty(ll)) continue; + if (!fs.existsSync(src + 'i18n/' + ll)) { + fs.mkdirSync(src + 'i18n/' + ll); + } + + fs.writeFileSync(src + 'i18n/' + ll + '/flat.txt', lang2data(langs[ll], langs.en)); + } + fs.writeFileSync(src + 'i18n/flat.txt', keys.join('\n')); + } else { + console.error('Cannot read or parse ' + fileName); + } +} +function languagesFlat2words(src) { + const dirs = fs.readdirSync(src + 'i18n/'); + let langs = {}; + let bigOne = {}; + const order = Object.keys(languages); + dirs.sort((a, b) => { + const posA = order.indexOf(a); + const posB = order.indexOf(b); + if (posA === -1 && posB === -1) { + if (a > b) return 1; + if (a < b) return -1; + return 0; + } else if (posA === -1) { + return -1; + } else if (posB === -1) { + return 1; + } else { + if (posA > posB) return 1; + if (posA < posB) return -1; + return 0; + } + }); + const keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n'); + + for (let l = 0; l < dirs.length; l++) { + if (dirs[l] === 'flat.txt') continue; + const lang = dirs[l]; + const values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n'); + langs[lang] = {}; + keys.forEach(function (word, i) { + langs[lang][word] = values[i].replace(/<\/ i>/g, '').replace(/<\/ b>/g, '').replace(/<\/ span>/g, '').replace(/% s/g, ' %s'); + }); + + const words = langs[lang]; + for (const word in words) { + if (words.hasOwnProperty(word)) { + bigOne[word] = bigOne[word] || {}; + if (words[word] !== EMPTY) { + bigOne[word][lang] = words[word]; + } + } + } + } + // read actual words.js + const aWords = readWordJs(); + + const temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt']; + if (aWords) { + // Merge words together + for (const w in aWords) { + if (aWords.hasOwnProperty(w)) { + if (!bigOne[w]) { + console.warn('Take from actual words.js: ' + w); + bigOne[w] = aWords[w] + } + dirs.forEach(function (lang) { + if (temporaryIgnore.indexOf(lang) !== -1) return; + if (!bigOne[w][lang]) { + console.warn('Missing "' + lang + '": ' + w); + } + }); + } + } + + } + + writeWordJs(bigOne, src); +} +function languages2words(src) { + const dirs = fs.readdirSync(src + 'i18n/'); + const langs = {}; + const bigOne = {}; + const order = Object.keys(languages); + dirs.sort((a, b) => { + const posA = order.indexOf(a); + const posB = order.indexOf(b); + if (posA === -1 && posB === -1) { + if (a > b) return 1; + if (a < b) return -1; + return 0; + } else if (posA === -1) { + return -1; + } else if (posB === -1) { + return 1; + } else { + if (posA > posB) return 1; + if (posA < posB) return -1; + return 0; + } + }); + for (let l = 0; l < dirs.length; l++) { + if (dirs[l] === 'flat.txt') continue; + const lang = dirs[l]; + langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString(); + langs[lang] = JSON.parse(langs[lang]); + const words = langs[lang]; + for (const word in words) { + if (words.hasOwnProperty(word)) { + bigOne[word] = bigOne[word] || {}; + if (words[word] !== EMPTY) { + bigOne[word][lang] = words[word]; + } + } + } + } + // read actual words.js + const aWords = readWordJs(); + + const temporaryIgnore = ['pt', 'fr', 'nl', 'it']; + if (aWords) { + // Merge words together + for (const w in aWords) { + if (aWords.hasOwnProperty(w)) { + if (!bigOne[w]) { + console.warn('Take from actual words.js: ' + w); + bigOne[w] = aWords[w] + } + dirs.forEach(function (lang) { + if (temporaryIgnore.indexOf(lang) !== -1) return; + if (!bigOne[w][lang]) { + console.warn('Missing "' + lang + '": ' + w); + } + }); + } + } + + } + + writeWordJs(bigOne, src); +} + +gulp.task('words2languages', done => { + words2languages('./src/'); + done(); +}); + +gulp.task('words2languagesFlat', done => { + words2languagesFlat('./src/'); + done(); +}); + +gulp.task('languagesFlat2words', done => { + languagesFlat2words('./src/'); + done(); +}); + +gulp.task('languages2words', done => { + languages2words('./src/'); + done(); +}); + + +gulp.task('updateEditHtml', done => { + let text = fs.readFileSync('./src/edit.html').toString('utf-8'); + let newText = text.replace(/Version: \d+\.\d+\.\d+<\/div>/, `Version: ${pkg.version}`); + if (newText !== text) { + fs.writeFileSync('./src/edit.html', newText); + } + done(); +}); + +gulp.task('updatePackages', done => { + iopackage.common.version = pkg.version; + iopackage.common.news = iopackage.common.news || {}; + if (!iopackage.common.news[pkg.version]) { + const news = iopackage.common.news; + const newNews = {}; + + newNews[pkg.version] = { + en: 'news', + de: 'neues', + ru: 'новое' + }; + iopackage.common.news = Object.assign(newNews, news); + } + fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4)); + done(); +}); + +gulp.task('updateReadme', done => { + const readme = fs.readFileSync('README.md').toString(); + const pos = readme.indexOf('## Changelog\n'); + if (pos !== -1) { + const readmeStart = readme.substring(0, pos + '## Changelog\n'.length); + const readmeEnd = readme.substring(pos + '## Changelog\n'.length); + + if (readme.indexOf(version) === -1) { + const timestamp = new Date(); + const date = timestamp.getFullYear() + '-' + + ('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' + + ('0' + (timestamp.getDate()).toString(10)).slice(-2); + + let news = ''; + if (iopackage.common.news && iopackage.common.news[pkg.version]) { + news += '* ' + iopackage.common.news[pkg.version].en; + } + + fs.writeFileSync('README.md', readmeStart + '### ' + version + ' (' + date + ')\n' + (news ? news + '\n\n' : '\n') + readmeEnd); + } + } + done(); +}); + +gulp.task('clean', () => { + return del([ + 'src/js/words.js', + 'www/**/*' + ]); +}); + +gulp.task('flotJS', () => { + return gulp.src([ + './src/lib/js/jquery.flot.min.js', + './src/lib/js/jquery.flot.resize.min.js', + './src/lib/js/jquery.flot.time.min.js', + './src/lib/js/jquery.flot.categories.min.js', + './src/lib/js/jquery.flot.spline.min.js', + './src/lib/js/jquery.flot.selection.min.js', + './src/lib/js/jquery.flot.hiddengraphs.js', + './src/lib/js/jquery.flot.fillbetween.js', + './src/lib/js/jquery.flot.navigate.min.js', + './src/lib/js/jquery.flot.dashes.js', + './src/lib/js/jquery.flot.grow.js', + './src/lib/js/jquery-deparam.js', + './src/js/days.js', + './src/js/chart.js', + './src/js/data.js' + ]) + .pipe(sourcemaps.init()) + .pipe(concat('flot.js')) + .pipe(uglify()) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('./www/js')); +}); + +gulp.task('editJS', ['languages2words'], () => { + return gulp.src([ + './src/lib/js/jquery-deparam.js', + './src/lib/js/jquery.colorpicker.js', + './src/js/words.js', + './src/js/settings.js', + './src/js/edit.js', + ]) + .pipe(sourcemaps.init()) + .pipe(concat('edit.js')) + .pipe(uglify()) + .on('error', function (err) { + gutil.log(gutil.colors.red('[Error]'), err.toString()); + }) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('./www/js')); +}); + +gulp.task('indexHTML', () => { + return gulp.src([ + './src/index.html' + ]) + .pipe(sourcemaps.init()) + .pipe(concat('index.html')) + .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('./www/')); +}); +gulp.task('editHTML', ['updateEditHtml'], () => { + return gulp.src([ + './src/edit.html' + ]) + .pipe(sourcemaps.init()) + .pipe(concat('edit.html')) + .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest('./www/')); +}); + +gulp.task('copyCSS', () => { + return gulp.src([ + './src/lib/css/**/*' + ]) + .pipe(gulp.dest('./www/css')); +}); + +gulp.task('copyImg', () => { + return gulp.src([ + './src/img/favicon.png' + ]) + .pipe(gulp.dest('./www/img')); +}); + +gulp.task('default', ['flotJS', 'editJS', 'indexHTML', 'editHTML', 'copyCSS', 'copyImg']); \ No newline at end of file diff --git a/img/example.png b/img/example.png new file mode 100644 index 0000000..83ad9b2 Binary files /dev/null and b/img/example.png differ diff --git a/img/screen1.jpg b/img/screen1.jpg new file mode 100644 index 0000000..0c54876 Binary files /dev/null and b/img/screen1.jpg differ diff --git a/img/screen2.jpg b/img/screen2.jpg new file mode 100644 index 0000000..3ac65bf Binary files /dev/null and b/img/screen2.jpg differ diff --git a/img/screen3.jpg b/img/screen3.jpg new file mode 100644 index 0000000..779e565 Binary files /dev/null and b/img/screen3.jpg differ diff --git a/img/screen4.jpg b/img/screen4.jpg new file mode 100644 index 0000000..bcb4b21 Binary files /dev/null and b/img/screen4.jpg differ diff --git a/img/screen5.jpg b/img/screen5.jpg new file mode 100644 index 0000000..a7d8c5b Binary files /dev/null and b/img/screen5.jpg differ diff --git a/img/screen6.jpg b/img/screen6.jpg new file mode 100644 index 0000000..c29295a Binary files /dev/null and b/img/screen6.jpg differ diff --git a/img/screen7.jpg b/img/screen7.jpg new file mode 100644 index 0000000..87150e7 Binary files /dev/null and b/img/screen7.jpg differ diff --git a/io-package.json b/io-package.json new file mode 100644 index 0000000..687b47c --- /dev/null +++ b/io-package.json @@ -0,0 +1,200 @@ +{ + "common": { + "name": "flot", + "version": "1.9.2", + "news": { + "1.9.2": { + "en": "Translations", + "de": "Übersetzungen", + "ru": "Переводы", + "pt": "Traduções", + "nl": "vertaalwerk", + "fr": "Traductions", + "it": "Traduzioni", + "es": "Traducciones", + "pl": "Tłumaczenia" + }, + "1.9.1": { + "en": "Added dashed lines\nAll JS files together are concatenated", + "de": "Gestrichelte Linien hinzugefügt\nAlle JS-Dateien zusammen sind verkettet", + "ru": "Добавлены пунктирные линии\nВсе файлы JS вместе объединены", + "pt": "Adicionado linhas tracejadas\nTodos os arquivos JS juntos são concatenados", + "nl": "Gestreepte lijnen toegevoegd\nAlle JS-bestanden samen zijn aaneengeschakeld", + "fr": "Ajout de lignes pointillées\nTous les fichiers JS sont concaténés", + "it": "Aggiunte linee tratteggiate\nTutti i file JS insieme sono concatenati", + "es": "Líneas discontinuas agregadas\nTodos los archivos JS juntos están concatenados", + "pl": "Dodano przerywane linie\nWszystkie pliki JS są ze sobą połączone" + }, + "1.8.0": { + "en": "Optimize communication", + "de": "Kommunikation optimieren", + "ru": "Оптимизация связи", + "pt": "Otimizar a comunicação", + "nl": "Optimaliseer communicatie", + "fr": "Optimiser la communication", + "it": "Ottimizza la comunicazione", + "es": "Optimizar la comunicación", + "pl": "Zoptymalizuj komunikację" + }, + "1.7.9": { + "en": "Added support of multi-languages in names", + "de": "Unterstützung von Multi-Sprachen in Namen hinzugefügt", + "ru": "Добавлена ​​поддержка нескольких языков в именах", + "pt": "Adicionado suporte de multi-idiomas em nomes", + "nl": "Ondersteuning van meerdere talen toegevoegd aan namen", + "fr": "Ajout du support de plusieurs langues dans les noms", + "it": "Aggiunto il supporto di più lingue nei nomi", + "es": "Se agregó soporte de múltiples idiomas en los nombres", + "pl": "Dodano obsługę wielu języków w nazwach" + }, + "1.7.7": { + "en": "fix month range", + "de": "Monatsspanne festlegen", + "ru": "исправить месячный диапазон", + "pt": "intervalo mensal fixo", + "nl": "bereik maandbereik", + "fr": "fixer la plage de mois", + "it": "fissare il range del mese", + "es": "arreglar rango de mes", + "pl": "popraw zakres miesięcy" + }, + "1.7.6": { + "en": "remove alert windows from errors, log instead", + "de": "Entfernen Sie Warnfenster von Fehlern, loggen Sie sich stattdessen ein", + "ru": "удалять окна предупреждений из ошибок, вместо этого записывать журнал", + "pt": "remova janelas de alerta de erros, registre em vez disso", + "nl": "verwijder waarschuwingsvensters van fouten, log in plaats daarvan", + "fr": "supprimer les fenêtres d'alerte des erreurs, consigner à la place", + "it": "rimuovere le finestre di avviso dagli errori, invece registrare", + "es": "eliminar ventanas de alerta de errores, registrar en su lugar", + "pl": "usuń okna alertów z błędów, zamiast tego zaloguj się" + }, + "1.7.5": { + "en": "try to fix small error", + "de": "Versuch einen kleinen Fehler zu beheben", + "ru": "попытка исправить небольшую ошибку", + "pt": "tente corrigir pequenos erros", + "nl": "probeer een kleine fout op te lossen", + "fr": "essayer de réparer une petite erreur", + "it": "prova a correggere un piccolo errore", + "es": "intenta arreglar un pequeño error", + "pl": "spróbuj naprawić mały błąd" + }, + "1.7.4": { + "en": "The loading via cloud is fixed", + "de": "Das Laden über die Cloud ist behoben", + "ru": "Погрузка через облако фиксирована", + "pt": "O carregamento por nuvem é fixo", + "nl": "Het laden via cloud is opgelost", + "fr": "Le chargement via le cloud est fixe", + "it": "Il caricamento tramite cloud è fisso" + }, + "1.7.1": { + "en": "Fixed the loading of presets\nAdded new date formats for X axis", + "de": "Das Laden von Presets wurde korrigiert\nNeue Datumsformate für die X-Achse hinzugefügt", + "ru": "Исправлена загрузка пресетов\nДобавлены новые форматы дат для оси X", + "pt": "Corrigido o carregamento de predefinições\nAdicionado novos formatos de data para o eixo X", + "fr": "Correction du chargement des presets\nAjout de nouveaux formats de date pour l'axe X", + "nl": "Het laden van presets verholpen\nNieuwe datumnotaties voor X-as toegevoegd" + }, + "1.7.0": { + "en": "Add presets", + "de": "Presets sind jinzugefügt", + "ru": "Добавлены пресеты" + }, + "1.6.2": { + "en": "Show chart at start", + "de": "Zeige Chart am Anfang", + "ru": "Показывать график при старте" + }, + "1.6.1": { + "en": "Change edit layout", + "de": "Ändere Edit Layout", + "ru": "Изменено положение элементов при редактировании " + }, + "1.5.9": { + "en": "New color picker\nIf 'none' for title selected => do not show any title\nadd date format 'dd.mm.'", + "de": "Neuer Farbselektor\nZeige keine Beschriftung falls 'none'\nNeues Datumformat 'dd.mm.'", + "ru": "Новый выбор цвета\nЕсли 'ничего' выбрано для подписи, то ничего не показывать\nдобавлен формат даты 'dd.mm.'" + }, + "1.5.8": { + "en": "Add series as X ticks", + "de": "Möglichkeit ein Wert als X Beschriftung zu benutzen", + "ru": "Возможность показывать X подписи из истории" + } + }, + "title": "Flot Charts", + "titleLang": { + "en": "Flot Charts", + "de": "Flot-Diagrammen", + "ru": "Графики c Flot", + "pt": "Flot Charts", + "nl": "Flot charts", + "fr": "Graphiques des Flot", + "it": "Grafici Flot", + "es": "Gráficos de Flot", + "pl": "Wykresy Flot" + }, + "desc": { + "en": "This adapter draws charts with Flot in yunkong2.", + "de": "Dieser Adapter zeichnet Diagramme mit Flot in yunkong2.", + "ru": "Драйвер строит графики с помощью Flot", + "nl": "Deze adapter tekent grafieken met Flot in yunkong2", + "fr": "Cet adaptateur dessine des graphiques avec Flot dans yunkong2", + "pt": "Este adaptador desenha gráficos com o Flot no yunkong2", + "it": "Questo adattatore disegna i grafici con Flot in yunkong2.", + "es": "Este adaptador dibuja tablas con Flot en yunkong2", + "pl": "Ten adapter rysuje wykresy za pomocą Flot w programie yunkong2" + }, + "authors": [ + "bluefox " + ], + "docs": { + "en": "docs/en/flot.md", + "ru": "docs/ru/flot.md", + "de": "docs/de/flot.md" + }, + "platform": "javascript/Node.js", + "icon": "flot.png", + "mode": "none", + "keywords": [ + "charts", + "graphics", + "grafiken" + ], + "extIcon": "https://git.spacen.net/yunkong2/yunkong2.flot/raw/master/admin/flot.png", + "readme": "https://git.spacen.net/yunkong2/yunkong2.flot/blob/master/README.md", + "loglevel": "info", + "dependencies": [ + { + "web": ">=1.7.1" + } + ], + "localLink": "%web_protocol%://%ip%:%web_port%/flot/edit.html", + "enabled": true, + "onlyWWW": true, + "singleton": true, + "type": "visualization", + "noConfig": true, + "nogit": true, + "welcomeScreen": { + "link": "flot/edit.html", + "name": "flot editor", + "img": "flot.admin/flot.png", + "color": "gray", + "order": 4 + } + }, + "native": {}, + "objects": [ + { + "_id": "_design/chart", + "language": "javascript", + "views": { + "chart": { + "map": "function(doc) { if (doc.type === 'chart') emit(doc.common.name, doc); }" + } + } + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..997a66c --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "yunkong2.flot", + "description": "This adapter draws charts with Flot in yunkong2.", + "version": "1.9.2", + "author": { + "name": "bluefox", + "email": "dogafox@gmail.com" + }, + "contributors": [ + { + "name": "bluefox", + "email": "dogafox@gmail.com" + } + ], + "homepage": "https://git.spacen.net/yunkong2/yunkong2.flot", + "repository": { + "type": "git", + "url": "https://git.spacen.net/yunkong2/yunkong2.flot" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://git.spacen.net/yunkong2/yunkong2.flot/blob/master/LICENSE" + } + ], + "keywords": [ + "yunkong2", + "flot", + "chart" + ], + "dependencies": {}, + "devDependencies": { + "gulp": "^3.9.1", + "gulp-uglify": "^3.0.0", + "gulp-concat": "^2.6.1", + "gulp-sourcemaps": "^2.6.4", + "gulp-htmlmin": "^4.0.0", + "del": "^3.0.0", + "gulp-util": "^3.0.8", + "mocha": "^5.2.0", + "chai": "^4.1.2" + }, + "bugs": { + "url": "https://git.spacen.net/yunkong2/yunkong2.flot/issues" + }, + "main": "Gruntfile.js", + "scripts": { + "test": "node node_modules/mocha/bin/mocha --exit", + "prepublish": "node node_modules/gulp/bin/gulp default" + }, + "license": "MIT" +} diff --git a/src/edit.html b/src/edit.html new file mode 100644 index 0000000..6ad44c9 --- /dev/null +++ b/src/edit.html @@ -0,0 +1,621 @@ + + + Flot Edit + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + + + + + + + + + + +
NameIDs
+
+ +
+ + + + +
+ + + + +
+
+ + +
+
+
+ +
+ + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
Line IDUpper value or IDLower value or IDColorFillØLØSTextText positionText offsetText sizeText color
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Time Span
+ + + + + + + + + + + + + + + + + +
Aggregate
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Appearance
+
+
+ +
+ + +
+
+
> +
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Bar settings
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Title
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Options
+
+
+
Version: 1.9.2
+
+
+ + + + +
+
+ + + + + + + + + diff --git a/src/i18n/de/translations.json b/src/i18n/de/translations.json new file mode 100644 index 0000000..5acdc94 --- /dev/null +++ b/src/i18n/de/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Ok", + "role": "Rolle", + "Update objects": "Objekte aktualisieren", + "All": "Alle", + "With": "mit", + "Without": "ohne", + "Update states": "States aktualisieren", + "edit file": "Datei editieren", + "restart script": "Skript neu starten", + "Select": "Auswählen", + "Select ID": "ID Auswählen", + "add children": "Sub-enums einfügen", + "edit enum": "Enum ändern", + "System settings": "Systemeinstellungen", + "reload": "Neu laden", + "Delete object": "Object löschen", + "no null": " kein NULL", + "%s ago": "vor %s", + "Y-Offset": "Y-Offset", + "ID": "ID", + "Role": "Rolle", + "Room": "Raum", + "Value": "Wert", + "none": "nichts", + "Save into:": "Save into:", + "Name:": "Name:", + "save": "Speichern", + "load": "laden", + "Presets": "Voreinstellung", + "IDs": "IDs", + "new": "unter neuen Namen", + "Enter chart name": "Chartname eintragen", + "save %s": "Speichern %s", + "Input data": "Eingangsdaten", + "Options": "Optionen", + "Range:": "Umfang:", + "5 seconds": "5 Sekunden", + "10 seconds": "10 Sekunden", + "15 seconds": "15 Sekunden", + "20 seconds": "20 Sekunden", + "30 seconds": "30 Sekunden", + "1 minute": "1 Minute", + "2 minutes": "2 Minuten", + "5 minutes": "5 Minuten", + "10 minutes": "10 Minuten", + "15 minutes": "15 Minuten", + "20 minutes": "20 Minuten", + "30 minutes": "30 Minuten", + "1 hour": "1 Stunde", + "2 hours": "2 Stunden", + "3 hours": "3 Stunden", + "6 hours": "6 Stunden", + "12 hours": "12 Stunden", + "1 day": "1 Tag", + "2 days": "2 Tage", + "3 days": "3 Tage", + "7 days": "7 Tage", + "14 days": "14 Tage", + "1 month": "1 Monat", + "2 months": "2 Monate", + "3 months": "3 Monate", + "6 months": "6 Monate", + "1 year": "1 Jahr", + "2 years": "2 Jahren", + "Width:": "Breite:", + "Height:": "Höhe:", + "line": "Linie", + "area": "Area", + "bar": "Bar", + "lineplot": "Liniendiagramm", + "scatterplot": "Streudiagramm", + "steps": "Schritte", + "spline": "Spline", + "Stack": "Stack", + "Window background:": "Fenster-Hintergrund:", + "Custom chart background:": "Anwender-Chart-Hintergrund:", + "Chart background:": "Chart-Hintergrund:", + "X axis labels color:": "X Beschriftungsfarbe:", + "Y axis labels color:": "Y Beschriftungsfarbe:", + "Show legend:": "Zeige Legende:", + "Title:": "Beschriftung:", + "Title position:": "Beschriftungs-Position:", + "Top, left, inside": "Oben, links, innen", + "Top, right, inside": "Oben, rechts, innen", + "Top, center, inside": "Oben, mittig, innen", + "Middle, left, inside": "Middle, links, innen", + "Middle, right, inside": "Middle, rechts, innen", + "Bottom, left, inside": "Unten, links, innen", + "Bottom, right, inside": "Unten, rechts, innen", + "Bottom, center, inside": "Unten, mittig, innen", + "Top, right, outside": "Oben, rechts, außen", + "Middle, right, outside": "Middle, rechts, außen", + "Bottom, right, outside": "Unten, rechts, außen", + "Bottom, center, outside": "Unten, mittig, außen", + "Min:": "Minimum:", + "Max:": "Maximum:", + "User defined names:": "Benutzerdefinierte Namen:", + "Predefined background:": "Vordefinierter Hintergrund:", + "User defined": "Anwenderdefiniert", + "Background:": "Hintergrund:", + "Hover details:": "Hover details:", + "Time format:": "Zeitformat:", + "Default": "Standard", + "Smoothing": "Glätten", + "After comma": "Nach Komma", + "Open": "Zeige im Fenster", + "Update": "Aktualisieren", + "Reset settings": "Einstellungen löschen", + "From": "Von", + "Last changed": "Letze Änderung", + "Time stamp": "Zeitstempel", + "Acknowledged": "Bestätigt", + "Edit": "Editieren", + "Members": "Mitglied", + "Loading...": "Lade...", + "Processing...": "Bearbeite...", + "With lines": "mit Linien", + "Without lines": "ohne Linien", + "Inside / With lines": "Innen / mit Linien", + "Outside/ With lines": "Außen/ mit Linien", + "Inside / No lines": "Innen / ohne Linien", + "Outside / No lines": "Außen / ohne Linien", + "Interpolate:": "Interpolieren:", + "Steps": "Schritte", + "Pie": "Kuchen", + "Top, left": "Oben, links", + "Top, right": "Oben, rechts", + "Bottom, left": "Unten, links", + "Bottom, right": "Unten, rechts", + "Title color:": "Titelfarbe:", + "Title size:": "Titelgröße:", + "Fill range:": "Ganzer Bereich:", + "Units:": "Einheiten:", + "yes": "ja", + "bottom": "unten", + "top": "oben", + "left": "links", + "right": "rechts", + "No border:": "Kein Rahmen:", + "Time": "Zeit", + "day": "Tag", + "month": "Monat", + "year": "Jahr", + "Individual": "Individuell", + "Aggregation:": "Art:", + "relative": "relative", + "static": "statik", + "now": "jetzt", + "today": "heute", + "this month": "dieser Monat", + "this year": "dieses Jahr", + "Start:": "Start:", + "End:": "Ende:", + "Aggregate": "Aggregation", + "Step type:": "Schritttyp:", + "seconds": "Sekunden", + "Seconds": "Sekunden", + "Step span:": "Schrittweite:", + "Link": "Link", + "Counts": "Anzahl", + "ignore 'null'": "'null' ignorieren", + "Time Span": "Zeit Spanne", + "Appearance": "Erscheinung", + "Title": "Beschriftung", + "Offset": "X-Offset", + "Aggregation": "Art", + "Chart Type": "Chart Type", + "Color": "Farbe", + "Min": "Min", + "Max": "Max", + "Unit": "Einheiten", + "Y Axis": "Y Axe", + "X Axis": "X Axe", + "update Preview": "Vorschau aktualisieren", + "Cancel": "Abbrechen", + "Name": "Name", + "Live update every:": "Autoupdate alle:", + "counts": "Anzahl", + "Add new line": "Linie hinzufügen", + "Animation:": "Animation:", + "no": "keine", + "0s": "0s", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 Sekunde", + "2s": "2 Sekunden", + "3s": "3 Sekunden", + "5s": "5 Sekunden", + "10s": "10 Sekunden", + "30s": "30 Sekunden", + "60s": "60 Sekunden", + "2m": "2 Minuten", + "3m": "3 Minuten", + "4m": "4 Minuten", + "5m": "5 Minuten", + "10m": "10 Minuten", + "15m": "15 Minuten", + "30m": "30 Minuten", + "45m": "45 Minuten", + "1H": "1 Stunde", + "2H": "2 Stunden", + "6H": "6 Stunden", + "12H": "12 Stunden", + "1D": "1 Tag", + "2D": "2 Tage", + "3D": "3 Tage", + "4D": "4 Tage", + "1W": "1 Woche", + "2W": "2 Wochen", + "4W": "4 Wochen", + "8W": "8 Wochen", + "12W": "12 Wochen", + "26W": "26 Wochen", + "1M": "1 Monat", + "2M": "2 Monate", + "3M": "3 Monate", + "6M": "6 Monate", + "1Y": "1 Jahr", + "2Y": "2 Jahre", + "average": "mittel", + "max": "max", + "min": "min", + "total": "total", + "off": "nichts", + "leftColor": "links farblich", + "rightColor": "rechts farblich", + "topColor": "oben farblich", + "bottomColor": "unten farblich", + "default": "default", + "Auto-update:": "Auto-update:", + "Use comma:": "Benutze Komma:", + "Common Y Axis": "Gemeinsame Y-Achse", + "Instance": "Instanz", + "Line Width": "Linienstärke", + "Shadow Size": "Schattengröße", + "ignore 'null':": "'null' ignorieren:", + "onchange": "bei Änderung", + "Border color:": "Rahmenfarbe:", + "Grid color:": "Gitterfarbe:", + "Border width:": "Rahmenbreite:", + "Enable zoom and pan:": "Aktiviere Zoom und Schieben:", + "Arrange bools": "Platziere Booleans", + "NULL as": "NULL als", + "MinMax": "MinMax", + "null": "null", + "true": "letztes Wert", + "last value": "letztes Wert", + "Hide edit button:": "Kein 'Edit'-Knopf:", + "minmax": "minmax", + "ØL": "ØL", + "ØS": "ØS", + "Line": "Linie", + "false": "null", + "end of minute": "Minutenende", + "end of 5 minutes": "Ende von 5 Minuten", + "end of 10 minutes": "Ende von 10 Minuten", + "end of 30 minutes": "Ende von 30 Minuten", + "end of hour": "Stundenende", + "end of 2 hours": "Ende von 2 Stunden", + "end of 3 hours": "Ende von 3 Stunden", + "end of 4 hours": "Ende von 4 Stunden", + "end of 6 hours": "Ende von 6 Stunden", + "end of 8 hours": "Ende von 8 Stunden", + "end of 12 hours": "Ende von 12 Stunden", + "end of day": "Tagesende", + "end of sunday": "Wochenssende", + "end of saturday": "Samstagsende", + "1minute": "Minutenende", + "5minutes": "Ende von 5 Minuten", + "10minutes": "Ende von 10 Minuten", + "30minutes": "Ende von 30 Minuten", + "1hour": "Stundenende", + "2hours": "Ende von 2 Stunden", + "3hours": "Ende von 3 Stunden", + "4hours": "Ende von 4 Stunden", + "6hours": "Ende von 6 Stunden", + "8hours": "Ende von 8 Stunden", + "12hours": "Ende von 12 Stunden", + "weekEurope": "Tagesende", + "weekUsa": "Wochenssende", + "Bar settings": "Bar-Einstellungen", + "Fill color:": "Füllfarbe color:", + "Show labels:": "Zeige Labels:", + "top over": "oben über", + "top under": "oben unten", + "middle": "mittig", + "Bars width:": "Barbreite:", + "Label font size:": "Labelschriftgröße:", + "Label color:": "Labelfarbe:", + "Markings": "Markierungen", + "Line ID": "Linie ID", + "Fill": "Füllen", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Text", + "Text position": "Textposition", + "Text offset": "Text-Offset", + "Text size": "Textgröße", + "Text color": "Textfarbe", + "Add new markings": "Neue Markierung hinzufügen", + "Left": "Links", + "Right": "Rechts", + "Upper value or ID": "Oberes Wert oder ID", + "Lower value or ID": "Unteres Wert oder ID", + "X-Axis ticks": "X-Achse-Ticks", + "Y-Axis ticks": "Y-Achse-Ticks", + "ignore null values": "null-Werte ignorieren", + "Ticks from:": "Benutze X-Ticks aus:", + "use 0 instead of null values": "0 statt null benutzen", + "More": "mehr", + "Edit options for line %s": "Editieren weitere Einstellungen für Linie %s", + "Legend columns:": "Spalten in Legende:", + "Legend opacity (from 0 to 1):": "Legende-Opacity (von 0 bis 1):", + "Legend background:": "Legende-Hintergrund:", + "Fill(0to1)": "Füllen(0bis1)", + "Points": "Punkte" +} diff --git a/src/i18n/en/translations.json b/src/i18n/en/translations.json new file mode 100644 index 0000000..4e6f121 --- /dev/null +++ b/src/i18n/en/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Ok", + "role": "role", + "Update objects": "Update objects", + "All": "All", + "With": "With", + "Without": "Without", + "Update states": "Update states", + "edit file": "edit file", + "restart script": "restart script", + "Select": "Select", + "Select ID": "Select ID", + "add children": "add children", + "edit enum": "edit enum", + "System settings": "System settings", + "reload": "reload", + "Delete object": "Delete object", + "no null": " no null", + "%s ago": "%s ago", + "Y-Offset": "Y-Offset", + "ID": "ID", + "Role": "Role", + "Room": "Room", + "Value": "Value", + "none": "none", + "Save into:": "Save into:", + "Name:": "Name:", + "save": "save", + "load": "load", + "Presets": "Presets", + "IDs": "IDs", + "new": "new", + "Enter chart name": "Enter chart name", + "save %s": "save %s", + "Input data": "Input data", + "Options": "Options", + "Range:": "Range:", + "5 seconds": "5 seconds", + "10 seconds": "10 seconds", + "15 seconds": "15 seconds", + "20 seconds": "20 seconds", + "30 seconds": "30 seconds", + "1 minute": "1 minute", + "2 minutes": "2 minutes", + "5 minutes": "5 minutes", + "10 minutes": "10 minutes", + "15 minutes": "15 minutes", + "20 minutes": "20 minutes", + "30 minutes": "30 minutes", + "1 hour": "1 hour", + "2 hours": "2 hours", + "3 hours": "3 hours", + "6 hours": "6 hours", + "12 hours": "12 hours", + "1 day": "1 day", + "2 days": "2 days", + "3 days": "3 days", + "7 days": "7 days", + "14 days": "14 days", + "1 month": "1 month", + "2 months": "2 months", + "3 months": "3 months", + "6 months": "6 months", + "1 year": "1 year", + "2 years": "2 years", + "Width:": "Width:", + "Height:": "Height:", + "line": "Line", + "area": "Area", + "bar": "Bar", + "lineplot": "Line plot", + "scatterplot": "Scatter plot", + "steps": "Steps", + "spline": "Spline", + "Stack": "Stack", + "Window background:": "Window background:", + "Custom chart background:": "Custom chart background:", + "Chart background:": "Chart background:", + "X axis labels color:": "X labels color:", + "Y axis labels color:": "Y labels color:", + "Show legend:": "Show legend:", + "Title:": "Title:", + "Title position:": "Title position:", + "Top, left, inside": "Top, left, inside", + "Top, right, inside": "Top, right, inside", + "Top, center, inside": "Top, center, inside", + "Middle, left, inside": "Middle, left, inside", + "Middle, right, inside": "Middle, right, inside", + "Bottom, left, inside": "Bottom, left, inside", + "Bottom, right, inside": "Bottom, right, inside", + "Bottom, center, inside": "Bottom, center, inside", + "Top, right, outside": "Top, right, outside", + "Middle, right, outside": "Middle, right, outside", + "Bottom, right, outside": "Bottom, right, outside", + "Bottom, center, outside": "Bottom, center, outside", + "Min:": "Minimum:", + "Max:": "Maximum:", + "User defined names:": "User defined names:", + "Predefined background:": "Predefined background:", + "User defined": "User defined", + "Background:": "Background:", + "Hover details:": "Hover details:", + "Time format:": "Time format:", + "Default": "Default", + "Smoothing": "Smoothing", + "After comma": "After comma", + "Open": "Open", + "Update": "Update", + "Reset settings": "Reset settings", + "From": "From: ", + "Last changed": "Last changed", + "Time stamp": "Time stamp", + "Acknowledged": "Acknowledged", + "Edit": "Edit", + "Members": "Members", + "Loading...": "Loading...", + "Processing...": "Processing...", + "With lines": "With lines", + "Without lines": "Without lines", + "Inside / With lines": "Inside / With lines", + "Outside/ With lines": "Outside/ With lines", + "Inside / No lines": "Inside / No lines", + "Outside / No lines": "Outside / No lines", + "Interpolate:": "Interpolate:", + "Steps": "Steps", + "Pie": "Pie", + "Top, left": "Top, left", + "Top, right": "Top, right", + "Bottom, left": "Bottom, left", + "Bottom, right": "Bottom, right", + "Title color:": "Title color:", + "Title size:": "Title size:", + "Fill range:": "Fill range:", + "Units:": "Units:", + "yes": "yes", + "bottom": "bottom", + "top": "top", + "left": "left", + "right": "right", + "No border:": "No border:", + "Time": "Time", + "day": "day", + "month": "month", + "year": "year", + "Individual": "Individual", + "Aggregation:": "Type:", + "relative": "relative", + "static": "static", + "now": "now", + "today": "today", + "this month": "this month", + "this year": "this year", + "Start:": "Start:", + "End:": "End:", + "Aggregate": "Aggregate", + "Step type:": "Step type:", + "seconds": "seconds", + "Seconds": "Seconds", + "Step span:": "Step span:", + "Link": "Link", + "Counts": "Counts", + "ignore 'null'": "ignore 'null'", + "Time Span": "Time Span", + "Appearance": "Appearance", + "Title": "Title", + "Offset": "X-Offset", + "Aggregation": "Type", + "Chart Type": "Chart Type", + "Color": "Color", + "Min": "Min", + "Max": "Max", + "Unit": "Unit", + "Y Axis": "Y Axis", + "X Axis": "X Axis", + "update Preview": "update Preview", + "Cancel": "Cancel", + "Name": "Name", + "Live update every:": "Live update every:", + "counts": "counts", + "Add new line": "Add new line", + "Animation:": "Animation:", + "no": "no", + "0s": "0 seconds", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 second", + "2s": "2 seconds", + "3s": "3 seconds", + "5s": "5 seconds", + "10s": "10 seconds", + "30s": "30 seconds", + "60s": "60 seconds", + "2m": "2 minutes", + "3m": "3 minutes", + "4m": "4 minutes", + "5m": "5 minutes", + "10m": "10 minutes", + "15m": "15 minutes", + "30m": "30 minutes", + "45m": "45 minutes", + "1H": "1 hour", + "2H": "2 hours", + "6H": "6 hours", + "12H": "12 hours", + "1D": "1 day", + "2D": "2 days", + "3D": "3 days", + "4D": "4 days", + "1W": "1 week", + "2W": "2 weeks", + "4W": "4 weeks", + "8W": "8 weeks", + "12W": "12 weeks", + "26W": "26 weeks", + "1M": "1 month", + "2M": "2 months", + "3M": "3 months", + "6M": "6 months", + "1Y": "1 year", + "2Y": "2 years", + "average": "average", + "max": "max", + "min": "min", + "total": "total", + "off": "off", + "leftColor": "left colored", + "rightColor": "right colored", + "topColor": "top colored", + "bottomColor": "bottom colored", + "default": "default", + "Auto-update:": "Auto-update:", + "Use comma:": "Use comma:", + "Common Y Axis": "Common Y Axis", + "Instance": "Instance", + "Line Width": "Line Width", + "Shadow Size": "Shadow Size", + "ignore 'null':": "ignore 'null':", + "onchange": "on change", + "Border color:": "Border color:", + "Grid color:": "Grid color:", + "Border width:": "Border width:", + "Enable zoom and pan:": "Enable zoom and pan:", + "Arrange bools": "Arrange booleans", + "NULL as": "NULL as", + "MinMax": "MinMax", + "null": "null", + "true": "last value", + "last value": "last value", + "Hide edit button:": "Hide edit button:", + "minmax": "minmax", + "ØL": "ØL", + "ØS": "ØS", + "Line": "Line", + "false": "null", + "end of minute": "end of minute", + "end of 5 minutes": "end of 5 minutes", + "end of 10 minutes": "end of 10 minutes", + "end of 30 minutes": "end of 30 minutes", + "end of hour": "end of hour", + "end of 2 hours": "end of 2 hours", + "end of 3 hours": "end of 3 hours", + "end of 4 hours": "end of 4 hours", + "end of 6 hours": "end of 6 hours", + "end of 8 hours": "end of 8 hours", + "end of 12 hours": "end of 12 hours", + "end of day": "end of day", + "end of sunday": "end of sunday", + "end of saturday": "end of saturday", + "1minute": "end of minute", + "5minutes": "end of 5 minutes", + "10minutes": "end of 10 minutes", + "30minutes": "end of 30 minutes", + "1hour": "end of hour", + "2hours": "end of 2 hours", + "3hours": "end of 3 hours", + "4hours": "end of 4 hours", + "6hours": "end of 6 hours", + "8hours": "end of 8 hours", + "12hours": "end of 12 hours", + "weekEurope": "end of day", + "weekUsa": "end of sunday", + "Bar settings": "Bar settings", + "Fill color:": "Fill color:", + "Show labels:": "Show labels:", + "top over": "top over", + "top under": "top under", + "middle": "middle", + "Bars width:": "Bars width:", + "Label font size:": "Label font size:", + "Label color:": "Label color:", + "Markings": "Markings", + "Line ID": "Line ID", + "Fill": "Fill", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Text", + "Text position": "Text position", + "Text offset": "Text offset", + "Text size": "Text size", + "Text color": "Text color", + "Add new markings": "Add new markings", + "Left": "Left", + "Right": "Right", + "Upper value or ID": "Upper value or ID", + "Lower value or ID": "Lower value or ID", + "X-Axis ticks": "X-Axis ticks", + "Y-Axis ticks": "Y-Axis ticks", + "ignore null values": "ignore null values", + "Ticks from:": "Use X-ticks from:", + "use 0 instead of null values": "use 0 instead of null values", + "More": "more", + "Edit options for line %s": "Edit options for line %s", + "Legend columns:": "Legend columns:", + "Legend opacity (from 0 to 1):": "Legend opacity (from 0 to 1):", + "Legend background:": "Legend background:", + "Fill(0to1)": "Fill(0to1)", + "Points": "Points" +} \ No newline at end of file diff --git a/src/i18n/es/translations.json b/src/i18n/es/translations.json new file mode 100644 index 0000000..8925c62 --- /dev/null +++ b/src/i18n/es/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "De acuerdo", + "role": "papel", + "Update objects": "Actualizar objetos", + "All": "Todas", + "With": "Con", + "Without": "Sin", + "Update states": "Actualizar estados", + "edit file": "editar archivo", + "restart script": "script de reinicio", + "Select": "Seleccionar", + "Select ID": "Seleccionar ID", + "add children": "agregar niños", + "edit enum": "editar enum", + "System settings": "Ajustes del sistema", + "reload": "recargar", + "Delete object": "Eliminar objeto", + "no null": "& nbsp; no null", + "%s ago": "hace% s", + "Y-Offset": "Y-Offset", + "ID": "CARNÉ DE IDENTIDAD", + "Role": "Papel", + "Room": "Habitación", + "Value": "Valor", + "none": "ninguna", + "Save into:": "Guardar en:", + "Name:": "Nombre:", + "save": "salvar", + "load": "carga", + "Presets": "Presets", + "IDs": "IDs", + "new": "nuevo", + "Enter chart name": "Ingrese el nombre del gráfico", + "save %s": "ahorra", + "Input data": "Datos de entrada", + "Options": "Opciones", + "Range:": "Distancia:", + "5 seconds": "5 segundos", + "10 seconds": "10 segundos", + "15 seconds": "15 segundos", + "20 seconds": "20 segundos", + "30 seconds": "30 segundos", + "1 minute": "1 minuto", + "2 minutes": "2 minutos", + "5 minutes": "5 minutos", + "10 minutes": "10 minutos", + "15 minutes": "15 minutos", + "20 minutes": "20 minutos", + "30 minutes": "30 minutos", + "1 hour": "1 hora", + "2 hours": "2 horas", + "3 hours": "3 horas", + "6 hours": "6 horas", + "12 hours": "12 horas", + "1 day": "1 día", + "2 days": "2 días", + "3 days": "3 días", + "7 days": "7 días", + "14 days": "14 dias", + "1 month": "1 mes", + "2 months": "2 meses", + "3 months": "3 meses", + "6 months": "6 meses", + "1 year": "1 año", + "2 years": "2 años", + "Width:": "Anchura:", + "Height:": "Altura:", + "line": "Línea", + "area": "Zona", + "bar": "Bar", + "lineplot": "Linear plot", + "scatterplot": "Gráfico de dispersión", + "steps": "Pasos", + "spline": "Ranura", + "Stack": "Apilar", + "Window background:": "Fondo de la ventana:", + "Custom chart background:": "Fondo de carta personalizada:", + "Chart background:": "Fondo de la carta:", + "X axis labels color:": "X etiquetas de color:", + "Y axis labels color:": "Color de etiquetas Y:", + "Show legend:": "Mostrar leyenda:", + "Title:": "Título:", + "Title position:": "Posición del título:", + "Top, left, inside": "Arriba, izquierda, adentro", + "Top, right, inside": "Arriba, derecha, adentro", + "Top, center, inside": "Arriba, centro, adentro", + "Middle, left, inside": "Medio, izquierdo, adentro", + "Middle, right, inside": "Medio, derecho, adentro", + "Bottom, left, inside": "Abajo, izquierda, adentro", + "Bottom, right, inside": "Abajo, derecha, adentro", + "Bottom, center, inside": "Abajo, centro, adentro", + "Top, right, outside": "Arriba, a la derecha, afuera", + "Middle, right, outside": "Medio, derecho, afuera", + "Bottom, right, outside": "Abajo, a la derecha, afuera", + "Bottom, center, outside": "Abajo, centro, afuera", + "Min:": "Mínimo:", + "Max:": "Máximo:", + "User defined names:": "Nombres definidos por el usuario:", + "Predefined background:": "Antecedentes predefinidos:", + "User defined": "Usuario definido", + "Background:": "Fondo:", + "Hover details:": "Hover detalles:", + "Time format:": "Formato de tiempo:", + "Default": "Defecto", + "Smoothing": "Suavizado", + "After comma": "Después de la coma", + "Open": "Abierto", + "Update": "Actualizar", + "Reset settings": "Reiniciar ajustes", + "From": "De:", + "Last changed": "Último cambio", + "Time stamp": "Marca de tiempo", + "Acknowledged": "Admitido", + "Edit": "Editar", + "Members": "Miembros", + "Loading...": "Cargando...", + "Processing...": "Tratamiento...", + "With lines": "Con líneas", + "Without lines": "Sin líneas", + "Inside / With lines": "Dentro / Con líneas", + "Outside/ With lines": "Fuera / Con líneas", + "Inside / No lines": "Dentro / Sin líneas", + "Outside / No lines": "Fuera / Sin líneas", + "Interpolate:": "Interpolar:", + "Steps": "Pasos", + "Pie": "Tarta", + "Top, left": "Arriba a la izquierda", + "Top, right": "Parte superior derecha", + "Bottom, left": "Abajo, izquierda", + "Bottom, right": "Abajo a la derecha", + "Title color:": "Color del título:", + "Title size:": "Tamaño del título:", + "Fill range:": "Rango de llenado:", + "Units:": "Unidades:", + "yes": "sí", + "bottom": "fondo", + "top": "parte superior", + "left": "izquierda", + "right": "derecho", + "No border:": "Sin bordes:", + "Time": "Hora", + "day": "día", + "month": "mes", + "year": "año", + "Individual": "Individual", + "Aggregation:": "Tipo:", + "relative": "relativo", + "static": "estático", + "now": "ahora", + "today": "hoy", + "this month": "este mes", + "this year": "este año", + "Start:": "Comienzo:", + "End:": "Fin:", + "Aggregate": "Agregar", + "Step type:": "Tipo de paso:", + "seconds": "segundos", + "Seconds": "Segundos", + "Step span:": "Lapso de paso:", + "Link": "Enlazar", + "Counts": "Cuenta", + "ignore 'null'": "ignorar 'nulo'", + "Time Span": "Espacio de tiempo", + "Appearance": "Apariencia", + "Title": "Título", + "Offset": "X-Offset", + "Aggregation": "Tipo", + "Chart Type": "Tipo de gráfico", + "Color": "Color", + "Min": "Min.", + "Max": "Max", + "Unit": "Unidad", + "Y Axis": "Eje Y", + "X Axis": "Eje X", + "update Preview": "actualización de Vista previa", + "Cancel": "Cancelar", + "Name": "Nombre", + "Live update every:": "Actualización en vivo cada:", + "counts": "conteos", + "Add new line": "Agregar nueva línea", + "Animation:": "Animación:", + "no": "no", + "0s": "0 segundos", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 segundo", + "2s": "2 segundos", + "3s": "3 segundos", + "5s": "5 segundos", + "10s": "10 segundos", + "30s": "30 segundos", + "60s": "60 segundos", + "2m": "2 minutos", + "3m": "3 minutos", + "4m": "4 minutos", + "5m": "5 minutos", + "10m": "10 minutos", + "15m": "15 minutos", + "30m": "30 minutos", + "45m": "45 minutos", + "1H": "1 hora", + "2H": "2 horas", + "6H": "6 horas", + "12H": "12 horas", + "1D": "1 día", + "2D": "2 días", + "3D": "3 días", + "4D": "4 dias", + "1W": "1 semana", + "2W": "2 semanas", + "4W": "4 semanas", + "8W": "8 semanas", + "12W": "12 semanas", + "26W": "26 semanas", + "1M": "1 mes", + "2M": "2 meses", + "3M": "3 meses", + "6M": "6 meses", + "1Y": "1 año", + "2Y": "2 años", + "average": "promedio", + "max": "máximo", + "min": "min", + "total": "total", + "off": "apagado", + "leftColor": "color izquierdo", + "rightColor": "color derecho", + "topColor": "tapa coloreada", + "bottomColor": "color de fondo", + "default": "defecto", + "Auto-update:": "Actualización automática:", + "Use comma:": "Usa la coma", + "Common Y Axis": "Eje Y común", + "Instance": "Ejemplo", + "Line Width": "Ancho de línea", + "Shadow Size": "Tamaño de las Sombras", + "ignore 'null':": "ignorar 'nulo':", + "onchange": "en cambio", + "Border color:": "Color del borde:", + "Grid color:": "Color de cuadrícula", + "Border width:": "Ancho del borde:", + "Enable zoom and pan:": "Habilitar zoom y pan:", + "Arrange bools": "Organizar booleanos", + "NULL as": "NULL como", + "MinMax": "Mínimo máximo", + "null": "nulo", + "true": "último valor", + "last value": "último valor", + "Hide edit button:": "Ocultar botón de edición:", + "minmax": "mínimo máximo", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Línea", + "false": "nulo", + "end of minute": "fin del minuto", + "end of 5 minutes": "fin de 5 minutos", + "end of 10 minutes": "fin de 10 minutos", + "end of 30 minutes": "fin de 30 minutos", + "end of hour": "fin de hora", + "end of 2 hours": "fin de 2 horas", + "end of 3 hours": "fin de 3 horas", + "end of 4 hours": "fin de 4 horas", + "end of 6 hours": "fin de 6 horas", + "end of 8 hours": "fin de 8 horas", + "end of 12 hours": "fin de 12 horas", + "end of day": "fin del día", + "end of sunday": "fin del domingo", + "end of saturday": "fin de sabado", + "1minute": "fin del minuto", + "5minutes": "fin de 5 minutos", + "10minutes": "fin de 10 minutos", + "30minutes": "fin de 30 minutos", + "1hour": "fin de hora", + "2hours": "fin de 2 horas", + "3hours": "fin de 3 horas", + "4hours": "fin de 4 horas", + "6hours": "fin de 6 horas", + "8hours": "fin de 8 horas", + "12hours": "fin de 12 horas", + "weekEurope": "fin del día", + "weekUsa": "fin del domingo", + "Bar settings": "Configuración de barra", + "Fill color:": "Color de relleno:", + "Show labels:": "Mostrar etiquetas:", + "top over": "arriba encima", + "top under": "arriba debajo", + "middle": "medio", + "Bars width:": "Ancho de barras:", + "Label font size:": "Tamaño de letra de la etiqueta:", + "Label color:": "Color de etiqueta:", + "Markings": "Marcas", + "Line ID": "Identificación de línea", + "Fill": "Llenar", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Texto", + "Text position": "Posición del texto", + "Text offset": "Offset de texto", + "Text size": "Tamano del texto", + "Text color": "Color de texto", + "Add new markings": "Agregar nuevas marcas", + "Left": "Izquierda", + "Right": "Derecha", + "Upper value or ID": "Valor superior o ID", + "Lower value or ID": "Menor valor o ID", + "X-Axis ticks": "Garrapatas X-Axis", + "Y-Axis ticks": "Señales del eje Y", + "ignore null values": "ignorar valores nulos", + "Ticks from:": "Use X-ticks desde:", + "use 0 instead of null values": "use 0 en lugar de valores nulos", + "More": "Más", + "Edit options for line %s": "Editar opciones para la línea% s", + "Legend columns:": "Columnas leyenda", + "Legend opacity (from 0 to 1):": "Opacidad de la leyenda (de 0 a 1):", + "Legend background:": "Antecedentes de leyenda:", + "Fill(0to1)": "Rellenar (0to1)", + "Points": "Puntos" +} \ No newline at end of file diff --git a/src/i18n/fr/translations.json b/src/i18n/fr/translations.json new file mode 100644 index 0000000..42fe6ae --- /dev/null +++ b/src/i18n/fr/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "D'accord", + "role": "rôle", + "Update objects": "Mettre à jour", + "All": "Tout", + "With": "Avec", + "Without": "Sans pour autant", + "Update states": "Mettre à jour", + "edit file": "modifier le fichier", + "restart script": "redémarrer le script", + "Select": "Sélectionner", + "Select ID": "Sélectionner un identifiant", + "add children": "ajouter des enfants", + "edit enum": "éditer enum", + "System settings": "Les paramètres du système", + "reload": "recharger", + "Delete object": "Supprimer un objet", + "no null": "& nbsp; non nul", + "%s ago": "il y a% s", + "Y-Offset": "Y-Offset", + "ID": "ID", + "Role": "Rôle", + "Room": "Chambre", + "Value": "Valeur", + "none": "aucun", + "Save into:": "Enregistrer dans:", + "Name:": "Prénom:", + "save": "enregistrer", + "load": "charge", + "Presets": "Presets", + "IDs": "ID", + "new": "Nouveau", + "Enter chart name": "Entrez le nom du diagramme", + "save %s": "enregistrer% s", + "Input data": "Des données d'entrée", + "Options": "Options", + "Range:": "Gamme:", + "5 seconds": "5 secondes", + "10 seconds": "10 secondes", + "15 seconds": "15 secondes", + "20 seconds": "20 secondes", + "30 seconds": "30 secondes", + "1 minute": "1 minute", + "2 minutes": "2 minutes", + "5 minutes": "5 minutes", + "10 minutes": "10 minutes", + "15 minutes": "15 minutes", + "20 minutes": "20 minutes", + "30 minutes": "30 minutes", + "1 hour": "1 heure", + "2 hours": "2 heures", + "3 hours": "3 heures", + "6 hours": "6 heures", + "12 hours": "12 heures", + "1 day": "Un jour", + "2 days": "2 jours", + "3 days": "3 jours", + "7 days": "7 jours", + "14 days": "14 jours", + "1 month": "1 mois", + "2 months": "2 mois", + "3 months": "3 mois", + "6 months": "6 mois", + "1 year": "1 an", + "2 years": "2 ans", + "Width:": "Largeur:", + "Height:": "La taille:", + "line": "Ligne", + "area": "Région", + "bar": "Bar", + "lineplot": "Graphique linéaire", + "scatterplot": "Scatter plot", + "steps": "Pas", + "spline": "Spline", + "Stack": "Empiler", + "Window background:": "Fond de fenêtre:", + "Custom chart background:": "Arrière-plan de graphique personnalisé:", + "Chart background:": "Arrière-plan du graphique", + "X axis labels color:": "X étiquettes couleur:", + "Y axis labels color:": "Couleur des étiquettes Y:", + "Show legend:": "Afficher la légende:", + "Title:": "Titre:", + "Title position:": "Titre du poste:", + "Top, left, inside": "Haut, gauche, intérieur", + "Top, right, inside": "En haut, à droite, à l'intérieur", + "Top, center, inside": "Haut, centre, intérieur", + "Middle, left, inside": "Milieu, gauche, intérieur", + "Middle, right, inside": "Moyen, droit, intérieur", + "Bottom, left, inside": "Bas, gauche, intérieur", + "Bottom, right, inside": "En bas, à droite, à l'intérieur", + "Bottom, center, inside": "Bas, centre, intérieur", + "Top, right, outside": "Haut, droit, dehors", + "Middle, right, outside": "Moyen, droit, dehors", + "Bottom, right, outside": "En bas, à droite, à l'extérieur", + "Bottom, center, outside": "Bas, centre, extérieur", + "Min:": "Le minimum:", + "Max:": "Maximum:", + "User defined names:": "Noms définis par l'utilisateur:", + "Predefined background:": "Arrière-plan prédéfini:", + "User defined": "Défini par l'utilisateur", + "Background:": "Contexte:", + "Hover details:": "Hover détails:", + "Time format:": "Format de l'heure:", + "Default": "Défaut", + "Smoothing": "Lissage", + "After comma": "Après la virgule", + "Open": "Ouvrir", + "Update": "Mettre à jour", + "Reset settings": "Réinitialiser les options", + "From": "De:", + "Last changed": "Dernière modification", + "Time stamp": "Horodatage", + "Acknowledged": "Reconnu", + "Edit": "modifier", + "Members": "Membres", + "Loading...": "Chargement...", + "Processing...": "En traitement...", + "With lines": "Avec des lignes", + "Without lines": "Sans lignes", + "Inside / With lines": "À l'intérieur / Avec des lignes", + "Outside/ With lines": "Extérieur / Avec lignes", + "Inside / No lines": "À l'intérieur / Pas de lignes", + "Outside / No lines": "Extérieur / Pas de lignes", + "Interpolate:": "Interpoler:", + "Steps": "Pas", + "Pie": "Tarte", + "Top, left": "En haut à gauche", + "Top, right": "En haut à droite", + "Bottom, left": "En bas à gauche", + "Bottom, right": "En bas à droite", + "Title color:": "Couleur du titre:", + "Title size:": "Taille du titre:", + "Fill range:": "Remplir gamme:", + "Units:": "Unités:", + "yes": "Oui", + "bottom": "bas", + "top": "Haut", + "left": "la gauche", + "right": "droite", + "No border:": "Pas de frontière:", + "Time": "Temps", + "day": "journée", + "month": "mois", + "year": "an", + "Individual": "Individuel", + "Aggregation:": "Type:", + "relative": "relatif", + "static": "statique", + "now": "à présent", + "today": "aujourd'hui", + "this month": "ce mois-ci", + "this year": "cette année", + "Start:": "Début:", + "End:": "Fin:", + "Aggregate": "Agrégat", + "Step type:": "Type d'étape:", + "seconds": "secondes", + "Seconds": "Secondes", + "Step span:": "Étape span:", + "Link": "Lien", + "Counts": "Compte", + "ignore 'null'": "ignore 'null'", + "Time Span": "Durée", + "Appearance": "Apparence", + "Title": "Titre", + "Offset": "X-Offset", + "Aggregation": "Type", + "Chart Type": "Type de graphique", + "Color": "Couleur", + "Min": "Min", + "Max": "Max", + "Unit": "Unité", + "Y Axis": "Axe Y", + "X Axis": "Axe X", + "update Preview": "aperçu de mise à jour", + "Cancel": "Annuler", + "Name": "prénom", + "Live update every:": "Mise à jour en direct tous les:", + "counts": "compte", + "Add new line": "Ajouter une nouvelle ligne", + "Animation:": "Animation:", + "no": "non", + "0s": "0 seconde", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 seconde", + "2s": "2 secondes", + "3s": "3 secondes", + "5s": "5 secondes", + "10s": "10 secondes", + "30s": "30 secondes", + "60s": "60 secondes", + "2m": "2 minutes", + "3m": "3 minutes", + "4m": "4 minutes", + "5m": "5 minutes", + "10m": "10 minutes", + "15m": "15 minutes", + "30m": "30 minutes", + "45m": "45 minutes", + "1H": "1 heure", + "2H": "2 heures", + "6H": "6 heures", + "12H": "12 heures", + "1D": "Un jour", + "2D": "2 jours", + "3D": "3 jours", + "4D": "4 jours", + "1W": "1 semaine", + "2W": "2 semaines", + "4W": "4 semaines", + "8W": "8 semaines", + "12W": "12 semaines", + "26W": "26 semaines", + "1M": "1 mois", + "2M": "2 mois", + "3M": "3 mois", + "6M": "6 mois", + "1Y": "1 an", + "2Y": "2 ans", + "average": "moyenne", + "max": "max", + "min": "min", + "total": "total", + "off": "de", + "leftColor": "laissé coloré", + "rightColor": "couleur droite", + "topColor": "top coloré", + "bottomColor": "fond coloré", + "default": "défaut", + "Auto-update:": "Mise à jour automatique:", + "Use comma:": "Utilisez une virgule:", + "Common Y Axis": "Axe Y commun", + "Instance": "Exemple", + "Line Width": "Largeur de ligne", + "Shadow Size": "Taille de l'ombre", + "ignore 'null':": "ignore 'null':", + "onchange": "sur le changement", + "Border color:": "Couleur de la bordure:", + "Grid color:": "Couleur de la grille:", + "Border width:": "Largeur de la bordure:", + "Enable zoom and pan:": "Activer le zoom et le panoramique:", + "Arrange bools": "Organiser les booléens", + "NULL as": "NULL comme", + "MinMax": "Min max", + "null": "nul", + "true": "dernière valeur", + "last value": "dernière valeur", + "Hide edit button:": "Masquer le bouton d'édition:", + "minmax": "min max", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Ligne", + "false": "nul", + "end of minute": "fin de minute", + "end of 5 minutes": "fin de 5 minutes", + "end of 10 minutes": "fin de 10 minutes", + "end of 30 minutes": "fin de 30 minutes", + "end of hour": "fin de l'heure", + "end of 2 hours": "fin de 2 heures", + "end of 3 hours": "fin de 3 heures", + "end of 4 hours": "fin de 4 heures", + "end of 6 hours": "fin de 6 heures", + "end of 8 hours": "fin de 8 heures", + "end of 12 hours": "fin de 12 heures", + "end of day": "fin de la journée", + "end of sunday": "fin de dimanche", + "end of saturday": "fin de samedi", + "1minute": "fin de minute", + "5minutes": "fin de 5 minutes", + "10minutes": "fin de 10 minutes", + "30minutes": "fin de 30 minutes", + "1hour": "fin de l'heure", + "2hours": "fin de 2 heures", + "3hours": "fin de 3 heures", + "4hours": "fin de 4 heures", + "6hours": "fin de 6 heures", + "8hours": "fin de 8 heures", + "12hours": "fin de 12 heures", + "weekEurope": "fin de la journée", + "weekUsa": "fin de dimanche", + "Bar settings": "Paramètres du bar", + "Fill color:": "La couleur de remplissage:", + "Show labels:": "Afficher les étiquettes:", + "top over": "dessus", + "top under": "haut sous", + "middle": "milieu", + "Bars width:": "Largeur des barres:", + "Label font size:": "Étiquette taille de la police:", + "Label color:": "Étiquette couleur:", + "Markings": "Marquages", + "Line ID": "Id de ligne", + "Fill": "Remplir", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Texte", + "Text position": "Position du texte", + "Text offset": "Décalage de texte", + "Text size": "Taille du texte", + "Text color": "Couleur du texte", + "Add new markings": "Ajouter de nouvelles marques", + "Left": "La gauche", + "Right": "Droite", + "Upper value or ID": "Valeur supérieure ou ID", + "Lower value or ID": "Valeur inférieure ou ID", + "X-Axis ticks": "Tiques de l'axe des X", + "Y-Axis ticks": "Tiques de l'axe des Y", + "ignore null values": "ignorer les valeurs nulles", + "Ticks from:": "Utilisez les X-ticks de:", + "use 0 instead of null values": "utilise 0 au lieu de valeurs nulles", + "More": "plus", + "Edit options for line %s": "Modifier les options pour la ligne% s", + "Legend columns:": "Colonnes de légende:", + "Legend opacity (from 0 to 1):": "Opacité de la légende (de 0 à 1):", + "Legend background:": "Contexte de la légende", + "Fill(0to1)": "Remplir (0to1)", + "Points": "Points" +} \ No newline at end of file diff --git a/src/i18n/it/translations.json b/src/i18n/it/translations.json new file mode 100644 index 0000000..df64cb8 --- /dev/null +++ b/src/i18n/it/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Ok", + "role": "ruolo", + "Update objects": "Aggiorna oggetti", + "All": "Tutti", + "With": "Con", + "Without": "Senza", + "Update states": "Stati di aggiornamento", + "edit file": "modifica file", + "restart script": "riavviare lo script", + "Select": "Selezionare", + "Select ID": "Seleziona ID", + "add children": "aggiungi bambini", + "edit enum": "modifica enum", + "System settings": "Impostazioni di sistema", + "reload": "ricaricare", + "Delete object": "Elimina oggetto", + "no null": "& nbsp; non null", + "%s ago": "% s fa", + "Y-Offset": "Y-Offset", + "ID": "ID", + "Role": "Ruolo", + "Room": "Camera", + "Value": "Valore", + "none": "nessuna", + "Save into:": "Salva in:", + "Name:": "Nome:", + "save": "salvare", + "load": "caricare", + "Presets": "Presets", + "IDs": "ID", + "new": "nuovo", + "Enter chart name": "Inserisci il nome del grafico", + "save %s": "salva% s", + "Input data": "Dati in ingresso", + "Options": "Opzioni", + "Range:": "Gamma:", + "5 seconds": "5 secondi", + "10 seconds": "10 secondi", + "15 seconds": "15 secondi", + "20 seconds": "20 secondi", + "30 seconds": "30 secondi", + "1 minute": "1 minuto", + "2 minutes": "2 minuti", + "5 minutes": "5 minuti", + "10 minutes": "10 minuti", + "15 minutes": "15 minuti", + "20 minutes": "20 minuti", + "30 minutes": "30 minuti", + "1 hour": "1 ora", + "2 hours": "2 ore", + "3 hours": "3 ore", + "6 hours": "6 ore", + "12 hours": "12 ore", + "1 day": "1 giorno", + "2 days": "2 giorni", + "3 days": "3 giorni", + "7 days": "7 giorni", + "14 days": "14 giorni", + "1 month": "1 mese", + "2 months": "Due mesi", + "3 months": "3 mesi", + "6 months": "6 mesi", + "1 year": "1 anno", + "2 years": "2 anni", + "Width:": "Larghezza:", + "Height:": "Altezza:", + "line": "Linea", + "area": "La zona", + "bar": "Bar", + "lineplot": "Trama di linea", + "scatterplot": "Trama sparsa", + "steps": "passi", + "spline": "linguetta", + "Stack": "Pila", + "Window background:": "Sfondo della finestra:", + "Custom chart background:": "Sfondo grafico personalizzato:", + "Chart background:": "Sfondo del grafico:", + "X axis labels color:": "Colore etichette X:", + "Y axis labels color:": "Il colore delle etichette Y:", + "Show legend:": "Mostra legenda:", + "Title:": "Titolo:", + "Title position:": "Posizione del titolo:", + "Top, left, inside": "In alto, a sinistra, dentro", + "Top, right, inside": "In alto, a destra, dentro", + "Top, center, inside": "In alto, al centro, dentro", + "Middle, left, inside": "Medio, a sinistra, dentro", + "Middle, right, inside": "Medio, giusto, dentro", + "Bottom, left, inside": "In basso, a sinistra, dentro", + "Bottom, right, inside": "In basso, a destra, dentro", + "Bottom, center, inside": "In basso, al centro, dentro", + "Top, right, outside": "In alto, a destra, fuori", + "Middle, right, outside": "Medio, giusto, esterno", + "Bottom, right, outside": "In basso, a destra, fuori", + "Bottom, center, outside": "In basso, al centro, fuori", + "Min:": "Minimo:", + "Max:": "Massimo:", + "User defined names:": "Nomi definiti dall'utente:", + "Predefined background:": "Sfondo predefinito:", + "User defined": "Definito dall'utente", + "Background:": "Sfondo:", + "Hover details:": "Dettagli al passaggio del mouse:", + "Time format:": "Formato orario:", + "Default": "Predefinito", + "Smoothing": "lisciatura", + "After comma": "Dopo la virgola", + "Open": "Aperto", + "Update": "Aggiornare", + "Reset settings": "Ripristina le impostazioni", + "From": "A partire dal:", + "Last changed": "Ultima modifica", + "Time stamp": "Data e ora", + "Acknowledged": "Riconosciuto", + "Edit": "modificare", + "Members": "Utenti", + "Loading...": "Caricamento in corso...", + "Processing...": "In lavorazione...", + "With lines": "Con le linee", + "Without lines": "Senza linee", + "Inside / With lines": "Interno / Con linee", + "Outside/ With lines": "Esterno / Con linee", + "Inside / No lines": "Dentro / Nessuna linea", + "Outside / No lines": "Fuori / Nessuna linea", + "Interpolate:": "Interpolare:", + "Steps": "passi", + "Pie": "Torta", + "Top, left": "A sinistra in alto", + "Top, right": "In alto a destra", + "Bottom, left": "In basso a sinistra", + "Bottom, right": "In basso a destra", + "Title color:": "Colore del titolo:", + "Title size:": "Dimensione del titolo:", + "Fill range:": "Gamma di riempimento:", + "Units:": "unità:", + "yes": "sì", + "bottom": "parte inferiore", + "top": "superiore", + "left": "sinistra", + "right": "destra", + "No border:": "Nessun confine:", + "Time": "Tempo", + "day": "giorno", + "month": "mese", + "year": "anno", + "Individual": "Individuale", + "Aggregation:": "Genere:", + "relative": "parente", + "static": "statico", + "now": "adesso", + "today": "oggi", + "this month": "questo mese", + "this year": "quest'anno", + "Start:": "Inizio:", + "End:": "Fine:", + "Aggregate": "Aggregato", + "Step type:": "Tipo di passaggio:", + "seconds": "secondi", + "Seconds": "secondi", + "Step span:": "Intervallo:", + "Link": "collegamento", + "Counts": "Conti", + "ignore 'null'": "ignora 'null'", + "Time Span": "Arco di tempo", + "Appearance": "Aspetto", + "Title": "Titolo", + "Offset": "X-Offset", + "Aggregation": "genere", + "Chart Type": "Tipo di grafico", + "Color": "Colore", + "Min": "min", + "Max": "Max", + "Unit": "Unità", + "Y Axis": "Asse Y.", + "X Axis": "Asse X.", + "update Preview": "Aggiorna anteprima", + "Cancel": "Annulla", + "Name": "Nome", + "Live update every:": "Aggiornamento live ogni:", + "counts": "conta", + "Add new line": "Aggiungi una nuova linea", + "Animation:": "Animazione:", + "no": "no", + "0s": "0 secondi", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 secondo", + "2s": "2 secondi", + "3s": "3 secondi", + "5s": "5 secondi", + "10s": "10 secondi", + "30s": "30 secondi", + "60s": "60 secondi", + "2m": "2 minuti", + "3m": "3 minuti", + "4m": "4 minuti", + "5m": "5 minuti", + "10m": "10 minuti", + "15m": "15 minuti", + "30m": "30 minuti", + "45m": "45 minuti", + "1H": "1 ora", + "2H": "2 ore", + "6H": "6 ore", + "12H": "12 ore", + "1D": "1 giorno", + "2D": "2 giorni", + "3D": "3 giorni", + "4D": "4 giorni", + "1W": "1 settimana", + "2W": "2 settimane", + "4W": "4 settimane", + "8W": "8 settimane", + "12W": "12 settimane", + "26W": "26 settimane", + "1M": "1 mese", + "2M": "Due mesi", + "3M": "3 mesi", + "6M": "6 mesi", + "1Y": "1 anno", + "2Y": "2 anni", + "average": "media", + "max": "max", + "min": "min", + "total": "totale", + "off": "via", + "leftColor": "lasciato colorato", + "rightColor": "giusto colorato", + "topColor": "top colorato", + "bottomColor": "fondo colorato", + "default": "predefinito", + "Auto-update:": "Aggiornamento automatico:", + "Use comma:": "Usa la virgola:", + "Common Y Axis": "Asse Y comune", + "Instance": "Esempio", + "Line Width": "Larghezza della linea", + "Shadow Size": "Dimensione dell'ombra", + "ignore 'null':": "ignora 'null':", + "onchange": "sul cambiamento", + "Border color:": "Colore del bordo:", + "Grid color:": "Colore griglia:", + "Border width:": "Larghezza del bordo:", + "Enable zoom and pan:": "Abilita zoom e panoramica:", + "Arrange bools": "Disporre i booleani", + "NULL as": "NULL come", + "MinMax": "Minimo Massimo", + "null": "nullo", + "true": "ultimo valore", + "last value": "ultimo valore", + "Hide edit button:": "Nascondi pulsante di modifica:", + "minmax": "minimo Massimo", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Linea", + "false": "nullo", + "end of minute": "fine del minuto", + "end of 5 minutes": "fine di 5 minuti", + "end of 10 minutes": "fine di 10 minuti", + "end of 30 minutes": "fine di 30 minuti", + "end of hour": "fine dell'ora", + "end of 2 hours": "fine di 2 ore", + "end of 3 hours": "fine di 3 ore", + "end of 4 hours": "fine di 4 ore", + "end of 6 hours": "fine di 6 ore", + "end of 8 hours": "fine di 8 ore", + "end of 12 hours": "fine di 12 ore", + "end of day": "fine del giorno", + "end of sunday": "fine della domenica", + "end of saturday": "fine di sabato", + "1minute": "fine del minuto", + "5minutes": "fine di 5 minuti", + "10minutes": "fine di 10 minuti", + "30minutes": "fine di 30 minuti", + "1hour": "fine dell'ora", + "2hours": "fine di 2 ore", + "3hours": "fine di 3 ore", + "4hours": "fine di 4 ore", + "6hours": "fine di 6 ore", + "8hours": "fine di 8 ore", + "12hours": "fine di 12 ore", + "weekEurope": "fine del giorno", + "weekUsa": "fine della domenica", + "Bar settings": "Impostazioni della barra", + "Fill color:": "Colore di riempimento:", + "Show labels:": "Mostra etichette:", + "top over": "sopra", + "top under": "sopra sotto", + "middle": "mezzo", + "Bars width:": "Larghezza delle barre:", + "Label font size:": "Dimensione del carattere dell'etichetta:", + "Label color:": "Colore dell'etichetta:", + "Markings": "marcature", + "Line ID": "ID linea", + "Fill": "Riempire", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Testo", + "Text position": "Posizione del testo", + "Text offset": "Offset del testo", + "Text size": "Dimensione del testo", + "Text color": "Colore del testo", + "Add new markings": "Aggiungi nuovi segni", + "Left": "Sinistra", + "Right": "Destra", + "Upper value or ID": "Valore massimo o ID", + "Lower value or ID": "Valore più basso o ID", + "X-Axis ticks": "Zecche X-Axis", + "Y-Axis ticks": "Zecche dell'asse Y.", + "ignore null values": "ignora valori nulli", + "Ticks from:": "Usa X-tick da:", + "use 0 instead of null values": "usa 0 invece di valori nulli", + "More": "Di Più", + "Edit options for line %s": "Modifica le opzioni per la riga% s", + "Legend columns:": "Colonne della legenda:", + "Legend opacity (from 0 to 1):": "Opacità della legenda (da 0 a 1):", + "Legend background:": "Sfondo leggenda:", + "Fill(0to1)": "Fill (0to1)", + "Points": "Punti" +} \ No newline at end of file diff --git a/src/i18n/nl/translations.json b/src/i18n/nl/translations.json new file mode 100644 index 0000000..dd4d68b --- /dev/null +++ b/src/i18n/nl/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "OK", + "role": "rol", + "Update objects": "Objecten bijwerken", + "All": "Alle", + "With": "Met", + "Without": "Zonder", + "Update states": "Status bijwerken", + "edit file": "bestand bewerken", + "restart script": "herstart script", + "Select": "kiezen", + "Select ID": "Selecteer ID", + "add children": "voeg kinderen toe", + "edit enum": "edit enum", + "System settings": "Systeem instellingen", + "reload": "herladen", + "Delete object": "Object verwijderen", + "no null": "& nbsp; geen null", + "%s ago": "% s geleden", + "Y-Offset": "Y-offset", + "ID": "ID kaart", + "Role": "Rol", + "Room": "Kamer", + "Value": "Waarde", + "none": "geen", + "Save into:": "Bewaar in:", + "Name:": "Naam:", + "save": "opslaan", + "load": "laden", + "Presets": "presets", + "IDs": "IDs", + "new": "nieuwe", + "Enter chart name": "Voer de diagramnaam in", + "save %s": "bespaar% s", + "Input data": "Invoergegevens", + "Options": "opties", + "Range:": "bereik:", + "5 seconds": "5 seconden", + "10 seconds": "10 seconden", + "15 seconds": "15 seconden", + "20 seconds": "20 seconden", + "30 seconds": "30 seconden", + "1 minute": "1 minuut", + "2 minutes": "2 minuten", + "5 minutes": "5 minuten", + "10 minutes": "10 minuten", + "15 minutes": "15 minuten", + "20 minutes": "20 minuten", + "30 minutes": "30 minuten", + "1 hour": "1 uur", + "2 hours": "twee uur", + "3 hours": "3 uur", + "6 hours": "6 uur", + "12 hours": "12 uren", + "1 day": "1 dag", + "2 days": "2 dagen", + "3 days": "3 dagen", + "7 days": "7 dagen", + "14 days": "14 dagen", + "1 month": "1 maand", + "2 months": "2 maanden", + "3 months": "3 maanden", + "6 months": "6 maanden", + "1 year": "1 jaar", + "2 years": "2 jaar", + "Width:": "Breedte:", + "Height:": "Hoogte:", + "line": "Lijn", + "area": "Gebied", + "bar": "Bar", + "lineplot": "Lijnplot", + "scatterplot": "Scatterplot", + "steps": "Stappen", + "spline": "spline", + "Stack": "stack", + "Window background:": "Venster achtergrond:", + "Custom chart background:": "Aangepaste grafiek achtergrond:", + "Chart background:": "Grafiek achtergrond:", + "X axis labels color:": "X labels kleur:", + "Y axis labels color:": "Y-labels kleur:", + "Show legend:": "Legenda weergeven:", + "Title:": "Titel:", + "Title position:": "Titel positie:", + "Top, left, inside": "Boven, links, binnen", + "Top, right, inside": "Boven, rechts, binnen", + "Top, center, inside": "Boven, midden, binnenkant", + "Middle, left, inside": "Midden, links, binnenkant", + "Middle, right, inside": "Midden, rechts, binnenkant", + "Bottom, left, inside": "Onder, links, binnen", + "Bottom, right, inside": "Onder, rechts, binnen", + "Bottom, center, inside": "Onder, midden, binnen", + "Top, right, outside": "Boven, rechts, buiten", + "Middle, right, outside": "Midden, rechts, buiten", + "Bottom, right, outside": "Onder, rechts, buiten", + "Bottom, center, outside": "Onder, midden, buiten", + "Min:": "Minimum:", + "Max:": "maximaal:", + "User defined names:": "Door de gebruiker gedefinieerde namen:", + "Predefined background:": "Voorgedefinieerde achtergrond:", + "User defined": "Gebruiker gedefinieerde", + "Background:": "Achtergrond:", + "Hover details:": "Hover details:", + "Time format:": "Tijd formaat:", + "Default": "Standaard", + "Smoothing": "smoothing", + "After comma": "Na een komma", + "Open": "Open", + "Update": "Bijwerken", + "Reset settings": "Reset instellingen", + "From": "Van:", + "Last changed": "Laatst gewijzigd", + "Time stamp": "Tijdstempel", + "Acknowledged": "Erkend", + "Edit": "Bewerk", + "Members": "leden", + "Loading...": "Bezig met laden...", + "Processing...": "Verwerken...", + "With lines": "Met lijnen", + "Without lines": "Zonder lijnen", + "Inside / With lines": "Binnen / met lijnen", + "Outside/ With lines": "Buiten / met lijnen", + "Inside / No lines": "Binnenkant / Geen regels", + "Outside / No lines": "Buiten / Geen lijnen", + "Interpolate:": "Interpoleren:", + "Steps": "Stappen", + "Pie": "Taart", + "Top, left": "Linksboven", + "Top, right": "Rechtsboven", + "Bottom, left": "Linksonder", + "Bottom, right": "Rechts onder", + "Title color:": "Titel kleur:", + "Title size:": "Titel grootte:", + "Fill range:": "Vulbereik:", + "Units:": "units:", + "yes": "Ja", + "bottom": "bodem", + "top": "top", + "left": "links", + "right": "rechts", + "No border:": "Geen grens:", + "Time": "Tijd", + "day": "dag", + "month": "maand", + "year": "jaar", + "Individual": "individu", + "Aggregation:": "Type:", + "relative": "familielid", + "static": "statisch", + "now": "nu", + "today": "vandaag", + "this month": "deze maand", + "this year": "dit jaar", + "Start:": "Begin:", + "End:": "Einde:", + "Aggregate": "Aggregaat", + "Step type:": "Stap type:", + "seconds": "seconden", + "Seconds": "seconden", + "Step span:": "Stap overspanning:", + "Link": "Link", + "Counts": "tellingen", + "ignore 'null'": "negeer 'null'", + "Time Span": "Tijdspanne", + "Appearance": "Uiterlijk", + "Title": "Titel", + "Offset": "-X Offset", + "Aggregation": "Type", + "Chart Type": "Diagramtype", + "Color": "Kleur", + "Min": "min", + "Max": "Max", + "Unit": "Eenheid", + "Y Axis": "Y-as", + "X Axis": "X-as", + "update Preview": "voorproefje van de nieuwe versie", + "Cancel": "Annuleer", + "Name": "Naam", + "Live update every:": "Live update elke:", + "counts": "tellingen", + "Add new line": "Voeg een nieuwe regel toe", + "Animation:": "animatie:", + "no": "Nee", + "0s": "0 seconden", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 seconde", + "2s": "2 seconden", + "3s": "3 seconden", + "5s": "5 seconden", + "10s": "10 seconden", + "30s": "30 seconden", + "60s": "60 seconden", + "2m": "2 minuten", + "3m": "3 minuten", + "4m": "4 minuten", + "5m": "5 minuten", + "10m": "10 minuten", + "15m": "15 minuten", + "30m": "30 minuten", + "45m": "45 minuten", + "1H": "1 uur", + "2H": "twee uur", + "6H": "6 uur", + "12H": "12 uren", + "1D": "1 dag", + "2D": "2 dagen", + "3D": "3 dagen", + "4D": "4 dagen", + "1W": "1 week", + "2W": "2 weken", + "4W": "4 weken", + "8W": "8 weken", + "12W": "12 weken", + "26W": "26 weken", + "1M": "1 maand", + "2M": "2 maanden", + "3M": "3 maanden", + "6M": "6 maanden", + "1Y": "1 jaar", + "2Y": "2 jaar", + "average": "gemiddelde", + "max": "max", + "min": "min", + "total": "totaal", + "off": "uit", + "leftColor": "links gekleurd", + "rightColor": "rechts gekleurd", + "topColor": "bovenaan gekleurd", + "bottomColor": "onderaan gekleurd", + "default": "standaard", + "Auto-update:": "Auto update:", + "Use comma:": "Gebruik komma:", + "Common Y Axis": "Gemeenschappelijke Y-as", + "Instance": "Aanleg", + "Line Width": "Lijnbreedte", + "Shadow Size": "Schaduwgrootte", + "ignore 'null':": "negeer 'null':", + "onchange": "over verandering", + "Border color:": "Rand kleur:", + "Grid color:": "Raster kleur:", + "Border width:": "Grensbreedte:", + "Enable zoom and pan:": "Zoom en pan inschakelen:", + "Arrange bools": "Booleans regelen", + "NULL as": "NULL als", + "MinMax": "MinMax", + "null": "nul", + "true": "laatste waarde", + "last value": "laatste waarde", + "Hide edit button:": "Verberg bewerken knop:", + "minmax": "MinMax", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Lijn", + "false": "nul", + "end of minute": "einde van de minuut", + "end of 5 minutes": "einde van 5 minuten", + "end of 10 minutes": "einde van 10 minuten", + "end of 30 minutes": "einde van 30 minuten", + "end of hour": "einde van het uur", + "end of 2 hours": "einde van 2 uur", + "end of 3 hours": "einde van 3 uur", + "end of 4 hours": "einde van 4 uur", + "end of 6 hours": "einde van 6 uur", + "end of 8 hours": "einde van 8 uur", + "end of 12 hours": "einde van 12 uur", + "end of day": "einde van de dag", + "end of sunday": "einde van zondag", + "end of saturday": "einde van zaterdag", + "1minute": "einde van de minuut", + "5minutes": "einde van 5 minuten", + "10minutes": "einde van 10 minuten", + "30minutes": "einde van 30 minuten", + "1hour": "einde van het uur", + "2hours": "einde van 2 uur", + "3hours": "einde van 3 uur", + "4hours": "einde van 4 uur", + "6hours": "einde van 6 uur", + "8hours": "einde van 8 uur", + "12hours": "einde van 12 uur", + "weekEurope": "einde van de dag", + "weekUsa": "einde van zondag", + "Bar settings": "Bar-instellingen", + "Fill color:": "Opvulkleur:", + "Show labels:": "Toon labels:", + "top over": "opnieuw gedaan", + "top under": "top onder", + "middle": "midden-", + "Bars width:": "Staaf breedte:", + "Label font size:": "Label lettergrootte:", + "Label color:": "Label kleur:", + "Markings": "markeringen", + "Line ID": "Lijn-ID", + "Fill": "Vullen", + "ØL": "ØL", + "ØS": "Os", + "Text": "Tekst", + "Text position": "Tekstpositie", + "Text offset": "Tekst offset", + "Text size": "Lettergrootte", + "Text color": "Tekst kleur", + "Add new markings": "Voeg nieuwe markeringen toe", + "Left": "Links", + "Right": "Rechts", + "Upper value or ID": "Hoogste waarde of ID", + "Lower value or ID": "Lagere waarde of ID", + "X-Axis ticks": "X-as-teken", + "Y-Axis ticks": "Y-as tikken", + "ignore null values": "Negeer waarden negeren", + "Ticks from:": "Gebruik X-ticks van:", + "use 0 instead of null values": "gebruik 0 in plaats van nulwaarden", + "More": "meer", + "Edit options for line %s": "Bewerk opties voor regel% s", + "Legend columns:": "Legenda kolommen:", + "Legend opacity (from 0 to 1):": "Legenda opaciteit (van 0 tot 1):", + "Legend background:": "Legenda achtergrond:", + "Fill(0to1)": "Fill (0to1)", + "Points": "punten" +} \ No newline at end of file diff --git a/src/i18n/pl/translations.json b/src/i18n/pl/translations.json new file mode 100644 index 0000000..b7bb7c8 --- /dev/null +++ b/src/i18n/pl/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Ok", + "role": "rola", + "Update objects": "Zaktualizuj obiekty", + "All": "Wszystko", + "With": "Z", + "Without": "Bez", + "Update states": "Zaktualizuj stany", + "edit file": "edytuj plik", + "restart script": "zrestartuj skrypt", + "Select": "Wybierz", + "Select ID": "Wybierz ID", + "add children": "dodaj dzieci", + "edit enum": "edytuj wyliczenie", + "System settings": "Ustawienia systemowe", + "reload": "przeładować", + "Delete object": "Usuń obiekt", + "no null": "& nbsp; no null", + "%s ago": "% s temu", + "Y-Offset": "Przesunięcie Y", + "ID": "ID", + "Role": "Rola", + "Room": "Pokój", + "Value": "Wartość", + "none": "Żaden", + "Save into:": "Zapisz w:", + "Name:": "Nazwa:", + "save": "zapisać", + "load": "obciążenie", + "Presets": "Presets", + "IDs": "ID", + "new": "Nowy", + "Enter chart name": "Wprowadź nazwę wykresu", + "save %s": "zapisz% s", + "Input data": "Dane wejściowe", + "Options": "Opcje", + "Range:": "Zasięg:", + "5 seconds": "5 sekund", + "10 seconds": "10 sekund", + "15 seconds": "15 sekund", + "20 seconds": "20 sekund", + "30 seconds": "30 sekund", + "1 minute": "1 minuta", + "2 minutes": "2 minuty", + "5 minutes": "5 minut", + "10 minutes": "10 minut", + "15 minutes": "15 minut", + "20 minutes": "20 minut", + "30 minutes": "30 minut", + "1 hour": "1 godzina", + "2 hours": "2 godziny", + "3 hours": "3 godziny", + "6 hours": "6 godzin", + "12 hours": "12 godzin", + "1 day": "1 dzień", + "2 days": "2 dni", + "3 days": "3 dni", + "7 days": "7 dni", + "14 days": "14 dni", + "1 month": "1 miesiąc", + "2 months": "2 miesiące", + "3 months": "3 miesiące", + "6 months": "6 miesięcy", + "1 year": "1 rok", + "2 years": "2 lata", + "Width:": "Szerokość:", + "Height:": "Wysokość:", + "line": "Linia", + "area": "Powierzchnia", + "bar": "Bar", + "lineplot": "Fabuła linii", + "scatterplot": "Wykres punktowy", + "steps": "Kroki", + "spline": "Klin", + "Stack": "Stos", + "Window background:": "Tło okna:", + "Custom chart background:": "Niestandardowe tło wykresu:", + "Chart background:": "Tło wykresu:", + "X axis labels color:": "Kolor etykiet X:", + "Y axis labels color:": "Kolor etykiet Y:", + "Show legend:": "Pokaż legendę:", + "Title:": "Tytuł:", + "Title position:": "Pozycja tytułu:", + "Top, left, inside": "Góra, lewa, wewnątrz", + "Top, right, inside": "Góra, prawo, wewnątrz", + "Top, center, inside": "Góra, środek, wnętrze", + "Middle, left, inside": "Środkowy, lewy, w środku", + "Middle, right, inside": "Środkowy, prawy, wewnątrz", + "Bottom, left, inside": "Dół, lewo, wnętrze", + "Bottom, right, inside": "Dół, prawo, wewnątrz", + "Bottom, center, inside": "Dół, środek, wnętrze", + "Top, right, outside": "Góra, prawo, na zewnątrz", + "Middle, right, outside": "Środkowy, prawy, na zewnątrz", + "Bottom, right, outside": "Dół, prawo, na zewnątrz", + "Bottom, center, outside": "Dół, środek, na zewnątrz", + "Min:": "Minimum:", + "Max:": "Maksymalny:", + "User defined names:": "Nazwy zdefiniowane przez użytkownika:", + "Predefined background:": "Wstępnie zdefiniowane tło:", + "User defined": "Określony przez użytkownika", + "Background:": "Tło:", + "Hover details:": "Po najechaniu szczegóły:", + "Time format:": "Format czasu:", + "Default": "Domyślna", + "Smoothing": "Wygładzanie", + "After comma": "Po przecinku", + "Open": "otwarty", + "Update": "Aktualizacja", + "Reset settings": "Resetowanie ustawień", + "From": "Od:", + "Last changed": "Ostatnia zmiana", + "Time stamp": "Znak czasu", + "Acknowledged": "Przyznane", + "Edit": "Edytować", + "Members": "Członkowie", + "Loading...": "Ładuję...", + "Processing...": "Przetwarzanie...", + "With lines": "Z liniami", + "Without lines": "Bez linii", + "Inside / With lines": "Wewnątrz / Z liniami", + "Outside/ With lines": "Na zewnątrz / Z liniami", + "Inside / No lines": "Wewnątrz / Bez linii", + "Outside / No lines": "Poza / Bez linii", + "Interpolate:": "Interpolować:", + "Steps": "Kroki", + "Pie": "Ciasto", + "Top, left": "Lewy górny", + "Top, right": "W prawym górnym rogu", + "Bottom, left": "Na dole po lewej", + "Bottom, right": "Prawy dolny", + "Title color:": "Kolor tytułu:", + "Title size:": "Rozmiar tytułu:", + "Fill range:": "Zakres wypełnienia:", + "Units:": "Jednostki:", + "yes": "tak", + "bottom": "Dolny", + "top": "Top", + "left": "lewo", + "right": "dobrze", + "No border:": "Bez granic:", + "Time": "Czas", + "day": "dzień", + "month": "miesiąc", + "year": "rok", + "Individual": "Indywidualny", + "Aggregation:": "Rodzaj:", + "relative": "krewny", + "static": "statyczny", + "now": "teraz", + "today": "dzisiaj", + "this month": "ten miesiąc", + "this year": "W tym roku", + "Start:": "Początek:", + "End:": "Koniec:", + "Aggregate": "Agregat", + "Step type:": "Rodzaj kroku:", + "seconds": "sekundy", + "Seconds": "sekundy", + "Step span:": "Zakres kroku:", + "Link": "Połączyć", + "Counts": "Liczy", + "ignore 'null'": "zignoruj ​​\"zero\"", + "Time Span": "Okres czasu", + "Appearance": "Wygląd", + "Title": "Tytuł", + "Offset": "X-Offset", + "Aggregation": "Rodzaj", + "Chart Type": "Typ wykresu", + "Color": "Kolor", + "Min": "Min", + "Max": "Max", + "Unit": "Jednostka", + "Y Axis": "Oś Y.", + "X Axis": "Oś X.", + "update Preview": "aktualizuj podgląd", + "Cancel": "Anuluj", + "Name": "Nazwa", + "Live update every:": "Aktualizacja na żywo co:", + "counts": "liczy", + "Add new line": "Dodaj nową linię", + "Animation:": "Animacja:", + "no": "Nie", + "0s": "0 sekund", + "300ms": "300ms", + "500ms": "500 ms", + "1s": "1 sekunda", + "2s": "2 sekundy", + "3s": "3 sekundy", + "5s": "5 sekund", + "10s": "10 sekund", + "30s": "30 sekund", + "60s": "60 sekund", + "2m": "2 minuty", + "3m": "3 minuty", + "4m": "4 minuty", + "5m": "5 minut", + "10m": "10 minut", + "15m": "15 minut", + "30m": "30 minut", + "45m": "45 minut", + "1H": "1 godzina", + "2H": "2 godziny", + "6H": "6 godzin", + "12H": "12 godzin", + "1D": "1 dzień", + "2D": "2 dni", + "3D": "3 dni", + "4D": "4 dni", + "1W": "1 tydzień", + "2W": "2 tygodnie", + "4W": "4 tygodnie", + "8W": "8 tygodni", + "12W": "12 tygodni", + "26W": "26 tygodni", + "1M": "1 miesiąc", + "2M": "2 miesiące", + "3M": "3 miesiące", + "6M": "6 miesięcy", + "1Y": "1 rok", + "2Y": "2 lata", + "average": "średni", + "max": "maks", + "min": "min", + "total": "całkowity", + "off": "poza", + "leftColor": "pozostawione w kolorze", + "rightColor": "prawe kolorowe", + "topColor": "górne kolorowe", + "bottomColor": "u dołu w kolorze", + "default": "domyślna", + "Auto-update:": "Automatyczna aktualizacja:", + "Use comma:": "Użyj przecinka:", + "Common Y Axis": "Wspólna oś Y.", + "Instance": "Instancja", + "Line Width": "Szerokość linii", + "Shadow Size": "Rozmiar cienia", + "ignore 'null':": "zignoruj ​​\"null\":", + "onchange": "o zmianie", + "Border color:": "Kolor ramki:", + "Grid color:": "Kolor siatki:", + "Border width:": "Szerokość granicy:", + "Enable zoom and pan:": "Włącz powiększanie i panoramowanie:", + "Arrange bools": "Rozmieść booleans", + "NULL as": "NULL as", + "MinMax": "Minimum maksimum", + "null": "zero", + "true": "ostatnia wartość", + "last value": "ostatnia wartość", + "Hide edit button:": "Ukryj przycisk edycji:", + "minmax": "minimum maksimum", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Linia", + "false": "zero", + "end of minute": "koniec minuty", + "end of 5 minutes": "koniec 5 minut", + "end of 10 minutes": "koniec 10 minut", + "end of 30 minutes": "koniec 30 minut", + "end of hour": "koniec godziny", + "end of 2 hours": "koniec 2 godzin", + "end of 3 hours": "koniec 3 godzin", + "end of 4 hours": "koniec 4 godzin", + "end of 6 hours": "koniec 6 godzin", + "end of 8 hours": "koniec 8 godzin", + "end of 12 hours": "koniec 12 godzin", + "end of day": "koniec dnia", + "end of sunday": "koniec niedzieli", + "end of saturday": "koniec soboty", + "1minute": "koniec minuty", + "5minutes": "koniec 5 minut", + "10minutes": "koniec 10 minut", + "30minutes": "koniec 30 minut", + "1hour": "koniec godziny", + "2hours": "koniec 2 godzin", + "3hours": "koniec 3 godzin", + "4hours": "koniec 4 godzin", + "6hours": "koniec 6 godzin", + "8hours": "koniec 8 godzin", + "12hours": "koniec 12 godzin", + "weekEurope": "koniec dnia", + "weekUsa": "koniec niedzieli", + "Bar settings": "Ustawienia paska", + "Fill color:": "Kolor wypełnienia:", + "Show labels:": "Pokaż etykiety:", + "top over": "do góry", + "top under": "górny pod", + "middle": "środkowy", + "Bars width:": "Szerokość prętów:", + "Label font size:": "Rozmiar czcionki etykiety:", + "Label color:": "Kolor etykiety:", + "Markings": "Znakowania", + "Line ID": "Identyfikator linii", + "Fill": "Napełnić", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Tekst", + "Text position": "Pozycja tekstu", + "Text offset": "Przesunięcie tekstu", + "Text size": "Rozmiar czcionki", + "Text color": "Kolor tekstu", + "Add new markings": "Dodaj nowe oznaczenia", + "Left": "Lewo", + "Right": "Dobrze", + "Upper value or ID": "Górna wartość lub ID", + "Lower value or ID": "Niższa wartość lub ID", + "X-Axis ticks": "Tiki X-Axis", + "Y-Axis ticks": "Tyksy Y-Axis", + "ignore null values": "ignoruj ​​wartości puste", + "Ticks from:": "Użyj tyknięć X z:", + "use 0 instead of null values": "użyj 0 zamiast wartości zerowych", + "More": "jeszcze", + "Edit options for line %s": "Edytuj opcje linii% s", + "Legend columns:": "Kolumny legendy:", + "Legend opacity (from 0 to 1):": "Krycie Legendy (od 0 do 1):", + "Legend background:": "Tło legendy:", + "Fill(0to1)": "Wypełnij (0to1)", + "Points": "Zwrotnica" +} \ No newline at end of file diff --git a/src/i18n/pt/translations.json b/src/i18n/pt/translations.json new file mode 100644 index 0000000..f953ac6 --- /dev/null +++ b/src/i18n/pt/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Está bem", + "role": "Função", + "Update objects": "Atualizar objetos", + "All": "Todos", + "With": "Com", + "Without": "Sem", + "Update states": "Estado de atualização", + "edit file": "editar arquivo", + "restart script": "reiniciar o script", + "Select": "Selecione", + "Select ID": "Selecione ID", + "add children": "adicionar filhos", + "edit enum": "editar enum", + "System settings": "Configurações de sistema", + "reload": "recarregar", + "Delete object": "Eliminar objeto", + "no null": "& nbsp; nulo", + "%s ago": "% s atrás", + "Y-Offset": "Y-Offset", + "ID": "identidade", + "Role": "Função", + "Room": "Quarto", + "Value": "Valor", + "none": "Nenhum", + "Save into:": "Salvar em:", + "Name:": "Nome:", + "save": "Salve ", + "load": "carga", + "Presets": "Presets", + "IDs": "IDs", + "new": "Novo", + "Enter chart name": "Digite o nome do gráfico", + "save %s": "salvar% s", + "Input data": "Dados de entrada", + "Options": "Opções", + "Range:": "Alcance:", + "5 seconds": "5 segundos", + "10 seconds": "10 segundos", + "15 seconds": "15 segundos", + "20 seconds": "20 segundos", + "30 seconds": "30 segundos", + "1 minute": "1 minuto", + "2 minutes": "2 minutos", + "5 minutes": "5 minutos", + "10 minutes": "10 minutos", + "15 minutes": "15 minutos", + "20 minutes": "20 minutos", + "30 minutes": "30 minutos", + "1 hour": "1 hora", + "2 hours": "2 horas", + "3 hours": "3 horas", + "6 hours": "6 horas", + "12 hours": "12 horas", + "1 day": "1 dia", + "2 days": "2 dias", + "3 days": "3 dias", + "7 days": "7 dias", + "14 days": "14 dias", + "1 month": "1 mês", + "2 months": "2 meses", + "3 months": "3 meses", + "6 months": "6 meses", + "1 year": "1 ano", + "2 years": "2 anos", + "Width:": "Largura:", + "Height:": "Altura:", + "line": "Linha", + "area": "Área", + "bar": "Barra", + "lineplot": "Trama de linha", + "scatterplot": "Parcela de dispersão", + "steps": "Passos", + "spline": "Spline", + "Stack": "Pilha", + "Window background:": "Fundo da janela:", + "Custom chart background:": "Fundo de gráfico personalizado:", + "Chart background:": "Contexto do gráfico:", + "X axis labels color:": "Cor de etiquetas X:", + "Y axis labels color:": "Etiquetas de etiquetas Y:", + "Show legend:": "Mostrar lenda:", + "Title:": "Título:", + "Title position:": "Posição do título:", + "Top, left, inside": "Topo, esquerda, dentro", + "Top, right, inside": "Topo, direito, dentro", + "Top, center, inside": "Topo, centro, dentro", + "Middle, left, inside": "Médio, esquerda, dentro", + "Middle, right, inside": "Médio, direito, dentro", + "Bottom, left, inside": "Parte inferior, esquerda, dentro", + "Bottom, right, inside": "Parte inferior, direita, dentro", + "Bottom, center, inside": "No fundo, no centro, no interior", + "Top, right, outside": "Topo, direito, fora", + "Middle, right, outside": "Médio, direito, fora", + "Bottom, right, outside": "Parte inferior, direita, fora", + "Bottom, center, outside": "Fundo, centro, fora", + "Min:": "Mínimo:", + "Max:": "Máximo:", + "User defined names:": "Nomes definidos pelo usuário:", + "Predefined background:": "Antecedentes predefinidos:", + "User defined": "Usuário definido", + "Background:": "Fundo:", + "Hover details:": "Detalhes do mouse:", + "Time format:": "Formato do tempo:", + "Default": "Padrão", + "Smoothing": "Suavização", + "After comma": "Após a vírgula", + "Open": "Aberto", + "Update": "Atualizar", + "Reset settings": "Redefinir configurações", + "From": "A partir de:", + "Last changed": "Última modificação", + "Time stamp": "Marca de horário", + "Acknowledged": "Reconhecido", + "Edit": "Editar", + "Members": "Membros", + "Loading...": "Carregando...", + "Processing...": "Em processamento...", + "With lines": "Com linhas", + "Without lines": "Sem linhas", + "Inside / With lines": "Dentro / Com linhas", + "Outside/ With lines": "Fora / Com linhas", + "Inside / No lines": "Dentro / Sem linhas", + "Outside / No lines": "Fora / Sem linhas", + "Interpolate:": "Interpolar:", + "Steps": "Passos", + "Pie": "Torta", + "Top, left": "Superior esquerdo", + "Top, right": "Canto superior direito", + "Bottom, left": "Inferior esquerdo", + "Bottom, right": "Canto inferior direito", + "Title color:": "Cor do título:", + "Title size:": "Tamanho do título:", + "Fill range:": "Faixa de preenchimento:", + "Units:": "Unidades:", + "yes": "sim", + "bottom": "inferior", + "top": "topo", + "left": "esquerda", + "right": "certo", + "No border:": "Sem borda:", + "Time": "Tempo", + "day": "dia", + "month": "mês", + "year": "ano", + "Individual": "Individual", + "Aggregation:": "Tipo:", + "relative": "relativo", + "static": "estático", + "now": "agora", + "today": "hoje", + "this month": "este mês", + "this year": "este ano", + "Start:": "Começar:", + "End:": "Fim:", + "Aggregate": "Agregar", + "Step type:": "Tipo de etapa:", + "seconds": "segundos", + "Seconds": "Segundos", + "Step span:": "Passo:", + "Link": "Ligação", + "Counts": "Contagens", + "ignore 'null'": "ignore 'null'", + "Time Span": "Intervalo de tempo", + "Appearance": "Aparência", + "Title": "Título", + "Offset": "X-Offset", + "Aggregation": "Tipo", + "Chart Type": "Tipo de gráfico", + "Color": "Cor", + "Min": "Min", + "Max": "Max", + "Unit": "Unidade", + "Y Axis": "Eixo Y", + "X Axis": "X Axis", + "update Preview": "atualização Visualização", + "Cancel": "Cancelar", + "Name": "Nome", + "Live update every:": "Atualização ao vivo a cada:", + "counts": "contagens", + "Add new line": "Adicionar nova linha", + "Animation:": "Animação:", + "no": "não", + "0s": "0 segundos", + "300ms": "300ms", + "500ms": "500ms", + "1s": "1 segundo", + "2s": "2 segundos", + "3s": "3 segundos", + "5s": "5 segundos", + "10s": "10 segundos", + "30s": "30 segundos", + "60s": "60 segundos", + "2m": "2 minutos", + "3m": "3 minutos", + "4m": "4 minutos", + "5m": "5 minutos", + "10m": "10 minutos", + "15m": "15 minutos", + "30m": "30 minutos", + "45m": "45 minutos", + "1H": "1 hora", + "2H": "2 horas", + "6H": "6 horas", + "12H": "12 horas", + "1D": "1 dia", + "2D": "2 dias", + "3D": "3 dias", + "4D": "4 dias", + "1W": "1 semana", + "2W": "2 semanas", + "4W": "4 semanas", + "8W": "8 semanas", + "12W": "12 semanas", + "26W": "26 semanas", + "1M": "1 mês", + "2M": "2 meses", + "3M": "3 meses", + "6M": "6 meses", + "1Y": "1 ano", + "2Y": "2 anos", + "average": "média", + "max": "máximo", + "min": "min", + "total": "total", + "off": "fora", + "leftColor": "colorido esquerdo", + "rightColor": "cor clara", + "topColor": "colorido superior", + "bottomColor": "colorido inferior", + "default": "padrão", + "Auto-update:": "Atualização automática:", + "Use comma:": "Usar vírgula:", + "Common Y Axis": "Eixo Y comum", + "Instance": "Instância", + "Line Width": "Espessura da linha", + "Shadow Size": "Tamanho da sombra", + "ignore 'null':": "ignore 'null':", + "onchange": "em mudança", + "Border color:": "Cor da borda:", + "Grid color:": "Cor da grade:", + "Border width:": "Largura da borda:", + "Enable zoom and pan:": "Ative o zoom e pan:", + "Arrange bools": "Organizar booleanos", + "NULL as": "NULL como", + "MinMax": "Mínimo máximo", + "null": "nulo", + "true": "último valor", + "last value": "último valor", + "Hide edit button:": "Ocultar botão de edição:", + "minmax": "mínimo máximo", + "ØL": "& # 216L", + "ØS": "& # 216S", + "Line": "Linha", + "false": "nulo", + "end of minute": "fim de minuto", + "end of 5 minutes": "fim de 5 minutos", + "end of 10 minutes": "fim de 10 minutos", + "end of 30 minutes": "fim de 30 minutos", + "end of hour": "fim de hora", + "end of 2 hours": "fim de 2 horas", + "end of 3 hours": "fim de 3 horas", + "end of 4 hours": "fim de 4 horas", + "end of 6 hours": "fim de 6 horas", + "end of 8 hours": "fim de 8 horas", + "end of 12 hours": "fim de 12 horas", + "end of day": "fim do dia", + "end of sunday": "fim de domingo", + "end of saturday": "fim de sábado", + "1minute": "fim de minuto", + "5minutes": "fim de 5 minutos", + "10minutes": "fim de 10 minutos", + "30minutes": "fim de 30 minutos", + "1hour": "fim de hora", + "2hours": "fim de 2 horas", + "3hours": "fim de 3 horas", + "4hours": "fim de 4 horas", + "6hours": "fim de 6 horas", + "8hours": "fim de 8 horas", + "12hours": "fim de 12 horas", + "weekEurope": "fim do dia", + "weekUsa": "fim de domingo", + "Bar settings": "Configurações da barra", + "Fill color:": "Cor de preenchimento:", + "Show labels:": "Mostrar rótulos:", + "top over": "mais alto", + "top under": "top sob", + "middle": "meio", + "Bars width:": "Largura das barras:", + "Label font size:": "Etiquetar tamanho da fonte:", + "Label color:": "Cor do rótulo:", + "Markings": "Marcas", + "Line ID": "ID da linha", + "Fill": "Preencher", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Texto", + "Text position": "Posição de texto", + "Text offset": "Deslocamento de texto", + "Text size": "Tamanho do texto", + "Text color": "Cor do texto", + "Add new markings": "Adicionar novas marcações", + "Left": "Esquerda", + "Right": "Certo", + "Upper value or ID": "Valor superior ou ID", + "Lower value or ID": "Menor valor ou ID", + "X-Axis ticks": "Carrapatos do X-Axis", + "Y-Axis ticks": "Carrapatos do Y-Axis", + "ignore null values": "ignore valores nulos", + "Ticks from:": "Use X-ticks de:", + "use 0 instead of null values": "use 0 em vez de valores nulos", + "More": "Mais", + "Edit options for line %s": "Editar opções para a linha% s", + "Legend columns:": "Colunas da legenda:", + "Legend opacity (from 0 to 1):": "Opacidade da legenda (de 0 a 1):", + "Legend background:": "Legend background:", + "Fill(0to1)": "Preencher (0 a 1)", + "Points": "Pontos" +} \ No newline at end of file diff --git a/src/i18n/ru/translations.json b/src/i18n/ru/translations.json new file mode 100644 index 0000000..4942926 --- /dev/null +++ b/src/i18n/ru/translations.json @@ -0,0 +1,324 @@ +{ + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "Ok": "Ok", + "role": "Роль", + "Update objects": "Обновить объекты", + "All": "все", + "With": "с", + "Without": "без", + "Update states": "Обновить состояния", + "edit file": "Редактировать", + "restart script": "Перезапустить скрипт", + "Select": "Выбрать", + "Select ID": "Выбрать ID", + "add children": "Добавить под-категории", + "edit enum": "Изменить категорию", + "System settings": "Системные настройки", + "reload": "Перезагрузить", + "Delete object": "Удалить объект", + "no null": " без null", + "%s ago": "%s назад", + "Y-Offset": "Сдвиг по Y", + "ID": "ID", + "Role": "Роль", + "Room": "Комната", + "Value": "Значение", + "none": "ничего", + "Save into:": "Сохранить как:", + "Name:": "Имя:", + "save": "сохранить", + "load": "загрузить", + "Presets": "Пресеты", + "IDs": "Объекты", + "new": "новое", + "Enter chart name": "Введите имя графика", + "save %s": "сохранить %s", + "Input data": "Входные данные", + "Options": "Опции", + "Range:": "Интервал:", + "5 seconds": "5 секунд", + "10 seconds": "10 секунд", + "15 seconds": "15 секунд", + "20 seconds": "20 секунд", + "30 seconds": "30 секунд", + "1 minute": "1 минуту", + "2 minutes": "2 минуты", + "5 minutes": "5 минут", + "10 minutes": "10 минут", + "15 minutes": "15 минут", + "20 minutes": "20 минут", + "30 minutes": "30 минут", + "1 hour": "1 час", + "2 hours": "2 часа", + "3 hours": "3 часа", + "6 hours": "6 часов", + "12 hours": "12 часов", + "1 day": "1 день", + "2 days": "2 дня", + "3 days": "3 дня", + "7 days": "7 дней", + "14 days": "14 дней", + "1 month": "1 месяц", + "2 months": "2 месяца", + "3 months": "3 месяца", + "6 months": "6 месяцев", + "1 year": "1 год", + "2 years": "2 года", + "Width:": "Ширина:", + "Height:": "Высота:", + "line": "Линия", + "area": "Область", + "bar": "Bar", + "lineplot": "Линия с точками", + "scatterplot": "Точки", + "steps": "Шаги", + "spline": "Сллайн", + "Stack": "Stack", + "Window background:": "Фон окна:", + "Custom chart background:": "Пользовательский фон графика:", + "Chart background:": "Фон графика:", + "X axis labels color:": "Цвет текста по оси X:", + "Y axis labels color:": "Цвет текста по оси Y:", + "Show legend:": "Показать легенду:", + "Title:": "Название:", + "Title position:": "Позиция названия:", + "Top, left, inside": "Сверху, слева, внутри", + "Top, right, inside": "Сверху, справа, внутри", + "Top, center, inside": "Сверху, по центру, внутри", + "Middle, left, inside": "Посередине, слева, внутри", + "Middle, right, inside": "Посередине, справа, внутри", + "Bottom, left, inside": "Снизу, слева, внутри", + "Bottom, right, inside": "Снизу, справа, внутри", + "Bottom, center, inside": "Снизу, по центру, внутри", + "Top, right, outside": "Сверху, справа, снаружи", + "Middle, right, outside": "Посередине, справа, снаружи", + "Bottom, right, outside": "Снизу, справа, снаружи", + "Bottom, center, outside": "Снизу, по центру, снаружи", + "Min:": "Минимум:", + "Max:": "Максимум:", + "User defined names:": "Задать имена графиков:", + "Predefined background:": "Выбрать фон:", + "User defined": "Пользовательские", + "Background:": "Фон:", + "Hover details:": "Показывать подсказку:", + "Time format:": "Формат времени:", + "Default": "по умолчанию", + "Smoothing": "Сглаживание", + "After comma": "После запятой", + "Open": "Показать", + "Update": "Обновить", + "Reset settings": "Сбросить настройки", + "From": "От", + "Last changed": "Изменён", + "Time stamp": "Время", + "Acknowledged": "Подтверждён", + "Edit": "Edit", + "Members": "Объекты", + "Loading...": "Загрузка...", + "Processing...": "Обработка...", + "With lines": "С линиями", + "Without lines": "Без линий", + "Inside / With lines": "Внутри / С линиями", + "Outside/ With lines": "Снаружи/ С линиями", + "Inside / No lines": "Внутри / Без линий", + "Outside / No lines": "Снаружи / Без линий", + "Interpolate:": "Интерполяция:", + "Steps": "Ступени", + "Pie": "Круговая диаграмма", + "Top, left": "Сверху, слева", + "Top, right": "Сверху, справа", + "Bottom, left": "Снизу, слева", + "Bottom, right": "Снизу, справа", + "Title color:": "Цвет названия:", + "Title size:": "Размер названия:", + "Fill range:": "Всегда весь интервал:", + "Units:": "Единицы:", + "yes": "да", + "bottom": "снизу", + "top": "сверху", + "left": "слева", + "right": "справа", + "No border:": "Без рамки:", + "Time": "Время", + "day": "День", + "month": "month", + "year": "year", + "Individual": "Индивидуально", + "Aggregation:": "Тип:", + "relative": "относительно", + "static": "постоянный", + "now": "сейчас", + "today": "сегодня", + "this month": "этот месяц", + "this year": "этот год", + "Start:": "Начало:", + "End:": "Конец:", + "Aggregate": "Объединение данных", + "Step type:": "Шаги:", + "seconds": "секунды", + "Seconds": "Cекунды", + "Step span:": "Интервал шага:", + "Link": "URL", + "Counts": "Кол-во значений", + "ignore 'null'": "Игнорировать 'null'", + "Time Span": "Временной интервал", + "Appearance": "Оформление", + "Title": "Подпись", + "Offset": "Сдвиг по Х", + "Aggregation": "Тип", + "Chart Type": "Тип графика", + "Color": "Цвет", + "Min": "Мин", + "Max": "Макс", + "Unit": "Единицы", + "Y Axis": "Ось Y", + "X Axis": "Ось X", + "update Preview": "Обновить", + "Cancel": "отменить", + "Name": "Имя", + "Live update every:": "Обновлять каждые:", + "counts": "кол-во", + "Add new line": "Добавить линию", + "Animation:": "Анимация:", + "no": "нет", + "0s": "0c", + "300ms": "300мс", + "500ms": "500мс", + "1s": "1 секунда", + "2s": "2 секунды", + "3s": "3 секунды", + "5s": "5 секунд", + "10s": "10 секунд", + "30s": "30 секунд", + "60s": "60 секунд", + "2m": "2 минуты", + "3m": "3 минуты", + "4m": "4 минуты", + "5m": "5 минут", + "10m": "10 минут", + "15m": "15 минут", + "30m": "30 минут", + "45m": "45 минут", + "1H": "1 час", + "2H": "2 часа", + "6H": "6 часов", + "12H": "12 часов", + "1D": "1 день", + "2D": "2 дня", + "3D": "3 дня", + "4D": "4 дня", + "1W": "1 неделя", + "2W": "2 недели", + "4W": "4 недели", + "8W": "8 недель", + "12W": "12 недель", + "26W": "26 недель", + "1M": "1 месяц", + "2M": "2 месяца", + "3M": "3 месяца", + "6M": "6 месяцев", + "1Y": "1 год", + "2Y": "2 года", + "average": "среднее", + "max": "макс", + "min": "мин", + "total": "всего", + "off": "скрыть", + "leftColor": "слева цветом", + "rightColor": "справа цветом", + "topColor": "сверху цветом", + "bottomColor": "снизу цветом", + "default": "по умолчанию", + "Auto-update:": "Обновлять сразу:", + "Use comma:": "Запятая-разделитель:", + "Common Y Axis": "Общая ось Y", + "Instance": "Драйвер", + "Line Width": "Ширина линии", + "Shadow Size": "Ширина тени", + "ignore 'null':": "Игнорировать 'null':", + "onchange": "при изменении", + "Border color:": "Цвет рамки:", + "Grid color:": "Цвет сетки:", + "Border width:": "Ширина рамки:", + "Enable zoom and pan:": "Разрешить увеличение и сдвиг:", + "Arrange bools": "Выстроить bool графики", + "NULL as": "NULL как", + "MinMax": "MinMax", + "null": "null", + "true": "пред. значение", + "last value": "пред. значение", + "Hide edit button:": "Скрыть кнопку 'Редактировать':", + "minmax": "minmax", + "ØL": "ØL", + "ØS": "ØS", + "Line": "Линия", + "false": "null", + "end of minute": "Конец минуты", + "end of 5 minutes": "Конец 5 minutes", + "end of 10 minutes": "Конец 10 minutes", + "end of 30 minutes": "Конец 30 minutes", + "end of hour": "Конец часа", + "end of 2 hours": "Конец 2 часов", + "end of 3 hours": "Конец 3 часов", + "end of 4 hours": "Конец 4 часов", + "end of 6 hours": "Конец 6 часов", + "end of 8 hours": "Конец 8 часов", + "end of 12 hours": "Конец 12 часов", + "end of day": "Конец дня", + "end of sunday": "Конец недели", + "end of saturday": "Конец субботы", + "1minute": "Конец минуты", + "5minutes": "Конец 5 minutes", + "10minutes": "Конец 10 minutes", + "30minutes": "Конец 30 minutes", + "1hour": "Конец часа", + "2hours": "Конец 2 часов", + "3hours": "Конец 3 часов", + "4hours": "Конец 4 часов", + "6hours": "Конец 6 часов", + "8hours": "Конец 8 часов", + "12hours": "Конец 12 часов", + "weekEurope": "Конец дня", + "weekUsa": "Конец недели", + "Bar settings": "Настройки Bar", + "Fill color:": "Цвет заливки:", + "Show labels:": "Подписи:", + "top over": "Сверху над", + "top under": "Сверху под", + "middle": "В середине", + "Bars width:": "Ширина бара:", + "Label font size:": "Шрифт подписи:", + "Label color:": "Цвет подписи:", + "Markings": "Разметка", + "Line ID": "ID линии", + "Fill": "Заливка", + "ØL": "ØL", + "ØS": "ØS", + "Text": "Текст", + "Text position": "Расположение текста", + "Text offset": "Сдвиг текста", + "Text size": "Размер текста", + "Text color": "Цвет текста", + "Add new markings": "Добавить разметку", + "Left": "слева", + "Right": "справа", + "Upper value or ID": "Верхнее значение или ID", + "Lower value or ID": "Нижнее значение или ID", + "X-Axis ticks": "Кол-во делений на шкале X", + "Y-Axis ticks": "Кол-во делений на шкале Y", + "ignore null values": "игнорировать значения null", + "Ticks from:": "Подписи X-делений из:", + "use 0 instead of null values": "Заменять null на 0", + "More": "ещё", + "Edit options for line %s": "Редактировать настройки для линии %s", + "Legend columns:": "Колонок в легенде:", + "Legend opacity (from 0 to 1):": "Прозрачность легенды (от 0 до 1):", + "Legend background:": "Фон легенды:", + "Fill(0to1)": "Фон(0to1)", + "Points": "Точки" +} \ No newline at end of file diff --git a/src/img/favicon.png b/src/img/favicon.png new file mode 100644 index 0000000..42987bd Binary files /dev/null and b/src/img/favicon.png differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..579561e --- /dev/null +++ b/src/index.html @@ -0,0 +1,302 @@ + + Flot Chart + + + + + + + + + + + + + + +
+
+
...
+
+
+
+ +
+
+
+ + + + + + diff --git a/src/js/chart.js b/src/js/chart.js new file mode 100644 index 0000000..86a423c --- /dev/null +++ b/src/js/chart.js @@ -0,0 +1,798 @@ +//options: { +// chartId: +// titleId: +// tooltipId: +// cbOnZoom: +// } + +function CustomChart(options, config, seriesData, markLines, ticks) { + 'use strict'; + + if (!(this instanceof CustomChart)) return new CustomChart(options, config, seriesData, markLines, ticks); + + this.chart = null; + this.config = config; + this.options = options; + + var that = this; + var series; + var markingsOffset = 0; + var settings; + var backgrounds = [ + ['#8e9eab', '#eef2f3'], // Portrait + ['#517fa4', '#243949'], // Instagram + ['#485563', '#29323c'], // ServQuick + ['#abbaab', '#00ffff'], // Metallic Toad + ['#ECE9E6', '#00ffff'], // Clouds + ['#16222A', '#3A6073'], // Mirage + ['#1F1C2C', '#928DAB'], // Steel Gray + ['#003973', '#E5E5BE'], // Horizon + ['#D1913C', '#FFD194'], // Koko Caramel + ['#136a8a', '#267871'] // Turquoise flow + ]; + + function _yFormatter(y, line) { + if (typeof y === 'boolean') return '' + y; + var unit = that.config.l[line].unit ? ' ' + that.config.l[line].unit : ''; + if (that.config.l[line].afterComma !== undefined && that.config.l[line].afterComma !== null) { + y = parseFloat(y); + if (that.config.useComma) { + return y.toFixed(that.config.l[line].afterComma).toString().replace('.', ',') + unit; + } else { + return y.toFixed(that.config.l[line].afterComma) + unit; + } + } else { + if (that.config.useComma) { + y = parseFloat(y); + return y.toString().replace('.', ',') + unit; + } else { + return y + unit; + } + } + } + + function _tickXFormatter(number, object) { + if (ticks) return ' '; + var now = new Date(parseInt(number, 10)); + if (that.config.timeFormatDate && that.config.timeFormatTime) { + if (!object.ticks.length) { + return '' + $.plot.formatDate(now, that.config.timeFormatDate, months[systemLang], days[systemLang]) + ''; + } + var d = new Date(object.ticks[object.ticks.length - 1].v); + if (d.getDate() !== now.getDate()) { + return '' + $.plot.formatDate(now, that.config.timeFormatDate, months[systemLang], days[systemLang]) + ''; + } + return $.plot.formatDate(now, that.config.timeFormatTime, months[systemLang], days[systemLang]); + } else { + return $.plot.formatDate(now, that.config.timeFormat, months[systemLang], days[systemLang]); + } + } + + function _tickYFormatter(number, object) { + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + var afterComma = that.config.l[object.n - 1].afterComma; + + if (afterComma !== null && afterComma !== undefined) { + var factor = afterComma ? Math.pow(10, afterComma) : 1; + var formatted = (Math.round(number * factor) / factor).toString(); + var decimal = formatted.indexOf('.'); + var precision = decimal === -1 ? 0 : formatted.length - decimal - 1; + + if (precision < afterComma) { + number = (precision ? formatted : formatted + '.') + factor.toString().substr(1, afterComma - precision); + } else { + number = formatted; + } + } + + if (that.config.useComma) number = number.toString().replace('.', ','); + + var unit = that.config.l[object.n - 1].unit; + + return number + (unit ? (' ' + unit) : ''); + } + + function showLabels (animation) { + if (that.config.barLabels) { + setTimeout(function () { + var data = that.chart.getData(); + + for (var d = 0; d < data.length; d++) { + if (!that.config.l[d] || that.config.l[d].chartType !== 'bar') continue; + + $.each(data[d].data, function (i, el) { + if (el[1] === null) return; + if (!i) return; + if (i === data[d].data.length - 1) return; + var o; + if (that.config.barLabels === 'topover') { + o = that.chart.pointOffset({x: el[0], y: el[1]}); + o.top -= 20; + } else if (that.config.barLabels === 'topunder') { + o = that.chart.pointOffset({x: el[0], y: el[1]}); + //o.top += 10; + } else if (that.config.barLabels === 'bottom') { + o = that.chart.pointOffset({x: el[0], y: 0}); + o.top += 20; + } else {//if (that.config.barLabels === 'middle') { + o = that.chart.pointOffset({x: el[0], y: el[1] / 2}); + } + + $('
' + _yFormatter(el[1], d) + '
').css({ + position: 'absolute', + left: o.left, + top: o.top + }).appendTo(that.chart.getPlaceholder()); + }); + } + if (that.config.barFontSize || that.config.barFontColor) { + $('.data-point-label').css({ + 'font-size': that.config.barFontSize || undefined, + color: that.config.barFontColor || undefined + }); + } + + }, animation ? parseInt(animation) + 200 : 0); + } + + if (markLines && markLines.length) { + setTimeout(function () { + var data = that.chart.getData(); + var num = 0; + for (var m = 0; m < markLines.length; m++) { + if (markLines[m].d && data[markLines[m].l + markingsOffset]) { + var line = data[num].data; + var o; + var text; + if (markLines[m].p === 'l') { + o = that.chart.pointOffset({x: line[0][0], y: line[0][1], yaxis: data[markLines[m].l + markingsOffset].yaxis, xaxis: data[markLines[m].l + markingsOffset].xaxis}); + o.top -= markLines[m].py; + text = markLines[m].d; + } else {//if (markLines[m].p === 'r') { + o = that.chart.pointOffset({x: line[1][0], y: line[1][1], yaxis: data[markLines[m].l + markingsOffset].yaxis, xaxis: data[markLines[m].l + markingsOffset].xaxis}); + o.top -= markLines[m].py; + text = '
' + markLines[m].d + '
'; + } + $('
' + text + '
').css({ + position: 'absolute', + left: o.left, + top: o.top, + 'font-size': markLines[m].fs || undefined, + color: markLines[m].fc || undefined + }).appendTo(that.chart.getPlaceholder()); + } + if (markLines[m].vl !== '' && markLines[m].vl !== null && markLines[m].vl !== undefined) { + num++; + } + num++; + } + }, animation ? parseInt(animation) + 200 : 0); + } + } + + (function _constructor () { + series = []; + var smoothing = false; + var $title = $('#' + that.options.titleId); + + if (that.config.title && !$title.html()) { + $title.html(that.config.titlePos ? decodeURI(that.config.title) : ''); + if (that.config.titleColor) $title.css('color', that.config.titleColor); + if (that.config.titleSize) $title.css('font-size', that.config.titleSize); + if (that.config.titlePos) { + var parts = that.config.titlePos.split(';'); + var css = {}; + for (var t = 0; t < parts.length; t++) { + var p = parts[t].split(':'); + + // Bottom inside + if (p[0] === 'bottom' && p[1] == '5') { + if (that.config.height.indexOf('%') === -1) { + css.top = parseInt(that.config.height, 10) - $title.height() - 45; + } else { + css.top = 'calc(' + that.config.height + ' - ' + ($title.height() + 45) + 'px)'; + } + } else // Bottom outside + if (p[0] === 'bottom' && p[1] == '-5') { + if (that.config.height.indexOf('%') === -1) { + css.top = parseInt(that.config.height, 10) + 5; + } else { + css.top = 'calc(' + that.config.height + ' + 5px)'; + } + } else // Middle + if (p[0] === 'top' && p[1] == '50') { + if (that.config.height.indexOf('%') === -1) { + css.top = (parseInt(that.config.height, 10) - $title.height()) / 2; + } else { + css.top = 'calc(50% - ' + ($title.height() / 2) + 'px)'; + } + } else // Center + if (p[0] === 'left' && p[1] == '50') { + if (that.config.width.indexOf('%') === -1) { + css.left = (parseInt(that.config.width, 10) - $title.width()) / 2; + } else { + css.left = 'calc(50% - ' + ($title.width() / 2) + 'px)'; + } + } else // Right inside + if (p[0] === 'right' && p[1] == '5') { + if (that.config.width.indexOf('%') === -1) { + css.left = parseInt(that.config.width, 10) - $title.width() - 45; + } else { + css.left = 'calc(' + that.config.width + ' - ' + ($title.width() + 45) + 'px)'; + } + } else // Right outside + if (p[0] === 'right' && p[1] == '-5') { + if (that.config.width.indexOf('%') === -1) { + css.left = parseInt(that.config.width, 10) + 25; + } else { + css.left = 'calc(' + that.config.width + ' + 5px)'; + } + } else { + css[p[0]] = p[1]; + } + } + + $title.css(css); + } + } + + // Replace background + if (that.config.bg && that.config.bg.length < 3 && backgrounds[that.config.bg]) that.config.bg = {colors: backgrounds[that.config.bg]}; + + markingsOffset = 0; + // draw horizontal lines + if (markLines && markLines.length) { + for (var m = 0; m < markLines.length; m++) { + markingsOffset++; + markLines[m].v = parseFloat(markLines[m].v) || 0; // value + markLines[m].l = parseInt(markLines[m].l) || 0; // line number + markLines[m].s = parseFloat(markLines[m].s) || 0; // shadow size + markLines[m].t = parseFloat(markLines[m].t) || 0; // line width + markLines[m].py = parseFloat(markLines[m].py) || 0; // y offset of label + series.push({ + id: 'line' + m, + xaxis: {show: false}, + color: markLines[m].c || undefined, + lines: { + show: true, + fill: markLines[m].f === '1' || markLines[m].f === 1 || markLines[m].f === 'true' || markLines[m].f === true, + steps: true, + lineWidth: markLines[m].t + }, + data: [[0, markLines[m].v], [100, markLines[m].v]], + label: '__hide_me__', + shadowSize: markLines[m].s + }); + // if lower value set + if (markLines[m].vl !== '' && markLines[m].vl !== null && markLines[m].vl !== undefined) { + markingsOffset++; + markLines[m].vl = parseFloat(markLines[m].vl) || 0; + series.push({ + xaxis: {show: false}, + color: markLines[m].c || undefined, + lines: { + show: true, + fill: true, + steps: true, + lineWidth: markLines[m].t + }, + data: [[0, markLines[m].vl], [100, markLines[m].vl]], + fillBetween: 'line' + m, + label: '__hide_me__', + shadowSize: markLines[m].s + }); + } + } + } + + //todo make bar working +// if (that.config.renderer !== 'bar' || that.config._ids.length <= 1) { + var xMin = Infinity; + var xMax = 0; + for (var i = 0; i < seriesData.length; i++) { + if (seriesData[i] && that.config.l[i]) { + + that.config.l[i].chartType = that.config.l[i].chartType || that.config.chartType || 'line'; + that.config.l[i].dashes = that.config.l[i].dashes === true || that.config.l[i].dashes === 'true'; + that.config.l[i].dashLength = parseFloat(that.config.l[i].dashLength) || 10; + that.config.l[i].spaceLength = parseFloat(that.config.l[i].spaceLength) || 10; + var isLine = that.config.l[i].chartType !== 'scatterplot' && that.config.l[i].chartType !== 'bar' && that.config.l[i].chartType !== 'spline'; + + var option = { + color: that.config.l[i].color || undefined, + lines: { + show: (!that.config.l[i].dashes && isLine), + fill: (that.config.l[i].fill && that.config.l[i].fill !== '0') ? parseFloat(that.config.l[i].fill) : (that.config.l[i].chartType === 'area' || that.config.l[i].chartType === 'bar'), + steps: (that.config.l[i].chartType === 'steps'), + lineWidth: that.config.l[i].thickness + }, + splines: { + show: (that.config.l[i].chartType === 'spline'), + tension: 0.5, //(float between 0 and 1, defaults to 0.5), + lineWidth: that.config.l[i].thickness, + fill: (that.config.l[i].fill && that.config.l[i].fill !== '0') ? parseFloat(that.config.l[i].fill) : false //(float between 0 .. 1 or false, as in flot documentation) + }, + bars: { + show: (that.config.l[i].chartType === 'bar'), + order: i + 1, + barWidth: 0.6, + lineWidth: that.config.l[i].thickness, + fill: (that.config.l[i].fill && that.config.l[i].fill !== '0') ? parseFloat(that.config.l[i].fill) : false, + fillColor: that.config.barColor || undefined, + align: 'center' + }, + points: { + show: (that.config.l[i].chartType === 'lineplot' || that.config.l[i].chartType === 'scatterplot' || that.config.l[i].points === 'true' || that.config.l[i].points === true) + }, + data: seriesData[i], + label: that.config.l[i].name, + shadowSize: that.config.l[i].shadowsize, + dashes: { + show: that.config.l[i].dashes && isLine, + lineWidth: that.config.l[i].thickness, + dashLength: [that.config.l[i].dashLength, that.config.l[i].spaceLength] + } + }; + + if ((that.config.smoothing && that.config.smoothing > 0) || (that.config.l[i].smoothing && that.config.l[i].smoothing > 0)) { + smoothing = true; + that.config.l[i].smoothing = parseInt(that.config.l[i].smoothing || that.config.smoothing); + option.data = avg(option.data, that.config.l[i].smoothing); + } else { + that.config.l[i].smoothing = 0; + } + + that.config.l[i].afterComma = (that.config.l[i].afterComma === undefined || that.config.l[i].afterComma === '') ? that.config.afterComma : parseInt(that.config.l[i].afterComma, 10); + + if (that.config.l[i].chartType === 'bar') { + option.bars.barWidth = (option.data[option.data.length - 1][0] - option.data[0][0]) / option.data.length * (parseFloat(that.config.barWidth) || 0.5); + } + /* + if (that.config.l[i].chartType === 'pie') { + series.legend = { + show: !!that.config.legend, + position: that.config.legend + }; + } else if (that.config.l[i].chartType === 'bar') { + var series = { + series: { + bars: { + show: that.config.l[i].chartType === 'bar', + barWidth: 0.6, + align: "center" + }, + pie: { + show: that.config.l[i].chartType === 'pie' + }, + legend: { + show: !!that.config.legend, + position: that.config.legend + } + } + }; + */ + + series.push(option); + + if (seriesData[i][0][0] < xMin) xMin = seriesData[i][0][0]; + if (seriesData[i][seriesData[i].length - 1][0] > xMax) xMax = seriesData[i][seriesData[i].length - 1][0]; + } + } + + + if (that.config.min === null || that.config.min === undefined || that.config.min === '' || that.config.min.toString() === 'NaN') { + that.config.min = undefined; + } else { + that.config.min = parseFloat(that.config.min); + } + + if (that.config.noBorder) { + if (!that.config.width) that.config.width = '100%'; + if (!that.config.height) that.config.height = '100%'; + + if (that.config.width.indexOf('%') !== -1) { + $('#chart_container').css({width: 'calc(' + that.config.width + ' - 20px)'}); // original 20px + } else { + $('#chart_container').css({width: that.config.width}); + } + if (that.config.height.indexOf('%') !== -1) { + $('#chart_container').css({height: 'calc(' + that.config.height + ' - 20px)'});// original 20px + } else { + $('#chart_container').css({height: that.config.height}); + } + + } else { + $('#chart_container').addClass('chart-container').css({width: that.config.width, height: that.config.height}); +// $('#chart_container').css({'padding-bottom':"100px"}) + } + + if (that.config.timeFormat === 'null') that.config.timeFormat = undefined; + + if (that.config.timeFormat) { + if (that.config.timeFormat.indexOf('%H:%M:%S') !== -1) { + that.config.timeFormatTime = '%H:%M:%S'; + } else if (that.config.timeFormat.indexOf('%I:%M:%S') !== -1) { + that.config.timeFormatTime = '%I:%M:%S'; + } else if (that.config.timeFormat.indexOf('%H:%M.') !== -1) { + that.config.timeFormatTime = '%H:%M.'; + } else if (that.config.timeFormat.indexOf('%H:%M') !== -1) { + that.config.timeFormatTime = '%H:%M'; + } else { + that.config.timeFormatTime = null; + } + if (that.config.timeFormat.indexOf('%d.%m.%y') !== -1) { + that.config.timeFormatDate = '%d.%m.%y'; + } else if (that.config.timeFormat.indexOf('%x %p') !== -1) { + that.config.timeFormatDate = '%x %p'; + } else if (that.config.timeFormat.indexOf('%d/%m/%y') !== -1) { + that.config.timeFormatDate = '%d/%m/%y'; + } else if (that.config.timeFormat.indexOf('%m.%d.%y') !== -1) { + that.config.timeFormatDate = '%m.%d.%y'; + } else if (that.config.timeFormat.indexOf('%d.%m') !== -1) { + that.config.timeFormatDate = '%d.%m'; + } else if (that.config.timeFormat.indexOf('%a') !== -1) { + that.config.timeFormatDate = '%a'; + } else { + that.config.timeFormatDate = null; + } + } + + settings = { + grid: { + hoverable: (that.config.hoverDetail === 'true' || that.config.hoverDetail === true), + backgroundColor: that.config.bg || undefined, + borderWidth: (!that.config.border_width && that.config.border_width !== '0' && that.config.border_width !== 0) ? undefined : parseInt(that.config.border_width, 10), + borderColor: that.config.border_color || undefined + }, + yaxes: [], + xaxes: [], + legend: { + show: !!that.config.legend, + position: that.config.legend, + hideable: true, + noColumns: parseInt(that.config.legColumns, 10) || undefined, + backgroundColor: that.config.legBg || undefined, + backgroundOpacity: that.config.legBgOpacity !== undefined ? parseFloat(that.config.legBgOpacity) : 0.85, + labelFormatter: function (label, series) { + if (label === '__hide_me__') return null; + return '' + label + ''; + } + } + }; + + if (that.config.zoom) { + settings.zoom = { + interactive: true, + trigger: 'dblclick', // or "click" for single click + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + }; + settings.pan = { + interactive: true, + cursor: 'move', // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 + }; + } + + var steps = that.config.animation < 1000 ? 20 : 50; + + var ii; + for (ii = 0; ii < that.config.l.length; ii++) { + + that.config.l[ii].yaxe = that.config.l[ii].yaxe || ''; + that.config.l[ii].xaxe = that.config.l[ii].xaxe || ''; + that.config.l[ii].commonYAxis = that.config.l[ii].commonYAxis || ''; + + var yaxi = { + show: that.config.l[ii].yaxe !== 'off', + min: (that.config.l[ii].min !== '' && that.config.l[ii].min !== null && that.config.l[ii].min !== undefined) ? parseFloat(that.config.l[ii].min) : undefined, + max: (that.config.l[ii].max !== '' && that.config.l[ii].max !== null && that.config.l[ii].max !== undefined) ? parseFloat(that.config.l[ii].max) : undefined, + position: that.config.l[ii].yaxe.indexOf('left') > -1 ? 'left' : 'right', + font: { + color: that.config.l[ii].yaxe.indexOf('Color') > -1 ? that.config.l[ii].color : (that.config.y_labels_color || 'black') + }, + zoomRange: false, // or [ number, number ] (min range, max range) or false + panRange: false, // or [ number, number ] (min, max) or false + // to do + /*{ + size: 11, + lineHeight: 13, + style: "italic", + weight: "bold", + family: "sans-serif", + variant: "small-caps", + color: "#545454" + }*/ + ticks: parseInt(that.config.l[ii].yticks, 10) || undefined, + tickColor: that.config.grid_color || undefined, + tickFormatter: _tickYFormatter + }; + + var xaxi = { + show: that.config.l[ii].xaxe !== 'off', + position: that.config.l[ii].xaxe.indexOf('top') !== -1 ? 'top' : 'bottom', + font: { + color: that.config.l[ii].xaxe.indexOf('Color') !== -1 ? that.config.l[ii].color : (that.config.x_labels_color || 'black') + }, + zoomRange: null, // or [ number, number ] (min range, max range) or false + panRange: null, // or [ number, number ] (min, max) or false + mode: 'time', + //timeformat: that.config.timeFormat, + //timezone: "browser", + tickFormatter: that.config.timeFormat ? _tickXFormatter : null, + minTickSize: (that.config.l[ii].chartType === 'bar') ? series[ii + markingsOffset].bars.barWidth : undefined, + tickColor: that.config.grid_color || undefined, + ticks: parseInt(that.config.l[ii].xticks, 10) || undefined, + min: undefined, + max: undefined + }; + + // prepare for bar + if (that.config.l[ii].chartType === 'bar') { + settings.legend.hideable = false; + + xaxi.ticks = []; + for (var m = 0; m < seriesData[ii].length; m++) { + xaxi.ticks.push(seriesData[ii][m][0]); + // Normally first and last points are invalid + } + seriesData[ii][0][1] = null; + seriesData[ii][seriesData[ii].length - 1][1] = null; + } else if (ticks) { + xaxi.ticks = ticks; + } + + if (that.config.zoom) { + var now = new Date(); + xaxi.zoomRange = [null, now.getTime()]; // or [ number, number] (min range, max range) or false + xaxi.panRange = [null, now.getTime()]; // or [ number, number] (min range, max range) or false + } + + settings.yaxes.push(yaxi); + settings.xaxes.push(xaxi); + + // Support for commonYAxis + if (that.config.l[ii].commonYAxis !== '') { + series[ii + markingsOffset].yaxis = parseInt(that.config.l[ii].commonYAxis); + } else { + series[ii + markingsOffset].yaxis = ii + 1; + } + series[ii + markingsOffset].xaxis = ii + 1; + + series[ii + markingsOffset].curvedLines = { + apply: !!that.config.l[ii].smoothing, + active: !!that.config.l[ii].smoothing, + monotonicFit: true + }; + } + + // set yaxis + if (markLines && markLines.length) { + var num = 0; + for (var mm = 0; mm < markLines.length; mm++) { + if (series[markLines[mm].l + markingsOffset]) { + markLines[mm].l = parseInt(markLines[mm].l, 10); + series[num].yaxis = series[markLines[mm].l + markingsOffset].yaxis; + series[num].data[0][0] = xMin; + series[num].data[1][0] = xMax; + num++; + // if lower value set + if (markLines[mm].vl !== '' && markLines[mm].vl !== null && markLines[mm].vl !== undefined) { + series[num].yaxis = series[markLines[mm].l + markingsOffset].yaxis; + series[num].data[0][0] = xMin; + series[num].data[1][0] = xMax; + num++; + } + } + } + } + + if (smoothing) { + settings.series = settings.series || {}; + settings.series.curvedLines = { + apply: true, + active: true, + monotonicFit: true + }; + } + if (that.config.animation) { + settings.series = settings.series || {}; + settings.series.grow = { + active: true, + steps: steps, + stepDelay: that.config.animation / steps + }; + } + + // hiddengraphs overload the labelFormatter, so we should overload the hiddengraphs + $.plot.plugins.push({ + init: function (plot) { + plot.hooks.processOptions.push(function checkOptions(plot, options) { + if (!options.legend.hideable) { + return; + } + + options.legend.labelFormatter = function(label, series) { + if (label === '__hide_me__') return null; + return '' + label + ''; + }; + }); + }, + options: options, + name: 'hiddenGraphsEx', + version: '1.0' + }); + + that.chart = $.plot('#' + that.options.chartId, series, settings); + + showLabels(that.config.animation); + + var $div = $('#' + that.options.chartId); + + that.options.tooltipId = that.options.tooltipId || 'tooltip'; + + // Hoover + if (that.config.hoverDetail === 'true' || that.config.hoverDetail === true) { + $div.unbind('plothover').bind('plothover', function (event, pos, item) { + if (item) { + var x = item.datapoint[0].toFixed(2); + var y; + + if (that.config.l[item.seriesIndex - markingsOffset].type === 'boolean') { + y = !!Math.round(item.datapoint[1] - that.config.l[item.seriesIndex - markingsOffset].yOffset); + } else { + y = (item.datapoint[1] - that.config.l[item.seriesIndex - markingsOffset].yOffset).toFixed(2); + } + + var text = item.series.label ? item.series.label + '
' : ''; + text += $.plot.formatDate(new Date(parseInt(x, 10)), that.config.timeFormat) + '
'; + text += '' + _yFormatter(y, item.seriesIndex - markingsOffset) + ''; + + var $tooltip = $('#' + that.options.tooltipId).html(text); + if ($(this).height() - item.pageY < $tooltip.height()) { + item.pageY -= 10 + $tooltip.height(); + } + if ($(this).width() - item.pageX < $tooltip.width()) { + item.pageX -= 10 + $tooltip.width(); + } + $tooltip.css({top: item.pageY + 5, left: item.pageX + 5}).fadeIn(200); + } else { + $('#tooltip').hide(); + } + }); + + if (!$('#' + that.options.tooltipId).length) { + $('
').css({ + position: 'absolute', + display: 'none', + border: '1px solid #fdd', + padding: '2px', + 'background-color': '#fee', + opacity: 0.80 + }).appendTo('body'); + } + } + + if (that.config.zoom && that.options.cbOnZoom) { + $div.unbind('plotzoom').bind('plotzoom', function (e, plot, args) { + if (that.zoomTimeout) clearTimeout(that.zoomTimeout); + that.zoomTimeout = setTimeout(that.options.cbOnZoom, 500); + }).unbind('plotpan').bind('plotpan', function (e, plot, args) { + if (that.zoomTimeout) clearTimeout(that.zoomTimeout); + that.zoomTimeout = setTimeout(that.options.cbOnZoom, 500); + }) + } + })(); + + this.update = function (newSeriesData, newMarkingsData, newTicks) { + if (newSeriesData) { + var xMin = Infinity; + var xMax = 0; + + for (var index = 0; index < config.l.length; index++) { + series[index + markingsOffset].data = newSeriesData[index]; + if (newSeriesData[index][0][0] < xMin) xMin = newSeriesData[index][0][0]; + if (newSeriesData[index][newSeriesData[index].length - 1][0] > xMax) xMax = newSeriesData[index][newSeriesData[index].length - 1][0]; + + // prepare for bar + if (config.l[index].chartType === 'bar') { + settings.xaxes[index].ticks = []; + for (var m = 0; m < newSeriesData[index].length; m++) { + settings.xaxes[index].ticks.push(newSeriesData[index][m][0]); + } + // Normally first and last points are invalid + newSeriesData[index][0][1] = null; + newSeriesData[index][newSeriesData[index].length - 1][1] = null; + } + } + + // update xmin and xmax + if (markLines && markLines.length) { + var num_ = 0; + for (var m = 0; m < markLines.length; m++) { + series[num_].data[0][0] = xMin; + series[num_].data[1][0] = xMax; + num_++; + // if lower value set + if (markLines[m].vl !== '' && markLines[m].vl !== null && markLines[m].vl !== undefined) { + series[num_].data[0][0] = xMin; + series[num_].data[1][0] = xMax; + num_++; + } + } + } + + $('.data-point-label').remove(); + $('.marklines-label').remove(); + + if (settings.series && settings.series.grow) settings.series.grow.active = false; + } + if (newMarkingsData) { + if (newMarkingsData && newMarkingsData.length) { + var num = 0; + for (var mm = 0; mm < newMarkingsData.length; mm++) { + series[num].data[0][1] = newMarkingsData[mm].v; + series[num].data[1][1] = newMarkingsData[mm].v; + num++; + // if lower value set + if (newMarkingsData[mm].vl !== '' && newMarkingsData[mm].vl !== null && newMarkingsData[mm].vl !== undefined) { + series[num].data[0][1] = newMarkingsData[mm].vl; + series[num].data[1][1] = newMarkingsData[mm].vl; + num++; + } + } + } + } + this.chart = $.plot('#' + this.options.chartId, series, settings); + showLabels(false); + }; + + this.getRange = function () { + var opt = this.chart.getOptions(); + var result = []; + for (var index = 0; index < opt.xaxes.length; index++) { + result[index] = { + min: Math.round(opt.xaxes[index].min), + max: Math.round(opt.xaxes[index].max) + }; + settings.xaxes[index].max = result[index].max; + settings.xaxes[index].min = result[index].min; + } + return result; + }; + + this.setRange = function (minMaxArr) { + for (var index = 0; index < settings.xaxes.length; index++) { + settings.xaxes[index].min = minMaxArr[index].min; + settings.xaxes[index].max = minMaxArr[index].max; + } + }; + + this.resetZoom = function (time) { + time = time || new Date(); + for (var index = 0; index < settings.xaxes.length; index++) { + settings.xaxes[index].zoomRange = [null, time.getTime()]; + settings.xaxes[index].panRange = [null, time.getTime()]; + } + }; + + this.zoom = function (positionX, amount) { + var offset = this.chart.offset(); + this.chart.zoom({ + center: { + left: positionX - offset.left, + height: this.chart.height() / 2 + }, + amount: amount + }); + }; + + this.pan = function (positionX) { + this.chart.pan({left: positionX, top: 0}); + }; + + return this; +} + + + diff --git a/src/js/data.js b/src/js/data.js new file mode 100644 index 0000000..2c197b3 --- /dev/null +++ b/src/js/data.js @@ -0,0 +1,850 @@ +'use strict'; + +// Show "no connection" message after 5 seconds +var disconnectTimeout = setTimeout(function () { + disconnectTimeout = null; + //Show disconnected message + $('#no-connection').show(); +}, 5000); + +var sessionId = 1; +// Analyse query +var path = location.href.split('?')[1]; + +var systemLang = 'en'; +if (typeof sysLang !== 'undefined') { + systemLang = sysLang || 'en'; +} + + +// convert old format to new one +// OLD: http://localhost:8082/flot/index.html?range=1440&renderer=line&axeX=l&axeY=inside&_ids=system.adapter.admin.0.memRss%2Csystem.adapter.email.0.memRss&_colors=%23c05020%3B%2330c020%3B%236060c0 +// NEW: http://localhost:8082/flot/index.html?l%5B0%5D%5Bid%5D=system.adapter.admin.0.memRss&l%5B0%5D%5Boffset%5D=0&l%5B0%5D%5Baggregate%5D=average&l%5B0%5D%5Bcolor%5D=%23FF0000&l%5B0%5D%5Bthickness%5D=3&l%5B1%5D%5Bid%5D=system.adapter.email.0.memRss&l%5B1%5D%5Boffset%5D=0&l%5B1%5D%5Bart%5D=average&l%5B1%5D%5Bcolor%5D=%2300FF00&l%5B1%5D%5Bthickness%5D=3&timeType=relative&relativeEnd=now&range=10&aggregateType=step&aggregateSpan=300&legend=sw +// OLD => +//{ +// _colors: "#c05020;#30c020;#6060c0" +// _ids: "system.adapter.admin.0.memRss,system.adapter.email.0.memRss" +// axeX: "lines" +// axeY: "inside" +// range: "1440" +// renderer: "line" +//} +// NEW => +//{ +// "l" : [ +// { +// "id" : "system.adapter.admin.0.memRss", +// "offset" : "0", +// "aggregate" : "minmax", +// "color" : "#FF0000", +// "thickness" : "3" +// }, { +// "id" : "system.adapter.email.0.memRss", +// "offset" : "0", +// "aggregate" : "minmax", +// "color" : "#00FF00", +// "thickness" : "3" +// } +// ], +// "timeType" : "relative", +// "relativeEnd" : "now", +// "range" : "10", +// "aggregateType" : "step", +// "aggregateSpan" : "300", +// "legend" : "sw //} + +var config = deparam(path || ''); + +if (config.lines) { + config.l = JSON.parse(JSON.stringify(config.lines)); + delete config.lines; +} + +if (config._ids) { + var ids = config._ids ? config._ids.split(';') : []; + var colors = config._colors ? config._colors.split(';') : []; + var names = config._names ? config._names.split(';') : []; + var units = config._units ? config._units.split(';') : []; + config.l = []; + for (var i = 0; i < ids.length; i++) { + config.l.push({ + id: ids[i], + offset: 0, + name: names[i] || '', + aggregate: 'onchange', + color: colors[i] || 'blue', + thickness: config.strokeWidth || 1, + shadowsize: config.strokeWidth || 1, + min: config.min || '', + max: config.max || '', + unit: units[i] || '' + }); + } + config.aggregateType = 'step'; + config.aggregateSpan = 300; + config.relativeEnd = 'now'; +} + +// convert art to aggregate +if (config.l) { + for (var j = 0; j < config.l.length; j++) { + if (config.l[j].art) { + config.l[j].aggregate = config.l[j].art; + delete config.l[j].art; + } + if (config.instance && !config.l[j].instance) { + config.l[j].instance = config.instance; + } + } +} + +// Set default values +config.width = config.width || '100%'; +config.height = config.height || '100%'; +config.timeFormat = config.timeFormat || '%H:%M:%S %e.%m.%y'; +config.useComma = config.useComma === 'true' || config.useComma === true; +config.zoom = config.zoom === 'true' || config.zoom === true; +config.animation = parseInt(config.animation) || 0; +config.noedit = config.noedit === 'true' || config.noedit === true; +config.afterComma = (config.afterComma === undefined) ? 2 : parseInt(config.afterComma, 10); +config.timeType = config.timeArt || config.timeType || 'relative'; +// if ((config.max !== undefined && config.max !== '' && config.max !== null && parseFloat(config.max) != NaN)) config.max = parseFloat(config.max); +var seriesData = []; +var ticks = null; +var liveInterval; + +var navOptions = {}; +var socketURL = ''; +var socketSESSION = ''; +var now = new Date(); +var divId = 'chart_placeholder'; + +// for zoom +var zoomTimeout = null; +var lastX = null; +var mouseDown = false; +var lastWidth = null; +var chart = null; + +var isApp = false; +var subscribes = []; +var subscribed = false; +// because of security issue +try { + if ((window.top !== window.self) && (typeof window.top.app !== 'undefined') && (typeof window.top.socketUrl !== 'undefined')) { + isApp = true; + } +} catch (e) { + +} + +if (isApp) { + socketURL = window.top.socketUrl; // if flot runs in iframe inside the app use the socketURL determined by app.js +} else { + if (typeof socketUrl !== 'undefined') { + socketURL = socketUrl; + if (socketURL && socketURL[0] === ':') { + socketURL = location.protocol + '//' + location.hostname + socketURL; + } + socketSESSION = socketSession; + } +} +var socket = io.connect(socketURL, { + 'query': 'key=' + socketSESSION, + 'reconnection limit': 10000, + 'max reconnection attempts': Infinity, + upgrade: typeof socketForceWebSockets !== 'undefined' ? !socketForceWebSockets : undefined, + rememberUpgrade: typeof socketForceWebSockets !== 'undefined' ? socketForceWebSockets : undefined, + transports: typeof socketForceWebSockets !== 'undefined' ? (socketForceWebSockets ? ['websocket'] : undefined) : undefined +}); + +socket.on('connect', function () { + if (disconnectTimeout) { + $('#no-connection').hide(); + clearTimeout(disconnectTimeout); + disconnectTimeout = null; + } + setTimeout(function () { + socket.emit('name', 'flot'); + }, 50); + + setTimeout(function () { + readData(); + }, 100); +}); + +socket.on('stateChange', function (id, state) { + if (!chart || !config || !config.m) return; + console.log(id + ' - ' + state.val); + for (var m = 0; m < config.m.length; m++) { + if (config.m[m].oid === id) { + config.m[m].v = parseFloat(state.val) || 0; + } + if (config.m[m].oidl === id) { + config.m[m].vl = parseFloat(state.val) || 0; + } + } + chart.update(null, config.m); +}); + +if (config.window_bg) $('body').css('background', config.window_bg); + +socket.on('disconnect', function () { + if (!disconnectTimeout) { + disconnectTimeout = setTimeout(function () { + disconnectTimeout = null; + //Show disconnected message + $('#no-connection').show(); + }, 5000); + } +}); + +function addTime(time, offset, plusOrMinus, isOffsetInMinutes) { + time = new Date(time); + + if (typeof offset === 'string') { + if (offset[1] === 'm') { + offset = parseInt(offset, 10); + time.setMonth(plusOrMinus ? time.getMonth() + offset : time.getMonth() - offset); + time = time.getTime(); + } else if (offset[1] === 'y') { + offset = parseInt(offset, 10); + time.setFullYear(plusOrMinus ? time.getFullYear() + offset : time.getFullYear() - offset); + time = time.getTime(); + } else { + time = time.getTime(); + if (isOffsetInMinutes) { + if (plusOrMinus) { + time += (parseInt(offset, 10) || 0) * 60000; + } else { + time -= (parseInt(offset, 10) || 0) * 60000; + } + + } else { + if (plusOrMinus) { + time += (parseInt(offset, 10) || 0) * 1000; + } else { + time -= (parseInt(offset, 10) || 0) * 1000; + } + } + } + } else { + time = time.getTime(); + if (isOffsetInMinutes) { + if (plusOrMinus) { + time += (parseInt(offset, 10) || 0) * 60000; + } else { + time -= (parseInt(offset, 10) || 0) * 60000; + } + + } else { + if (plusOrMinus) { + time += (parseInt(offset, 10) || 0) * 1000; + } else { + time -= (parseInt(offset, 10) || 0) * 1000; + } + } + } + return time; +} + +function getStartStop(index, step) { + var option = {}; + var end; + var start; + var _now; + config.l[index].offset = config.l[index].offset || 0; + + var isMonthRange = (config.range.indexOf('m') === -1) ? false : true; + // check config range + if (isMonthRange && config.l.length > 1) { + var monthRange = parseInt(config.range, 10) || 1; + for (var a = 0; a < config.l.length; a++) { + if (config.l[a].offset && config.l[a].offset !== 0) { + // Check what the month has first index + _now = addTime(now, config.l[0].offset); + var minusMonth = new Date(_now); + minusMonth.setMonth(minusMonth.getMonth() - monthRange); + config.range = Math.floor((_now - minusMonth.getTime()) / 60000) + ''; + break; + } + } + } + + if (config.zoomed) { + navOptions[index].end = config.l[index].zMax; + navOptions[index].start = config.l[index].zMin; + return navOptions[index]; + } else { + if (!step) { + if (config.timeType === 'static') { + var startTime; + var endTime; + var y; + var m; + if (config.start_time !== undefined) { + startTime = config.start_time.split(':').map(Number); + } else { + startTime = [0, 0]; + } + + if (config.end_time !== undefined) { + endTime = config.end_time.split(':').map(Number); + } else { + endTime = [24, 0]; + } + + // offset is in seconds + start = new Date(config.start).setHours(startTime[0], startTime[1]); + end = new Date(config.end) .setHours(endTime[0], endTime[1]); + start = addTime(start, config.l[index].offset); + end = addTime(end, config.l[index].offset); + } else { + if (config.relativeEnd === 'now') { + _now = new Date(now); + } else if (config.relativeEnd.indexOf('minute') !== -1) { + var minutes = parseInt(config.relativeEnd, 10) || 1; + _now = new Date(now); + _now.setMinutes(Math.floor(_now.getMinutes() / minutes) * minutes + minutes); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd.indexOf('hour') !== -1) { + var hours = parseInt(config.relativeEnd, 10) || 1; + _now = new Date(now); + _now.setHours(Math.floor(_now.getHours() / hours) * hours + hours); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd === 'today') { + _now = new Date(now); + _now.setDate(_now.getDate() + 1); + _now.setHours(0); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd === 'weekUsa') { + //var week = parseInt(config.relativeEnd, 10) || 1; + _now = new Date(now); + _now.setDate(_now.getDate() - _now.getDay() + 7); + _now.setHours(0); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd === 'weekEurope') { + //var _week = parseInt(config.relativeEnd, 10) || 1; + _now = new Date(now); + // If + if (_now.getDay() === 0) { + _now.setDate(_now.getDate() + 1); + } else { + _now.setDate(_now.getDate() - _now.getDay() + 8); + } + _now.setHours(0); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd === 'month') { + _now = new Date(now); + _now.setMonth(_now.getMonth() + 1); + _now.setDate(1); + _now.setHours(0); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } else if (config.relativeEnd === 'year') { + _now = new Date(now); + _now.setFullYear(_now.getFullYear() + 1); + _now.setMonth(0); + _now.setDate(1); + _now.setHours(0); + _now.setMinutes(0); + _now.setSeconds(0); + _now.setMilliseconds(0); + } + + end = addTime(_now, config.l[index].offset); + start = addTime(end, config.range, false, true); + } + + option = { + start: start, + end: end, + ignoreNull: (config.l[index].ignoreNull === undefined) ? config.ignoreNull : config.l[index].ignoreNull, + aggregate: config.l[index].aggregate || config.aggregate || 'minmax' + }; + + if (config.aggregateType === 'step') { + option.step = config.aggregateSpan * 1000; + } else if (config.aggregateType === 'count') { + option.count = config.aggregateSpan || (document.getElementById('chart_container').clientWidth / 10); + } + + navOptions[index] = option; + return option; + + } else { + end = addTime(now, config.l[index].offset); + start = end - step; + + option = { + start: start, + end: end, + ignoreNull: (config.l[index].ignoreNull === undefined) ? config.ignoreNull : config.l[index].ignoreNull, + aggregate: config.l[index].aggregate || config.aggregate || 'minmax', + count: 1 + }; + + navOptions[index].end = end; + navOptions[index].start = addTime(end, config.range, false, true); + return option; + } + } +} + +function readOneChart(id, instance, index, callback) { + + var option = getStartStop(index); + option.instance = instance; + option.sessionId = sessionId; + config.l[index].yOffset = parseFloat(config.l[index].yOffset) || 0; + + //console.log(JSON.stringify(option)); + console.log(new Date(option.start) + ' - ' + new Date(option.end)); + socket.emit('getHistory', id, option, function (err, res, stepIgnore, _sessionId) { + if (err) console.error(err); + + if (sessionId && _sessionId && _sessionId !== sessionId) { + console.warn('Ignore request with sessionId=' + _sessionId + ', actual is ' + sessionId); + return; + } + + if (!err && res) { + //option.ignoreNull = (config.l[index].ignoreNull === undefined) ? (config.ignoreNull === 'true' || config.ignoreNull === true) : (config.l[index].ignoreNull === 'true' || config.l[index].ignoreNull === true); + option.yOffset = config.l[index].yOffset; + + var _series = seriesData[index]; + + for (var i = 0; i < res.length; i++) { + // if less 2000.01.01 00:00:00 + if (res[i].ts < 946681200000) res[i].ts = res[i].ts * 1000; + + // Convert boolean values to numbers + if (res[i].val === 'true' || res[i].val === true) { + res[i].val = 1; + } else if (res[i].val === 'false' || res[i].val === false) { + res[i].val = 0; + } + if (typeof res[i].val === 'string') res[i].val = parseFloat(res[i].val); + + _series.push([res[i].ts, res[i].val !== null ? res[i].val + option.yOffset : null]); + } + // add start and end + if (_series.length) { + if (_series[0][0] > option.start) _series.unshift([option.start, null]); + if (_series[_series.length - 1][0] < option.end) _series.push([option.end, null]); + } else { + _series.push([option.start, null]); + _series.push([option.end, null]); + } + // free memory + res = null; + } + + if (callback) callback(id, index); + }); +} + +function readValue(id, index, callback) { + socket.emit('getState', id, function (err, state) { + if (state) { + callback(index, parseFloat(state.val) || 0); + } else { + callback(index, 0); + } + }); +} + +function prepareChart() { + chart = new CustomChart({ + chartId: divId, + titleId: 'title', + tooltipId: 'tooltip', + cbOnZoom: onZoom + }, config, seriesData, config.m, ticks); + + if (config.zoom) { + $('#resetZoom').unbind('click').click(function () { + seriesData = []; + $('#resetZoom').hide(); + config.zoomed = false; + now = new Date(); + readData(true); + }); + + // handlers for zoom and pan + $('#' + divId) + // flot can pan and zoom with mouse itself + /*.unbind('mousedown') + .mousedown(function (e) { + mouseDown = true; + lastX = e.pageX; + }) + .unbind('mouseup').mouseup(function () { + mouseDown = false; + if (zoomTimeout) clearTimeout(zoomTimeout); + zoomTimeout = setTimeout(onZoom, 500); + }) + .unbind('mousemove') + .mousemove(function(e) { + if (mouseDown) { + chart.pan(e.pageX - lastX); + } + lastX = e.pageX; + }) + .unbind('mousewheel DOMMouseScroll') + .bind('mousewheel DOMMouseScroll', function(event) { + var amount = (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) ? 0.9 : 1.1; + chart.zoom(event.originalEvent.pageX, amount); + if (zoomTimeout) clearTimeout(zoomTimeout); + zoomTimeout = setTimeout(onZoom, 500); + })*/ + .unbind('touchstart') + .on('touchstart', function (e) { + e.preventDefault(); + mouseDown = true; + var touches = e.touches || e.originalEvent.touches; + if (touches) { + lastX = touches[touches.length - 1].pageX; + if (touches.length > 1) { + lastWidth = Math.abs(touches[0].pageX - touches[1].pageX); + } else { + lastWidth = null; + } + } + }) + .unbind('touchend') + .on('touchend', function(e) { + e.preventDefault(); + mouseDown = false; + if (zoomTimeout) clearTimeout(zoomTimeout); + zoomTimeout = setTimeout(onZoom, 500); + }) + .unbind('touchmove') + .on('touchmove', function (e) { + e.preventDefault(); + var touches = e.touches || e.originalEvent.touches; + if (!touches) return; + if (mouseDown) { + var pageX = touches[touches.length - 1].pageX; + if (touches.length > 1) { + // zoom + var width = Math.abs(touches[0].pageX - touches[1].pageX); + + if (lastWidth !== null && width !== lastWidth) { + var amount = (width > lastWidth) ? 1.1 : 0.9; + var positionX = (touches[0].pageX > touches[1].pageX) ? (touches[1].pageX + width / 2) : (touches[0].pageX + width / 2); + + chart.zoom(positionX, amount); + + if (zoomTimeout) clearTimeout(zoomTimeout); + zoomTimeout = setTimeout(onZoom, 500); + } + lastWidth = width; + } else { + // swipe + chart.pan(lastX - pageX); + } + } + lastX = pageX; + }); + } + + if (config.live && config.timeType === 'relative') { + if (config.live === true || config.live === 'true') config.live = 30; + config.live = parseInt(config.live, 10) || 30; + startLiveUpdate(); + } +} + +function _readOneLine(index, cb) { + socket.emit('getObject', config.l[index].id, function (err, res) { + if (!err && res && res.common) { + config.l[index].name = config.l[index].name || res.common.name; + config.l[index].unit = config.l[index].unit || (res.common.unit ? res.common.unit.replace('�', '°') : ''); + config.l[index].type = res.common.type; + } else { + config.l[index].name = config.l[index].name || config.l[index].id; + config.l[index].unit = config.l[index].unit || ''; + } + if (typeof config.l[index].name === 'object') { + config.l[index].name = config.l[index].name[systemLang] || config.l[index].name.en; + } + readOneChart(config.l[index].id, config.l[index].instance, index, cb); + }); +} + +function readTicks(callback) { + if (!config.ticks) { + callback && callback(null); + } else { + socket.emit('getObject', config.ticks, function (err, res) { + var index = 0; + var option = JSON.parse(JSON.stringify(getStartStop(index))); + option.instance = config.l[index].instance; + option.sessionId = sessionId; + option.aggregate = 'onchange'; + + //console.log(JSON.stringify(option)); + console.log('Ticks: ' + new Date(option.start) + ' - ' + new Date(option.end)); + socket.emit('getHistory', config.ticks, option, function (err, res, stepIgnore, _sessionId) { + if (err) console.error(err); + + if (sessionId && _sessionId && _sessionId !== sessionId) { + console.warn('Ignore request with sessionId=' + _sessionId + ', actual is ' + sessionId); + return; + } + + if (!err && res) { + var _series = ticks || []; + if (ticks && ticks.length) ticks.splice(0, ticks.length); + + for (var i = 0; i < res.length; i++) { + // if less 2000.01.01 00:00:00 + if (res[i].ts < 946681200000) res[i].ts = res[i].ts * 1000; + + if (!res[i].val !== null) _series.push([res[i].ts, res[i].val]); + } + // add start and end + if (_series.length) { + if (_series[0][0] > option.start) _series.unshift([option.start, '']); + if (_series[_series.length - 1][0] < option.end) _series.push([option.end, '']); + } else { + _series.push([option.start, '']); + _series.push([option.end, '']); + } + // free memory + res = null; + ticks = _series; + } + if (callback) callback(_series); + }); + }); + } +} + +function readMarkings(cb, m) { + m = m || 0; + if (!config.m || !config.m.length || m >= config.m.length) { + return cb && cb(); + } else { + if (!config.m[m].oid && config.m[m].v && parseFloat(config.m[m].v) != config.m[m].v && config.m[m].v.indexOf('.') !== -1) { + if (subscribes.indexOf(config.m[m].v) === -1) subscribes.push(config.m[m].v); + + readValue(config.m[m].v, m, function (index, val) { + config.m[index].oid = config.m[index].v; + config.m[index].v = val; + + if (!config.m[m].oidl && config.m[m].vl && parseFloat(config.m[m].vl) != config.m[m].vl && config.m[m].vl.indexOf('.') !== -1) { + if (subscribes.indexOf(config.m[m].vl) === -1) subscribes.push(config.m[m].vl); + readValue(config.m[m].vl, m, function (index, val) { + config.m[index].oidl = config.m[index].vl; + config.m[index].vl = val; + setTimeout(readMarkings, 0, cb, m + 1); + }); + } else { + setTimeout(readMarkings, 0, cb, m + 1); + } + }); + } else + if (!config.m[m].oidl && config.m[m].vl && parseFloat(config.m[m].vl) != config.m[m].vl && config.m[m].vl.indexOf('.') !== -1) { + if (subscribes.indexOf(config.m[m].vl) === -1) subscribes.push(config.m[m].vl); + readValue(config.m[m].vl, m, function (index, val) { + config.m[index].oidl = config.m[index].vl; + config.m[index].vl = val; + setTimeout(readMarkings, 0, cb, m + 1); + }); + } else { + setTimeout(readMarkings, 0, cb, m + 1); + } + } +} + +function _readData(callback, j) { + j = j || 0; + if (j >= config.l.length) { + return callback && callback(); + } else { + if (config.l[j] !== '' && config.l[j] !== undefined) seriesData.push([]); + _readOneLine(j, function () { + setTimeout(function () { + _readData(callback, j + 1); + }, 10); + }); + } +} + +function subscribeAll(subscribes, cb, s) { + s = s || 0; + if (!subscribes || !subscribes.length || s >= subscribes.length) { + cb && cb(); + } else { + socket.emit('subscribe', subscribes[s], function () { + setTimeout(function () { + subscribeAll(subscribes, cb, s + 1); + }, 0); + }); + } +} + +function readData(hidden) { + if (disconnectTimeout) { + $('#no-connection').hide(); + clearTimeout(disconnectTimeout); + disconnectTimeout = null; + } + sessionId++; + + if (config.l) { + if (!hidden) $('#server-disconnect').show(); + + // todo +// if (config.renderer === 'pie' || (config.renderer === 'bar' && config._ids.length > 1)) { +// +// seriesData = [[]]; +// for (var j = 0; j < config._ids.length; j++) { +// readOneValue(config._ids[j], j, function (_id, _index, value) { +// if (config.renderer === 'pie') { +// seriesData[0][_index] = {label: config.l[_index].name, data: value}; +// } else { +// seriesData[0][_index] = [config.l[_index].name, value]; +// } +// if (_index === config._ids.length - 1) { +// graphCreate(divId, ); +// } +// }); +// } +// } else { + _readData(function () { + readTicks(function (_ticks) { + readMarkings(function () { + if (!subscribed) { + subscribed = true; + subscribeAll(); + } + + $('#server-disconnect').hide(); + prepareChart(); + }); + }); + }); + } + + if (!config.noedit) { + // install edit button + $('#edit') + .show() + .click(function () { + var win = window.open(location.href.replace('index.html', 'edit.html'), 'flot'); + win.focus(); + }); + } +} + +function startLiveUpdate() { + liveInterval = setInterval(function () { + if (config.zoomed) { + var max = 0; + var min = null; + + // Find min and max of all lines + for (var index = 0; index < config.l.length; index++) { + if (max < config.l[index].zMax) max = config.l[index].zMax; + if (min === null || min > config.l[index].zMin) min = config.l[index].zMin; + } + + // if 20% + if ((max + ((max - min) / 20)) >= new Date().getTime()) { + max = new Date().getTime() - now.getTime(); + var result = []; + for (var _index = 0; _index < config.l.length; _index++) { + config.l[_index].zMax += max; + config.l[_index].zMin += max; + result.push({min: config.l[_index].zMin, max: config.l[_index].zMax}); + } + chart.setRange(result); + } else { + return; + } + } + + console.log('on time'); + updateLive(); + }, config.live * 1000); +} + +function updateLive() { + var ready = 0; + now = new Date(); + $('.loader').show(); + sessionId++; + + if (config.zoom) chart.resetZoom(now); + + for (var index = 0; index < config.l.length; index++) { + ready++; + seriesData[index] = []; + readOneChart(config.l[index].id, config.l[index].instance, index, function () { + if (!--ready) { + readTicks(function (_ticks) { + chart.update(seriesData, null, _ticks); + $('.loader').hide(); + }); + } + }); + } +} + +function avg(data, range) { + var r = []; + var rd; + var i1; + var s; + var cnt; + for(var i = 0; i < data.length; i++) { + if (i < range) { + i1 = 0; + } else { + i1 = i - range + 1; + } + rd = [data[i][0], null]; + if (data[i][1] !== null) { + s = 0; + cnt = 0; + for(var j = i1; j <= i; j++) { + if (data[j][1] === null) continue; + s += data[j][1]; + cnt++; + } + rd[1] = s / cnt; + } + r.push(rd); + } + return r; +} + +function onZoom() { + if (!config.zoomed) { + $('#resetZoom').show(); + config.zoomed = true; + } + + var result = chart.getRange(); + + for (var r = 0; r < result.length; r++) { + config.l[r].zMin = result[r].min; + config.l[r].zMax = result[r].max; + } + + console.log('on zoom'); + updateLive(); +} diff --git a/src/js/days.js b/src/js/days.js new file mode 100644 index 0000000..aac1ab4 --- /dev/null +++ b/src/js/days.js @@ -0,0 +1,22 @@ +var months = { + 'en': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + 'de': ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], + 'ru': ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], + 'es': ['Jan', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], + 'fr': ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + 'it': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + 'pl': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + 'pt': ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Set', 'Out', 'Nov', 'Dez'], + 'nl': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] +}; +var days = { + 'en': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'de': ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], + 'ru': ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'], + 'es': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'fr': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'it': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'pl': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'pt': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + 'nl': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] +}; \ No newline at end of file diff --git a/src/js/edit.js b/src/js/edit.js new file mode 100644 index 0000000..eb56a1a --- /dev/null +++ b/src/js/edit.js @@ -0,0 +1,1540 @@ +$(document).ready(function () { + 'use strict'; + + var defaultColors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#800000', '#008000', '#000080', '#808000', '#800080', '#008080']; + var instances = []; + var timer = null; + var showTimer = null; + var defaultHistory = ''; + var presets = {}; + var currentChart = null; + var onlyOneChart = false; + var loaded = false; + var socket; + var instance = 0; + var setup = { + options: { + l: [] + } + }; + + function parseSettings(path) { + if (path) { + setup.options = deparam(path || ''); + // for compatibility. Not used any more + if (setup.options._ids) { + var ids = setup.options._ids ? setup.options._ids.split(';') : []; + var colors = setup.options._colors ? setup.options._colors.split(';') : []; + var names = setup.options._names ? setup.options._names.split(';') : []; + var units = setup.options._units ? setup.options._units.split(';') : []; + setup.options.l = []; + for (var i = 0; i < ids.length; i++) { + setup.options.l.push({ + id: ids[i], + offset: 0, + name: names[i] || '', + aggregate: 'minmax', + color: colors[i] || 'blue', + thickness: setup.options.strokeWidth || 1, + shadowsize: setup.options.strokeWidth || 1, + smoothing: setup.options.smoothing || 0, + afterComma: setup.options.afterComma || 0, + min: setup.options.min || '', + max: setup.options.max || '', + unit: units[i] || '' + }); + } + setup.options.aggregateType = 'step'; + setup.options.aggregateSpan = 300; + setup.options.relativeEnd = 'now'; + if (setup.options._colors) delete setup.options._colors; + if (setup.options._names) delete setup.options._names; + if (setup.options._ids) delete setup.options._ids; + } + setup.options.l = setup.options.l || []; + } + + // convert art to aggregate + for (var j = 0; j < setup.options.l.length; j++) { + if (setup.options.l[j].art) { + setup.options.l[j].aggregate = setup.options.l[j].art; + delete setup.options.l[j].art; + } + } + // rename timeArt + if (setup.options.timeArt) { + setup.options.timeType = setup.options.timeArt; + delete setup.options.timeArt; + } + var $presetsTable = $('#presets_table'); + + $presetsTable.find('tr').removeClass('presets-selected'); + $presetsTable.find('tr[data-name="' + currentChart + '"]').addClass('presets-selected'); + + if (setup.options.lines) { + setup.options.l = JSON.parse(JSON.stringify(setup.options.lines)); + delete setup.options.lines; + } + setup.options.ignoreNull = undefined; + setup.options.afterComma = undefined; + setup.options.smoothing = undefined; + + if (!setup.options.l || !setup.options.l.length) addLine(); + } + + function addLine() { + if (!setup.options.l) setup.options.l = []; + var index = setup.options.l.length; + + setup.options.l.push({ + id: '', + instance: '', + offset: 0, + aggregate: 'minmax', + color: defaultColors[index] || '#00FFFF', + min: '', + max: '', + thickness: 3, + shadowsize: 3, + unit: '', + name: '' + }); + + return index; + } + + function addMarkline() { + if (!setup.options.m) setup.options.m = []; + var index = setup.options.m.length; + setup.options.m.push({ + l: 0, // line index + v: 0, // value + f: false, + c: defaultColors[index] || '#00FFFF', // color + t: 3, // thickness + s: 3, // shadowsize + d: '', // description + p: 'l', // position : left / right + py: 0, // description y offset + fc: defaultColors[index] || '#00FFFF', // color of text + fs: '' // font-size + }); + + return index; + } + + function showMarklines(callback) { + setTimeout(function () { + if (!settings.option_markline) { + $('.markline-option').hide(); + return; + } + + var text = ''; + // line index + var textLines = ''; + for (var t = 0; t < setup.options.l.length; t++) { + textLines += '\n'; + } + + var textPosition = ''; + textPosition += ''; + + if (setup.options.m) { + for (var i = 0; i < setup.options.m.length; i++) { + text += ''; + // line index + text += ''; + + // upper value + text += ''; + text += ''; + // lower value + text += ''; + text += ''; + // color + text += ''; + // fill + text += ''; + // thickness + text += ''; + // shadowsize + text += ''; + // description + text += ''; + // description position + text += ''; + // description-offset + text += ''; + // font-size + text += ''; + // font-color + text += ''; + // delete + text += '\n'; + + text += ''; + } + } + $('#markline_list').html(text); + + $('.markline-value').each(function () { + var id = $(this).data('index'); + var name = $(this).data('option'); + if ($(this).attr('type') === 'checkbox') { + if (setup.options.m[id][name] === 'true') setup.options.m[id][name] = true; + if (setup.options.m[id][name] === 'false') setup.options.m[id][name] = false; + $(this).prop('checked', !!setup.options.m[id][name]); + } else { + $(this).val(setup.options.m[id][name]); + } + }); + + /*$('.markline-color').colorPicker({ + renderCallback: function ($elm, toggled) { + if (toggled === false) { + $elm.trigger('change'); + } + } + });*/ + $('.markline-color').colorpicker({ + colorFormat: '#HEX' + }).on('change', function () { + $(this).css({'background-color': $(this).val(), color: invertColor($(this).val())}); + }).trigger('change'); + + $('.markline-remove').button({ + icons: {primary: 'ui-icon-trash'}, + text: false + }).click(function () { + if (setup.options.m.length) { + var i = $(this).data('index'); + setup.options.m.splice(i, 1); + showMarklines(); + save(); + delayedUpdate(); + } + }).css({width: 22, height: 22}); + + $('.markline-select-dialog').button({ + text: false, + icons: { + primary: 'ui-icon-folder-open' + } + }).css({width: 25, height: 22}).click(function () { + var index = $(this).data('index'); + var attr = $(this).data('option'); + $('#dialog-select-member').selectId('show', setup.options.m[index][attr], { + common: { + custom: false + } + }, + function (newId, ignore, obj) { + setup.options.l[index][attr] = newId; + $('.markline-value[data-index="' + index + '"][data-option="' + attr + '"]').val(newId).trigger('change'); + }); + }); + }, 100); + } + + function showOptionsDialog(index) { + var options = setup.options.l[index]; + var $dialogLineOptions = $('#dialog-line-options'); + $dialogLineOptions.data('index', index); + + if (!$dialogLineOptions.data('inited')) { + $dialogLineOptions.data('inited', true); + + var count = 0; + var text = ''; + for (var attr in settings.extraOptions) { + if (!settings.extraOptions.hasOwnProperty(attr)) continue; + count++; + text += ''; + text += ''; + if (attr === 'offset') { + text += '\n'; + } else if (!settings.extraOptions[attr].values) { + text += ''; + } else { + text += ''; + } + text += ''; + } + $dialogLineOptions.find('table').html(text); + + $dialogLineOptions.dialog({ + autoOpen: false, + modal: true, + width: 430, + resizable: false, + height: count * 32 + 120, + buttons: [ + { + text: _('Ok'), + click: function () { + var $dialogLineOptions = $('#dialog-line-options'); + var index = $dialogLineOptions.data('index'); + var changed = false; + var options = setup.options.l[index]; + $dialogLineOptions.find('.dialog-line-option').each(function () { + var attr = $(this).data('option'); + + if ($(this).attr('type') === 'checkbox') { + if ($(this).prop('checked') !== options[attr]) { + changed = true; + options[attr] = $(this).prop('checked'); + } + } else { + if ($(this).val() != options[attr]) { + changed = true; + options[attr] = $(this).val(); + } + } + }); + + if (changed) update(); + + $dialogLineOptions.dialog('close'); + } + }, + { + text: _('Cancel'), + click: function () { + $('#dialog-line-options').dialog('close'); + } + } + ] + }); + + } + + + $dialogLineOptions.find('.dialog-line-option').each(function () { + var attr = $(this).data('option'); + if ($(this).attr('type') === 'checkbox') { + if (options[attr] === 'true') options[attr] = true; + if (options[attr] === 'false') options[attr] = false; + if ($(this).data('default') !== null && $(this).data('default') !== undefined && + (options[attr] === undefined || options[attr] === '' || options[attr] === null)) { + options[attr] = $(this).data('default') === 'true'; + } + $(this).prop('checked', options[attr] === true); + } else { + if ($(this).data('default') !== null && $(this).data('default') !== undefined && + (options[attr] === undefined || options[attr] === '' || options[attr] === null)) { + options[attr] = $(this).data('default'); + } + $(this).val(options[attr] === undefined ? '' : options[attr]); + } + }); + + $dialogLineOptions.dialog('option', 'title', _('Edit options for line %s', index + 1)); + $dialogLineOptions.dialog('open'); + } + + function showIds(callback) { + setTimeout(function () { + var text = ''; + var colgroup = '\n'; + var thead = '\n'; + + var textInstances = '\n'; + for (var t = 0; t < instances.length; t++) { + textInstances += '\n'; + } + + var colindex = 0; + for (var s in settings.line) { + if (settings.line.hasOwnProperty(s) && settings.line[s].enabled) { + colgroup += '\n'; + thead += '' + _(settings.line[s].name) + '\n'; + colindex++; + } + } + colgroup += ''; + thead += ''; + + for (var i = 0; i < setup.options.l.length && i < settings.maxLines; i++) { + var line = setup.options.l[i]; + + text += '\n'; + for (var s in settings.line) { + if (!settings.line.hasOwnProperty(s) || !settings.line[s] || !settings.line[s].enabled) continue; + settings.line[s].style = settings.line[s].style || ''; + settings.line[s]._class = settings.line[s]._class || ''; + + if (s === 'min') { + line.min = (line.min === undefined) ? '' : line.min; + } else if (s === 'max') { + line.max = (line.max === undefined) ? '' : line.max; + } + + if (s === 'number') { + text += '' + (i + 1) + '\n'; + } else if (s === 'idSelect') { + text += '\n'; + } else if (s === 'instance') { + text += '\n'; + } else if (s === 'offset') { + text += '\n'; + text += '\n'; + } else if (s === 'removeButton') { + text += '\n'; + } else if (s === 'extraOptions') { + text += '\n'; + } else { + text += '\n'; + if (settings.line[s].values) { + text += '\n'; + } else { + text += '\n'; + } + text += '\n'; + } + } + + text += ''; + } + + $('#idslist').html(thead + text); + + /*$('.input-color').colorPicker({ + renderCallback: function ($elm, toggled) { + if (toggled === false) { + $elm.trigger('change'); + } + } + });*/ + if (systemLang === 'de') { + $.colorpicker.regional = { + '': { + ok: 'OK', + cancel: 'Abbrechen', + none: 'Nichts', + button: 'Farbe', + title: 'Farbe wählen', + transparent: 'Transparent', + hsvH: 'H', + hsvS: 'S', + hsvV: 'V', + rgbR: 'R', + rgbG: 'G', + rgbB: 'B', + labL: 'L', + labA: 'a', + labB: 'b', + hslH: 'H', + hslS: 'S', + hslL: 'L', + cmykC: 'C', + cmykM: 'M', + cmykY: 'Y', + cmykK: 'K', + alphaA: 'A' + } + }; + } else if (systemLang === 'ru') { + $.colorpicker.regional = { + '': { + ok: 'OK', + cancel: 'Отмена', + none: 'Нет', + button: 'Цвет', + title: 'Выбрать цвет', + transparent: 'Прозрачность', + hsvH: 'H', + hsvS: 'S', + hsvV: 'V', + rgbR: 'R', + rgbG: 'G', + rgbB: 'B', + labL: 'L', + labA: 'a', + labB: 'b', + hslH: 'H', + hslS: 'S', + hslL: 'L', + cmykC: 'C', + cmykM: 'M', + cmykY: 'Y', + cmykK: 'K', + alphaA: 'A' + } + }; + } + + $('.input-color').colorpicker({ + colorFormat: '#HEX' + }).on('change', function () { + $(this).css({'background-color': $(this).val(), color: invertColor($(this).val())}); + }).trigger('change'); + + $('.id-remove').button({ + icons: {primary: 'ui-icon-trash'}, + text: false + }).click(function () { + if (setup.options.l.length) { + var i = $(this).data('index'); + setup.options.l.splice(i, 1); + if (!setup.options.l.length) { + addLine(); + } + showIds(); + save(); + delayedUpdate(); + } + }).css({width: 22, height: 22}); + + $('.id-options').button({ + icons: {primary: 'ui-icon-gear'}, + text: false + }).click(function () { + showOptionsDialog($(this).data('index')); + }).css({width: 22, height: 22}); + + $('.select-dialog').button({ + text: false, + icons: { + primary: 'ui-icon-folder-open' + } + }).css({width: 25, height: 22}).click(function () { + var index = $(this).data('index'); + // get instance + var instance = $('[data-option="instance"][data-index="' + index + '"]').val(); + if (!instance) instance = defaultHistory; + + $('#dialog-select-member').selectId('show', setup.options.l[index].id, { + common: { + custom: instance + } + }, + function (newId, ignore, obj) { + setup.options.l[index].id = newId; + $('.ids[data-index="' + index + '"]').val(newId).trigger('change'); + if (obj && obj.common.type === 'boolean') { + $('select[data-option="aggregate"][data-index="' + index + '"]').val('onchange').trigger('change'); + $('select[data-option="chartType"][data-index="' + index + '"]').val('steps').trigger('change'); + $('input[data-option="min"][data-index="' + index + '"]').val(0).trigger('change'); + $('input[data-option="max"][data-index="' + index + '"]').val(10).trigger('change'); + } + showIds(); + }); + }); + + $('.options-lines').each(function () { + var $this = $(this); + var index = $(this).data('index'); + var opt = $(this).data('option'); + + if (setup.options.l[index][opt] !== undefined) { + if ($this.attr('type') === 'checkbox') { + if (setup.options.l[index][opt] === 'true') setup.options.l[index][opt] = true; + if (setup.options.l[index][opt] === 'false') setup.options.l[index][opt] = false; + + $this.prop('checked', !!setup.options.l[index][opt]); + } else { + $this.val(setup.options.l[index][opt]); + } + } + }); + $('.spinner-lines').attr('type', 'number'); + /*$('.spinner-lines').spinner().on('stop', function () { + $(this).trigger('change'); + }).parent().addClass('input');*/ + + if (typeof callback === 'function') callback(); + + $('.toggleable').click(function () { + var index = $(this).data('index'); + var $col = $('col[data-index="' + index + '"]'); + if (!$col.data('width')) $col.data('width', $col.attr('width')); + if ($col.data('hidden')) { + $col.data('hidden', false); + $col.attr('width', $col.data('width')); + $(this).css('width', $col.data('width')); + } else { + $col.data('hidden', true); + $col.attr('width', '10px'); + $(this).css('width', '10px'); + } + }); + $('select[data-option="chartType"]').on('change', function () { + if ($(this).val() === 'spline') { + alert('Experimental'); + } + }); + + showMarklines(); + }, 100); + } + + function getSettings() { + var _options = JSON.parse(JSON.stringify(setup.options)); + + // clean options + for (var y in _options) { + if (_options.hasOwnProperty(y) && _options[y] === '') { + delete _options[y]; + } + } + + // clean lines + for (var i = 0; i < _options.l.length; i++) { + if (_options.l[i].id === '') { + _options.l.splice(i, 1); + i--; + } else { + for (var x in _options.l[i]) { + if (_options.l[i].hasOwnProperty(x) && _options.l[i][x] === '') { + delete _options.l[i][x]; + } + } + } + } + + //console.log(deparam($.param(_options))); + + return $.param(_options); + } + + function delayedUpdate() { + if (timer) clearTimeout(timer); + timer = setTimeout(update, 500); + } + + function update() { + if (!loaded) return; + clearTimeout(timer); + timer = null; + + // Store settings + if (typeof(Storage) !== 'undefined') { + $('.value').each(function () { + if ($(this).attr('type') === 'checkbox') { + setup.options[$(this).attr('id')] = $(this).prop('checked'); + } else { + setup.options[$(this).attr('id')] = $(this).val(); + } + }); + + save(); + } + + var settings = getSettings(); + if (currentChart) { + if (settings !== presets[currentChart].native.url) { + $('.save').button('enable'); + } else { + $('.save').button('disable'); + } + } else { + $('.save').button('enable'); + } + + + $('#link').val(location.href.split('?')[0].replace('edit.html', 'index.html') + '?' + settings); + $('#updatePreview').button('option', 'disabled', false); + + if ($('#aggregateType').val() === 'step') { + $('#spanName').text(_('Seconds') + ':'); + } else { + $('#spanName').text(_('Counts') + ':'); + } + + $('.relative, .static').hide(); + + $('.' + $('#timeType').val()).show(); + + if ($('#autoUpdate').prop('checked')) { + delayedPreview(); + $('#updatePreview').hide(); + } + + // calculate span + var text = ''; + if (setup.options.timeType === 'relative') { + text = _('%s ago', $('#range').find('option:selected').text()) + ' - ' + _(setup.options.relativeEnd); + } else { + text = new Date(setup.options.start).toLocaleDateString() + ' ' + + new Date(setup.options.start + ' ' + setup.options.start_time).toLocaleTimeString() + ' - ' + + new Date(setup.options.end).toLocaleDateString() + ' ' + + new Date(setup.options.end + ' ' + setup.options.end_time).toLocaleTimeString(); + } + $('#time_span').html('[' + text + ']'); + } + + function save() { + if (typeof(Storage) !== 'undefined') { + localStorage.setItem('yunkong2.Flot', JSON.stringify(setup)); + } + } + + function delayedPreview() { + if (showTimer) clearTimeout(showTimer); + showTimer = setTimeout(updatePreview, 500); + } + + function updatePreview() { + var $chart = $('#chart'); + var height = parseInt($('#height').val(), 10); + if (height) { + $chart.css({height: (height || 500) + 90}); + } else { + $chart.css({height: 'calc(100% - 350px)'}); + } + + var settings = getSettings(); + $chart.attr('src', ''); + setTimeout(function () { + $chart.attr('src', 'index.html?' + settings + '&' + (new Date()).getTime()); + }, 0); + + $('#updatePreview').button('option', 'disabled', true); + } + + function invertColor(hexcolor) { + hexcolor = hexcolor.replace('#', ''); + var r = parseInt(hexcolor.substr(0, 2), 16); + var g = parseInt(hexcolor.substr(2, 2), 16); + var b = parseInt(hexcolor.substr(4, 2), 16); + var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; + return (yiq >= 128) ? 'black' : 'white'; + } + + function saveChart(id, name, callback) { + if (!id || !presets[id]) { + id = name2Chart(name); + + presets[id] = { + common: { + name: name + }, + type: 'chart', + native: { + url: getSettings() + } + }; + } else { + presets[id].native.url = getSettings(); + } + + currentChart = id; + + socket.emit('setObject', id, presets[id], function (err) { + $('.save').button('disable'); + callback && callback(err) + }); + } + + function loadChart(id, callback) { + socket.emit('getObject', id, function (err, obj) { + if (!obj) { + alert(_('Not found')); + callback && callback(); + } else { + currentChart = obj._id; + presets[obj._id] = obj; + parseSettings(obj.native.url); + $('#accordion').tabs({active: 1}); + showIds(); + fillValues(); + + update(); + + delayedPreview(); + callback && callback(); + } + }); + } + + function name2Chart(name) { + return 'flot.' + instance + '.' + name.replace(/[.,\s]+/, '_'); + } + + function renameChart(id, newName, callback) { + socket.emit('getObject', id, function (err, obj) { + socket.emit('delObject', obj._id, function (err) { + delete presets[obj._id]; + obj.common.name = newName; + obj._id = name2Chart(name); + socket.emit('setObject', obj._id, obj, function (err) { + presets[obj._id] = obj; + currentChart = obj._id; + showPresets(); + callback && callback(); + }); + }); + }); + } + + function getDesc(url) { + var parts = deparam(url || ''); + if (parts.l) { + var ids = []; + for (var i = 0; i < parts.l.length; i++) { + ids.push(parts.l[i].id); + } + return ids.join(', '); + } + + return ''; + } + + function showPresets() { + var texts = ''; + var settings = getSettings(); + for (var id in presets) { + if (!presets.hasOwnProperty(id)) continue; + var obj = presets[id]; + if (!currentChart && obj.native.url === settings) { + currentChart = id; + } + texts += ''; + texts += ''; + texts += '' + obj.common.name + ''; + texts += '' + getDesc(obj.native.url) + ''; + texts += ''; + texts += ''; + } + var $presetsTable = $('#presets_table'); + $presetsTable.html(texts); + + $('.presets-btn-load').button().click(function () { + var id = $(this).data('name'); + loadChart(id, function () { + $presetsTable.find('tr').removeClass('presets-selected'); + $presetsTable.find('tr[data-name="' + id + '"]').addClass('presets-selected'); + }); + }); + + $('.presets-btn-delete').button({ + icons: {secondary: 'ui-icon-trash'}, + text: false + }).click(function () { + var id = $(this).data('name'); + if (window.confirm(_('Are you sure?'))) { + socket.emit('delObject', id, function (err) { + delete presets[id]; + showPresets(); + }); + } + }).css({width: 32, height: 32}); + $('.presets-btn-rename').button({ + icons: {secondary: 'ui-icon-pencil'}, + text: false + }).click(function () { + var id = $(this).data('name'); + $('#dialog-new-preset-name').val(presets[id].common.name); + + $('#dialog-new-preset-info-tr').hide(); + + $('#dialog-new-preset').dialog({ + autoOpen: true, + modal: true, + title: _('Enter chart name'), + width: 430, + resizable: false, + buttons: [ + { + id: 'dialog-new-preset-ok', + text: _('Ok'), + click: function () { + var newName = $('#dialog-new-preset-name').val(); + var newId = name2Chart(newName); + if (presets[newId] && !window.confirm(_('Overwrite existing?'))) { + return; + } + + renameChart(id, newName, function () { + $('#dialog-new-preset').dialog('close'); + }); + } + }, + { + text: _('Cancel'), + click: function () { + $('#dialog-new-preset').dialog('close'); + } + } + ] + }); + }).css({width: 32, height: 32}); + } + + function fillValues() { + $('.value') + .each(function () { + var $this = $(this); + var id = $this.attr('id'); + if (setup.options[id] !== undefined) { + if ($this.attr('type') === 'checkbox') { + if (setup.options[id] === 'true') setup.options[id] = true; + if (setup.options[id] === 'false') setup.options[id] = false; + $this.prop('checked', !!setup.options[id]); + } else { + $this.val(setup.options[id]); + } + } + }); + if (setup.options.bg || setup.options.bg === 0) { + if (setup.options.bg && setup.options.bg.length < 3 && parseInt(setup.options.bg, 10).toString() === setup.options.bg.toString()) { + $('#bg').hide(); + $('#bg_predefined').show().val(setup.options.bg); + } else { + $('#bg_custom').prop('checked', true); + $('#bg').show(); + $('#bg_predefined').hide(); + } + } + } + + function init() { + console.log('Initialize...'); + // hide/show settings + if (settings.maxLines < 2) { + $('#ids_add').hide(); + } + for (var s in settings) { + if (!settings.hasOwnProperty(s)) continue; + if (typeof settings[s] === 'object' && settings[s].enabled === false) { + $('.' + s).remove(); + } + } + + addLine(); + var params = location.href.split('?')[1]; + if (params && params.match(/^preset=/)) { + currentChart = params.replace(/^preset=/, ''); + onlyOneChart = true; + } else { + parseSettings(location.href.split('?')[1]); + } + + if (typeof sysLang !== 'undefined') { + systemLang = sysLang || 'en'; + } + + $('#dialog-select-member').selectId('init', { + filter: { + common: { + custom: true + } + }, + imgPath: '../lib/css/fancytree/', + noMultiselect: true, + connCfg: { + socketUrl: socketUrl, + socketSession: socketSession, + socketName: 'flotEditDialog', + upgrade: typeof socketForceWebSockets !== 'undefined' ? !socketForceWebSockets : undefined, + rememberUpgrade: typeof socketForceWebSockets !== 'undefined' ? socketForceWebSockets : undefined, + transports: typeof socketForceWebSockets !== 'undefined' ? (socketForceWebSockets ? ['websocket'] : undefined) : undefined + }, + columns: ['name', 'role', 'room', 'value'], + texts: { + select: _('Select'), + cancel: _('Cancel'), + all: _('All'), + id: _('ID'), + name: _('Name'), + role: _('Role'), + room: _('Room'), + value: _('Value'), + selectid: _('Select ID'), + from: _('From'), + lc: _('Last changed'), + ts: _('Time stamp'), + wait: _('Processing...'), + ack: _('Acknowledged') + } + }); + + if (typeof(Storage) !== 'undefined' && !currentChart) { + var _setup = localStorage.getItem('yunkong2.Flot'); + if (_setup) { + try { + _setup = JSON.parse(_setup); + var parts = document.location.href.split('?'); + if (parts[1]) { + _setup.options = setup.options; + setup = _setup; + save(); + document.location.href = parts[0]; + } else if (_setup.options) { + setup = _setup; + } + } + catch (e) { + console.log('Cannot parse stored settings'); + } + } + } + + $('#autoUpdate').change(function () { + setup['auto-update'] = $(this).prop('checked') ? 'true' : 'false'; + update(); + if (setup['auto-update'] === 'true') { + $('#updatePreview').hide(); + } else { + $('#updatePreview').show(); + } + }).prop('checked', setup['auto-update'] === 'true'); + + $('#arrangeBools').button().click(function () { + // arrange all boolean values automatically + // calculate + var count = 0; + var axis = null; + for (var k = 0; k < setup.options.l.length; k++) { + if (setup.options.l[k].chartType === 'steps') { + if (axis === null) axis = k; + count++; + } + } + + var t = 0; + for (var i = 0; i < setup.options.l.length; i++) { + if (setup.options.l[i].chartType === 'steps') { + setup.options.l[i].max = Math.round(count * 2 * 1.2 * 10) / 10; + setup.options.l[i].commonYAxis = axis + 1; + setup.options.l[i].yOffset = Math.round(-(t + 1) * 1.2 * 10) / 10; + setup.options.l[i].min = Math.round((-count * 1.2 - 0.1) * 10) / 10; + setup.options.l[i].yaxe = 'off'; + t++; + } + setup.options.l[i].min = Math.round((-count * 1.2 - 0.1) * 10) / 10; + } + showIds(); + save(); + delayedUpdate(); + }); + + var $accordion = $('#accordion'); + + $accordion + .on('change', '.options-lines', function () { + var index = $(this).data('index'); + if ($(this).attr('type') === 'checkbox') { + setup.options.l[index][$(this).data('option')] = $(this).prop('checked'); + } else { + setup.options.l[index][$(this).data('option')] = $(this).val(); + } + if ($(this).hasClass('spinner-lines')) { + delayedUpdate(); + } else { + update(); + } + }) + .on('keyup', '.options-lines', function () { + $(this).trigger('change'); + }); + + $accordion + .on('change', '.markline-value', function () { + var index = $(this).data('index'); + if ($(this).attr('type') === 'checkbox') { + setup.options.m[index][$(this).data('option')] = $(this).prop('checked') ? 1 : 0; + } else { + setup.options.m[index][$(this).data('option')] = $(this).val(); + } + update(); + }) + .on('keyup', '.markline-value', function () { + $(this).trigger('change'); + }); + + // hide presets + if (onlyOneChart) { + $($accordion.find('li')[0]).hide(); + $('#chapter_presets').hide(); + } + + $('#ids_add').button({ + icons: {secondary: 'ui-icon-plus'}, + text: true + }).click(function () { + addLine(); + showIds(); + }).css({height: 30}); + + $('#markline_add').button({ + icons: {secondary: 'ui-icon-plus'}, + text: true + }).click(function () { + addMarkline(); + showMarklines(); + }).css({height: 30}); + + $('#clear').button({ + icons: {primary: 'ui-icon-trash'}, + text: false + }).click(function () { + localStorage.setItem('yunkong2.Flot', JSON.stringify({reset: true})); + location.reload(); + }).css({width: 30, height: 30}); + + $('.value') + .change(function () { + if ($(this).hasClass('spinner') || $(this).hasClass('input-static-color')) { + delayedUpdate(); + } else { + update(); + } + }) + .keyup(function () { + $(this).trigger('change'); + }); + + /*$('.input-static-color').colorPicker({ + renderCallback: function ($elm, toggled) { + if (toggled === false) { + $elm.trigger('change'); + } + } + });*/ + $('.input-static-color').colorpicker({ + colorFormat: '#HEX' + }).on('change', function () { + $(this).css({'background-color': $(this).val(), color: invertColor($(this).val())}); + }).trigger('change'); + + $('.clear-button').hide(); + /*.button({ + icons: { + primary: 'ui-icon-trash' + }, + text: false + }).css({width: 22, height: 22}).click(function () { + var id = $(this).data('clear'); + setTimeout(function () { + $('#' + id) + .val('') + .css({color: '#000', 'background-color': '#FFF'}); + //.trigger('change'); + }, 500); + });*/ + + $('#timeType').change(function () { + $('.relative, .static').hide(); + $('.' + $(this).val()).show(); + }); + + $('.spinner').attr('type', 'number'); + /*$('.spinner').spinner().on('stop', function () { + $(this).trigger('change'); + }).parent().addClass('input');*/ + + $('#bg_custom').change(function () { + if ($(this).prop('checked')) { + $('#bg').show(); + $('#bg_predefined').hide(); + } else { + $('#bg').hide(); + $('#bg_predefined') + .show() + .val(0) + .trigger('change'); + } + }); + + $('#bg_predefined').change(function () { + $('#bg').val($(this).val()).trigger('change'); + }); + + $('#ticks_select').button({ + text: false, + icons: { + primary: 'ui-icon-folder-open' + } + }).css({width: 25, height: 22}).click(function () { + $('#dialog-select-member').selectId('show', $('#ticks').val(), { + common: { + custom: true + } + }, + function (newId, ignore, obj) { + if (newId) { + $('#ticks').val(newId).trigger('change'); + } + }); + }); + + + $('#aggregateType').change(function () { + if ($('#aggregateType').val() === 'step') { + $('#spanName').text(_('Seconds')); + } else { + $('#spanName').text(_('Counts')); + } + }); + + // $('#range').val(options.range); + // $('#axeX').val(options.axeX); + $('#updatePreview') + .button({ + icons: { + primary: 'ui-icon-refresh' + } + }) + .click(updatePreview) + .button('option', 'disabled', true) + .css({'font-size': 14, 'white-space': 'nowrap'}); + + $('#open').button({ + icons: { + primary: 'ui-icon-play' + } + }).click(function () { + window.open($('#link').val(), 'flot'); + }).css({'font-size': 14, 'white-space': 'nowrap'}); + + translateAll(); + + $accordion.tabs({ + active: parseInt(setup.acc) || 0, + animate: { + easing: 'linear', + duration: 200 + }, + activate: function (event, ui) { + setup.acc = $(ui.newHeader).attr('id'); + save(); + } + }); + + // Handler for .ready() called. + var bottomElemOriginalHeight = $('#chart').height(); + $('#resizable1').resizable({ + autoHide: true, + handles: 's', + resize: function (e, ui) { + /*var parent = ui.element.parent(); + var remainingSpace = parent.height() - ui.element.outerHeight(); + var divTwo = ui.element.next(); + var divTwoWidth = (remainingSpace - (divTwo.outerHeight() - divTwo.height())) / parent.height() * 100 + '%'; + divTwo.width(divTwoWidth);*/ + $('#chart').height(bottomElemOriginalHeight - (ui.element.outerHeight() - ui.originalSize.height)); + }, + stop: function (e, ui) { + bottomElemOriginalHeight = $('#chart').height(); + /* var parent = ui.element.parent(); + ui.element.css({height: ui.element.height() / parent.height() * 100 + '%'}); */ + $('#temp_div').remove(); + }, + start: function () { + var $ifr = $('#chart'); + var $d = $('
'); + + $('body').append($d[0]); + $d[0].id = 'temp_div'; + $d.css({position: 'absolute'}); + $d.css({top: $ifr.position().top, left: 0}); + $d.height($ifr.height()); + $d.width('100%'); + } + }); + + window.onbeforeunload = function (e) { + console.log('onbeforeunload'); + if (onlyOneChart && currentChart) { + var settings = getSettings(); + if (settings !== presets[currentChart].native.url) { + e.returnValue = _('You have unsaved settings. Discard?'); + return e.returnValue; + } else { + return null; + } + } else { + return null; + } + }; + + fillValues(); + + setTimeout(function () { + initSocket(); + }, 200); + } + + function getPresets(socket, callback) { + // read presets + socket.emit('getObjectView', 'chart', 'chart', { + startkey: 'flot.' + instance + '.', + endkey: 'flot.' + instance + '.\u9999' + }, function (err, res) { + presets = {}; + loaded = true; + if (res && res.rows) { + for (var i = 0; i < res.rows.length; i++) { + presets[res.rows[i].value._id] = res.rows[i].value; + } + } + if (currentChart && !presets[currentChart]) { + alert(_('Chart ID %s not found', currentChart)); + currentChart = ''; + onlyOneChart = false; + $($('#accordion').find('li')[0]).show(); + $('#chapter_presets').show(); + } + + if (currentChart) { + var _callback = callback; + callback = null; + setTimeout(function () { + loadChart(currentChart, _callback); + }, 200); + } + showPresets(); + + var $save = $('.save'); + $save + .button({ + icons: { + primary: 'ui-icon-arrowthickstop-1-s' + }, + label: onlyOneChart ? _('save %s', presets[currentChart].common.name) : _('save'), + showLabel: true + }) + .click(function () { + if (onlyOneChart && currentChart) { + saveChart(currentChart); + return; + } + + var texts = ''; + for (var id in presets) { + texts += ''; + } + + $('#dialog-new-preset-info-tr').show(); + + $('#dialog-new-preset-into') + .html(texts) + .val(currentChart) + .unbind('change') + .bind('change', function () { + var val = $(this).val(); + if (!val) { + $('#dialog-new-preset-name-tr').show(); + } else { + $('#dialog-new-preset-name-tr').hide(); + } + }).trigger('change'); + + $('#dialog-new-preset').dialog({ + autoOpen: true, + modal: true, + title: _('Enter chart name'), + width: 430, + resizable: false, + buttons: [ + { + id: 'dialog-new-preset-ok', + text: _('Ok'), + click: function () { + var name = $('#dialog-new-preset-into').val(); + var id = name; + + if (!name) { + name = $('#dialog-new-preset-name').val(); + id = name2Chart(name); + if (presets[id]) { + // Warning. Overwrite? + if (!window.confirm(_('Overwrite existing?'))) { + return; + } + } + } + + saveChart(id, name, function () { + showPresets(); + $('#dialog-new-preset').dialog('close'); + }); + } + }, + { + text: _('Cancel'), + click: function () { + $('#dialog-new-preset').dialog('close'); + } + } + ] + }); + }) + .css({'font-size': 14, 'white-space': 'nowrap'}); + + // select editor tab if no presets + if (!res || !res.rows || !res.rows.length) { + $('#accordion').tabs({active: 1}); + $save.button('enable'); + } else if (currentChart) { + $save.button('disable'); + } + + $('#dialog-new-preset-name').keyup(function (e) { + if (e.keyCode === 13) { + $('#dialog-new-preset-ok').trigger('click'); + } + }); + callback && callback(); + }); + } + + function initSocket() { + console.log('Init connection...'); + // Read instances + socket = io.connect(socketUrl, { + query: { + key: socketSession + }, + reconnectionDelay: 10000, + reconnectionAttempts: Infinity, + upgrade: typeof socketForceWebSockets !== 'undefined' ? !socketForceWebSockets : undefined, + rememberUpgrade: typeof socketForceWebSockets !== 'undefined' ? socketForceWebSockets : undefined, + transports: typeof socketForceWebSockets !== 'undefined' ? (socketForceWebSockets ? ['websocket'] : undefined) : undefined + }); + + socket.on('connect', function () { + console.log('Connected'); + + // modifiy it later to socket.emit('name', 'flotEdit', function () { do }); 2018_05_04 BF + setTimeout(function () { + socket.emit('name', 'flotEdit'); + }, 50); + + setTimeout(function () { + getPresets(socket, function () { + socket.emit('getObject', 'system.config', function (err, obj) { + if (obj && obj.common) defaultHistory = obj.common.defaultHistory || 'history.0'; + // load history instances + socket.emit('getObjectView', 'system', 'instance', { + startkey: 'system.adapter.', + endkey: 'system.adapter.\u9999' + }, function (err, doc) { + if (!err && doc && doc.rows) { + if (doc.rows.length !== 0) { + for (var i = 0; i < doc.rows.length; i++) { + var obj = doc.rows[i].value; + if (obj && obj.type === 'instance' && obj.common && obj.common.type === 'storage') { + if (instances.indexOf(obj._id.substring('system.adapter.'.length)) === -1) instances.push(obj._id.substring('system.adapter.'.length)); + } + } + } + } + showIds(); + + update(); + + delayedPreview(); + + setTimeout(function() { + $('iframe').attr('src', 'index.html'); + }, 500); + + // not need to disconnect, because socket-io uses pool + //socket.disconnect(); + //socket = null; + }); + }); + }); + }, 100); + }); + + socket.on('disconnect', function () { + console.log('Lost connection'); + }); + + socket.on('error', function (e) { + console.error('Socket error: ' + e); + }); + socket.on('connect_error', function (e) { + console.error('Socket error: ' + e); + }); + } + + init(); +}); diff --git a/src/js/settings.js b/src/js/settings.js new file mode 100644 index 0000000..55d6365 --- /dev/null +++ b/src/js/settings.js @@ -0,0 +1,84 @@ +var settings = { + maxLines: 20, // maximal number of the lines + button_arrange_bools: {enabled: true}, // if button arrange bool is visible + line: { + number: {enabled: true, name: ''}, + instance: {enabled: true, name: 'Instance'}, + id: {enabled: true, name: 'ID', width: '200px', style: 'padding-left: 4px', _class: 'ids', inputStyle: ''}, + idSelect: {enabled: true, name: '', style: 'padding-left: 4px'}, + aggregate: {enabled: true, name: 'Aggregation', width: '70px', style: 'padding-left: 5px', values: ['minmax', 'average', 'min', 'max', 'total', 'onchange']}, + chartType: {enabled: true, name: 'Chart Type', width: '90px', values: ['line', 'bar', 'scatterplot', 'steps', /*'pie',*/ 'spline']}, + fill: {enabled: true, name: 'Fill(0to1)', width: '70px', style: 'width: 70px; text-align: right'}, + points: {enabled: true, name: 'Points', width: '50px', type: 'checkbox'}, + color: {enabled: true, name: 'Color', width: '120px', style: 'padding-left: 5px', _class: 'input-color'}, + min: {enabled: true, name: 'Min', width: '50px', style: 'padding-left: 5px'}, + max: {enabled: true, name: 'Max', width: '50px', style: 'padding-left: 5px'}, + unit: {enabled: true, name: 'Unit', width: '70px', style: 'padding-left: 5px'}, + yaxe: {enabled: true, name: 'Y Axis', width: '140px', style: 'padding-left: 5px', values: ['', 'off', 'left', 'right', 'leftColor', 'rightColor'], defaultValueName: 'default'}, + xaxe: {enabled: true, name: 'X Axis', width: '140px', style: 'padding-left: 5px', values: ['', 'off', 'top', 'bottom', 'topColor', 'bottomColor'], defaultValueName: 'default'}, + name: {enabled: true, name: 'Name', width: '200px', style: 'padding-left: 5px'}, + extraOptions: {enabled: true, name: 'More', width: '90px', style: 'text-align: center'}, + removeButton: {enabled: true, name: '', width: '', style: 'padding-left: 5px'} + }, + extraOptions: { + offset: {enabled: true, name: 'Offset', width: '130px', style: '', type: 'number'}, // support of time offset + yOffset: {enabled: true, name: 'Y-Offset', width: '70px', style: '', type: 'number'}, // support of Y offset + xticks: {enabled: true, name: 'X-Axis ticks', width: '70px', style: '', type: 'number'}, + yticks: {enabled: true, name: 'Y-Axis ticks', width: '70px', style: '', type: 'number'}, + thickness: {enabled: true, name: 'ØL', width: '70px', style: '', type: 'number', title: 'Line Width', default: 1}, + shadowsize: {enabled: true, name: 'ØS', width: '70px', style: '', type: 'number', title: 'Shadow Size', default: 0}, + commonYAxis: {enabled: true, name: 'Common Y Axis', width: '', style: '', values: ['', '1', '2', '3', '4', '5'], default: '', names: ['default']}, + ignoreNull: {enabled: true, name: 'NULL as', width: '', style: '', values: ['false', 'true', '0'], default: 'false', names: ['default', 'ignore null values', 'use 0 instead of null values']}, + smoothing: {enabled: false, name: 'Smoothing', width: '70px', style: '', type: 'number'}, + afterComma: {enabled: true, name: 'After comma', width: '70px', style: '', type: 'number', default: 2}, + dashes: {enabled: true, name: 'Dashes', width: '', style: '', type: 'checkbox', default: false}, + dashLength: {enabled: true, name: 'Dashes length', width: '70px', style: '', type: 'number', default: 10}, + spaceLength: {enabled: true, name: 'Space length', width: '70px', style: '', type: 'number', default: 10} + }, + chapter_time: {enabled: true}, + time_timeType: {enabled: true}, + time_relativeEnd: {enabled: true}, + time_range: {enabled: true}, + time_live: {enabled: true}, + time_start: {enabled: true}, + time_end: {enabled: true}, + time_aggregateType: {enabled: true}, + time_aggregateSpan: {enabled: true}, + time_ticks: {enabled: true}, + + chapter_options: {enabled: true}, + options_width: {enabled: true}, + options_height: {enabled: true}, + options_noborder: {enabled: true}, + options_window_bg: {enabled: true}, + options_bg_custom: {enabled: true}, + options_bg: {enabled: true}, + options_x_labels_color: {enabled: true}, + options_y_labels_color: {enabled: true}, + options_title: {enabled: true}, + options_titlePos: {enabled: true}, + options_titleColor: {enabled: true}, + options_titleSize: {enabled: true}, + options_legend: {enabled: true}, + options_legColumns: {enabled: true}, + options_legBg: {enabled: true}, + options_legBgOpacity: {enabled: true}, + + options_barColor: {enabled: true}, + options_barLabels: {enabled: true}, + options_barWidth: {enabled: true}, + options_barFontSize:{enabled: true}, + options_barFontColor:{enabled: true}, + + options_smoothing: {enabled: false}, + options_afterComma: {enabled: false}, + options_useComma: {enabled: true}, + options_zoom: {enabled: true}, + options_noedit: {enabled: true}, + options_animation: {enabled: true}, + options_border_color: {enabled: true}, + options_grid_color: {enabled: true}, + options_border_width: {enabled: true}, + + option_markline: {enabled: true} // it is extra option and not options +}; \ No newline at end of file diff --git a/src/js/words.js b/src/js/words.js new file mode 100644 index 0000000..1fa3cca --- /dev/null +++ b/src/js/words.js @@ -0,0 +1,328 @@ +// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n +/*global systemDictionary:true */ +'use strict'; + +systemDictionary = { + "0": { "en": "0", "de": "0", "ru": "0", "pt": "0", "nl": "0", "fr": "0", "it": "0", "es": "0", "pl": "0"}, + "1": { "en": "1", "de": "1", "ru": "1", "pt": "1", "nl": "1", "fr": "1", "it": "1", "es": "1", "pl": "1"}, + "2": { "en": "2", "de": "2", "ru": "2", "pt": "2", "nl": "2", "fr": "2", "it": "2", "es": "2", "pl": "2"}, + "3": { "en": "3", "de": "3", "ru": "3", "pt": "3", "nl": "3", "fr": "3", "it": "3", "es": "3", "pl": "3"}, + "4": { "en": "4", "de": "4", "ru": "4", "pt": "4", "nl": "4", "fr": "4", "it": "4", "es": "4", "pl": "4"}, + "5": { "en": "5", "de": "5", "ru": "5", "pt": "5", "nl": "5", "fr": "5", "it": "5", "es": "5", "pl": "5"}, + "Ok": { "en": "Ok", "de": "Ok", "ru": "Ok", "pt": "Está bem", "nl": "OK", "fr": "D'accord", "it": "Ok", "es": "De acuerdo", "pl": "Ok"}, + "role": { "en": "role", "de": "Rolle", "ru": "Роль", "pt": "Função", "nl": "rol", "fr": "rôle", "it": "ruolo", "es": "papel", "pl": "rola"}, + "Update objects": { "en": "Update objects", "de": "Objekte aktualisieren", "ru": "Обновить объекты", "pt": "Atualizar objetos", "nl": "Objecten bijwerken", "fr": "Mettre à jour", "it": "Aggiorna oggetti", "es": "Actualizar objetos", "pl": "Zaktualizuj obiekty"}, + "All": { "en": "All", "de": "Alle", "ru": "все", "pt": "Todos", "nl": "Alle", "fr": "Tout", "it": "Tutti", "es": "Todas", "pl": "Wszystko"}, + "With": { "en": "With", "de": "mit", "ru": "с", "pt": "Com", "nl": "Met", "fr": "Avec", "it": "Con", "es": "Con", "pl": "Z"}, + "Without": { "en": "Without", "de": "ohne", "ru": "без", "pt": "Sem", "nl": "Zonder", "fr": "Sans pour autant", "it": "Senza", "es": "Sin", "pl": "Bez"}, + "Update states": { "en": "Update states", "de": "States aktualisieren", "ru": "Обновить состояния", "pt": "Estado de atualização", "nl": "Status bijwerken", "fr": "Mettre à jour", "it": "Stati di aggiornamento", "es": "Actualizar estados", "pl": "Zaktualizuj stany"}, + "edit file": { "en": "edit file", "de": "Datei editieren", "ru": "Редактировать", "pt": "editar arquivo", "nl": "bestand bewerken", "fr": "modifier le fichier", "it": "modifica file", "es": "editar archivo", "pl": "edytuj plik"}, + "restart script": { "en": "restart script", "de": "Skript neu starten", "ru": "Перезапустить скрипт", "pt": "reiniciar o script", "nl": "herstart script", "fr": "redémarrer le script", "it": "riavviare lo script", "es": "script de reinicio", "pl": "zrestartuj skrypt"}, + "Select": { "en": "Select", "de": "Auswählen", "ru": "Выбрать", "pt": "Selecione", "nl": "kiezen", "fr": "Sélectionner", "it": "Selezionare", "es": "Seleccionar", "pl": "Wybierz"}, + "Select ID": { "en": "Select ID", "de": "ID Auswählen", "ru": "Выбрать ID", "pt": "Selecione ID", "nl": "Selecteer ID", "fr": "Sélectionner un identifiant", "it": "Seleziona ID", "es": "Seleccionar ID", "pl": "Wybierz ID"}, + "add children": { "en": "add children", "de": "Sub-enums einfügen", "ru": "Добавить под-категории", "pt": "adicionar filhos", "nl": "voeg kinderen toe", "fr": "ajouter des enfants", "it": "aggiungi bambini", "es": "agregar niños", "pl": "dodaj dzieci"}, + "edit enum": { "en": "edit enum", "de": "Enum ändern", "ru": "Изменить категорию", "pt": "editar enum", "nl": "edit enum", "fr": "éditer enum", "it": "modifica enum", "es": "editar enum", "pl": "edytuj wyliczenie"}, + "System settings": { "en": "System settings", "de": "Systemeinstellungen", "ru": "Системные настройки", "pt": "Configurações de sistema", "nl": "Systeem instellingen", "fr": "Les paramètres du système", "it": "Impostazioni di sistema", "es": "Ajustes del sistema", "pl": "Ustawienia systemowe"}, + "reload": { "en": "reload", "de": "Neu laden", "ru": "Перезагрузить", "pt": "recarregar", "nl": "herladen", "fr": "recharger", "it": "ricaricare", "es": "recargar", "pl": "przeładować"}, + "Delete object": { "en": "Delete object", "de": "Object löschen", "ru": "Удалить объект", "pt": "Eliminar objeto", "nl": "Object verwijderen", "fr": "Supprimer un objet", "it": "Elimina oggetto", "es": "Eliminar objeto", "pl": "Usuń obiekt"}, + "no null": { "en": " no null", "de": " kein NULL", "ru": " без null", "pt": "& nbsp; nulo", "nl": "& nbsp; geen null", "fr": "& nbsp; non nul", "it": "& nbsp; non null", "es": "& nbsp; no null", "pl": "& nbsp; no null"}, + "%s ago": { "en": "%s ago", "de": "vor %s", "ru": "%s назад", "pt": "% s atrás", "nl": "% s geleden", "fr": "il y a% s", "it": "% s fa", "es": "hace% s", "pl": "% s temu"}, + "Y-Offset": { "en": "Y-Offset", "de": "Y-Offset", "ru": "Сдвиг по Y", "pt": "Y-Offset", "nl": "Y-offset", "fr": "Y-Offset", "it": "Y-Offset", "es": "Y-Offset", "pl": "Przesunięcie Y"}, + "ID": { "en": "ID", "de": "ID", "ru": "ID", "pt": "identidade", "nl": "ID kaart", "fr": "ID", "it": "ID", "es": "CARNÉ DE IDENTIDAD", "pl": "ID"}, + "Role": { "en": "Role", "de": "Rolle", "ru": "Роль", "pt": "Função", "nl": "Rol", "fr": "Rôle", "it": "Ruolo", "es": "Papel", "pl": "Rola"}, + "Room": { "en": "Room", "de": "Raum", "ru": "Комната", "pt": "Quarto", "nl": "Kamer", "fr": "Chambre", "it": "Camera", "es": "Habitación", "pl": "Pokój"}, + "Value": { "en": "Value", "de": "Wert", "ru": "Значение", "pt": "Valor", "nl": "Waarde", "fr": "Valeur", "it": "Valore", "es": "Valor", "pl": "Wartość"}, + "none": { "en": "none", "de": "nichts", "ru": "ничего", "pt": "Nenhum", "nl": "geen", "fr": "aucun", "it": "nessuna", "es": "ninguna", "pl": "Żaden"}, + "Save into:": { "en": "Save into:", "de": "Save into:", "ru": "Сохранить как:", "pt": "Salvar em:", "nl": "Bewaar in:", "fr": "Enregistrer dans:", "it": "Salva in:", "es": "Guardar en:", "pl": "Zapisz w:"}, + "Name:": { "en": "Name:", "de": "Name:", "ru": "Имя:", "pt": "Nome:", "nl": "Naam:", "fr": "Prénom:", "it": "Nome:", "es": "Nombre:", "pl": "Nazwa:"}, + "save": { "en": "save", "de": "Speichern", "ru": "сохранить", "pt": "Salve ", "nl": "opslaan", "fr": "enregistrer", "it": "salvare", "es": "salvar", "pl": "zapisać"}, + "load": { "en": "load", "de": "laden", "ru": "загрузить", "pt": "carga", "nl": "laden", "fr": "charge", "it": "caricare", "es": "carga", "pl": "obciążenie"}, + "Presets": { "en": "Presets", "de": "Voreinstellung", "ru": "Пресеты", "pt": "Presets", "nl": "presets", "fr": "Presets", "it": "Presets", "es": "Presets", "pl": "Presets"}, + "IDs": { "en": "IDs", "de": "IDs", "ru": "Объекты", "pt": "IDs", "nl": "IDs", "fr": "ID", "it": "ID", "es": "IDs", "pl": "ID"}, + "new": { "en": "new", "de": "unter neuen Namen", "ru": "новое", "pt": "Novo", "nl": "nieuwe", "fr": "Nouveau", "it": "nuovo", "es": "nuevo", "pl": "Nowy"}, + "Enter chart name": { "en": "Enter chart name", "de": "Chartname eintragen", "ru": "Введите имя графика", "pt": "Digite o nome do gráfico", "nl": "Voer de diagramnaam in", "fr": "Entrez le nom du diagramme", "it": "Inserisci il nome del grafico", "es": "Ingrese el nombre del gráfico", "pl": "Wprowadź nazwę wykresu"}, + "save %s": { "en": "save %s", "de": "Speichern %s", "ru": "сохранить %s", "pt": "salvar% s", "nl": "bespaar% s", "fr": "enregistrer% s", "it": "salva% s", "es": "ahorra", "pl": "zapisz% s"}, + "Input data": { "en": "Input data", "de": "Eingangsdaten", "ru": "Входные данные", "pt": "Dados de entrada", "nl": "Invoergegevens", "fr": "Des données d'entrée", "it": "Dati in ingresso", "es": "Datos de entrada", "pl": "Dane wejściowe"}, + "Options": { "en": "Options", "de": "Optionen", "ru": "Опции", "pt": "Opções", "nl": "opties", "fr": "Options", "it": "Opzioni", "es": "Opciones", "pl": "Opcje"}, + "Range:": { "en": "Range:", "de": "Umfang:", "ru": "Интервал:", "pt": "Alcance:", "nl": "bereik:", "fr": "Gamme:", "it": "Gamma:", "es": "Distancia:", "pl": "Zasięg:"}, + "5 seconds": { "en": "5 seconds", "de": "5 Sekunden", "ru": "5 секунд", "pt": "5 segundos", "nl": "5 seconden", "fr": "5 secondes", "it": "5 secondi", "es": "5 segundos", "pl": "5 sekund"}, + "10 seconds": { "en": "10 seconds", "de": "10 Sekunden", "ru": "10 секунд", "pt": "10 segundos", "nl": "10 seconden", "fr": "10 secondes", "it": "10 secondi", "es": "10 segundos", "pl": "10 sekund"}, + "15 seconds": { "en": "15 seconds", "de": "15 Sekunden", "ru": "15 секунд", "pt": "15 segundos", "nl": "15 seconden", "fr": "15 secondes", "it": "15 secondi", "es": "15 segundos", "pl": "15 sekund"}, + "20 seconds": { "en": "20 seconds", "de": "20 Sekunden", "ru": "20 секунд", "pt": "20 segundos", "nl": "20 seconden", "fr": "20 secondes", "it": "20 secondi", "es": "20 segundos", "pl": "20 sekund"}, + "30 seconds": { "en": "30 seconds", "de": "30 Sekunden", "ru": "30 секунд", "pt": "30 segundos", "nl": "30 seconden", "fr": "30 secondes", "it": "30 secondi", "es": "30 segundos", "pl": "30 sekund"}, + "1 minute": { "en": "1 minute", "de": "1 Minute", "ru": "1 минуту", "pt": "1 minuto", "nl": "1 minuut", "fr": "1 minute", "it": "1 minuto", "es": "1 minuto", "pl": "1 minuta"}, + "2 minutes": { "en": "2 minutes", "de": "2 Minuten", "ru": "2 минуты", "pt": "2 minutos", "nl": "2 minuten", "fr": "2 minutes", "it": "2 minuti", "es": "2 minutos", "pl": "2 minuty"}, + "5 minutes": { "en": "5 minutes", "de": "5 Minuten", "ru": "5 минут", "pt": "5 minutos", "nl": "5 minuten", "fr": "5 minutes", "it": "5 minuti", "es": "5 minutos", "pl": "5 minut"}, + "10 minutes": { "en": "10 minutes", "de": "10 Minuten", "ru": "10 минут", "pt": "10 minutos", "nl": "10 minuten", "fr": "10 minutes", "it": "10 minuti", "es": "10 minutos", "pl": "10 minut"}, + "15 minutes": { "en": "15 minutes", "de": "15 Minuten", "ru": "15 минут", "pt": "15 minutos", "nl": "15 minuten", "fr": "15 minutes", "it": "15 minuti", "es": "15 minutos", "pl": "15 minut"}, + "20 minutes": { "en": "20 minutes", "de": "20 Minuten", "ru": "20 минут", "pt": "20 minutos", "nl": "20 minuten", "fr": "20 minutes", "it": "20 minuti", "es": "20 minutos", "pl": "20 minut"}, + "30 minutes": { "en": "30 minutes", "de": "30 Minuten", "ru": "30 минут", "pt": "30 minutos", "nl": "30 minuten", "fr": "30 minutes", "it": "30 minuti", "es": "30 minutos", "pl": "30 minut"}, + "1 hour": { "en": "1 hour", "de": "1 Stunde", "ru": "1 час", "pt": "1 hora", "nl": "1 uur", "fr": "1 heure", "it": "1 ora", "es": "1 hora", "pl": "1 godzina"}, + "2 hours": { "en": "2 hours", "de": "2 Stunden", "ru": "2 часа", "pt": "2 horas", "nl": "twee uur", "fr": "2 heures", "it": "2 ore", "es": "2 horas", "pl": "2 godziny"}, + "3 hours": { "en": "3 hours", "de": "3 Stunden", "ru": "3 часа", "pt": "3 horas", "nl": "3 uur", "fr": "3 heures", "it": "3 ore", "es": "3 horas", "pl": "3 godziny"}, + "6 hours": { "en": "6 hours", "de": "6 Stunden", "ru": "6 часов", "pt": "6 horas", "nl": "6 uur", "fr": "6 heures", "it": "6 ore", "es": "6 horas", "pl": "6 godzin"}, + "12 hours": { "en": "12 hours", "de": "12 Stunden", "ru": "12 часов", "pt": "12 horas", "nl": "12 uren", "fr": "12 heures", "it": "12 ore", "es": "12 horas", "pl": "12 godzin"}, + "1 day": { "en": "1 day", "de": "1 Tag", "ru": "1 день", "pt": "1 dia", "nl": "1 dag", "fr": "Un jour", "it": "1 giorno", "es": "1 día", "pl": "1 dzień"}, + "2 days": { "en": "2 days", "de": "2 Tage", "ru": "2 дня", "pt": "2 dias", "nl": "2 dagen", "fr": "2 jours", "it": "2 giorni", "es": "2 días", "pl": "2 dni"}, + "3 days": { "en": "3 days", "de": "3 Tage", "ru": "3 дня", "pt": "3 dias", "nl": "3 dagen", "fr": "3 jours", "it": "3 giorni", "es": "3 días", "pl": "3 dni"}, + "7 days": { "en": "7 days", "de": "7 Tage", "ru": "7 дней", "pt": "7 dias", "nl": "7 dagen", "fr": "7 jours", "it": "7 giorni", "es": "7 días", "pl": "7 dni"}, + "14 days": { "en": "14 days", "de": "14 Tage", "ru": "14 дней", "pt": "14 dias", "nl": "14 dagen", "fr": "14 jours", "it": "14 giorni", "es": "14 dias", "pl": "14 dni"}, + "1 month": { "en": "1 month", "de": "1 Monat", "ru": "1 месяц", "pt": "1 mês", "nl": "1 maand", "fr": "1 mois", "it": "1 mese", "es": "1 mes", "pl": "1 miesiąc"}, + "2 months": { "en": "2 months", "de": "2 Monate", "ru": "2 месяца", "pt": "2 meses", "nl": "2 maanden", "fr": "2 mois", "it": "Due mesi", "es": "2 meses", "pl": "2 miesiące"}, + "3 months": { "en": "3 months", "de": "3 Monate", "ru": "3 месяца", "pt": "3 meses", "nl": "3 maanden", "fr": "3 mois", "it": "3 mesi", "es": "3 meses", "pl": "3 miesiące"}, + "6 months": { "en": "6 months", "de": "6 Monate", "ru": "6 месяцев", "pt": "6 meses", "nl": "6 maanden", "fr": "6 mois", "it": "6 mesi", "es": "6 meses", "pl": "6 miesięcy"}, + "1 year": { "en": "1 year", "de": "1 Jahr", "ru": "1 год", "pt": "1 ano", "nl": "1 jaar", "fr": "1 an", "it": "1 anno", "es": "1 año", "pl": "1 rok"}, + "2 years": { "en": "2 years", "de": "2 Jahren", "ru": "2 года", "pt": "2 anos", "nl": "2 jaar", "fr": "2 ans", "it": "2 anni", "es": "2 años", "pl": "2 lata"}, + "Width:": { "en": "Width:", "de": "Breite:", "ru": "Ширина:", "pt": "Largura:", "nl": "Breedte:", "fr": "Largeur:", "it": "Larghezza:", "es": "Anchura:", "pl": "Szerokość:"}, + "Height:": { "en": "Height:", "de": "Höhe:", "ru": "Высота:", "pt": "Altura:", "nl": "Hoogte:", "fr": "La taille:", "it": "Altezza:", "es": "Altura:", "pl": "Wysokość:"}, + "line": { "en": "Line", "de": "Linie", "ru": "Линия", "pt": "Linha", "nl": "Lijn", "fr": "Ligne", "it": "Linea", "es": "Línea", "pl": "Linia"}, + "area": { "en": "Area", "de": "Area", "ru": "Область", "pt": "Área", "nl": "Gebied", "fr": "Région", "it": "La zona", "es": "Zona", "pl": "Powierzchnia"}, + "bar": { "en": "Bar", "de": "Bar", "ru": "Bar", "pt": "Barra", "nl": "Bar", "fr": "Bar", "it": "Bar", "es": "Bar", "pl": "Bar"}, + "lineplot": { "en": "Line plot", "de": "Liniendiagramm", "ru": "Линия с точками", "pt": "Trama de linha", "nl": "Lijnplot", "fr": "Graphique linéaire", "it": "Trama di linea", "es": "Linear plot", "pl": "Fabuła linii"}, + "scatterplot": { "en": "Scatter plot", "de": "Streudiagramm", "ru": "Точки", "pt": "Parcela de dispersão", "nl": "Scatterplot", "fr": "Scatter plot", "it": "Trama sparsa", "es": "Gráfico de dispersión", "pl": "Wykres punktowy"}, + "steps": { "en": "Steps", "de": "Schritte", "ru": "Шаги", "pt": "Passos", "nl": "Stappen", "fr": "Pas", "it": "passi", "es": "Pasos", "pl": "Kroki"}, + "spline": { "en": "Spline", "de": "Spline", "ru": "Сллайн", "pt": "Spline", "nl": "spline", "fr": "Spline", "it": "linguetta", "es": "Ranura", "pl": "Klin"}, + "Stack": { "en": "Stack", "de": "Stack", "ru": "Stack", "pt": "Pilha", "nl": "stack", "fr": "Empiler", "it": "Pila", "es": "Apilar", "pl": "Stos"}, + "Window background:": { "en": "Window background:", "de": "Fenster-Hintergrund:", "ru": "Фон окна:", "pt": "Fundo da janela:", "nl": "Venster achtergrond:", "fr": "Fond de fenêtre:", "it": "Sfondo della finestra:", "es": "Fondo de la ventana:", "pl": "Tło okna:"}, + "Custom chart background:": { "en": "Custom chart background:", "de": "Anwender-Chart-Hintergrund:", "ru": "Пользовательский фон графика:", "pt": "Fundo de gráfico personalizado:", "nl": "Aangepaste grafiek achtergrond:", "fr": "Arrière-plan de graphique personnalisé:", "it": "Sfondo grafico personalizzato:", "es": "Fondo de carta personalizada:", "pl": "Niestandardowe tło wykresu:"}, + "Chart background:": { "en": "Chart background:", "de": "Chart-Hintergrund:", "ru": "Фон графика:", "pt": "Contexto do gráfico:", "nl": "Grafiek achtergrond:", "fr": "Arrière-plan du graphique", "it": "Sfondo del grafico:", "es": "Fondo de la carta:", "pl": "Tło wykresu:"}, + "X axis labels color:": { "en": "X labels color:", "de": "X Beschriftungsfarbe:", "ru": "Цвет текста по оси X:", "pt": "Cor de etiquetas X:", "nl": "X labels kleur:", "fr": "X étiquettes couleur:", "it": "Colore etichette X:", "es": "X etiquetas de color:", "pl": "Kolor etykiet X:"}, + "Y axis labels color:": { "en": "Y labels color:", "de": "Y Beschriftungsfarbe:", "ru": "Цвет текста по оси Y:", "pt": "Etiquetas de etiquetas Y:", "nl": "Y-labels kleur:", "fr": "Couleur des étiquettes Y:", "it": "Il colore delle etichette Y:", "es": "Color de etiquetas Y:", "pl": "Kolor etykiet Y:"}, + "Show legend:": { "en": "Show legend:", "de": "Zeige Legende:", "ru": "Показать легенду:", "pt": "Mostrar lenda:", "nl": "Legenda weergeven:", "fr": "Afficher la légende:", "it": "Mostra legenda:", "es": "Mostrar leyenda:", "pl": "Pokaż legendę:"}, + "Title:": { "en": "Title:", "de": "Beschriftung:", "ru": "Название:", "pt": "Título:", "nl": "Titel:", "fr": "Titre:", "it": "Titolo:", "es": "Título:", "pl": "Tytuł:"}, + "Title position:": { "en": "Title position:", "de": "Beschriftungs-Position:", "ru": "Позиция названия:", "pt": "Posição do título:", "nl": "Titel positie:", "fr": "Titre du poste:", "it": "Posizione del titolo:", "es": "Posición del título:", "pl": "Pozycja tytułu:"}, + "Top, left, inside": { "en": "Top, left, inside", "de": "Oben, links, innen", "ru": "Сверху, слева, внутри", "pt": "Topo, esquerda, dentro", "nl": "Boven, links, binnen", "fr": "Haut, gauche, intérieur", "it": "In alto, a sinistra, dentro", "es": "Arriba, izquierda, adentro", "pl": "Góra, lewa, wewnątrz"}, + "Top, right, inside": { "en": "Top, right, inside", "de": "Oben, rechts, innen", "ru": "Сверху, справа, внутри", "pt": "Topo, direito, dentro", "nl": "Boven, rechts, binnen", "fr": "En haut, à droite, à l'intérieur", "it": "In alto, a destra, dentro", "es": "Arriba, derecha, adentro", "pl": "Góra, prawo, wewnątrz"}, + "Top, center, inside": { "en": "Top, center, inside", "de": "Oben, mittig, innen", "ru": "Сверху, по центру, внутри", "pt": "Topo, centro, dentro", "nl": "Boven, midden, binnenkant", "fr": "Haut, centre, intérieur", "it": "In alto, al centro, dentro", "es": "Arriba, centro, adentro", "pl": "Góra, środek, wnętrze"}, + "Middle, left, inside": { "en": "Middle, left, inside", "de": "Middle, links, innen", "ru": "Посередине, слева, внутри", "pt": "Médio, esquerda, dentro", "nl": "Midden, links, binnenkant", "fr": "Milieu, gauche, intérieur", "it": "Medio, a sinistra, dentro", "es": "Medio, izquierdo, adentro", "pl": "Środkowy, lewy, w środku"}, + "Middle, right, inside": { "en": "Middle, right, inside", "de": "Middle, rechts, innen", "ru": "Посередине, справа, внутри", "pt": "Médio, direito, dentro", "nl": "Midden, rechts, binnenkant", "fr": "Moyen, droit, intérieur", "it": "Medio, giusto, dentro", "es": "Medio, derecho, adentro", "pl": "Środkowy, prawy, wewnątrz"}, + "Bottom, left, inside": { "en": "Bottom, left, inside", "de": "Unten, links, innen", "ru": "Снизу, слева, внутри", "pt": "Parte inferior, esquerda, dentro", "nl": "Onder, links, binnen", "fr": "Bas, gauche, intérieur", "it": "In basso, a sinistra, dentro", "es": "Abajo, izquierda, adentro", "pl": "Dół, lewo, wnętrze"}, + "Bottom, right, inside": { "en": "Bottom, right, inside", "de": "Unten, rechts, innen", "ru": "Снизу, справа, внутри", "pt": "Parte inferior, direita, dentro", "nl": "Onder, rechts, binnen", "fr": "En bas, à droite, à l'intérieur", "it": "In basso, a destra, dentro", "es": "Abajo, derecha, adentro", "pl": "Dół, prawo, wewnątrz"}, + "Bottom, center, inside": { "en": "Bottom, center, inside", "de": "Unten, mittig, innen", "ru": "Снизу, по центру, внутри", "pt": "No fundo, no centro, no interior", "nl": "Onder, midden, binnen", "fr": "Bas, centre, intérieur", "it": "In basso, al centro, dentro", "es": "Abajo, centro, adentro", "pl": "Dół, środek, wnętrze"}, + "Top, right, outside": { "en": "Top, right, outside", "de": "Oben, rechts, außen", "ru": "Сверху, справа, снаружи", "pt": "Topo, direito, fora", "nl": "Boven, rechts, buiten", "fr": "Haut, droit, dehors", "it": "In alto, a destra, fuori", "es": "Arriba, a la derecha, afuera", "pl": "Góra, prawo, na zewnątrz"}, + "Middle, right, outside": { "en": "Middle, right, outside", "de": "Middle, rechts, außen", "ru": "Посередине, справа, снаружи", "pt": "Médio, direito, fora", "nl": "Midden, rechts, buiten", "fr": "Moyen, droit, dehors", "it": "Medio, giusto, esterno", "es": "Medio, derecho, afuera", "pl": "Środkowy, prawy, na zewnątrz"}, + "Bottom, right, outside": { "en": "Bottom, right, outside", "de": "Unten, rechts, außen", "ru": "Снизу, справа, снаружи", "pt": "Parte inferior, direita, fora", "nl": "Onder, rechts, buiten", "fr": "En bas, à droite, à l'extérieur", "it": "In basso, a destra, fuori", "es": "Abajo, a la derecha, afuera", "pl": "Dół, prawo, na zewnątrz"}, + "Bottom, center, outside": { "en": "Bottom, center, outside", "de": "Unten, mittig, außen", "ru": "Снизу, по центру, снаружи", "pt": "Fundo, centro, fora", "nl": "Onder, midden, buiten", "fr": "Bas, centre, extérieur", "it": "In basso, al centro, fuori", "es": "Abajo, centro, afuera", "pl": "Dół, środek, na zewnątrz"}, + "Min:": { "en": "Minimum:", "de": "Minimum:", "ru": "Минимум:", "pt": "Mínimo:", "nl": "Minimum:", "fr": "Le minimum:", "it": "Minimo:", "es": "Mínimo:", "pl": "Minimum:"}, + "Max:": { "en": "Maximum:", "de": "Maximum:", "ru": "Максимум:", "pt": "Máximo:", "nl": "maximaal:", "fr": "Maximum:", "it": "Massimo:", "es": "Máximo:", "pl": "Maksymalny:"}, + "User defined names:": { "en": "User defined names:", "de": "Benutzerdefinierte Namen:", "ru": "Задать имена графиков:", "pt": "Nomes definidos pelo usuário:", "nl": "Door de gebruiker gedefinieerde namen:", "fr": "Noms définis par l'utilisateur:", "it": "Nomi definiti dall'utente:", "es": "Nombres definidos por el usuario:", "pl": "Nazwy zdefiniowane przez użytkownika:"}, + "Predefined background:": { "en": "Predefined background:", "de": "Vordefinierter Hintergrund:", "ru": "Выбрать фон:", "pt": "Antecedentes predefinidos:", "nl": "Voorgedefinieerde achtergrond:", "fr": "Arrière-plan prédéfini:", "it": "Sfondo predefinito:", "es": "Antecedentes predefinidos:", "pl": "Wstępnie zdefiniowane tło:"}, + "User defined": { "en": "User defined", "de": "Anwenderdefiniert", "ru": "Пользовательские", "pt": "Usuário definido", "nl": "Gebruiker gedefinieerde", "fr": "Défini par l'utilisateur", "it": "Definito dall'utente", "es": "Usuario definido", "pl": "Określony przez użytkownika"}, + "Background:": { "en": "Background:", "de": "Hintergrund:", "ru": "Фон:", "pt": "Fundo:", "nl": "Achtergrond:", "fr": "Contexte:", "it": "Sfondo:", "es": "Fondo:", "pl": "Tło:"}, + "Hover details:": { "en": "Hover details:", "de": "Hover details:", "ru": "Показывать подсказку:", "pt": "Detalhes do mouse:", "nl": "Hover details:", "fr": "Hover détails:", "it": "Dettagli al passaggio del mouse:", "es": "Hover detalles:", "pl": "Po najechaniu szczegóły:"}, + "Time format:": { "en": "Time format:", "de": "Zeitformat:", "ru": "Формат времени:", "pt": "Formato do tempo:", "nl": "Tijd formaat:", "fr": "Format de l'heure:", "it": "Formato orario:", "es": "Formato de tiempo:", "pl": "Format czasu:"}, + "Default": { "en": "Default", "de": "Standard", "ru": "по умолчанию", "pt": "Padrão", "nl": "Standaard", "fr": "Défaut", "it": "Predefinito", "es": "Defecto", "pl": "Domyślna"}, + "Smoothing": { "en": "Smoothing", "de": "Glätten", "ru": "Сглаживание", "pt": "Suavização", "nl": "smoothing", "fr": "Lissage", "it": "lisciatura", "es": "Suavizado", "pl": "Wygładzanie"}, + "After comma": { "en": "After comma", "de": "Nach Komma", "ru": "После запятой", "pt": "Após a vírgula", "nl": "Na een komma", "fr": "Après la virgule", "it": "Dopo la virgola", "es": "Después de la coma", "pl": "Po przecinku"}, + "Open": { "en": "Open", "de": "Zeige im Fenster", "ru": "Показать", "pt": "Aberto", "nl": "Open", "fr": "Ouvrir", "it": "Aperto", "es": "Abierto", "pl": "otwarty"}, + "Update": { "en": "Update", "de": "Aktualisieren", "ru": "Обновить", "pt": "Atualizar", "nl": "Bijwerken", "fr": "Mettre à jour", "it": "Aggiornare", "es": "Actualizar", "pl": "Aktualizacja"}, + "Reset settings": { "en": "Reset settings", "de": "Einstellungen löschen", "ru": "Сбросить настройки", "pt": "Redefinir configurações", "nl": "Reset instellingen", "fr": "Réinitialiser les options", "it": "Ripristina le impostazioni", "es": "Reiniciar ajustes", "pl": "Resetowanie ustawień"}, + "From": { "en": "From: ", "de": "Von", "ru": "От", "pt": "A partir de:", "nl": "Van:", "fr": "De:", "it": "A partire dal:", "es": "De:", "pl": "Od:"}, + "Last changed": { "en": "Last changed", "de": "Letze Änderung", "ru": "Изменён", "pt": "Última modificação", "nl": "Laatst gewijzigd", "fr": "Dernière modification", "it": "Ultima modifica", "es": "Último cambio", "pl": "Ostatnia zmiana"}, + "Time stamp": { "en": "Time stamp", "de": "Zeitstempel", "ru": "Время", "pt": "Marca de horário", "nl": "Tijdstempel", "fr": "Horodatage", "it": "Data e ora", "es": "Marca de tiempo", "pl": "Znak czasu"}, + "Acknowledged": { "en": "Acknowledged", "de": "Bestätigt", "ru": "Подтверждён", "pt": "Reconhecido", "nl": "Erkend", "fr": "Reconnu", "it": "Riconosciuto", "es": "Admitido", "pl": "Przyznane"}, + "Edit": { "en": "Edit", "de": "Editieren", "ru": "Edit", "pt": "Editar", "nl": "Bewerk", "fr": "modifier", "it": "modificare", "es": "Editar", "pl": "Edytować"}, + "Members": { "en": "Members", "de": "Mitglied", "ru": "Объекты", "pt": "Membros", "nl": "leden", "fr": "Membres", "it": "Utenti", "es": "Miembros", "pl": "Członkowie"}, + "Loading...": { "en": "Loading...", "de": "Lade...", "ru": "Загрузка...", "pt": "Carregando...", "nl": "Bezig met laden...", "fr": "Chargement...", "it": "Caricamento in corso...", "es": "Cargando...", "pl": "Ładuję..."}, + "Processing...": { "en": "Processing...", "de": "Bearbeite...", "ru": "Обработка...", "pt": "Em processamento...", "nl": "Verwerken...", "fr": "En traitement...", "it": "In lavorazione...", "es": "Tratamiento...", "pl": "Przetwarzanie..."}, + "With lines": { "en": "With lines", "de": "mit Linien", "ru": "С линиями", "pt": "Com linhas", "nl": "Met lijnen", "fr": "Avec des lignes", "it": "Con le linee", "es": "Con líneas", "pl": "Z liniami"}, + "Without lines": { "en": "Without lines", "de": "ohne Linien", "ru": "Без линий", "pt": "Sem linhas", "nl": "Zonder lijnen", "fr": "Sans lignes", "it": "Senza linee", "es": "Sin líneas", "pl": "Bez linii"}, + "Inside / With lines": { "en": "Inside / With lines", "de": "Innen / mit Linien", "ru": "Внутри / С линиями", "pt": "Dentro / Com linhas", "nl": "Binnen / met lijnen", "fr": "À l'intérieur / Avec des lignes", "it": "Interno / Con linee", "es": "Dentro / Con líneas", "pl": "Wewnątrz / Z liniami"}, + "Outside/ With lines": { "en": "Outside/ With lines", "de": "Außen/ mit Linien", "ru": "Снаружи/ С линиями", "pt": "Fora / Com linhas", "nl": "Buiten / met lijnen", "fr": "Extérieur / Avec lignes", "it": "Esterno / Con linee", "es": "Fuera / Con líneas", "pl": "Na zewnątrz / Z liniami"}, + "Inside / No lines": { "en": "Inside / No lines", "de": "Innen / ohne Linien", "ru": "Внутри / Без линий", "pt": "Dentro / Sem linhas", "nl": "Binnenkant / Geen regels", "fr": "À l'intérieur / Pas de lignes", "it": "Dentro / Nessuna linea", "es": "Dentro / Sin líneas", "pl": "Wewnątrz / Bez linii"}, + "Outside / No lines": { "en": "Outside / No lines", "de": "Außen / ohne Linien", "ru": "Снаружи / Без линий", "pt": "Fora / Sem linhas", "nl": "Buiten / Geen lijnen", "fr": "Extérieur / Pas de lignes", "it": "Fuori / Nessuna linea", "es": "Fuera / Sin líneas", "pl": "Poza / Bez linii"}, + "Interpolate:": { "en": "Interpolate:", "de": "Interpolieren:", "ru": "Интерполяция:", "pt": "Interpolar:", "nl": "Interpoleren:", "fr": "Interpoler:", "it": "Interpolare:", "es": "Interpolar:", "pl": "Interpolować:"}, + "Steps": { "en": "Steps", "de": "Schritte", "ru": "Ступени", "pt": "Passos", "nl": "Stappen", "fr": "Pas", "it": "passi", "es": "Pasos", "pl": "Kroki"}, + "Pie": { "en": "Pie", "de": "Kuchen", "ru": "Круговая диаграмма", "pt": "Torta", "nl": "Taart", "fr": "Tarte", "it": "Torta", "es": "Tarta", "pl": "Ciasto"}, + "Top, left": { "en": "Top, left", "de": "Oben, links", "ru": "Сверху, слева", "pt": "Superior esquerdo", "nl": "Linksboven", "fr": "En haut à gauche", "it": "A sinistra in alto", "es": "Arriba a la izquierda", "pl": "Lewy górny"}, + "Top, right": { "en": "Top, right", "de": "Oben, rechts", "ru": "Сверху, справа", "pt": "Canto superior direito", "nl": "Rechtsboven", "fr": "En haut à droite", "it": "In alto a destra", "es": "Parte superior derecha", "pl": "W prawym górnym rogu"}, + "Bottom, left": { "en": "Bottom, left", "de": "Unten, links", "ru": "Снизу, слева", "pt": "Inferior esquerdo", "nl": "Linksonder", "fr": "En bas à gauche", "it": "In basso a sinistra", "es": "Abajo, izquierda", "pl": "Na dole po lewej"}, + "Bottom, right": { "en": "Bottom, right", "de": "Unten, rechts", "ru": "Снизу, справа", "pt": "Canto inferior direito", "nl": "Rechts onder", "fr": "En bas à droite", "it": "In basso a destra", "es": "Abajo a la derecha", "pl": "Prawy dolny"}, + "Title color:": { "en": "Title color:", "de": "Titelfarbe:", "ru": "Цвет названия:", "pt": "Cor do título:", "nl": "Titel kleur:", "fr": "Couleur du titre:", "it": "Colore del titolo:", "es": "Color del título:", "pl": "Kolor tytułu:"}, + "Title size:": { "en": "Title size:", "de": "Titelgröße:", "ru": "Размер названия:", "pt": "Tamanho do título:", "nl": "Titel grootte:", "fr": "Taille du titre:", "it": "Dimensione del titolo:", "es": "Tamaño del título:", "pl": "Rozmiar tytułu:"}, + "Fill range:": { "en": "Fill range:", "de": "Ganzer Bereich:", "ru": "Всегда весь интервал:", "pt": "Faixa de preenchimento:", "nl": "Vulbereik:", "fr": "Remplir gamme:", "it": "Gamma di riempimento:", "es": "Rango de llenado:", "pl": "Zakres wypełnienia:"}, + "Units:": { "en": "Units:", "de": "Einheiten:", "ru": "Единицы:", "pt": "Unidades:", "nl": "units:", "fr": "Unités:", "it": "unità:", "es": "Unidades:", "pl": "Jednostki:"}, + "yes": { "en": "yes", "de": "ja", "ru": "да", "pt": "sim", "nl": "Ja", "fr": "Oui", "it": "sì", "es": "sí", "pl": "tak"}, + "bottom": { "en": "bottom", "de": "unten", "ru": "снизу", "pt": "inferior", "nl": "bodem", "fr": "bas", "it": "parte inferiore", "es": "fondo", "pl": "Dolny"}, + "top": { "en": "top", "de": "oben", "ru": "сверху", "pt": "topo", "nl": "top", "fr": "Haut", "it": "superiore", "es": "parte superior", "pl": "Top"}, + "left": { "en": "left", "de": "links", "ru": "слева", "pt": "esquerda", "nl": "links", "fr": "la gauche", "it": "sinistra", "es": "izquierda", "pl": "lewo"}, + "right": { "en": "right", "de": "rechts", "ru": "справа", "pt": "certo", "nl": "rechts", "fr": "droite", "it": "destra", "es": "derecho", "pl": "dobrze"}, + "No border:": { "en": "No border:", "de": "Kein Rahmen:", "ru": "Без рамки:", "pt": "Sem borda:", "nl": "Geen grens:", "fr": "Pas de frontière:", "it": "Nessun confine:", "es": "Sin bordes:", "pl": "Bez granic:"}, + "Time": { "en": "Time", "de": "Zeit", "ru": "Время", "pt": "Tempo", "nl": "Tijd", "fr": "Temps", "it": "Tempo", "es": "Hora", "pl": "Czas"}, + "day": { "en": "day", "de": "Tag", "ru": "День", "pt": "dia", "nl": "dag", "fr": "journée", "it": "giorno", "es": "día", "pl": "dzień"}, + "month": { "en": "month", "de": "Monat", "ru": "month", "pt": "mês", "nl": "maand", "fr": "mois", "it": "mese", "es": "mes", "pl": "miesiąc"}, + "year": { "en": "year", "de": "Jahr", "ru": "year", "pt": "ano", "nl": "jaar", "fr": "an", "it": "anno", "es": "año", "pl": "rok"}, + "Individual": { "en": "Individual", "de": "Individuell", "ru": "Индивидуально", "pt": "Individual", "nl": "individu", "fr": "Individuel", "it": "Individuale", "es": "Individual", "pl": "Indywidualny"}, + "Aggregation:": { "en": "Type:", "de": "Art:", "ru": "Тип:", "pt": "Tipo:", "nl": "Type:", "fr": "Type:", "it": "Genere:", "es": "Tipo:", "pl": "Rodzaj:"}, + "relative": { "en": "relative", "de": "relative", "ru": "относительно", "pt": "relativo", "nl": "familielid", "fr": "relatif", "it": "parente", "es": "relativo", "pl": "krewny"}, + "static": { "en": "static", "de": "statik", "ru": "постоянный", "pt": "estático", "nl": "statisch", "fr": "statique", "it": "statico", "es": "estático", "pl": "statyczny"}, + "now": { "en": "now", "de": "jetzt", "ru": "сейчас", "pt": "agora", "nl": "nu", "fr": "à présent", "it": "adesso", "es": "ahora", "pl": "teraz"}, + "today": { "en": "today", "de": "heute", "ru": "сегодня", "pt": "hoje", "nl": "vandaag", "fr": "aujourd'hui", "it": "oggi", "es": "hoy", "pl": "dzisiaj"}, + "this month": { "en": "this month", "de": "dieser Monat", "ru": "этот месяц", "pt": "este mês", "nl": "deze maand", "fr": "ce mois-ci", "it": "questo mese", "es": "este mes", "pl": "ten miesiąc"}, + "this year": { "en": "this year", "de": "dieses Jahr", "ru": "этот год", "pt": "este ano", "nl": "dit jaar", "fr": "cette année", "it": "quest'anno", "es": "este año", "pl": "W tym roku"}, + "Start:": { "en": "Start:", "de": "Start:", "ru": "Начало:", "pt": "Começar:", "nl": "Begin:", "fr": "Début:", "it": "Inizio:", "es": "Comienzo:", "pl": "Początek:"}, + "End:": { "en": "End:", "de": "Ende:", "ru": "Конец:", "pt": "Fim:", "nl": "Einde:", "fr": "Fin:", "it": "Fine:", "es": "Fin:", "pl": "Koniec:"}, + "Aggregate": { "en": "Aggregate", "de": "Aggregation", "ru": "Объединение данных", "pt": "Agregar", "nl": "Aggregaat", "fr": "Agrégat", "it": "Aggregato", "es": "Agregar", "pl": "Agregat"}, + "Step type:": { "en": "Step type:", "de": "Schritttyp:", "ru": "Шаги:", "pt": "Tipo de etapa:", "nl": "Stap type:", "fr": "Type d'étape:", "it": "Tipo di passaggio:", "es": "Tipo de paso:", "pl": "Rodzaj kroku:"}, + "seconds": { "en": "seconds", "de": "Sekunden", "ru": "секунды", "pt": "segundos", "nl": "seconden", "fr": "secondes", "it": "secondi", "es": "segundos", "pl": "sekundy"}, + "Seconds": { "en": "Seconds", "de": "Sekunden", "ru": "Cекунды", "pt": "Segundos", "nl": "seconden", "fr": "Secondes", "it": "secondi", "es": "Segundos", "pl": "sekundy"}, + "Step span:": { "en": "Step span:", "de": "Schrittweite:", "ru": "Интервал шага:", "pt": "Passo:", "nl": "Stap overspanning:", "fr": "Étape span:", "it": "Intervallo:", "es": "Lapso de paso:", "pl": "Zakres kroku:"}, + "Link": { "en": "Link", "de": "Link", "ru": "URL", "pt": "Ligação", "nl": "Link", "fr": "Lien", "it": "collegamento", "es": "Enlazar", "pl": "Połączyć"}, + "Counts": { "en": "Counts", "de": "Anzahl", "ru": "Кол-во значений", "pt": "Contagens", "nl": "tellingen", "fr": "Compte", "it": "Conti", "es": "Cuenta", "pl": "Liczy"}, + "ignore 'null'": { "en": "ignore 'null'", "de": "'null' ignorieren", "ru": "Игнорировать 'null'", "pt": "ignore 'null'", "nl": "negeer 'null'", "fr": "ignore 'null'", "it": "ignora 'null'", "es": "ignorar 'nulo'", "pl": "zignoruj ​​\"zero\""}, + "Time Span": { "en": "Time Span", "de": "Zeit Spanne", "ru": "Временной интервал", "pt": "Intervalo de tempo", "nl": "Tijdspanne", "fr": "Durée", "it": "Arco di tempo", "es": "Espacio de tiempo", "pl": "Okres czasu"}, + "Appearance": { "en": "Appearance", "de": "Erscheinung", "ru": "Оформление", "pt": "Aparência", "nl": "Uiterlijk", "fr": "Apparence", "it": "Aspetto", "es": "Apariencia", "pl": "Wygląd"}, + "Title": { "en": "Title", "de": "Beschriftung", "ru": "Подпись", "pt": "Título", "nl": "Titel", "fr": "Titre", "it": "Titolo", "es": "Título", "pl": "Tytuł"}, + "Offset": { "en": "X-Offset", "de": "X-Offset", "ru": "Сдвиг по Х", "pt": "X-Offset", "nl": "-X Offset", "fr": "X-Offset", "it": "X-Offset", "es": "X-Offset", "pl": "X-Offset"}, + "Aggregation": { "en": "Type", "de": "Art", "ru": "Тип", "pt": "Tipo", "nl": "Type", "fr": "Type", "it": "genere", "es": "Tipo", "pl": "Rodzaj"}, + "Chart Type": { "en": "Chart Type", "de": "Chart Type", "ru": "Тип графика", "pt": "Tipo de gráfico", "nl": "Diagramtype", "fr": "Type de graphique", "it": "Tipo di grafico", "es": "Tipo de gráfico", "pl": "Typ wykresu"}, + "Color": { "en": "Color", "de": "Farbe", "ru": "Цвет", "pt": "Cor", "nl": "Kleur", "fr": "Couleur", "it": "Colore", "es": "Color", "pl": "Kolor"}, + "Min": { "en": "Min", "de": "Min", "ru": "Мин", "pt": "Min", "nl": "min", "fr": "Min", "it": "min", "es": "Min.", "pl": "Min"}, + "Max": { "en": "Max", "de": "Max", "ru": "Макс", "pt": "Max", "nl": "Max", "fr": "Max", "it": "Max", "es": "Max", "pl": "Max"}, + "Unit": { "en": "Unit", "de": "Einheiten", "ru": "Единицы", "pt": "Unidade", "nl": "Eenheid", "fr": "Unité", "it": "Unità", "es": "Unidad", "pl": "Jednostka"}, + "Y Axis": { "en": "Y Axis", "de": "Y Axe", "ru": "Ось Y", "pt": "Eixo Y", "nl": "Y-as", "fr": "Axe Y", "it": "Asse Y.", "es": "Eje Y", "pl": "Oś Y."}, + "X Axis": { "en": "X Axis", "de": "X Axe", "ru": "Ось X", "pt": "X Axis", "nl": "X-as", "fr": "Axe X", "it": "Asse X.", "es": "Eje X", "pl": "Oś X."}, + "update Preview": { "en": "update Preview", "de": "Vorschau aktualisieren", "ru": "Обновить", "pt": "atualização Visualização", "nl": "voorproefje van de nieuwe versie", "fr": "aperçu de mise à jour", "it": "Aggiorna anteprima", "es": "actualización de Vista previa", "pl": "aktualizuj podgląd"}, + "Cancel": { "en": "Cancel", "de": "Abbrechen", "ru": "отменить", "pt": "Cancelar", "nl": "Annuleer", "fr": "Annuler", "it": "Annulla", "es": "Cancelar", "pl": "Anuluj"}, + "Name": { "en": "Name", "de": "Name", "ru": "Имя", "pt": "Nome", "nl": "Naam", "fr": "prénom", "it": "Nome", "es": "Nombre", "pl": "Nazwa"}, + "Live update every:": { "en": "Live update every:", "de": "Autoupdate alle:", "ru": "Обновлять каждые:", "pt": "Atualização ao vivo a cada:", "nl": "Live update elke:", "fr": "Mise à jour en direct tous les:", "it": "Aggiornamento live ogni:", "es": "Actualización en vivo cada:", "pl": "Aktualizacja na żywo co:"}, + "counts": { "en": "counts", "de": "Anzahl", "ru": "кол-во", "pt": "contagens", "nl": "tellingen", "fr": "compte", "it": "conta", "es": "conteos", "pl": "liczy"}, + "Add new line": { "en": "Add new line", "de": "Linie hinzufügen", "ru": "Добавить линию", "pt": "Adicionar nova linha", "nl": "Voeg een nieuwe regel toe", "fr": "Ajouter une nouvelle ligne", "it": "Aggiungi una nuova linea", "es": "Agregar nueva línea", "pl": "Dodaj nową linię"}, + "Animation:": { "en": "Animation:", "de": "Animation:", "ru": "Анимация:", "pt": "Animação:", "nl": "animatie:", "fr": "Animation:", "it": "Animazione:", "es": "Animación:", "pl": "Animacja:"}, + "no": { "en": "no", "de": "keine", "ru": "нет", "pt": "não", "nl": "Nee", "fr": "non", "it": "no", "es": "no", "pl": "Nie"}, + "0s": { "en": "0 seconds", "de": "0s", "ru": "0c", "pt": "0 segundos", "nl": "0 seconden", "fr": "0 seconde", "it": "0 secondi", "es": "0 segundos", "pl": "0 sekund"}, + "300ms": { "en": "300ms", "de": "300ms", "ru": "300мс", "pt": "300ms", "nl": "300ms", "fr": "300ms", "it": "300ms", "es": "300ms", "pl": "300ms"}, + "500ms": { "en": "500ms", "de": "500ms", "ru": "500мс", "pt": "500ms", "nl": "500ms", "fr": "500ms", "it": "500ms", "es": "500ms", "pl": "500 ms"}, + "1s": { "en": "1 second", "de": "1 Sekunde", "ru": "1 секунда", "pt": "1 segundo", "nl": "1 seconde", "fr": "1 seconde", "it": "1 secondo", "es": "1 segundo", "pl": "1 sekunda"}, + "2s": { "en": "2 seconds", "de": "2 Sekunden", "ru": "2 секунды", "pt": "2 segundos", "nl": "2 seconden", "fr": "2 secondes", "it": "2 secondi", "es": "2 segundos", "pl": "2 sekundy"}, + "3s": { "en": "3 seconds", "de": "3 Sekunden", "ru": "3 секунды", "pt": "3 segundos", "nl": "3 seconden", "fr": "3 secondes", "it": "3 secondi", "es": "3 segundos", "pl": "3 sekundy"}, + "5s": { "en": "5 seconds", "de": "5 Sekunden", "ru": "5 секунд", "pt": "5 segundos", "nl": "5 seconden", "fr": "5 secondes", "it": "5 secondi", "es": "5 segundos", "pl": "5 sekund"}, + "10s": { "en": "10 seconds", "de": "10 Sekunden", "ru": "10 секунд", "pt": "10 segundos", "nl": "10 seconden", "fr": "10 secondes", "it": "10 secondi", "es": "10 segundos", "pl": "10 sekund"}, + "30s": { "en": "30 seconds", "de": "30 Sekunden", "ru": "30 секунд", "pt": "30 segundos", "nl": "30 seconden", "fr": "30 secondes", "it": "30 secondi", "es": "30 segundos", "pl": "30 sekund"}, + "60s": { "en": "60 seconds", "de": "60 Sekunden", "ru": "60 секунд", "pt": "60 segundos", "nl": "60 seconden", "fr": "60 secondes", "it": "60 secondi", "es": "60 segundos", "pl": "60 sekund"}, + "2m": { "en": "2 minutes", "de": "2 Minuten", "ru": "2 минуты", "pt": "2 minutos", "nl": "2 minuten", "fr": "2 minutes", "it": "2 minuti", "es": "2 minutos", "pl": "2 minuty"}, + "3m": { "en": "3 minutes", "de": "3 Minuten", "ru": "3 минуты", "pt": "3 minutos", "nl": "3 minuten", "fr": "3 minutes", "it": "3 minuti", "es": "3 minutos", "pl": "3 minuty"}, + "4m": { "en": "4 minutes", "de": "4 Minuten", "ru": "4 минуты", "pt": "4 minutos", "nl": "4 minuten", "fr": "4 minutes", "it": "4 minuti", "es": "4 minutos", "pl": "4 minuty"}, + "5m": { "en": "5 minutes", "de": "5 Minuten", "ru": "5 минут", "pt": "5 minutos", "nl": "5 minuten", "fr": "5 minutes", "it": "5 minuti", "es": "5 minutos", "pl": "5 minut"}, + "10m": { "en": "10 minutes", "de": "10 Minuten", "ru": "10 минут", "pt": "10 minutos", "nl": "10 minuten", "fr": "10 minutes", "it": "10 minuti", "es": "10 minutos", "pl": "10 minut"}, + "15m": { "en": "15 minutes", "de": "15 Minuten", "ru": "15 минут", "pt": "15 minutos", "nl": "15 minuten", "fr": "15 minutes", "it": "15 minuti", "es": "15 minutos", "pl": "15 minut"}, + "30m": { "en": "30 minutes", "de": "30 Minuten", "ru": "30 минут", "pt": "30 minutos", "nl": "30 minuten", "fr": "30 minutes", "it": "30 minuti", "es": "30 minutos", "pl": "30 minut"}, + "45m": { "en": "45 minutes", "de": "45 Minuten", "ru": "45 минут", "pt": "45 minutos", "nl": "45 minuten", "fr": "45 minutes", "it": "45 minuti", "es": "45 minutos", "pl": "45 minut"}, + "1H": { "en": "1 hour", "de": "1 Stunde", "ru": "1 час", "pt": "1 hora", "nl": "1 uur", "fr": "1 heure", "it": "1 ora", "es": "1 hora", "pl": "1 godzina"}, + "2H": { "en": "2 hours", "de": "2 Stunden", "ru": "2 часа", "pt": "2 horas", "nl": "twee uur", "fr": "2 heures", "it": "2 ore", "es": "2 horas", "pl": "2 godziny"}, + "6H": { "en": "6 hours", "de": "6 Stunden", "ru": "6 часов", "pt": "6 horas", "nl": "6 uur", "fr": "6 heures", "it": "6 ore", "es": "6 horas", "pl": "6 godzin"}, + "12H": { "en": "12 hours", "de": "12 Stunden", "ru": "12 часов", "pt": "12 horas", "nl": "12 uren", "fr": "12 heures", "it": "12 ore", "es": "12 horas", "pl": "12 godzin"}, + "1D": { "en": "1 day", "de": "1 Tag", "ru": "1 день", "pt": "1 dia", "nl": "1 dag", "fr": "Un jour", "it": "1 giorno", "es": "1 día", "pl": "1 dzień"}, + "2D": { "en": "2 days", "de": "2 Tage", "ru": "2 дня", "pt": "2 dias", "nl": "2 dagen", "fr": "2 jours", "it": "2 giorni", "es": "2 días", "pl": "2 dni"}, + "3D": { "en": "3 days", "de": "3 Tage", "ru": "3 дня", "pt": "3 dias", "nl": "3 dagen", "fr": "3 jours", "it": "3 giorni", "es": "3 días", "pl": "3 dni"}, + "4D": { "en": "4 days", "de": "4 Tage", "ru": "4 дня", "pt": "4 dias", "nl": "4 dagen", "fr": "4 jours", "it": "4 giorni", "es": "4 dias", "pl": "4 dni"}, + "1W": { "en": "1 week", "de": "1 Woche", "ru": "1 неделя", "pt": "1 semana", "nl": "1 week", "fr": "1 semaine", "it": "1 settimana", "es": "1 semana", "pl": "1 tydzień"}, + "2W": { "en": "2 weeks", "de": "2 Wochen", "ru": "2 недели", "pt": "2 semanas", "nl": "2 weken", "fr": "2 semaines", "it": "2 settimane", "es": "2 semanas", "pl": "2 tygodnie"}, + "4W": { "en": "4 weeks", "de": "4 Wochen", "ru": "4 недели", "pt": "4 semanas", "nl": "4 weken", "fr": "4 semaines", "it": "4 settimane", "es": "4 semanas", "pl": "4 tygodnie"}, + "8W": { "en": "8 weeks", "de": "8 Wochen", "ru": "8 недель", "pt": "8 semanas", "nl": "8 weken", "fr": "8 semaines", "it": "8 settimane", "es": "8 semanas", "pl": "8 tygodni"}, + "12W": { "en": "12 weeks", "de": "12 Wochen", "ru": "12 недель", "pt": "12 semanas", "nl": "12 weken", "fr": "12 semaines", "it": "12 settimane", "es": "12 semanas", "pl": "12 tygodni"}, + "26W": { "en": "26 weeks", "de": "26 Wochen", "ru": "26 недель", "pt": "26 semanas", "nl": "26 weken", "fr": "26 semaines", "it": "26 settimane", "es": "26 semanas", "pl": "26 tygodni"}, + "1M": { "en": "1 month", "de": "1 Monat", "ru": "1 месяц", "pt": "1 mês", "nl": "1 maand", "fr": "1 mois", "it": "1 mese", "es": "1 mes", "pl": "1 miesiąc"}, + "2M": { "en": "2 months", "de": "2 Monate", "ru": "2 месяца", "pt": "2 meses", "nl": "2 maanden", "fr": "2 mois", "it": "Due mesi", "es": "2 meses", "pl": "2 miesiące"}, + "3M": { "en": "3 months", "de": "3 Monate", "ru": "3 месяца", "pt": "3 meses", "nl": "3 maanden", "fr": "3 mois", "it": "3 mesi", "es": "3 meses", "pl": "3 miesiące"}, + "6M": { "en": "6 months", "de": "6 Monate", "ru": "6 месяцев", "pt": "6 meses", "nl": "6 maanden", "fr": "6 mois", "it": "6 mesi", "es": "6 meses", "pl": "6 miesięcy"}, + "1Y": { "en": "1 year", "de": "1 Jahr", "ru": "1 год", "pt": "1 ano", "nl": "1 jaar", "fr": "1 an", "it": "1 anno", "es": "1 año", "pl": "1 rok"}, + "2Y": { "en": "2 years", "de": "2 Jahre", "ru": "2 года", "pt": "2 anos", "nl": "2 jaar", "fr": "2 ans", "it": "2 anni", "es": "2 años", "pl": "2 lata"}, + "average": { "en": "average", "de": "mittel", "ru": "среднее", "pt": "média", "nl": "gemiddelde", "fr": "moyenne", "it": "media", "es": "promedio", "pl": "średni"}, + "max": { "en": "max", "de": "max", "ru": "макс", "pt": "máximo", "nl": "max", "fr": "max", "it": "max", "es": "máximo", "pl": "maks"}, + "min": { "en": "min", "de": "min", "ru": "мин", "pt": "min", "nl": "min", "fr": "min", "it": "min", "es": "min", "pl": "min"}, + "total": { "en": "total", "de": "total", "ru": "всего", "pt": "total", "nl": "totaal", "fr": "total", "it": "totale", "es": "total", "pl": "całkowity"}, + "off": { "en": "off", "de": "nichts", "ru": "скрыть", "pt": "fora", "nl": "uit", "fr": "de", "it": "via", "es": "apagado", "pl": "poza"}, + "leftColor": { "en": "left colored", "de": "links farblich", "ru": "слева цветом", "pt": "colorido esquerdo", "nl": "links gekleurd", "fr": "laissé coloré", "it": "lasciato colorato", "es": "color izquierdo", "pl": "pozostawione w kolorze"}, + "rightColor": { "en": "right colored", "de": "rechts farblich", "ru": "справа цветом", "pt": "cor clara", "nl": "rechts gekleurd", "fr": "couleur droite", "it": "giusto colorato", "es": "color derecho", "pl": "prawe kolorowe"}, + "topColor": { "en": "top colored", "de": "oben farblich", "ru": "сверху цветом", "pt": "colorido superior", "nl": "bovenaan gekleurd", "fr": "top coloré", "it": "top colorato", "es": "tapa coloreada", "pl": "górne kolorowe"}, + "bottomColor": { "en": "bottom colored", "de": "unten farblich", "ru": "снизу цветом", "pt": "colorido inferior", "nl": "onderaan gekleurd", "fr": "fond coloré", "it": "fondo colorato", "es": "color de fondo", "pl": "u dołu w kolorze"}, + "default": { "en": "default", "de": "default", "ru": "по умолчанию", "pt": "padrão", "nl": "standaard", "fr": "défaut", "it": "predefinito", "es": "defecto", "pl": "domyślna"}, + "Auto-update:": { "en": "Auto-update:", "de": "Auto-update:", "ru": "Обновлять сразу:", "pt": "Atualização automática:", "nl": "Auto update:", "fr": "Mise à jour automatique:", "it": "Aggiornamento automatico:", "es": "Actualización automática:", "pl": "Automatyczna aktualizacja:"}, + "Use comma:": { "en": "Use comma:", "de": "Benutze Komma:", "ru": "Запятая-разделитель:", "pt": "Usar vírgula:", "nl": "Gebruik komma:", "fr": "Utilisez une virgule:", "it": "Usa la virgola:", "es": "Usa la coma", "pl": "Użyj przecinka:"}, + "Common Y Axis": { "en": "Common Y Axis", "de": "Gemeinsame Y-Achse", "ru": "Общая ось Y", "pt": "Eixo Y comum", "nl": "Gemeenschappelijke Y-as", "fr": "Axe Y commun", "it": "Asse Y comune", "es": "Eje Y común", "pl": "Wspólna oś Y."}, + "Instance": { "en": "Instance", "de": "Instanz", "ru": "Драйвер", "pt": "Instância", "nl": "Aanleg", "fr": "Exemple", "it": "Esempio", "es": "Ejemplo", "pl": "Instancja"}, + "Line Width": { "en": "Line Width", "de": "Linienstärke", "ru": "Ширина линии", "pt": "Espessura da linha", "nl": "Lijnbreedte", "fr": "Largeur de ligne", "it": "Larghezza della linea", "es": "Ancho de línea", "pl": "Szerokość linii"}, + "Shadow Size": { "en": "Shadow Size", "de": "Schattengröße", "ru": "Ширина тени", "pt": "Tamanho da sombra", "nl": "Schaduwgrootte", "fr": "Taille de l'ombre", "it": "Dimensione dell'ombra", "es": "Tamaño de las Sombras", "pl": "Rozmiar cienia"}, + "ignore 'null':": { "en": "ignore 'null':", "de": "'null' ignorieren:", "ru": "Игнорировать 'null':", "pt": "ignore 'null':", "nl": "negeer 'null':", "fr": "ignore 'null':", "it": "ignora 'null':", "es": "ignorar 'nulo':", "pl": "zignoruj ​​\"null\":"}, + "onchange": { "en": "on change", "de": "bei Änderung", "ru": "при изменении", "pt": "em mudança", "nl": "over verandering", "fr": "sur le changement", "it": "sul cambiamento", "es": "en cambio", "pl": "o zmianie"}, + "Border color:": { "en": "Border color:", "de": "Rahmenfarbe:", "ru": "Цвет рамки:", "pt": "Cor da borda:", "nl": "Rand kleur:", "fr": "Couleur de la bordure:", "it": "Colore del bordo:", "es": "Color del borde:", "pl": "Kolor ramki:"}, + "Grid color:": { "en": "Grid color:", "de": "Gitterfarbe:", "ru": "Цвет сетки:", "pt": "Cor da grade:", "nl": "Raster kleur:", "fr": "Couleur de la grille:", "it": "Colore griglia:", "es": "Color de cuadrícula", "pl": "Kolor siatki:"}, + "Border width:": { "en": "Border width:", "de": "Rahmenbreite:", "ru": "Ширина рамки:", "pt": "Largura da borda:", "nl": "Grensbreedte:", "fr": "Largeur de la bordure:", "it": "Larghezza del bordo:", "es": "Ancho del borde:", "pl": "Szerokość granicy:"}, + "Enable zoom and pan:": { "en": "Enable zoom and pan:", "de": "Aktiviere Zoom und Schieben:", "ru": "Разрешить увеличение и сдвиг:", "pt": "Ative o zoom e pan:", "nl": "Zoom en pan inschakelen:", "fr": "Activer le zoom et le panoramique:", "it": "Abilita zoom e panoramica:", "es": "Habilitar zoom y pan:", "pl": "Włącz powiększanie i panoramowanie:"}, + "Arrange bools": { "en": "Arrange booleans", "de": "Platziere Booleans", "ru": "Выстроить bool графики", "pt": "Organizar booleanos", "nl": "Booleans regelen", "fr": "Organiser les booléens", "it": "Disporre i booleani", "es": "Organizar booleanos", "pl": "Rozmieść booleans"}, + "NULL as": { "en": "NULL as", "de": "NULL als", "ru": "NULL как", "pt": "NULL como", "nl": "NULL als", "fr": "NULL comme", "it": "NULL come", "es": "NULL como", "pl": "NULL as"}, + "MinMax": { "en": "MinMax", "de": "MinMax", "ru": "MinMax", "pt": "Mínimo máximo", "nl": "MinMax", "fr": "Min max", "it": "Minimo Massimo", "es": "Mínimo máximo", "pl": "Minimum maksimum"}, + "null": { "en": "null", "de": "null", "ru": "null", "pt": "nulo", "nl": "nul", "fr": "nul", "it": "nullo", "es": "nulo", "pl": "zero"}, + "true": { "en": "last value", "de": "letztes Wert", "ru": "пред. значение", "pt": "último valor", "nl": "laatste waarde", "fr": "dernière valeur", "it": "ultimo valore", "es": "último valor", "pl": "ostatnia wartość"}, + "last value": { "en": "last value", "de": "letztes Wert", "ru": "пред. значение", "pt": "último valor", "nl": "laatste waarde", "fr": "dernière valeur", "it": "ultimo valore", "es": "último valor", "pl": "ostatnia wartość"}, + "Hide edit button:": { "en": "Hide edit button:", "de": "Kein 'Edit'-Knopf:", "ru": "Скрыть кнопку 'Редактировать':", "pt": "Ocultar botão de edição:", "nl": "Verberg bewerken knop:", "fr": "Masquer le bouton d'édition:", "it": "Nascondi pulsante di modifica:", "es": "Ocultar botón de edición:", "pl": "Ukryj przycisk edycji:"}, + "minmax": { "en": "minmax", "de": "minmax", "ru": "minmax", "pt": "mínimo máximo", "nl": "MinMax", "fr": "min max", "it": "minimo Massimo", "es": "mínimo máximo", "pl": "minimum maksimum"}, + "ØL": { "en": "ØL", "de": "ØL", "ru": "ØL", "pt": "& # 216L", "nl": "& # 216L", "fr": "& # 216L", "it": "& # 216L", "es": "& # 216L", "pl": "& # 216L"}, + "ØS": { "en": "ØS", "de": "ØS", "ru": "ØS", "pt": "& # 216S", "nl": "& # 216S", "fr": "& # 216S", "it": "& # 216S", "es": "& # 216S", "pl": "& # 216S"}, + "Line": { "en": "Line", "de": "Linie", "ru": "Линия", "pt": "Linha", "nl": "Lijn", "fr": "Ligne", "it": "Linea", "es": "Línea", "pl": "Linia"}, + "false": { "en": "null", "de": "null", "ru": "null", "pt": "nulo", "nl": "nul", "fr": "nul", "it": "nullo", "es": "nulo", "pl": "zero"}, + "end of minute": { "en": "end of minute", "de": "Minutenende", "ru": "Конец минуты", "pt": "fim de minuto", "nl": "einde van de minuut", "fr": "fin de minute", "it": "fine del minuto", "es": "fin del minuto", "pl": "koniec minuty"}, + "end of 5 minutes": { "en": "end of 5 minutes", "de": "Ende von 5 Minuten", "ru": "Конец 5 minutes", "pt": "fim de 5 minutos", "nl": "einde van 5 minuten", "fr": "fin de 5 minutes", "it": "fine di 5 minuti", "es": "fin de 5 minutos", "pl": "koniec 5 minut"}, + "end of 10 minutes": { "en": "end of 10 minutes", "de": "Ende von 10 Minuten", "ru": "Конец 10 minutes", "pt": "fim de 10 minutos", "nl": "einde van 10 minuten", "fr": "fin de 10 minutes", "it": "fine di 10 minuti", "es": "fin de 10 minutos", "pl": "koniec 10 minut"}, + "end of 30 minutes": { "en": "end of 30 minutes", "de": "Ende von 30 Minuten", "ru": "Конец 30 minutes", "pt": "fim de 30 minutos", "nl": "einde van 30 minuten", "fr": "fin de 30 minutes", "it": "fine di 30 minuti", "es": "fin de 30 minutos", "pl": "koniec 30 minut"}, + "end of hour": { "en": "end of hour", "de": "Stundenende", "ru": "Конец часа", "pt": "fim de hora", "nl": "einde van het uur", "fr": "fin de l'heure", "it": "fine dell'ora", "es": "fin de hora", "pl": "koniec godziny"}, + "end of 2 hours": { "en": "end of 2 hours", "de": "Ende von 2 Stunden", "ru": "Конец 2 часов", "pt": "fim de 2 horas", "nl": "einde van 2 uur", "fr": "fin de 2 heures", "it": "fine di 2 ore", "es": "fin de 2 horas", "pl": "koniec 2 godzin"}, + "end of 3 hours": { "en": "end of 3 hours", "de": "Ende von 3 Stunden", "ru": "Конец 3 часов", "pt": "fim de 3 horas", "nl": "einde van 3 uur", "fr": "fin de 3 heures", "it": "fine di 3 ore", "es": "fin de 3 horas", "pl": "koniec 3 godzin"}, + "end of 4 hours": { "en": "end of 4 hours", "de": "Ende von 4 Stunden", "ru": "Конец 4 часов", "pt": "fim de 4 horas", "nl": "einde van 4 uur", "fr": "fin de 4 heures", "it": "fine di 4 ore", "es": "fin de 4 horas", "pl": "koniec 4 godzin"}, + "end of 6 hours": { "en": "end of 6 hours", "de": "Ende von 6 Stunden", "ru": "Конец 6 часов", "pt": "fim de 6 horas", "nl": "einde van 6 uur", "fr": "fin de 6 heures", "it": "fine di 6 ore", "es": "fin de 6 horas", "pl": "koniec 6 godzin"}, + "end of 8 hours": { "en": "end of 8 hours", "de": "Ende von 8 Stunden", "ru": "Конец 8 часов", "pt": "fim de 8 horas", "nl": "einde van 8 uur", "fr": "fin de 8 heures", "it": "fine di 8 ore", "es": "fin de 8 horas", "pl": "koniec 8 godzin"}, + "end of 12 hours": { "en": "end of 12 hours", "de": "Ende von 12 Stunden", "ru": "Конец 12 часов", "pt": "fim de 12 horas", "nl": "einde van 12 uur", "fr": "fin de 12 heures", "it": "fine di 12 ore", "es": "fin de 12 horas", "pl": "koniec 12 godzin"}, + "end of day": { "en": "end of day", "de": "Tagesende", "ru": "Конец дня", "pt": "fim do dia", "nl": "einde van de dag", "fr": "fin de la journée", "it": "fine del giorno", "es": "fin del día", "pl": "koniec dnia"}, + "end of sunday": { "en": "end of sunday", "de": "Wochenssende", "ru": "Конец недели", "pt": "fim de domingo", "nl": "einde van zondag", "fr": "fin de dimanche", "it": "fine della domenica", "es": "fin del domingo", "pl": "koniec niedzieli"}, + "end of saturday": { "en": "end of saturday", "de": "Samstagsende", "ru": "Конец субботы", "pt": "fim de sábado", "nl": "einde van zaterdag", "fr": "fin de samedi", "it": "fine di sabato", "es": "fin de sabado", "pl": "koniec soboty"}, + "1minute": { "en": "end of minute", "de": "Minutenende", "ru": "Конец минуты", "pt": "fim de minuto", "nl": "einde van de minuut", "fr": "fin de minute", "it": "fine del minuto", "es": "fin del minuto", "pl": "koniec minuty"}, + "5minutes": { "en": "end of 5 minutes", "de": "Ende von 5 Minuten", "ru": "Конец 5 minutes", "pt": "fim de 5 minutos", "nl": "einde van 5 minuten", "fr": "fin de 5 minutes", "it": "fine di 5 minuti", "es": "fin de 5 minutos", "pl": "koniec 5 minut"}, + "10minutes": { "en": "end of 10 minutes", "de": "Ende von 10 Minuten", "ru": "Конец 10 minutes", "pt": "fim de 10 minutos", "nl": "einde van 10 minuten", "fr": "fin de 10 minutes", "it": "fine di 10 minuti", "es": "fin de 10 minutos", "pl": "koniec 10 minut"}, + "30minutes": { "en": "end of 30 minutes", "de": "Ende von 30 Minuten", "ru": "Конец 30 minutes", "pt": "fim de 30 minutos", "nl": "einde van 30 minuten", "fr": "fin de 30 minutes", "it": "fine di 30 minuti", "es": "fin de 30 minutos", "pl": "koniec 30 minut"}, + "1hour": { "en": "end of hour", "de": "Stundenende", "ru": "Конец часа", "pt": "fim de hora", "nl": "einde van het uur", "fr": "fin de l'heure", "it": "fine dell'ora", "es": "fin de hora", "pl": "koniec godziny"}, + "2hours": { "en": "end of 2 hours", "de": "Ende von 2 Stunden", "ru": "Конец 2 часов", "pt": "fim de 2 horas", "nl": "einde van 2 uur", "fr": "fin de 2 heures", "it": "fine di 2 ore", "es": "fin de 2 horas", "pl": "koniec 2 godzin"}, + "3hours": { "en": "end of 3 hours", "de": "Ende von 3 Stunden", "ru": "Конец 3 часов", "pt": "fim de 3 horas", "nl": "einde van 3 uur", "fr": "fin de 3 heures", "it": "fine di 3 ore", "es": "fin de 3 horas", "pl": "koniec 3 godzin"}, + "4hours": { "en": "end of 4 hours", "de": "Ende von 4 Stunden", "ru": "Конец 4 часов", "pt": "fim de 4 horas", "nl": "einde van 4 uur", "fr": "fin de 4 heures", "it": "fine di 4 ore", "es": "fin de 4 horas", "pl": "koniec 4 godzin"}, + "6hours": { "en": "end of 6 hours", "de": "Ende von 6 Stunden", "ru": "Конец 6 часов", "pt": "fim de 6 horas", "nl": "einde van 6 uur", "fr": "fin de 6 heures", "it": "fine di 6 ore", "es": "fin de 6 horas", "pl": "koniec 6 godzin"}, + "8hours": { "en": "end of 8 hours", "de": "Ende von 8 Stunden", "ru": "Конец 8 часов", "pt": "fim de 8 horas", "nl": "einde van 8 uur", "fr": "fin de 8 heures", "it": "fine di 8 ore", "es": "fin de 8 horas", "pl": "koniec 8 godzin"}, + "12hours": { "en": "end of 12 hours", "de": "Ende von 12 Stunden", "ru": "Конец 12 часов", "pt": "fim de 12 horas", "nl": "einde van 12 uur", "fr": "fin de 12 heures", "it": "fine di 12 ore", "es": "fin de 12 horas", "pl": "koniec 12 godzin"}, + "weekEurope": { "en": "end of day", "de": "Tagesende", "ru": "Конец дня", "pt": "fim do dia", "nl": "einde van de dag", "fr": "fin de la journée", "it": "fine del giorno", "es": "fin del día", "pl": "koniec dnia"}, + "weekUsa": { "en": "end of sunday", "de": "Wochenssende", "ru": "Конец недели", "pt": "fim de domingo", "nl": "einde van zondag", "fr": "fin de dimanche", "it": "fine della domenica", "es": "fin del domingo", "pl": "koniec niedzieli"}, + "Bar settings": { "en": "Bar settings", "de": "Bar-Einstellungen", "ru": "Настройки Bar", "pt": "Configurações da barra", "nl": "Bar-instellingen", "fr": "Paramètres du bar", "it": "Impostazioni della barra", "es": "Configuración de barra", "pl": "Ustawienia paska"}, + "Fill color:": { "en": "Fill color:", "de": "Füllfarbe color:", "ru": "Цвет заливки:", "pt": "Cor de preenchimento:", "nl": "Opvulkleur:", "fr": "La couleur de remplissage:", "it": "Colore di riempimento:", "es": "Color de relleno:", "pl": "Kolor wypełnienia:"}, + "Show labels:": { "en": "Show labels:", "de": "Zeige Labels:", "ru": "Подписи:", "pt": "Mostrar rótulos:", "nl": "Toon labels:", "fr": "Afficher les étiquettes:", "it": "Mostra etichette:", "es": "Mostrar etiquetas:", "pl": "Pokaż etykiety:"}, + "top over": { "en": "top over", "de": "oben über", "ru": "Сверху над", "pt": "mais alto", "nl": "opnieuw gedaan", "fr": "dessus", "it": "sopra", "es": "arriba encima", "pl": "do góry"}, + "top under": { "en": "top under", "de": "oben unten", "ru": "Сверху под", "pt": "top sob", "nl": "top onder", "fr": "haut sous", "it": "sopra sotto", "es": "arriba debajo", "pl": "górny pod"}, + "middle": { "en": "middle", "de": "mittig", "ru": "В середине", "pt": "meio", "nl": "midden-", "fr": "milieu", "it": "mezzo", "es": "medio", "pl": "środkowy"}, + "Bars width:": { "en": "Bars width:", "de": "Barbreite:", "ru": "Ширина бара:", "pt": "Largura das barras:", "nl": "Staaf breedte:", "fr": "Largeur des barres:", "it": "Larghezza delle barre:", "es": "Ancho de barras:", "pl": "Szerokość prętów:"}, + "Label font size:": { "en": "Label font size:", "de": "Labelschriftgröße:", "ru": "Шрифт подписи:", "pt": "Etiquetar tamanho da fonte:", "nl": "Label lettergrootte:", "fr": "Étiquette taille de la police:", "it": "Dimensione del carattere dell'etichetta:", "es": "Tamaño de letra de la etiqueta:", "pl": "Rozmiar czcionki etykiety:"}, + "Label color:": { "en": "Label color:", "de": "Labelfarbe:", "ru": "Цвет подписи:", "pt": "Cor do rótulo:", "nl": "Label kleur:", "fr": "Étiquette couleur:", "it": "Colore dell'etichetta:", "es": "Color de etiqueta:", "pl": "Kolor etykiety:"}, + "Markings": { "en": "Markings", "de": "Markierungen", "ru": "Разметка", "pt": "Marcas", "nl": "markeringen", "fr": "Marquages", "it": "marcature", "es": "Marcas", "pl": "Znakowania"}, + "Line ID": { "en": "Line ID", "de": "Linie ID", "ru": "ID линии", "pt": "ID da linha", "nl": "Lijn-ID", "fr": "Id de ligne", "it": "ID linea", "es": "Identificación de línea", "pl": "Identyfikator linii"}, + "Fill": { "en": "Fill", "de": "Füllen", "ru": "Заливка", "pt": "Preencher", "nl": "Vullen", "fr": "Remplir", "it": "Riempire", "es": "Llenar", "pl": "Napełnić"}, + "ØL": { "en": "ØL", "de": "ØL", "ru": "ØL", "pt": "ØL", "nl": "ØL", "fr": "ØL", "it": "ØL", "es": "ØL", "pl": "ØL"}, + "ØS": { "en": "ØS", "de": "ØS", "ru": "ØS", "pt": "ØS", "nl": "Os", "fr": "ØS", "it": "ØS", "es": "ØS", "pl": "ØS"}, + "Text": { "en": "Text", "de": "Text", "ru": "Текст", "pt": "Texto", "nl": "Tekst", "fr": "Texte", "it": "Testo", "es": "Texto", "pl": "Tekst"}, + "Text position": { "en": "Text position", "de": "Textposition", "ru": "Расположение текста", "pt": "Posição de texto", "nl": "Tekstpositie", "fr": "Position du texte", "it": "Posizione del testo", "es": "Posición del texto", "pl": "Pozycja tekstu"}, + "Text offset": { "en": "Text offset", "de": "Text-Offset", "ru": "Сдвиг текста", "pt": "Deslocamento de texto", "nl": "Tekst offset", "fr": "Décalage de texte", "it": "Offset del testo", "es": "Offset de texto", "pl": "Przesunięcie tekstu"}, + "Text size": { "en": "Text size", "de": "Textgröße", "ru": "Размер текста", "pt": "Tamanho do texto", "nl": "Lettergrootte", "fr": "Taille du texte", "it": "Dimensione del testo", "es": "Tamano del texto", "pl": "Rozmiar czcionki"}, + "Text color": { "en": "Text color", "de": "Textfarbe", "ru": "Цвет текста", "pt": "Cor do texto", "nl": "Tekst kleur", "fr": "Couleur du texte", "it": "Colore del testo", "es": "Color de texto", "pl": "Kolor tekstu"}, + "Add new markings": { "en": "Add new markings", "de": "Neue Markierung hinzufügen", "ru": "Добавить разметку", "pt": "Adicionar novas marcações", "nl": "Voeg nieuwe markeringen toe", "fr": "Ajouter de nouvelles marques", "it": "Aggiungi nuovi segni", "es": "Agregar nuevas marcas", "pl": "Dodaj nowe oznaczenia"}, + "Left": { "en": "Left", "de": "Links", "ru": "слева", "pt": "Esquerda", "nl": "Links", "fr": "La gauche", "it": "Sinistra", "es": "Izquierda", "pl": "Lewo"}, + "Right": { "en": "Right", "de": "Rechts", "ru": "справа", "pt": "Certo", "nl": "Rechts", "fr": "Droite", "it": "Destra", "es": "Derecha", "pl": "Dobrze"}, + "Upper value or ID": { "en": "Upper value or ID", "de": "Oberes Wert oder ID", "ru": "Верхнее значение или ID", "pt": "Valor superior ou ID", "nl": "Hoogste waarde of ID", "fr": "Valeur supérieure ou ID", "it": "Valore massimo o ID", "es": "Valor superior o ID", "pl": "Górna wartość lub ID"}, + "Lower value or ID": { "en": "Lower value or ID", "de": "Unteres Wert oder ID", "ru": "Нижнее значение или ID", "pt": "Menor valor ou ID", "nl": "Lagere waarde of ID", "fr": "Valeur inférieure ou ID", "it": "Valore più basso o ID", "es": "Menor valor o ID", "pl": "Niższa wartość lub ID"}, + "X-Axis ticks": { "en": "X-Axis ticks", "de": "X-Achse-Ticks", "ru": "Кол-во делений на шкале X", "pt": "Carrapatos do X-Axis", "nl": "X-as-teken", "fr": "Tiques de l'axe des X", "it": "Zecche X-Axis", "es": "Garrapatas X-Axis", "pl": "Tiki X-Axis"}, + "Y-Axis ticks": { "en": "Y-Axis ticks", "de": "Y-Achse-Ticks", "ru": "Кол-во делений на шкале Y", "pt": "Carrapatos do Y-Axis", "nl": "Y-as tikken", "fr": "Tiques de l'axe des Y", "it": "Zecche dell'asse Y.", "es": "Señales del eje Y", "pl": "Tyksy Y-Axis"}, + "ignore null values": { "en": "ignore null values", "de": "null-Werte ignorieren", "ru": "игнорировать значения null", "pt": "ignore valores nulos", "nl": "Negeer waarden negeren", "fr": "ignorer les valeurs nulles", "it": "ignora valori nulli", "es": "ignorar valores nulos", "pl": "ignoruj ​​wartości puste"}, + "Ticks from:": { "en": "Use X-ticks from:", "de": "Benutze X-Ticks aus:", "ru": "Подписи X-делений из:", "pt": "Use X-ticks de:", "nl": "Gebruik X-ticks van:", "fr": "Utilisez les X-ticks de:", "it": "Usa X-tick da:", "es": "Use X-ticks desde:", "pl": "Użyj tyknięć X z:"}, + "use 0 instead of null values": { "en": "use 0 instead of null values", "de": "0 statt null benutzen", "ru": "Заменять null на 0", "pt": "use 0 em vez de valores nulos", "nl": "gebruik 0 in plaats van nulwaarden", "fr": "utilise 0 au lieu de valeurs nulles", "it": "usa 0 invece di valori nulli", "es": "use 0 en lugar de valores nulos", "pl": "użyj 0 zamiast wartości zerowych"}, + "More": { "en": "more", "de": "mehr", "ru": "ещё", "pt": "Mais", "nl": "meer", "fr": "plus", "it": "Di Più", "es": "Más", "pl": "jeszcze"}, + "Edit options for line %s": { "en": "Edit options for line %s", "de": "Editieren weitere Einstellungen für Linie %s", "ru": "Редактировать настройки для линии %s", "pt": "Editar opções para a linha% s", "nl": "Bewerk opties voor regel% s", "fr": "Modifier les options pour la ligne% s", "it": "Modifica le opzioni per la riga% s", "es": "Editar opciones para la línea% s", "pl": "Edytuj opcje linii% s"}, + "Legend columns:": { "en": "Legend columns:", "de": "Spalten in Legende:", "ru": "Колонок в легенде:", "pt": "Colunas da legenda:", "nl": "Legenda kolommen:", "fr": "Colonnes de légende:", "it": "Colonne della legenda:", "es": "Columnas leyenda", "pl": "Kolumny legendy:"}, + "Legend opacity (from 0 to 1):": { "en": "Legend opacity (from 0 to 1):", "de": "Legende-Opacity (von 0 bis 1):", "ru": "Прозрачность легенды (от 0 до 1):", "pt": "Opacidade da legenda (de 0 a 1):", "nl": "Legenda opaciteit (van 0 tot 1):", "fr": "Opacité de la légende (de 0 à 1):", "it": "Opacità della legenda (da 0 a 1):", "es": "Opacidad de la leyenda (de 0 a 1):", "pl": "Krycie Legendy (od 0 do 1):"}, + "Legend background:": { "en": "Legend background:", "de": "Legende-Hintergrund:", "ru": "Фон легенды:", "pt": "Legend background:", "nl": "Legenda achtergrond:", "fr": "Contexte de la légende", "it": "Sfondo leggenda:", "es": "Antecedentes de leyenda:", "pl": "Tło legendy:"}, + "Fill(0to1)": { "en": "Fill(0to1)", "de": "Füllen(0bis1)", "ru": "Фон(0to1)", "pt": "Preencher (0 a 1)", "nl": "Fill (0to1)", "fr": "Remplir (0to1)", "it": "Fill (0to1)", "es": "Rellenar (0to1)", "pl": "Wypełnij (0to1)"}, + "Points": { "en": "Points", "de": "Punkte", "ru": "Точки", "pt": "Pontos", "nl": "punten", "fr": "Points", "it": "Punti", "es": "Puntos", "pl": "Zwrotnica"}, +}; \ No newline at end of file diff --git a/src/lib/css/images/128/bar-alpha.png b/src/lib/css/images/128/bar-alpha.png new file mode 100644 index 0000000..454dc9e Binary files /dev/null and b/src/lib/css/images/128/bar-alpha.png differ diff --git a/src/lib/css/images/128/bar.png b/src/lib/css/images/128/bar.png new file mode 100644 index 0000000..32d0c8f Binary files /dev/null and b/src/lib/css/images/128/bar.png differ diff --git a/src/lib/css/images/128/map.png b/src/lib/css/images/128/map.png new file mode 100644 index 0000000..37e8cae Binary files /dev/null and b/src/lib/css/images/128/map.png differ diff --git a/src/lib/css/images/bar-alpha.png b/src/lib/css/images/bar-alpha.png new file mode 100644 index 0000000..2950dae Binary files /dev/null and b/src/lib/css/images/bar-alpha.png differ diff --git a/src/lib/css/images/bar-opacity.png b/src/lib/css/images/bar-opacity.png new file mode 100644 index 0000000..e42ad08 Binary files /dev/null and b/src/lib/css/images/bar-opacity.png differ diff --git a/src/lib/css/images/bar-pointer.png b/src/lib/css/images/bar-pointer.png new file mode 100644 index 0000000..6e980cf Binary files /dev/null and b/src/lib/css/images/bar-pointer.png differ diff --git a/src/lib/css/images/bar.png b/src/lib/css/images/bar.png new file mode 100644 index 0000000..80eb2bb Binary files /dev/null and b/src/lib/css/images/bar.png differ diff --git a/src/lib/css/images/map-opacity.png b/src/lib/css/images/map-opacity.png new file mode 100644 index 0000000..6756cee Binary files /dev/null and b/src/lib/css/images/map-opacity.png differ diff --git a/src/lib/css/images/map-pointer.png b/src/lib/css/images/map-pointer.png new file mode 100644 index 0000000..6499296 Binary files /dev/null and b/src/lib/css/images/map-pointer.png differ diff --git a/src/lib/css/images/map.png b/src/lib/css/images/map.png new file mode 100644 index 0000000..853d38c Binary files /dev/null and b/src/lib/css/images/map.png differ diff --git a/src/lib/css/images/preview-opacity.png b/src/lib/css/images/preview-opacity.png new file mode 100644 index 0000000..0dd9a2f Binary files /dev/null and b/src/lib/css/images/preview-opacity.png differ diff --git a/src/lib/css/images/ui-colorpicker.png b/src/lib/css/images/ui-colorpicker.png new file mode 100644 index 0000000..e244c68 Binary files /dev/null and b/src/lib/css/images/ui-colorpicker.png differ diff --git a/src/lib/css/jquery.colorpicker.css b/src/lib/css/jquery.colorpicker.css new file mode 100644 index 0000000..11ecbe7 --- /dev/null +++ b/src/lib/css/jquery.colorpicker.css @@ -0,0 +1,239 @@ +.ui-colorpicker, +.ui-dialog.ui-colorpicker { + width: auto; + white-space: nowrap; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ui-colorpicker-inline { + position: static; +} + +.ui-colorpicker-buttonset { + float: left; + margin-left: .4em; +} + +.ui-colorpicker-buttonset .ui-button { + margin: .5em 0 .5em 0; + cursor: pointer; +} + +.ui-colorpicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} + +.ui-colorpicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} + +.ui-colorpicker-buttonpane button.ui-colorpicker-current { + float: left; +} + +.ui-colorpicker table { + width: 100%; + font-size: 100%; /* Reset browser table font-size */ + margin: 0; +} + +.ui-colorpicker table td { + vertical-align: top; +} + +.ui-colorpicker-padding-left { + padding-left: 10px; +} +.ui-colorpicker-padding-top { + padding-top: 10px; +} + +.ui-colorpicker-border { + border: 1px inset; + display: inline-block; +} + +/* Bar & map */ +.ui-colorpicker-map > *, +.ui-colorpicker-bar > * { + position: absolute; + cursor: crosshair; +} + +.ui-colorpicker-map-pointer, +.ui-colorpicker-bar-pointer { + position: absolute; + left: 0; +} + +/* Map */ +.ui-colorpicker-map, +.ui-colorpicker-map > * { + display: block; + width: 256px; + height: 256px; + overflow: hidden; +} + +.ui-colorpicker-map-layer-1, +.ui-colorpicker-map-layer-2 { + background: url(images/map.png) no-repeat; +} + +.ui-colorpicker-map-128, +.ui-colorpicker-map-128 > * { + width: 128px; + height: 128px; +} + +.ui-colorpicker-map-128 .ui-colorpicker-map-layer-1, +.ui-colorpicker-map-128 .ui-colorpicker-map-layer-2 { + background: url(images/128/map.png) no-repeat; +} + +.ui-colorpicker-map-layer-alpha { + background: url(images/map-opacity.png); +} + +.ui-colorpicker-map-pointer { + display: inline-block; + width: 15px; + height: 15px; + background: url(images/map-pointer.png) no-repeat; +} + +/* Bar */ +.ui-colorpicker-bar, +.ui-colorpicker-bar > * { + display: block; + width: 20px; + height: 256px; + overflow: hidden; + background-repeat: repeat-x; +} + +.ui-colorpicker-bar-128, +.ui-colorpicker-bar-128 > * { + height: 128px; +} + +.ui-colorpicker-bar-layer-1, +.ui-colorpicker-bar-layer-2, +.ui-colorpicker-bar-layer-3, +.ui-colorpicker-bar-layer-4 { + background: url(images/bar.png) repeat-x; +} + +.ui-colorpicker-bar-128 .ui-colorpicker-bar-layer-1, +.ui-colorpicker-bar-128 .ui-colorpicker-bar-layer-2, +.ui-colorpicker-bar-128 .ui-colorpicker-bar-layer-3, +.ui-colorpicker-bar-128 .ui-colorpicker-bar-layer-4 { + background: url(images/128/bar.png) repeat-x; +} + +.ui-colorpicker-bar-layer-alpha { + background: url(images/bar-opacity.png); +} + +.ui-colorpicker-bar-layer-alphabar { + background: url(images/bar-alpha.png); +} + +.ui-colorpicker-bar-128 .ui-colorpicker-bar-layer-alphabar { + background: url(images/128/bar-alpha.png); +} + +.ui-colorpicker-bar-pointer { + display: inline-block; + width: 20px; + height: 7px; + background: url(images/bar-pointer.png) no-repeat; +} + +/* Preview */ +.ui-colorpicker-preview { + text-align: center; + height: 20px; +} + +.ui-colorpicker-preview-initial { + cursor: pointer; +} + +.ui-colorpicker-preview-initial, +.ui-colorpicker-preview-current { + width: 50px; + height: 20px; + display: inline-block; +} + +.ui-colorpicker-preview-initial-alpha, +.ui-colorpicker-preview-current-alpha { + width: 50px; + height: 20px; + display: inline-block; + background: url(images/preview-opacity.png) repeat; +} + +/* Inputs */ +.ui-colorpicker-rgb label, +.ui-colorpicker-hsv label, +.ui-colorpicker-hsl label, +.ui-colorpicker-lab label, +.ui-colorpicker-cmyk label, +.ui-colorpicker-alpha label { + width: 1.5em; + display: inline-block; +} + +.ui-colorpicker-number { + margin: .1em; + width: 4em; +} + +/* Hex */ +.ui-colorpicker-hex { + text-align: center; +} + +/* Swatches */ +.ui-colorpicker-swatches { + height: 256px; + overflow: auto; + background-color: #f8f8f8; +} + +.ui-colorpicker-swatch { + cursor: pointer; + float: left; + width: 11px; + height: 11px; + border-right: 1px solid black; + border-bottom: 1px solid black; +} + +.ui-colorpicker-disabled { + opacity: .5; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; + filter: alpha(opacity=50); + pointer-events: none; +} + +.ui-colorpicker-disabled * { + cursor: default !important; +} \ No newline at end of file diff --git a/src/lib/js/curvedLines.js b/src/lib/js/curvedLines.js new file mode 100644 index 0000000..fcacbeb --- /dev/null +++ b/src/lib/js/curvedLines.js @@ -0,0 +1,483 @@ +/* The MIT License + + Copyright (c) 2011 by Michael Zinsmaier and nergal.dev + Copyright (c) 2012 by Thomas Ritou + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* +____________________________________________________ + + what it is: + ____________________________________________________ + + curvedLines is a plugin for flot, that tries to display lines in a smoother way. + This is achieved through adding of more data points. The plugin is a data processor and can thus be used + in combination with standard line / point rendering options. + + => 1) with large data sets you may get trouble + => 2) if you want to display the points too, you have to plot them as 2nd data series over the lines + => 3) consecutive x data points are not allowed to have the same value + + Feel free to further improve the code + + ____________________________________________________ + + how to use it: + ____________________________________________________ + + var d1 = [[5,5],[7,3],[9,12]]; + + var options = { series: { curvedLines: { active: true }}}; + + $.plot($("#placeholder"), [{data: d1, lines: { show: true}, curvedLines: {apply: true}}], options); + + _____________________________________________________ + + options: + _____________________________________________________ + + active: bool true => plugin can be used + apply: bool true => series will be drawn as curved line + monotonicFit: bool true => uses monotone cubic interpolation (preserve monotonicity) + tension: int defines the tension parameter of the hermite spline interpolation (no effect if monotonicFit is set) + nrSplinePoints: int defines the number of sample points (of the spline) in between two consecutive points + + deprecated options from flot prior to 1.0.0: + ------------------------------------------------ + legacyOverride bool true => use old default + OR + legacyOverride optionArray + { + fit: bool true => forces the max,mins of the curve to be on the datapoints + curvePointFactor int defines how many "virtual" points are used per "real" data point to + emulate the curvedLines (points total = real points * curvePointFactor) + fitPointDist: int defines the x axis distance of the additional two points that are used + } to enforce the min max condition. + */ + +/* + * v0.1 initial commit + * v0.15 negative values should work now (outcommented a negative -> 0 hook hope it does no harm) + * v0.2 added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi) + * v0.3 improved saddle handling and added basic handling of Dates + * v0.4 rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug + * v0.5 rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou). + * This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill, + * shadow) are now supported out of the box + * v0.6 flot 0.8 compatibility and some bug fixes + * v0.6.x changed versioning schema + * + * v1.0.0 API Break marked existing implementation/options as deprecated + * v1.1.0 added the new curved line calculations based on hermite splines + * v1.1.1 added a rough parameter check to make sure the new options are used + */ + +(function($) { + + var options = { + series : { + curvedLines : { + active : false, + apply : false, + monotonicFit : false, + tension : 0.5, + nrSplinePoints : 20, + legacyOverride : undefined + } + } + }; + + function init(plot) { + + plot.hooks.processOptions.push(processOptions); + + //if the plugin is active register processDatapoints method + function processOptions(plot, options) { + if (options.series.curvedLines.active) { + plot.hooks.processDatapoints.unshift(processDatapoints); + } + } + + //only if the plugin is active + function processDatapoints(plot, series, datapoints) { + var nrPoints = datapoints.points.length / datapoints.pointsize; + var EPSILON = 0.005; + + //detects missplaced legacy parameters (prior v1.x.x) in the options object + //this can happen if somebody upgrades to v1.x.x without adjusting the parameters or uses old examples + var invalidLegacyOptions = hasInvalidParameters(series.curvedLines); + + if (!invalidLegacyOptions && series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) { + if (series.lines.fill) { + + var pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1); + var pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2); + //flot makes sure for us that we've got a second y point if fill is true ! + + //Merge top and bottom curve + datapoints.pointsize = 3; + datapoints.points = []; + var j = 0; + var k = 0; + var i = 0; + var ps = 2; + while (i < pointsTop.length || j < pointsBottom.length) { + if (pointsTop[i] == pointsBottom[j]) { + datapoints.points[k] = pointsTop[i]; + datapoints.points[k + 1] = pointsTop[i + 1]; + datapoints.points[k + 2] = pointsBottom[j + 1]; + j += ps; + i += ps; + + } else if (pointsTop[i] < pointsBottom[j]) { + datapoints.points[k] = pointsTop[i]; + datapoints.points[k + 1] = pointsTop[i + 1]; + datapoints.points[k + 2] = k > 0 ? datapoints.points[k - 1] : null; + i += ps; + } else { + datapoints.points[k] = pointsBottom[j]; + datapoints.points[k + 1] = k > 1 ? datapoints.points[k - 2] : null; + datapoints.points[k + 2] = pointsBottom[j + 1]; + j += ps; + } + k += 3; + } + } else if (series.lines.lineWidth > 0) { + datapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1); + datapoints.pointsize = 2; + } + } + } + + function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) { + if ( typeof curvedLinesOptions.legacyOverride != 'undefined' && curvedLinesOptions.legacyOverride != false) { + var defaultOptions = { + fit : false, + curvePointFactor : 20, + fitPointDist : undefined + }; + var legacyOptions = jQuery.extend(defaultOptions, curvedLinesOptions.legacyOverride); + return calculateLegacyCurvePoints(datapoints, legacyOptions, yPos); + } + + return calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos); + } + + function calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos) { + var points = datapoints.points; + var ps = datapoints.pointsize; + + //create interpolant fuction + var splines = createHermiteSplines(datapoints, curvedLinesOptions, yPos); + var result = []; + + //sample the function + // (the result is intependent from the input data => + // it is ok to alter the input after this method) + var j = 0; + for (var i = 0; i < points.length - ps; i += ps) { + var curX = i; + var curY = i + yPos; + + var xStart = points[curX]; + var xEnd = points[curX + ps]; + var xStep = (xEnd - xStart) / Number(curvedLinesOptions.nrSplinePoints); + + //add point + result.push(points[curX]); + result.push(points[curY]); + + //add curve point + for (var x = (xStart += xStep); x < xEnd; x += xStep) { + result.push(x); + result.push(splines[j](x)); + } + + j++; + } + + //add last point + result.push(points[points.length - ps]); + result.push(points[points.length - ps + yPos]); + + return result; + } + + + + // Creates an array of splines, one for each segment of the original curve. Algorithm based on the wikipedia articles: + // + // http://de.wikipedia.org/w/index.php?title=Kubisch_Hermitescher_Spline&oldid=130168003 and + // http://en.wikipedia.org/w/index.php?title=Monotone_cubic_interpolation&oldid=622341725 and the description of Fritsch-Carlson from + // http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation + // for a detailed description see https://github.com/MichaelZinsmaier/CurvedLines/docu + function createHermiteSplines(datapoints, curvedLinesOptions, yPos) { + var points = datapoints.points; + var ps = datapoints.pointsize; + + // preparation get length (x_{k+1} - x_k) and slope s=(p_{k+1} - p_k) / (x_{k+1} - x_k) of the segments + var segmentLengths = []; + var segmentSlopes = []; + + for (var i = 0; i < points.length - ps; i += ps) { + var curX = i; + var curY = i + yPos; + var dx = points[curX + ps] - points[curX]; + var dy = points[curY + ps] - points[curY]; + + segmentLengths.push(dx); + segmentSlopes.push(dy / dx); + } + + //get the values for the desired gradients m_k for all points k + //depending on the used method the formula is different + var gradients = [segmentSlopes[0]]; + if (curvedLinesOptions.monotonicFit) { + // Fritsch Carlson + for (var i = 1; i < segmentLengths.length; i++) { + var slope = segmentSlopes[i]; + var prev_slope = segmentSlopes[i - 1]; + if (slope * prev_slope <= 0) { // sign(prev_slope) != sign(slpe) + gradients.push(0); + } else { + var length = segmentLengths[i]; + var prev_length = segmentLengths[i - 1]; + var common = length + prev_length; + //m = 3 (prev_length + length) / ((2 length + prev_length) / prev_slope + (length + 2 prev_length) / slope) + gradients.push(3 * common / ((common + length) / prev_slope + (common + prev_length) / slope)); + } + } + } else { + // Cardinal spline with t € [0,1] + // Catmull-Rom for t = 0 + for (var i = ps; i < points.length - ps; i += ps) { + var curX = i; + var curY = i + yPos; + gradients.push(Number(curvedLinesOptions.tension) * (points[curY + ps] - points[curY - ps]) / (points[curX + ps] - points[curX - ps])); + } + } + gradients.push(segmentSlopes[segmentSlopes.length - 1]); + + //get the two major coefficients (c'_{oef1} and c'_{oef2}) for each segment spline + var coefs1 = []; + var coefs2 = []; + for (i = 0; i < segmentLengths.length; i++) { + var m_k = gradients[i]; + var m_k_plus = gradients[i + 1]; + var slope = segmentSlopes[i]; + var invLength = 1 / segmentLengths[i]; + var common = m_k + m_k_plus - slope - slope; + + coefs1.push(common * invLength * invLength); + coefs2.push((slope - common - m_k) * invLength); + } + + //create functions with from the coefficients and capture the parameters + var ret = []; + for (var i = 0; i < segmentLengths.length; i ++) { + var spline = function (x_k, coef1, coef2, coef3, coef4) { + // spline for a segment + return function (x) { + var diff = x - x_k; + var diffSq = diff * diff; + return coef1 * diff * diffSq + coef2 * diffSq + coef3 * diff + coef4; + }; + }; + + ret.push(spline(points[i * ps], coefs1[i], coefs2[i], gradients[i], points[i * ps + yPos])); + } + + return ret; + }; + + //no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226 + //if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code. + function calculateLegacyCurvePoints(datapoints, curvedLinesOptions, yPos) { + + var points = datapoints.points; + var ps = datapoints.pointsize; + var num = Number(curvedLinesOptions.curvePointFactor) * (points.length / ps); + + var xdata = new Array; + var ydata = new Array; + + var curX = -1; + var curY = -1; + var j = 0; + + if (curvedLinesOptions.fit) { + //insert a point before and after the "real" data point to force the line + //to have a max,min at the data point. + + var fpDist; + if ( typeof curvedLinesOptions.fitPointDist == 'undefined') { + //estimate it + var minX = points[0]; + var maxX = points[points.length - ps]; + fpDist = (maxX - minX) / (500 * 100); + //x range / (estimated pixel length of placeholder * factor) + } else { + //use user defined value + fpDist = Number(curvedLinesOptions.fitPointDist); + } + + for (var i = 0; i < points.length; i += ps) { + + var frontX; + var backX; + curX = i; + curY = i + yPos; + + //add point X s + frontX = points[curX] - fpDist; + backX = points[curX] + fpDist; + + var factor = 2; + while (frontX == points[curX] || backX == points[curX]) { + //inside the ulp + frontX = points[curX] - (fpDist * factor); + backX = points[curX] + (fpDist * factor); + factor++; + } + + //add curve points + xdata[j] = frontX; + ydata[j] = points[curY]; + j++; + + xdata[j] = points[curX]; + ydata[j] = points[curY]; + j++; + + xdata[j] = backX; + ydata[j] = points[curY]; + j++; + } + } else { + //just use the datapoints + for (var i = 0; i < points.length; i += ps) { + curX = i; + curY = i + yPos; + + xdata[j] = points[curX]; + ydata[j] = points[curY]; + j++; + } + } + + var n = xdata.length; + + var y2 = new Array(); + var delta = new Array(); + y2[0] = 0; + y2[n - 1] = 0; + delta[0] = 0; + + for (var i = 1; i < n - 1; ++i) { + var d = (xdata[i + 1] - xdata[i - 1]); + if (d == 0) { + //point before current point and after current point need some space in between + return []; + } + + var s = (xdata[i] - xdata[i - 1]) / d; + var p = s * y2[i - 1] + 2; + y2[i] = (s - 1) / p; + delta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]); + delta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p; + } + + for (var j = n - 2; j >= 0; --j) { + y2[j] = y2[j] * y2[j + 1] + delta[j]; + } + + // xmax - xmin / #points + var step = (xdata[n - 1] - xdata[0]) / (num - 1); + + var xnew = new Array; + var ynew = new Array; + var result = new Array; + + xnew[0] = xdata[0]; + ynew[0] = ydata[0]; + + result.push(xnew[0]); + result.push(ynew[0]); + + for ( j = 1; j < num; ++j) { + //new x point (sampling point for the created curve) + xnew[j] = xnew[0] + j * step; + + var max = n - 1; + var min = 0; + + while (max - min > 1) { + var k = Math.round((max + min) / 2); + if (xdata[k] > xnew[j]) { + max = k; + } else { + min = k; + } + } + + //found point one to the left and one to the right of generated new point + var h = (xdata[max] - xdata[min]); + + if (h == 0) { + //similar to above two points from original x data need some space between them + return []; + } + + var a = (xdata[max] - xnew[j]) / h; + var b = (xnew[j] - xdata[min]) / h; + + ynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6; + + result.push(xnew[j]); + result.push(ynew[j]); + } + + return result; + } + + function hasInvalidParameters(curvedLinesOptions) { + if (typeof curvedLinesOptions.fit != 'undefined' || + typeof curvedLinesOptions.curvePointFactor != 'undefined' || + typeof curvedLinesOptions.fitPointDist != 'undefined') { + throw new Error("CurvedLines detected illegal parameters. The CurvedLines API changed with version 1.0.0 please check the options object."); + return true; + } + return false; + } + + + }//end init + + + $.plot.plugins.push({ + init : init, + options : options, + name : 'curvedLines', + version : '1.1.1' + }); + +})(jQuery); + diff --git a/src/lib/js/jqColorPicker.min.js b/src/lib/js/jqColorPicker.min.js new file mode 100644 index 0000000..30e5226 --- /dev/null +++ b/src/lib/js/jqColorPicker.min.js @@ -0,0 +1,3 @@ +/*! tinyColorPicker - v1.0.0 2015-09-06 */ + +!function(a,b){"use strict";function c(a,c,d,f,g){if("string"==typeof c){var c=t.txt2color(c);d=c.type,n[d]=c[d],g=g!==b?g:c.alpha}else if(c)for(var h in c)a[d][h]=k(c[h]/l[d][h][1],0,1);return g!==b&&(a.alpha=k(+g,0,1)),e(d,f?a:b)}function d(a,b,c){var d=m.options.grey,e={};return e.RGB={r:a.r,g:a.g,b:a.b},e.rgb={r:b.r,g:b.g,b:b.b},e.alpha=c,e.equivalentGrey=Math.round(d.r*a.r+d.g*a.g+d.b*a.b),e.rgbaMixBlack=i(b,{r:0,g:0,b:0},c,1),e.rgbaMixWhite=i(b,{r:1,g:1,b:1},c,1),e.rgbaMixBlack.luminance=h(e.rgbaMixBlack,!0),e.rgbaMixWhite.luminance=h(e.rgbaMixWhite,!0),m.options.customBG&&(e.rgbaMixCustom=i(b,m.options.customBG,c,1),e.rgbaMixCustom.luminance=h(e.rgbaMixCustom,!0),m.options.customBG.luminance=h(m.options.customBG,!0)),e}function e(a,b){var c,e,k,o=b||n,p=t,q=m.options,r=l,s=o.RND,u="",v="",w={hsl:"hsv",rgb:a},x=s.rgb;if("alpha"!==a){for(var y in r)if(!r[y][y]){a!==y&&(v=w[y]||"rgb",o[y]=p[v+"2"+y](o[v])),s[y]||(s[y]={}),c=o[y];for(u in c)s[y][u]=Math.round(c[u]*r[y][u][1])}x=s.rgb,o.HEX=p.RGB2HEX(x),o.equivalentGrey=q.grey.r*o.rgb.r+q.grey.g*o.rgb.g+q.grey.b*o.rgb.b,o.webSave=e=f(x,51),o.webSmart=k=f(x,17),o.saveColor=x.r===e.r&&x.g===e.g&&x.b===e.b?"web save":x.r===k.r&&x.g===k.g&&x.b===k.b?"web smart":"",o.hueRGB=t.hue2RGB(o.hsv.h),b&&(o.background=d(x,o.rgb,o.alpha))}var z,A,B,C=o.rgb,D=o.alpha,E="luminance",F=o.background;return z=i(C,{r:0,g:0,b:0},D,1),z[E]=h(z,!0),o.rgbaMixBlack=z,A=i(C,{r:1,g:1,b:1},D,1),A[E]=h(A,!0),o.rgbaMixWhite=A,q.customBG&&(B=i(C,F.rgbaMixCustom,D,1),B[E]=h(B,!0),B.WCAG2Ratio=j(B[E],F.rgbaMixCustom[E]),o.rgbaMixBGMixCustom=B,B.luminanceDelta=Math.abs(B[E]-F.rgbaMixCustom[E]),B.hueDelta=g(F.rgbaMixCustom,B,!0)),o.RGBLuminance=h(x),o.HUELuminance=h(o.hueRGB),q.convertCallback&&q.convertCallback(o,a),o}function f(a,b){var c={},d=0,e=b/2;for(var f in a)d=a[f]%b,c[f]=a[f]+(d>e?b-d:-d);return c}function g(a,b,c){return(Math.max(a.r-b.r,b.r-a.r)+Math.max(a.g-b.g,b.g-a.g)+Math.max(a.b-b.b,b.b-a.b))*(c?255:1)/765}function h(a,b){for(var c=b?1:255,d=[a.r/c,a.g/c,a.b/c],e=m.options.luminance,f=d.length;f--;)d[f]=d[f]<=.03928?d[f]/12.92:Math.pow((d[f]+.055)/1.055,2.4);return e.r*d[0]+e.g*d[1]+e.b*d[2]}function i(a,c,d,e){var f={},g=d!==b?d:1,h=e!==b?e:1,i=g+h*(1-g);for(var j in a)f[j]=(a[j]*g+c[j]*h*(1-g))/i;return f.a=i,f}function j(a,b){var c=1;return c=a>=b?(a+.05)/(b+.05):(b+.05)/(a+.05),Math.round(100*c)/100}function k(a,b,c){return a>c?c:b>a?b:a}var l={rgb:{r:[0,255],g:[0,255],b:[0,255]},hsv:{h:[0,360],s:[0,100],v:[0,100]},hsl:{h:[0,360],s:[0,100],l:[0,100]},alpha:{alpha:[0,1]},HEX:{HEX:[0,16777215]}},m={},n={},o={r:.298954,g:.586434,b:.114612},p={r:.2126,g:.7152,b:.0722},q=a.Colors=function(a){this.colors={RND:{}},this.options={color:"rgba(204, 82, 37, 0.8)",grey:o,luminance:p,valueRanges:l},r(this,a||{})},r=function(a,d){var e,f=a.options;s(a);for(var g in d)d[g]!==b&&(f[g]=d[g]);e=f.customBG,f.customBG="string"==typeof e?t.txt2color(e).rgb:e,n=c(a.colors,f.color,b,!0)},s=function(a){m!==a&&(m=a,n=a.colors)};q.prototype.setColor=function(a,d,f){return s(this),a?c(this.colors,a,d,b,f):(f!==b&&(this.colors.alpha=k(f,0,1)),e(d))},q.prototype.setCustomBackground=function(a){return s(this),this.options.customBG="string"==typeof a?t.txt2color(a).rgb:a,c(this.colors,b,"rgb")},q.prototype.saveAsBackground=function(){return s(this),c(this.colors,b,"rgb",!0)};var t={txt2color:function(a){var b={},c=a.replace(/(?:#|\)|%)/g,"").split("("),d=(c[1]||"").split(/,\s*/),e=c[1]?c[0].substr(0,3):"rgb",f="";if(b.type=e,b[e]={},c[1])for(var g=3;g--;)f=e[g]||e.charAt(g),b[e][f]=+d[g]/l[e][f][1];else b.rgb=t.HEX2rgb(c[0]);return b.alpha=d[3]?+d[3]:1,b},RGB2HEX:function(a){return((a.r<16?"0":"")+a.r.toString(16)+(a.g<16?"0":"")+a.g.toString(16)+(a.b<16?"0":"")+a.b.toString(16)).toUpperCase()},HEX2rgb:function(a){return a=a.split(""),{r:parseInt(a[0]+a[a[3]?1:0],16)/255,g:parseInt(a[a[3]?2:1]+(a[3]||a[1]),16)/255,b:parseInt((a[4]||a[2])+(a[5]||a[2]),16)/255}},hue2RGB:function(a){var b=6*a,c=~~b%6,d=6===b?0:b-c;return{r:Math.round(255*[1,1-d,0,0,d,1][c]),g:Math.round(255*[d,1,1,1-d,0,0][c]),b:Math.round(255*[0,0,d,1,1,1-d][c])}},rgb2hsv:function(a){var b,c,d,e=a.r,f=a.g,g=a.b,h=0;return g>f&&(f=g+(g=f,0),h=-1),c=g,f>e&&(e=f+(f=e,0),h=-2/6-h,c=Math.min(f,g)),b=e-c,d=e?b/e:0,{h:1e-15>d?n&&n.hsl&&n.hsl.h||0:b?Math.abs(h+(f-g)/(6*b)):0,s:e?b/e:n&&n.hsv&&n.hsv.s||0,v:e}},hsv2rgb:function(a){var b=6*a.h,c=a.s,d=a.v,e=~~b,f=b-e,g=d*(1-c),h=d*(1-f*c),i=d*(1-(1-f)*c),j=e%6;return{r:[d,h,g,g,i,d][j],g:[i,d,d,h,g,g][j],b:[g,g,i,d,d,h][j]}},hsv2hsl:function(a){var b=(2-a.s)*a.v,c=a.s*a.v;return c=a.s?1>b?b?c/b:0:c/(2-b):0,{h:a.h,s:a.v||c?c:n&&n.hsl&&n.hsl.s||0,l:b/2}},rgb2hsl:function(a,b){var c=t.rgb2hsv(a);return t.hsv2hsl(b?c:n.hsv=c)},hsl2rgb:function(a){var b=6*a.h,c=a.s,d=a.l,e=.5>d?d*(1+c):d+c-c*d,f=d+d-e,g=e?(e-f)/e:0,h=~~b,i=b-h,j=e*g*i,k=f+j,l=e-j,m=h%6;return{r:[e,l,f,f,k,e][m],g:[k,e,e,l,f,f][m],b:[f,f,k,e,e,l][m]}}}}(window),function(a,b,c){"use strict";function d(b){return b.value||b.getAttribute("value")||a(b).css("background-color")||"#fff"}function e(a){return a=a.originalEvent&&a.originalEvent.touches?a.originalEvent.touches[0]:a,a.originalEvent?a.originalEvent:a}function f(b){return a(b.find(r.doRender)[0]||b[0])}function g(b){var c=a(this),e=c.offset(),g=a(window),i=r.gap;b?(s=f(c),p.$trigger=c,(t||h()).css({left:(t[0]._left=e.left)-((t[0]._left=t[0]._left+t[0]._width-(g.scrollLeft()+g.width()))+i>0?t[0]._left+i:0),top:(t[0]._top=e.top+c.outerHeight())-((t[0]._top=t[0]._top+t[0]._height-(g.scrollTop()+g.height()))+i>0?t[0]._top+i:0)}).show(r.animationSpeed,function(){b!==!0&&(x._width=x.width(),u._width=u.width(),u._height=u.height(),q.setColor(d(s[0])),m(!0))})):a(t).hide(r.animationSpeed,function(){s.blur(),p.$trigger=null,m(!1)})}function h(){return a("head").append('"),p.$UI=t=a(G).css({margin:r.margin}).appendTo("body").show(0,function(){var b=a(this);E=r.GPU&&b.css("perspective")!==c,u=a(".cp-xy-slider",this),v=a(".cp-xy-cursor",this),w=a(".cp-z-cursor",this),x=a(".cp-alpha",this).toggle(!!r.opacity),y=a(".cp-alpha-cursor",this),r.buildCallback.call(p,b),b.prepend("
").children().eq(0).css("width",b.children().eq(0).width()),this._width=this.offsetWidth,this._height=this.offsetHeight}).hide().on(C,".cp-xy-slider,.cp-z-slider,.cp-alpha",i)}function i(b){var c=this.className.replace(/cp-(.*?)(?:\s*|$)/,"$1").replace("-","_");b.preventDefault&&b.preventDefault(),b.returnValue=!1,s._offset=a(this).offset(),(c="xy_slider"===c?j:"z_slider"===c?k:l)(b),m(),z.on(D,function(){z.off(".a")}).on(B,function(a){c(a),m()})}function j(a){var b=e(a),c=b.pageX-s._offset.left,d=b.pageY-s._offset.top;q.setColor({s:c/u._width*100,v:100-d/u._height*100},"hsv")}function k(a){var b=e(a).pageY-s._offset.top;q.setColor({h:360-b/u._height*360},"hsv")}function l(a){var b=e(a).pageX-s._offset.left,c=b/x._width;q.setColor({},"rgb",c)}function m(a){var b=q.colors,d=b.hueRGB,e=b.RND.rgb,f=b.RND.hsl,g="#222",h="#ddd",i=s.data("colorMode"),j=1!==b.alpha,k=Math.round(100*b.alpha)/100,l=e.r+", "+e.g+", "+e.b,m="HEX"!==i||j?"rgb"===i||"HEX"===i&&j?j?"rgba("+l+", "+k+")":"rgb("+l+")":"hsl"+(j?"a(":"(")+f.h+", "+f.s+"%, "+f.l+"%"+(j?", "+k:"")+")":"#"+b.HEX,o=b.HUELuminance>.22?g:h,p=b.rgbaMixBlack.luminance>.22?g:h,r=(1-b.hsv.h)*u._height,t=b.hsv.s*u._width,z=(1-b.hsv.v)*u._height,A=k*x._width,B=E?"translate3d":"",C=s.val(),D=s[0].hasAttribute("value")&&""===C&&a!==c;u._css={backgroundColor:"rgb("+d.r+","+d.g+","+d.b+")"},v._css={transform:B+"("+t+"px, "+z+"px, 0)",left:E?"":t,top:E?"":z,borderColor:b.RGBLuminance>.22?g:h},w._css={transform:B+"(0, "+r+"px, 0)",top:E?"":r,borderColor:"transparent "+o},x._css={backgroundColor:"rgb("+l+")"},y._css={transform:B+"("+A+"px, 0, 0)",left:E?"":A,borderColor:p+" transparent"},s._css={backgroundColor:D?"":m,color:D?"":b.rgbaMixBGMixCustom.luminance>.22?g:h},s.text=D?"":C!==m?m:"",a!==c?n(a):F(n)}function n(a){u.css(u._css),v.css(v._css),w.css(w._css),x.css(x._css),y.css(y._css),r.doRender&&s.css(s._css),s.text&&s.val(s.text),r.renderCallback.call(p,s,"boolean"==typeof a?a:c)}var o,p,q,r,s,t,u,v,w,x,y,z=a(document),A="",B="touchmove.a mousemove.a pointermove.a",C="touchstart.a mousedown.a pointerdown.a",D="touchend.a mouseup.a pointerup.a",E=!1,F=window.requestAnimationFrame||window.webkitRequestAnimationFrame||function(a){a()},G='
',H=".cp-color-picker{position:absolute;overflow:hidden;padding:6px 6px 0;background-color:#444;color:#bbb;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:400;cursor:default;border-radius:5px}.cp-color-picker>div{position:relative;overflow:hidden}.cp-xy-slider{float:left;height:128px;width:128px;margin-bottom:6px;background:linear-gradient(to right,#FFF,rgba(255,255,255,0))}.cp-white{height:100%;width:100%;background:linear-gradient(rgba(0,0,0,0),#000)}.cp-xy-cursor{position:absolute;top:0;width:10px;height:10px;margin:-5px;border:1px solid #fff;border-radius:100%;box-sizing:border-box}.cp-z-slider{float:right;margin-left:6px;height:128px;width:20px;background:linear-gradient(red 0,#f0f 17%,#00f 33%,#0ff 50%,#0f0 67%,#ff0 83%,red 100%)}.cp-z-cursor{position:absolute;margin-top:-4px;width:100%;border:4px solid #fff;border-color:transparent #fff;box-sizing:border-box}.cp-alpha{clear:both;width:100%;height:16px;margin:6px 0;background:linear-gradient(to right,#444,rgba(0,0,0,0))}.cp-alpha-cursor{position:absolute;margin-left:-4px;height:100%;border:4px solid #fff;border-color:#fff transparent;box-sizing:border-box}",I=function(a){q=this.color=new b(a),r=q.options};I.prototype={render:m,toggle:g},a.fn.colorPicker=function(b){var c=function(){};return b=a.extend({animationSpeed:150,GPU:!0,doRender:!0,customBG:"#FFF",opacity:!0,renderCallback:c,buildCallback:c,body:document.body,scrollResize:!0,gap:4},b),!p&&b.scrollResize&&a(window).on("resize.a scroll.a",function(){p.$trigger&&p.toggle.call(p.$trigger[0],!0)}),o=o?o.add(this):this,o.colorPicker=p||(p=new I(b)),A+=(A?", ":"")+this.selector,a(b.body).off(".a").on(C,function(b){var c=a(b.target);-1!==a.inArray(c.closest(A)[0],o)||c.closest(t).length||g()}).on("focus.a click.a",A,g).on("change.a",A,function(){q.setColor(this.value||"#FFF"),o.colorPicker.render(!0)}),this.each(function(){var c=d(this),e=c.split("("),g=f(a(this));g.data("colorMode",e[1]?e[0].substr(0,3):"HEX").attr("readonly",r.preventFocus),b.doRender&&g.css({"background-color":c,color:function(){return q.setColor(c).rgbaMixBGMixCustom.luminance>.22?"#222":"#ddd"}})})},a.fn.colorPicker.destroy=function(){a(p.color.options.body).off(".a"),p.toggle(!1),o=null,A=""}}(jQuery,Colors); diff --git a/src/lib/js/jquery-deparam.js b/src/lib/js/jquery-deparam.js new file mode 100644 index 0000000..4fac917 --- /dev/null +++ b/src/lib/js/jquery-deparam.js @@ -0,0 +1,112 @@ +(function(deparam){ + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + var jquery = require('jquery'); + module.exports = deparam(jquery); + } else if (typeof define === 'function' && define.amd){ + define(['jquery'], function(jquery){ + return deparam(jquery); + }); + } else { + var global + try { + global = (false || eval)('this'); // best cross-browser way to determine global for < ES5 + } catch (e) { + global = window; // fails only if browser (https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives) + } + global.deparam = deparam(jQuery); // assume jQuery is in global namespace + } +})(function ($) { + var deparam = function( params, coerce ) { + var obj = {}, + coerce_types = { 'true': !0, 'false': !1, 'null': null }; + + // Iterate over all name=value pairs. + params.replace(/\+/g, ' ').split('&').forEach(function(v){ + var param = v.split( '=' ), + key = decodeURIComponent( param[0] ), + val, + cur = obj, + i = 0, + + // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it + // into its component parts. + keys = key.split( '][' ), + keys_last = keys.length - 1; + + // If the first keys part contains [ and the last ends with ], then [] + // are correctly balanced. + if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) { + // Remove the trailing ] from the last keys part. + keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' ); + + // Split first keys part into two parts on the [ and add them back onto + // the beginning of the keys array. + keys = keys.shift().split('[').concat( keys ); + + keys_last = keys.length - 1; + } else { + // Basic 'foo' style key. + keys_last = 0; + } + + // Are we dealing with a name=value pair, or just a name? + if ( param.length === 2 ) { + val = decodeURIComponent( param[1] ); + + // Coerce values. + if ( coerce ) { + val = val && !isNaN(val) && ((+val + '') === val) ? +val // number + : val === 'undefined' ? undefined // undefined + : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null + : val; // string + } + + if ( keys_last ) { + // Complex key, build deep object structure based on a few rules: + // * The 'cur' pointer starts at the object top-level. + // * [] = array push (n is set to array length), [n] = array if n is + // numeric, otherwise object. + // * If at the last keys part, set the value. + // * For each keys part, if the current level is undefined create an + // object or array based on the type of the next keys part. + // * Move the 'cur' pointer to the next level. + // * Rinse & repeat. + for ( ; i <= keys_last; i++ ) { + key = keys[i] === '' ? cur.length : keys[i]; + cur = cur[key] = i < keys_last + ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) + : val; + } + + } else { + // Simple key, even simpler rules, since only scalars and shallow + // arrays are allowed. + + if ( Object.prototype.toString.call( obj[key] ) === '[object Array]' ) { + // val is already an array, so push on the next value. + obj[key].push( val ); + + } else if ( {}.hasOwnProperty.call(obj, key) ) { + // val isn't an array, but since a second value has been specified, + // convert val into an array. + obj[key] = [ obj[key], val ]; + + } else { + // val is a scalar. + obj[key] = val; + } + } + + } else if ( key ) { + // No value was defined, so set something meaningful. + obj[key] = coerce + ? undefined + : ''; + } + }); + + return obj; + }; + $.prototype.deparam = $.deparam = deparam; + return deparam; +}); diff --git a/src/lib/js/jquery.colorpicker.js b/src/lib/js/jquery.colorpicker.js new file mode 100644 index 0000000..c095867 --- /dev/null +++ b/src/lib/js/jquery.colorpicker.js @@ -0,0 +1,3264 @@ +/*jslint devel: true, bitwise: true, regexp: true, browser: true, confusion: true, unparam: true, eqeq: true, white: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */ +/*globals jQuery,Color,define */ + +/*! + * ColorPicker + * + * Copyright (c) 2011-2017 Martijn W. van der Lee + * Licensed under the MIT. + */ +/* Full-featured colorpicker for jQueryUI with full theming support. + * Most images from jPicker by Christopher T. Tillman. + * Sourcecode created from scratch by Martijn W. van der Lee. + */ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ + "jquery" + ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} (function ($) { + "use strict"; + + var _colorpicker_index = 0, + + _container_popup = '', + _container_inlineFrame = '
', + _container_inline = '
', + + _intToHex = function (dec) { + var result = Math.round(dec).toString(16); + if (result.length === 1) { + result = ('0' + result); + } + return result.toLowerCase(); + }, + + _keycode = { + isPrint: function(keycode) { + return keycode == 32 // spacebar + || (keycode >= 48 && keycode <= 57) // number keys + || (keycode >= 65 && keycode <= 90) // letter keys + || (keycode >= 96 && keycode <= 111) // numpad keys + || (keycode >= 186 && keycode < 192) // ;=,-./` (in order) + || (keycode >= 219 && keycode < 222); // [\]' (in order) + }, + isHex: function(keycode) { + return (keycode >= 48 && keycode <= 57) // number keys + || (keycode >= 65 && keycode <= 70); // a-f + } + }, + + _layoutTable = function(layout, callback) { + var bitmap, + x, y, + width, height, + columns, rows, + index, + cell, + html, + w, h, + colspan, + walked; + + layout.sort(function(a, b) { + if (a.pos[1] === b.pos[1]) { + return a.pos[0] - b.pos[0]; + } + return a.pos[1] - b.pos[1]; + }); + + // Determine dimensions of the table + width = 0; + height = 0; + $.each (layout, function(index, part) { + width = Math.max(width, part.pos[0] + part.pos[2]); + height = Math.max(height, part.pos[1] + part.pos[3]); + }); + + // Initialize bitmap + bitmap = []; + for (x = 0; x < width; ++x) { + bitmap.push([]); + } + + // Mark rows and columns which have layout assigned + rows = []; + columns = []; + $.each(layout, function(index, part) { + // mark columns + for (x = 0; x < part.pos[2]; x += 1) { + columns[part.pos[0] + x] = true; + } + for (y = 0; y < part.pos[3]; y += 1) { + rows[part.pos[1] + y] = true; + } + }); + + // Generate the table + html = ''; + cell = layout[index = 0]; + for (y = 0; y < height; ++y) { + html += ''; + x = 0; + while (x < width) { + if (typeof cell !== 'undefined' && x === cell.pos[0] && y === cell.pos[1]) { + // Create a "real" cell + html += callback(cell, x, y); + + for (h = 0; h < cell.pos[3]; h +=1) { + for (w = 0; w < cell.pos[2]; w +=1) { + bitmap[x + w][y + h] = true; + } + } + + x += cell.pos[2]; + cell = layout[++index]; + } else { + // Fill in the gaps + colspan = 0; + walked = false; + + while (x < width && bitmap[x][y] === undefined && (cell === undefined || y < cell.pos[1] || (y === cell.pos[1] && x < cell.pos[0]))) { + if (columns[x] === true) { + colspan += 1; + } + walked = true; + x += 1; + } + + if (colspan > 0) { + html += ''; + } else if (!walked) { + x += 1; + } + } + } + html += ''; + } + + return '' + html + '
'; + }; + + $.colorpicker = new function() { + this.regional = { + '': { + ok: 'OK', + cancel: 'Cancel', + none: 'None', + button: 'Color', + title: 'Pick a color', + transparent: 'Transparent', + hsvH: 'H', + hsvS: 'S', + hsvV: 'V', + rgbR: 'R', + rgbG: 'G', + rgbB: 'B', + labL: 'L', + labA: 'a', + labB: 'b', + hslH: 'H', + hslS: 'S', + hslL: 'L', + cmykC: 'C', + cmykM: 'M', + cmykY: 'Y', + cmykK: 'K', + alphaA: 'A' + } + }; + + this.swatchesNames = { + 'html': 'HTML' + }; + + this.swatches = { + 'html': [ + {name: 'black', r: 0, g: 0, b: 0}, + {name: 'dimgray', r: 0.4117647058823529, g: 0.4117647058823529, b: 0.4117647058823529}, + {name: 'gray', r: 0.5019607843137255, g: 0.5019607843137255, b: 0.5019607843137255}, + {name: 'darkgray', r: 0.6627450980392157, g: 0.6627450980392157, b: 0.6627450980392157}, + {name: 'silver', r: 0.7529411764705882, g: 0.7529411764705882, b: 0.7529411764705882}, + {name: 'lightgrey', r: 0.8274509803921568, g: 0.8274509803921568, b: 0.8274509803921568}, + {name: 'gainsboro', r: 0.8627450980392157, g: 0.8627450980392157, b: 0.8627450980392157}, + {name: 'whitesmoke', r: 0.9607843137254902, g: 0.9607843137254902, b: 0.9607843137254902}, + {name: 'white', r: 1, g: 1, b: 1}, + {name: 'rosybrown', r: 0.7372549019607844, g: 0.5607843137254902, b: 0.5607843137254902}, + {name: 'indianred', r: 0.803921568627451, g: 0.3607843137254902, b: 0.3607843137254902}, + {name: 'brown', r: 0.6470588235294118, g: 0.16470588235294117, b: 0.16470588235294117}, + {name: 'firebrick', r: 0.6980392156862745, g: 0.13333333333333333, b: 0.13333333333333333}, + {name: 'lightcoral', r: 0.9411764705882353, g: 0.5019607843137255, b: 0.5019607843137255}, + {name: 'maroon', r: 0.5019607843137255, g: 0, b: 0}, + {name: 'darkred', r: 0.5450980392156862, g: 0, b: 0}, + {name: 'red', r: 1, g: 0, b: 0}, + {name: 'snow', r: 1, g: 0.9803921568627451, b: 0.9803921568627451}, + {name: 'salmon', r: 0.9803921568627451, g: 0.5019607843137255, b: 0.4470588235294118}, + {name: 'mistyrose', r: 1, g: 0.8941176470588236, b: 0.8823529411764706}, + {name: 'tomato', r: 1, g: 0.38823529411764707, b: 0.2784313725490196}, + {name: 'darksalmon', r: 0.9137254901960784, g: 0.5882352941176471, b: 0.47843137254901963}, + {name: 'orangered', r: 1, g: 0.27058823529411763, b: 0}, + {name: 'coral', r: 1, g: 0.4980392156862745, b: 0.3137254901960784}, + {name: 'lightsalmon', r: 1, g: 0.6274509803921569, b: 0.47843137254901963}, + {name: 'sienna', r: 0.6274509803921569, g: 0.3215686274509804, b: 0.17647058823529413}, + {name: 'seashell', r: 1, g: 0.9607843137254902, b: 0.9333333333333333}, + {name: 'chocolate', r: 0.8235294117647058, g: 0.4117647058823529, b: 0.11764705882352941}, + {name: 'saddlebrown', r: 0.5450980392156862, g: 0.27058823529411763, b: 0.07450980392156863}, + {name: 'sandybrown', r: 0.9568627450980393, g: 0.6431372549019608, b: 0.3764705882352941}, + {name: 'peachpuff', r: 1, g: 0.8549019607843137, b: 0.7254901960784313}, + {name: 'peru', r: 0.803921568627451, g: 0.5215686274509804, b: 0.24705882352941178}, + {name: 'linen', r: 0.9803921568627451, g: 0.9411764705882353, b: 0.9019607843137255}, + {name: 'darkorange', r: 1, g: 0.5490196078431373, b: 0}, + {name: 'bisque', r: 1, g: 0.8941176470588236, b: 0.7686274509803922}, + {name: 'burlywood', r: 0.8705882352941177, g: 0.7215686274509804, b: 0.5294117647058824}, + {name: 'tan', r: 0.8235294117647058, g: 0.7058823529411765, b: 0.5490196078431373}, + {name: 'antiquewhite', r: 0.9803921568627451, g: 0.9215686274509803, b: 0.8431372549019608}, + {name: 'navajowhite', r: 1, g: 0.8705882352941177, b: 0.6784313725490196}, + {name: 'blanchedalmond', r: 1, g: 0.9215686274509803, b: 0.803921568627451}, + {name: 'papayawhip', r: 1, g: 0.9372549019607843, b: 0.8352941176470589}, + {name: 'orange', r: 1, g: 0.6470588235294118, b: 0}, + {name: 'moccasin', r: 1, g: 0.8941176470588236, b: 0.7098039215686275}, + {name: 'wheat', r: 0.9607843137254902, g: 0.8705882352941177, b: 0.7019607843137254}, + {name: 'oldlace', r: 0.9921568627450981, g: 0.9607843137254902, b: 0.9019607843137255}, + {name: 'floralwhite', r: 1, g: 0.9803921568627451, b: 0.9411764705882353}, + {name: 'goldenrod', r: 0.8549019607843137, g: 0.6470588235294118, b: 0.12549019607843137}, + {name: 'darkgoldenrod', r: 0.7215686274509804, g: 0.5254901960784314, b: 0.043137254901960784}, + {name: 'cornsilk', r: 1, g: 0.9725490196078431, b: 0.8627450980392157}, + {name: 'gold', r: 1, g: 0.8431372549019608, b: 0}, + {name: 'palegoldenrod', r: 0.9333333333333333, g: 0.9098039215686274, b: 0.6666666666666666}, + {name: 'khaki', r: 0.9411764705882353, g: 0.9019607843137255, b: 0.5490196078431373}, + {name: 'lemonchiffon', r: 1, g: 0.9803921568627451, b: 0.803921568627451}, + {name: 'darkkhaki', r: 0.7411764705882353, g: 0.7176470588235294, b: 0.4196078431372549}, + {name: 'beige', r: 0.9607843137254902, g: 0.9607843137254902, b: 0.8627450980392157}, + {name: 'lightgoldenrodyellow', r: 0.9803921568627451, g: 0.9803921568627451, b: 0.8235294117647058}, + {name: 'olive', r: 0.5019607843137255, g: 0.5019607843137255, b: 0}, + {name: 'yellow', r: 1, g: 1, b: 0}, + {name: 'lightyellow', r: 1, g: 1, b: 0.8784313725490196}, + {name: 'ivory', r: 1, g: 1, b: 0.9411764705882353}, + {name: 'olivedrab', r: 0.4196078431372549, g: 0.5568627450980392, b: 0.13725490196078433}, + {name: 'yellowgreen', r: 0.6039215686274509, g: 0.803921568627451, b: 0.19607843137254902}, + {name: 'darkolivegreen', r: 0.3333333333333333, g: 0.4196078431372549, b: 0.1843137254901961}, + {name: 'greenyellow', r: 0.6784313725490196, g: 1, b: 0.1843137254901961}, + {name: 'lawngreen', r: 0.48627450980392156, g: 0.9882352941176471, b: 0}, + {name: 'chartreuse', r: 0.4980392156862745, g: 1, b: 0}, + {name: 'darkseagreen', r: 0.5607843137254902, g: 0.7372549019607844, b: 0.5607843137254902}, + {name: 'forestgreen', r: 0.13333333333333333, g: 0.5450980392156862, b: 0.13333333333333333}, + {name: 'limegreen', r: 0.19607843137254902, g: 0.803921568627451, b: 0.19607843137254902}, + {name: 'lightgreen', r: 0.5647058823529412, g: 0.9333333333333333, b: 0.5647058823529412}, + {name: 'palegreen', r: 0.596078431372549, g: 0.984313725490196, b: 0.596078431372549}, + {name: 'darkgreen', r: 0, g: 0.39215686274509803, b: 0}, + {name: 'green', r: 0, g: 0.5019607843137255, b: 0}, + {name: 'lime', r: 0, g: 1, b: 0}, + {name: 'honeydew', r: 0.9411764705882353, g: 1, b: 0.9411764705882353}, + {name: 'mediumseagreen', r: 0.23529411764705882, g: 0.7019607843137254, b: 0.44313725490196076}, + {name: 'seagreen', r: 0.1803921568627451, g: 0.5450980392156862, b: 0.3411764705882353}, + {name: 'springgreen', r: 0, g: 1, b: 0.4980392156862745}, + {name: 'mintcream', r: 0.9607843137254902, g: 1, b: 0.9803921568627451}, + {name: 'mediumspringgreen', r: 0, g: 0.9803921568627451, b: 0.6039215686274509}, + {name: 'mediumaquamarine', r: 0.4, g: 0.803921568627451, b: 0.6666666666666666}, + {name: 'aquamarine', r: 0.4980392156862745, g: 1, b: 0.8313725490196079}, + {name: 'turquoise', r: 0.25098039215686274, g: 0.8784313725490196, b: 0.8156862745098039}, + {name: 'lightseagreen', r: 0.12549019607843137, g: 0.6980392156862745, b: 0.6666666666666666}, + {name: 'mediumturquoise', r: 0.2823529411764706, g: 0.8196078431372549, b: 0.8}, + {name: 'darkslategray', r: 0.1843137254901961, g: 0.30980392156862746, b: 0.30980392156862746}, + {name: 'paleturquoise', r: 0.6862745098039216, g: 0.9333333333333333, b: 0.9333333333333333}, + {name: 'teal', r: 0, g: 0.5019607843137255, b: 0.5019607843137255}, + {name: 'darkcyan', r: 0, g: 0.5450980392156862, b: 0.5450980392156862}, + {name: 'darkturquoise', r: 0, g: 0.807843137254902, b: 0.8196078431372549}, + {name: 'aqua', r: 0, g: 1, b: 1}, + {name: 'cyan', r: 0, g: 1, b: 1}, + {name: 'lightcyan', r: 0.8784313725490196, g: 1, b: 1}, + {name: 'azure', r: 0.9411764705882353, g: 1, b: 1}, + {name: 'cadetblue', r: 0.37254901960784315, g: 0.6196078431372549, b: 0.6274509803921569}, + {name: 'powderblue', r: 0.6901960784313725, g: 0.8784313725490196, b: 0.9019607843137255}, + {name: 'lightblue', r: 0.6784313725490196, g: 0.8470588235294118, b: 0.9019607843137255}, + {name: 'deepskyblue', r: 0, g: 0.7490196078431373, b: 1}, + {name: 'skyblue', r: 0.5294117647058824, g: 0.807843137254902, b: 0.9215686274509803}, + {name: 'lightskyblue', r: 0.5294117647058824, g: 0.807843137254902, b: 0.9803921568627451}, + {name: 'steelblue', r: 0.27450980392156865, g: 0.5098039215686274, b: 0.7058823529411765}, + {name: 'aliceblue', r: 0.9411764705882353, g: 0.9725490196078431, b: 1}, + {name: 'dodgerblue', r: 0.11764705882352941, g: 0.5647058823529412, b: 1}, + {name: 'slategray', r: 0.4392156862745098, g: 0.5019607843137255, b: 0.5647058823529412}, + {name: 'lightslategray', r: 0.4666666666666667, g: 0.5333333333333333, b: 0.6}, + {name: 'lightsteelblue', r: 0.6901960784313725, g: 0.7686274509803922, b: 0.8705882352941177}, + {name: 'cornflowerblue', r: 0.39215686274509803, g: 0.5843137254901961, b: 0.9294117647058824}, + {name: 'royalblue', r: 0.2549019607843137, g: 0.4117647058823529, b: 0.8823529411764706}, + {name: 'midnightblue', r: 0.09803921568627451, g: 0.09803921568627451, b: 0.4392156862745098}, + {name: 'lavender', r: 0.9019607843137255, g: 0.9019607843137255, b: 0.9803921568627451}, + {name: 'navy', r: 0, g: 0, b: 0.5019607843137255}, + {name: 'darkblue', r: 0, g: 0, b: 0.5450980392156862}, + {name: 'mediumblue', r: 0, g: 0, b: 0.803921568627451}, + {name: 'blue', r: 0, g: 0, b: 1}, + {name: 'ghostwhite', r: 0.9725490196078431, g: 0.9725490196078431, b: 1}, + {name: 'darkslateblue', r: 0.2823529411764706, g: 0.23921568627450981, b: 0.5450980392156862}, + {name: 'slateblue', r: 0.41568627450980394, g: 0.35294117647058826, b: 0.803921568627451}, + {name: 'mediumslateblue', r: 0.4823529411764706, g: 0.40784313725490196, b: 0.9333333333333333}, + {name: 'mediumpurple', r: 0.5764705882352941, g: 0.4392156862745098, b: 0.8588235294117647}, + {name: 'blueviolet', r: 0.5411764705882353, g: 0.16862745098039217, b: 0.8862745098039215}, + {name: 'indigo', r: 0.29411764705882354, g: 0, b: 0.5098039215686274}, + {name: 'darkorchid', r: 0.6, g: 0.19607843137254902, b: 0.8}, + {name: 'darkviolet', r: 0.5803921568627451, g: 0, b: 0.8274509803921568}, + {name: 'mediumorchid', r: 0.7294117647058823, g: 0.3333333333333333, b: 0.8274509803921568}, + {name: 'thistle', r: 0.8470588235294118, g: 0.7490196078431373, b: 0.8470588235294118}, + {name: 'plum', r: 0.8666666666666667, g: 0.6274509803921569, b: 0.8666666666666667}, + {name: 'violet', r: 0.9333333333333333, g: 0.5098039215686274, b: 0.9333333333333333}, + {name: 'purple', r: 0.5019607843137255, g: 0, b: 0.5019607843137255}, + {name: 'darkmagenta', r: 0.5450980392156862, g: 0, b: 0.5450980392156862}, + {name: 'magenta', r: 1, g: 0, b: 1}, + {name: 'fuchsia', r: 1, g: 0, b: 1}, + {name: 'orchid', r: 0.8549019607843137, g: 0.4392156862745098, b: 0.8392156862745098}, + {name: 'mediumvioletred', r: 0.7803921568627451, g: 0.08235294117647059, b: 0.5215686274509804}, + {name: 'deeppink', r: 1, g: 0.0784313725490196, b: 0.5764705882352941}, + {name: 'hotpink', r: 1, g: 0.4117647058823529, b: 0.7058823529411765}, + {name: 'palevioletred', r: 0.8588235294117647, g: 0.4392156862745098, b: 0.5764705882352941}, + {name: 'lavenderblush', r: 1, g: 0.9411764705882353, b: 0.9607843137254902}, + {name: 'crimson', r: 0.8627450980392157, g: 0.0784313725490196, b: 0.23529411764705882}, + {name: 'pink', r: 1, g: 0.7529411764705882, b: 0.796078431372549}, + {name: 'lightpink', r: 1, g: 0.7137254901960784, b: 0.7568627450980392} + ] + }; + + this.writers = { + '#HEX': function(color, that) { + return that._formatColor('#rxgxbx', color); + } + , '#HEX3': function(color, that) { + var hex3 = $.colorpicker.writers.HEX3(color); + return hex3 === false? false : '#'+hex3; + } + , 'HEX': function(color, that) { + return that._formatColor('rxgxbx', color); + } + , 'HEX3': function(color, that) { + var rgb = color.getRGB(), + r = Math.round(rgb.r * 255), + g = Math.round(rgb.g * 255), + b = Math.round(rgb.b * 255); + + if (((r >>> 4) === (r &= 0xf)) + && ((g >>> 4) === (g &= 0xf)) + && ((b >>> 4) === (b &= 0xf))) { + return r.toString(16)+g.toString(16)+b.toString(16); + } + return false; + } + , '#HEXA': function(color, that) { + return that._formatColor('#rxgxbxax', color); + } + , '#HEXA4': function(color, that) { + var hexa4 = $.colorpicker.writers.HEXA4(color, that); + return hexa4 === false? false : '#'+hexa4; + } + , 'HEXA': function(color, that) { + return that._formatColor('rxgxbxax', color); + } + , 'HEXA4': function(color, that) { + var a = Math.round(color.getAlpha() * 255); + + if ((a >>> 4) === (a &= 0xf)) { + return $.colorpicker.writers.HEX3(color, that)+a.toString(16); + } + return false; + } + , 'RGB': function(color, that) { + return color.getAlpha() >= 1 + ? that._formatColor('rgb(rd,gd,bd)', color) + : false; + } + , 'RGBA': function(color, that) { + return that._formatColor('rgba(rd,gd,bd,af)', color); + } + , 'RGB%': function(color, that) { + return color.getAlpha() >= 1 + ? that._formatColor('rgb(rp%,gp%,bp%)', color) + : false; + } + , 'RGBA%': function(color, that) { + return that._formatColor('rgba(rp%,gp%,bp%,af)', color); + } + , 'HSL': function(color, that) { + return color.getAlpha() >= 1 + ? that._formatColor('hsl(hd,sd,vd)', color) + : false; + } + , 'HSLA': function(color, that) { + return that._formatColor('hsla(hd,sd,vd,af)', color); + } + , 'HSL%': function(color, that) { + return color.getAlpha() >= 1 + ? that._formatColor('hsl(hp%,sp%,vp%)', color) + : false; + } + , 'HSLA%': function(color, that) { + return that._formatColor('hsla(hp%,sp%,vp%,af)', color); + } + , 'NAME': function(color, that) { + return that._closestName(color); + } + , 'EXACT': function(color, that) { + return that._exactName(color); + } + }; + + this.parsers = { + '': function(color) { + if (color === '') { + return new $.colorpicker.Color(); + } + } + , 'NAME': function(color, that) { + var c = that._getSwatch($.trim(color)); + if (c) { + return new $.colorpicker.Color(c.r, c.g, c.b); + } + } + , 'RGBA': function(color) { + var m = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return new $.colorpicker.Color( + m[1] / 255, + m[2] / 255, + m[3] / 255, + parseFloat(m[4]) + ); + } + } + , 'RGBA%': function(color) { + var m = /^rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return new $.colorpicker.Color( + m[1] / 100, + m[2] / 100, + m[3] / 100, + m[4] / 100 + ); + } + } + , 'HSLA': function(color) { + var m = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return (new $.colorpicker.Color()).setHSL( + m[1] / 255, + m[2] / 255, + m[3] / 255).setAlpha(parseFloat(m[4])); + } + } + , 'HSLA%': function(color) { + var m = /^hsla?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)$/.exec(color); + if (m) { + return (new $.colorpicker.Color()).setHSL( + m[1] / 100, + m[2] / 100, + m[3] / 100).setAlpha(m[4] / 100); + } + } + , '#HEX': function(color) { + var m = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(m[1], 16) / 255, + parseInt(m[2], 16) / 255, + parseInt(m[3], 16) / 255 + ); + } + } + , '#HEX3': function(color) { + var m = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(String(m[1]) + m[1], 16) / 255, + parseInt(String(m[2]) + m[2], 16) / 255, + parseInt(String(m[3]) + m[3], 16) / 255 + ); + } + } + , 'HEX': function(color) { + var m = /^([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(m[1], 16) / 255, + parseInt(m[2], 16) / 255, + parseInt(m[3], 16) / 255 + ); + } + } + , 'HEX3': function(color) { + var m = /^([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(String(m[1]) + m[1], 16) / 255, + parseInt(String(m[2]) + m[2], 16) / 255, + parseInt(String(m[3]) + m[3], 16) / 255 + ); + } + } + , '#HEXA': function(color) { + var m = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(m[1], 16) / 255, + parseInt(m[2], 16) / 255, + parseInt(m[3], 16) / 255, + parseInt(m[4], 16) / 255 + ); + } + } + , '#HEXA4': function(color) { + var m = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(String(m[1]) + m[1], 16) / 255, + parseInt(String(m[2]) + m[2], 16) / 255, + parseInt(String(m[3]) + m[3], 16) / 255, + parseInt(String(m[4]) + m[4], 16) / 255 + ); + } + } + , 'HEXA': function(color) { + var m = /^([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(m[1], 16) / 255, + parseInt(m[2], 16) / 255, + parseInt(m[3], 16) / 255, + parseInt(m[4], 16) / 255 + ); + } + } + , 'HEXA4': function(color) { + var m = /^([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color); + if (m) { + return new $.colorpicker.Color( + parseInt(String(m[1]) + m[1], 16) / 255, + parseInt(String(m[2]) + m[2], 16) / 255, + parseInt(String(m[3]) + m[3], 16) / 255, + parseInt(String(m[4]) + m[4], 16) / 255 + ); + } + } + }; + + this.partslists = { + 'full': ['header', 'map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'lab', 'cmyk', 'preview', 'swatches', 'footer'], + 'popup': ['map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview', 'footer'], + 'draggable': ['header', 'map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview', 'footer'], + 'inline': ['map', 'bar', 'hex', 'hsv', 'rgb', 'alpha', 'preview'] + }; + + this.limits = { + 'websafe': function(color) { + color.limit(6); + }, + 'nibble': function(color) { + color.limit(16); + }, + 'binary': function(color) { + color.limit(2); + }, + 'name': function(color, that) { + var swatch = that._getSwatch(that._closestName(color)); + color.setRGB(swatch.r, swatch.g, swatch.b); + } + }; + + this.parts = { + header: function (inst) { + var that = this, + part = null, + _html = function() { + var title = inst.options.title || inst._getRegional('title'), + html = '' + title + ''; + + if (!inst.inline && inst.options.showCloseButton) { + html += '' + + 'close'; + } + + return '
' + html + '
'; + }, + _onclick = function(event) { + event.preventDefault(); + inst.close(inst.options.revert); + }; + + this.init = function() { + part = $(_html()).prependTo(inst.dialog); + + var close = $('.ui-dialog-titlebar-close', part); + inst._hoverable(close); + inst._focusable(close); + close.on('click', _onclick); + + if (!inst.inline && inst.options.draggable) { + var draggableOptions = { + handle: part, + } + if (inst.options.containment) { + draggableOptions.containment = inst.options.containment; + } + inst.dialog.draggable(draggableOptions); + } + }; + + this.disable = function (disable) { + $('.ui-dialog-titlebar-close', part)[disable ? 'off' : 'on']('click', _onclick); + }; + }, + + map: function (inst) { + var that = this, + part = null, + pointer, width, height, layers = {}, + _mousedown, _mouseup, _mousemove, _keydown, _html; + + _mousedown = function (event) { + if (!inst.opened) { + return; + } + + var offset = layers.p.offset(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + if (x >= 0 && x < width && y >= 0 && y < height) { + event.stopImmediatePropagation(); + event.preventDefault(); + part.off('mousedown', _mousedown).focus(); + $(document).on('mouseup', _mouseup); + $(document).on('mousemove', _mousemove); + _mousemove(event); + } + }; + + _mouseup = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(document).off('mouseup', _mouseup); + $(document).off('mousemove', _mousemove); + part.on('mousedown', _mousedown); + + inst._callback('stop'); + }; + + _mousemove = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + + if (event.pageX === that.x && event.pageY === that.y) { + return; + } + that.x = event.pageX; + that.y = event.pageY; + + var offset = layers.p.offset(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + x = Math.max(0, Math.min(x / width, 1)); + y = Math.max(0, Math.min(y / height, 1)); + + // interpret values + switch (inst.mode) { + case 'h': + inst.color.setHSV(null, x, 1 - y); + break; + + case 's': + case 'a': + inst.color.setHSV(x, null, 1 - y); + break; + + case 'v': + inst.color.setHSV(x, 1 - y, null); + break; + + case 'r': + inst.color.setRGB(null, 1 - y, x); + break; + + case 'g': + inst.color.setRGB(1 - y, null, x); + break; + + case 'b': + inst.color.setRGB(x, 1 - y, null); + break; + } + + inst._change(false); + }; + + _keydown = function(event) { + var x_channel_map = { + 'h': 's', + 's': 'h', + 'v': 'h', + 'r': 'b', + 'g': 'b', + 'b': 'r', + 'a': 'h' + }, + x_change = { + 37: -1, + 39: 1, + }, + y_channel_map = { + 'h': 'v', + 's': 'v', + 'v': 's', + 'r': 'g', + 'g': 'r', + 'b': 'g', + 'a': 'v' + }, + y_change = { + 38: 1, + 40: -1 + }, + set = { + 35: 0, + 36: 1 + }, + change, value; + + if (typeof x_change[event.which] !== 'undefined') { + value = inst.color.getChannel(x_channel_map[inst.mode]) * width; + change = x_change[event.which]; + if (event.shiftKey) { + change *= 10; + } else if (event.ctrlKey) { + change *= width; + } + inst.color.setChannel(x_channel_map[inst.mode], (value + change) / width); + inst._change(false); + } else if (typeof y_change[event.which] !== 'undefined') { + value = inst.color.getChannel(y_channel_map[inst.mode]) * height; + change = y_change[event.which]; + if (event.shiftKey) { + change *= 10; + } else if (event.ctrlKey) { + change *= height; + } + inst.color.setChannel(y_channel_map[inst.mode], (value + change) / height); + inst._change(false); + } else if (typeof set[event.which] !== 'undefined') { + inst.color.setChannel(x_channel_map[inst.mode], 1 - set[event.which]); + inst.color.setChannel(y_channel_map[inst.mode], set[event.which]); + inst._change(false); + } + }; + + _html = function () { + var html = '
' + + ' ' + + ' ' + + (inst.options.alpha ? ' ' : '') + + '
'; + return html; + }; + + this.init = function () { + part = $(_html()).appendTo($('.ui-colorpicker-map-container', inst.dialog)); + + part.on('mousedown', _mousedown); + part.on('keydown', _keydown); + + // cache + layers[1] = $('.ui-colorpicker-map-layer-1', part); + layers[2] = $('.ui-colorpicker-map-layer-2', part); + layers.a = $('.ui-colorpicker-map-layer-alpha', part); + layers.p = $('.ui-colorpicker-map-layer-pointer', part); + width = layers.p.width(); + height = layers.p.height(); + + pointer = $('.ui-colorpicker-map-pointer', part); + }; + + this.update = function () { + var step = ((inst.options.part.map.size || 256) * 65 / 64); + + switch (inst.mode) { + case 'h': + layers[1].css({'background-position': '0 0', 'opacity': ''}).show(); + layers[2].hide(); + break; + + case 's': + case 'a': + layers[1].css({'background-position': '0 ' + (-step) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 2) + 'px', 'opacity': ''}).show(); + break; + + case 'v': + part.css('background-color', 'black'); + layers[1].css({'background-position': '0 ' + (-step * 3) + 'px', 'opacity': ''}).show(); + layers[2].hide(); + break; + + case 'r': + layers[1].css({'background-position': '0 ' + (-step * 4) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 5) + 'px', 'opacity': ''}).show(); + break; + + case 'g': + layers[1].css({'background-position': '0 ' + (-step * 6) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 7) + 'px', 'opacity': ''}).show(); + break; + + case 'b': + layers[1].css({'background-position': '0 ' + (-step * 8) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 9) + 'px', 'opacity': ''}).show(); + break; + } + + that.repaint(); + }; + + this.repaint = function () { + var x = 0, + y = 0; + + switch (inst.mode) { + case 'h': + var hsv = inst.color.getHSV(); + x = hsv.s * width; + y = (1 - hsv.v) * width; + part.css('background-color', inst.color.copy().setHSV(null, 1, 1).toCSS()); + break; + + case 's': + case 'a': + var hsv = inst.color.getHSV(); + x = hsv.h * width; + y = (1 - hsv.v) * width; + layers[2].css('opacity', 1 - hsv.s); + break; + + case 'v': + var hsv = inst.color.getHSV(); + x = hsv.h * width; + y = (1 - hsv.s) * width; + layers[1].css('opacity', hsv.v); + break; + + case 'r': + var rgb = inst.color.getRGB() + x = rgb.b * width; + y = (1 - rgb.g) * width; + layers[2].css('opacity', rgb.r); + break; + + case 'g': + var rgb = inst.color.getRGB(); + x = rgb.b * width; + y = (1 - rgb.r) * width; + layers[2].css('opacity', rgb.g); + break; + + case 'b': + var rgb = inst.color.getRGB() + x = rgb.r * width; + y = (1 - rgb.g) * width; + layers[2].css('opacity', rgb.b); + break; + } + + if (inst.options.alpha) { + layers.a.css('opacity', 1 - inst.color.getAlpha()); + } + + pointer.css({ + 'left': x - 7, + 'top': y - 7 + }); + }; + + this.disable = function (disable) { + part[disable ? 'off' : 'on']('mousedown', _mousedown); + part[disable ? 'off' : 'on']('keydown', _keydown); + }; + }, + + bar: function (inst) { + var that = this, + part = null, + pointer, width, height, layers = {}, + _mousedown, _mouseup, _mousemove, _keydown, _html; + + _mousedown = function (event) { + if (!inst.opened) { + return; + } + + var offset = layers.p.offset(), + x = event.pageX - offset.left, + y = event.pageY - offset.top; + + if (x >= 0 && x < width && y >= 0 && y < height) { + event.stopImmediatePropagation(); + event.preventDefault(); + part.off('mousedown', _mousedown).focus(); + $(document).on('mouseup', _mouseup); + $(document).on('mousemove', _mousemove); + _mousemove(event); + } + }; + + _mouseup = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(document).off('mouseup', _mouseup); + $(document).off('mousemove', _mousemove); + part.on('mousedown', _mousedown); + + inst._callback('stop'); + }; + + _mousemove = function (event) { + event.stopImmediatePropagation(); + event.preventDefault(); + + if (event.pageY === that.y) { + return; + } + that.y = event.pageY; + + var offset = layers.p.offset(), + y = event.pageY - offset.top; + + y = Math.max(0, Math.min(y / height, 1)); + + // interpret values + switch (inst.mode) { + case 'h': + inst.color.setHSV(1 - y, null, null); + break; + + case 's': + inst.color.setHSV(null, 1 - y, null); + break; + + case 'v': + inst.color.setHSV(null, null, 1 - y); + break; + + case 'r': + inst.color.setRGB(1 - y, null, null); + break; + + case 'g': + inst.color.setRGB(null, 1 - y, null); + break; + + case 'b': + inst.color.setRGB(null, null, 1 - y); + break; + + case 'a': + inst.color.setAlpha(1 - y); + break; + } + + inst._change(false); + }; + + _keydown = function(event) { + var change = { + 38: 1, + 40: -1, + 33: 10, + 34: -10 + }, + set = { + 35: 0, + 36: 1 + }, + change, value; + + if (typeof change[event.which] !== 'undefined') { + value = inst.color.getChannel(inst.mode) * height; + change = change[event.which]; + if (event.shiftKey) { + change *= 10; + } else if (event.ctrlKey) { + change *= height; + } + inst.color.setChannel(inst.mode, (value + change) / height); + inst._change(false); + } else if (typeof set[event.which] !== 'undefined') { + inst.color.setChannel(inst.mode, set[event.which]); + inst._change(false); + } + }; + + _html = function () { + var html = '
' + + ' ' + + ' ' + + ' ' + + ' '; + + if (inst.options.alpha) { + html += ' ' + + ' '; + } + + html += '
'; + + return html; + }; + + this.init = function () { + part = $(_html()).appendTo($('.ui-colorpicker-bar-container', inst.dialog)); + + part.on('mousedown', _mousedown); + part.on('keydown', _keydown); + + // cache + layers[1] = $('.ui-colorpicker-bar-layer-1', part); + layers[2] = $('.ui-colorpicker-bar-layer-2', part); + layers[3] = $('.ui-colorpicker-bar-layer-3', part); + layers[4] = $('.ui-colorpicker-bar-layer-4', part); + layers.a = $('.ui-colorpicker-bar-layer-alpha', part); + layers.ab = $('.ui-colorpicker-bar-layer-alphabar', part); + layers.p = $('.ui-colorpicker-bar-layer-pointer', part); + width = layers.p.width(); + height = layers.p.height(); + + pointer = $('.ui-colorpicker-bar-pointer', part); + }; + + this.update = function () { + var step = ((inst.options.part.bar.size || 256) * 65 / 64); + + switch (inst.mode) { + case 'h': + case 's': + case 'v': + case 'r': + case 'g': + case 'b': + layers.a.show(); + layers.ab.hide(); + break; + + case 'a': + layers.a.hide(); + layers.ab.show(); + break; + } + + switch (inst.mode) { + case 'h': + layers[1].css({'background-position': '0 0', 'opacity': ''}).show(); + layers[2].hide(); + layers[3].hide(); + layers[4].hide(); + break; + + case 's': + layers[1].css({'background-position': '0 ' + (-step) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 2) + 'px', 'opacity': ''}).show(); + layers[3].hide(); + layers[4].hide(); + break; + + case 'v': + layers[1].css({'background-position': '0 ' + (-step * 2) + 'px', 'opacity': ''}).show(); + layers[2].hide(); + layers[3].hide(); + layers[4].hide(); + break; + + case 'r': + layers[1].css({'background-position': '0 ' + (-step * 6) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 5) + 'px', 'opacity': ''}).show(); + layers[3].css({'background-position': '0 ' + (-step * 3) + 'px', 'opacity': ''}).show(); + layers[4].css({'background-position': '0 ' + (-step * 4) + 'px', 'opacity': ''}).show(); + break; + + case 'g': + layers[1].css({'background-position': '0 ' + (-step * 10) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 9) + 'px', 'opacity': ''}).show(); + layers[3].css({'background-position': '0 ' + (-step * 7) + 'px', 'opacity': ''}).show(); + layers[4].css({'background-position': '0 ' + (-step * 8) + 'px', 'opacity': ''}).show(); + break; + + case 'b': + layers[1].css({'background-position': '0 ' + (-step * 14) + 'px', 'opacity': ''}).show(); + layers[2].css({'background-position': '0 ' + (-step * 13) + 'px', 'opacity': ''}).show(); + layers[3].css({'background-position': '0 ' + (-step * 11) + 'px', 'opacity': ''}).show(); + layers[4].css({'background-position': '0 ' + (-step * 12) + 'px', 'opacity': ''}).show(); + break; + + case 'a': + layers[1].hide(); + layers[2].hide(); + layers[3].hide(); + layers[4].hide(); + break; + } + + that.repaint(); + }; + + this.repaint = function () { + var y = 0; + + switch (inst.mode) { + case 'h': + y = (1 - inst.color.getHSV().h) * height; + break; + + case 's': + var hsv = inst.color.getHSV(); + y = (1 - hsv.s) * height; + layers[2].css('opacity', 1 - hsv.v); + part.css('background-color', inst.color.copy().setHSV(null, 1, null).toCSS()); + break; + + case 'v': + y = (1 - inst.color.getHSV().v) * height; + part.css('background-color', inst.color.copy().setHSV(null, null, 1).toCSS()); + break; + + case 'r': + var rgb = inst.color.getRGB(); + y = (1 - rgb.r) * height; + layers[2].css('opacity', Math.max(0, (rgb.b - rgb.g))); + layers[3].css('opacity', Math.max(0, (rgb.g - rgb.b))); + layers[4].css('opacity', Math.min(rgb.b, rgb.g)); + break; + + case 'g': + var rgb = inst.color.getRGB(); + y = (1 - rgb.g) * height; + layers[2].css('opacity', Math.max(0, (rgb.b - rgb.r))); + layers[3].css('opacity', Math.max(0, (rgb.r - rgb.b))); + layers[4].css('opacity', Math.min(rgb.r, rgb.b)); + break; + + case 'b': + var rgb = inst.color.getRGB(); + y = (1 - rgb.b) * height; + layers[2].css('opacity', Math.max(0, (rgb.r - rgb.g))); + layers[3].css('opacity', Math.max(0, (rgb.g - rgb.r))); + layers[4].css('opacity', Math.min(rgb.r, rgb.g)); + break; + + case 'a': + y = (1 - inst.color.getAlpha()) * height; + part.css('background-color', inst.color.copy().toCSS()); + break; + } + + if (inst.mode !== 'a') { + layers.a.css('opacity', 1 - inst.color.getAlpha()); + } + + pointer.css('top', y - 3); + }; + + this.disable = function (disable) { + part[disable ? 'off' : 'on']('mousedown', _mousedown); + part[disable ? 'off' : 'on']('keydown', _keydown); + }; + }, + + preview: function (inst) { + var that = this, + part = null, + both, + initial, initial_alpha, + current, current_alpha, + _html, + onclick = function () { + inst.color = inst.currentColor.copy(); + inst._change(); + }; + + _html = function () { + return '
' + + '
' + + '
' + + '
'; + }; + + this.init = function () { + part = $(_html()).appendTo($('.ui-colorpicker-preview-container', inst.dialog)); + + $('.ui-colorpicker-preview-initial', part).on('click', onclick); + + // cache + initial = $('.ui-colorpicker-preview-initial', part); + initial_alpha = $('.ui-colorpicker-preview-initial-alpha', part); + current = $('.ui-colorpicker-preview-current', part); + current_alpha = $('.ui-colorpicker-preview-current-alpha', part); + both = $('.ui-colorpicker-preview-initial-alpha, .ui-colorpicker-preview-current-alpha', part); + }; + + this.update = function () { + both[inst.options.alpha ? 'show' : 'hide'](); + + this.repaint(); + }; + + this.repaint = function () { + initial.css('background-color', inst.currentColor.set ? inst.currentColor.toCSS() : '').attr('title', inst.currentColor.set ? inst.currentColor.toCSS() : ''); + initial_alpha.css('opacity', 1 - inst.currentColor.getAlpha()); + current.css('background-color', inst.color.set ? inst.color.toCSS() : '').attr('title', inst.color.set ? inst.color.toCSS() : ''); + current_alpha.css('opacity', 1 - inst.color.getAlpha()); + }; + + this.disable = function (disable) { + $('.ui-colorpicker-preview-initial', part)[disable ? 'off' : 'on']('click', onclick); + }; + }, + + hsv: function (inst) { + var that = this, + part = null, + inputs = {}, + _html; + + _html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
°
' + + '
%
' + + '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(_html()).appendTo($('.ui-colorpicker-hsv-container', inst.dialog)); + + $('.ui-colorpicker-mode', part).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + inputs.h = $('.ui-colorpicker-hsv-h .ui-colorpicker-number', part); + inputs.s = $('.ui-colorpicker-hsv-s .ui-colorpicker-number', part); + inputs.v = $('.ui-colorpicker-hsv-v .ui-colorpicker-number', part); + + $('.ui-colorpicker-number', part).on('change keyup', function () { + inst.color.setHSV( + inputs.h.val() / 360, + inputs.s.val() / 100, + inputs.v.val() / 100 + ); + inst._change(); + }); + }; + + this.repaint = function () { + var hsv = inst.color.getHSV(); + inputs.h.val(Math.round(hsv.h * 360)); + inputs.s.val(Math.round(hsv.s * 100)); + inputs.v.val(Math.round(hsv.v * 100)); + }; + + this.update = function () { + $('.ui-colorpicker-mode', part).each(function () { + var $this = $(this); + $this.prop('checked', $this.val() === inst.mode); + }); + this.repaint(); + }; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + rgb: function (inst) { + var that = this, + part = null, + inputs = {}, + _html; + + _html = function () { + var html = ''; + + if (inst.options.rgb) { + html += '
' + + '
' + + '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(_html()).appendTo($('.ui-colorpicker-rgb-container', inst.dialog)); + + $('.ui-colorpicker-mode', part).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + inputs.r = $('.ui-colorpicker-rgb-r .ui-colorpicker-number', part); + inputs.g = $('.ui-colorpicker-rgb-g .ui-colorpicker-number', part); + inputs.b = $('.ui-colorpicker-rgb-b .ui-colorpicker-number', part); + + $('.ui-colorpicker-number', part).on('change keyup', function () { + var r = $('.ui-colorpicker-rgb-r .ui-colorpicker-number', part).val(); + inst.color.setRGB( + inputs.r.val() / 255, + inputs.g.val() / 255, + inputs.b.val() / 255 + ); + + inst._change(); + }); + }; + + this.repaint = function () { + var rgb = inst.color.getRGB(); + inputs.r.val(Math.round(rgb.r * 255)); + inputs.g.val(Math.round(rgb.g * 255)); + inputs.b.val(Math.round(rgb.b * 255)); + }; + + this.update = function () { + $('.ui-colorpicker-mode', part).each(function () { + var $this = $(this); + $this.prop('checked', $this.val() === inst.mode); + }); + this.repaint(); + }; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + lab: function (inst) { + var that = this, + part = null, + inputs = {}, + html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
' + + '
' + + '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + var data = 0; + + part = $(html()).appendTo($('.ui-colorpicker-lab-container', inst.dialog)); + + inputs.l = $('.ui-colorpicker-lab-l .ui-colorpicker-number', part); + inputs.a = $('.ui-colorpicker-lab-a .ui-colorpicker-number', part); + inputs.b = $('.ui-colorpicker-lab-b .ui-colorpicker-number', part); + + $('.ui-colorpicker-number', part).on('change keyup', function (event) { + inst.color.setLAB( + parseInt(inputs.l.val(), 10) / 100, + (parseInt(inputs.a.val(), 10) + 128) / 255, + (parseInt(inputs.b.val(), 10) + 128) / 255 + ); + inst._change(); + }); + }; + + this.repaint = function () { + var lab = inst.color.getLAB(); + inputs.l.val(Math.round(lab.l * 100)); + inputs.a.val(Math.round(lab.a * 255) - 128); + inputs.b.val(Math.round(lab.b * 255) - 128); + }; + + this.update = this.repaint; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + cmyk: function (inst) { + var that = this, + part = null, + inputs = {}, + html = function () { + var html = ''; + + if (inst.options.hsv) { + html += '
%
' + + '
%
' + + '
%
' + + '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo($('.ui-colorpicker-cmyk-container', inst.dialog)); + + inputs.c = $('.ui-colorpicker-cmyk-c .ui-colorpicker-number', part); + inputs.m = $('.ui-colorpicker-cmyk-m .ui-colorpicker-number', part); + inputs.y = $('.ui-colorpicker-cmyk-y .ui-colorpicker-number', part); + inputs.k = $('.ui-colorpicker-cmyk-k .ui-colorpicker-number', part); + + $('.ui-colorpicker-number', part).on('change keyup', function (event) { + inst.color.setCMYK( + parseInt(inputs.c.val(), 10) / 100, + parseInt(inputs.m.val(), 10) / 100, + parseInt(inputs.y.val(), 10) / 100, + parseInt(inputs.k.val(), 10) / 100 + ); + inst._change(); + }); + }; + + this.repaint = function () { + var cmyk = inst.color.getCMYK(); + inputs.c.val(Math.round(cmyk.c * 100)); + inputs.m.val(Math.round(cmyk.m * 100)); + inputs.y.val(Math.round(cmyk.y * 100)); + inputs.k.val(Math.round(cmyk.k * 100)); + }; + + this.update = this.repaint; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + alpha: function (inst) { + var that = this, + part = null, + input, + html = function () { + var html = ''; + + if (inst.options.alpha) { + html += '
%
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo($('.ui-colorpicker-alpha-container', inst.dialog)); + + $('.ui-colorpicker-mode', part).click(function () { + inst.mode = $(this).val(); + inst._updateAllParts(); + }); + + input = $('.ui-colorpicker-a .ui-colorpicker-number', part); + + $('.ui-colorpicker-number', part).on('change keyup', function () { + inst.color.setAlpha(input.val() / 100); + inst._change(); + }); + }; + + this.update = function () { + $('.ui-colorpicker-mode', part).each(function () { + $(this).prop('checked', $(this).val() === inst.mode); + }); + this.repaint(); + }; + + this.repaint = function () { + input.val(Math.round(inst.color.getAlpha() * 100)); + }; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + hex: function (inst) { + var that = this, + part = null, + inputs = {}, + parseHex = function(color) { + var c, + m; + + // {#}rgb + m = /^#?([a-fA-F0-9]{1,3})$/.exec(color); + if (m) { + c = parseInt(m[1], 16); + return new $.colorpicker.Color( + ((c >> 8) & 0xF) / 15, + ((c >> 4) & 0xF) / 15, + (c & 0xF) / 15 + ); + } + + // {#}rrggbb + m = /^#?([a-fA-F0-9]{1,6})$/.exec(color); + if (m) { + c = parseInt(m[1], 16); + return new $.colorpicker.Color( + ((c >> 16) & 0xFF) / 255, + ((c >> 8) & 0xFF) / 255, + (c & 0xFF) / 255 + ); + } + + return new $.colorpicker.Color(); + }, + html = function () { + var html = ''; + + if (inst.options.alpha) { + html += ''; + } + + html += ''; + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo($('.ui-colorpicker-hex-container', inst.dialog)); + + inputs.color = $('.ui-colorpicker-hex-input', part); + inputs.alpha = $('.ui-colorpicker-hex-alpha', part); + + inputs.color.on('keydown keyup', function(e) { + return e.ctrlKey || _keycode.isHex(e.which) || !_keycode.isPrint(e.which); + }); + + // repeat here makes the invalid input disappear faster + inputs.color.on('change', function () { + if (/[^a-fA-F0-9]/.test(inputs.color.val())) { + inputs.color.val(inputs.color.val().replace(/[^a-fA-F0-9]/, '')); + } + }); + + inputs.color.on('change keyup', function () { + // repeat here makes sure that the invalid input doesn't get parsed + inst.color = parseHex(inputs.color.val()).setAlpha(inst.color.getAlpha()); + inst._change(); + }); + + inputs.alpha.on('keydown keyup', function(e) { + return e.ctrlKey || _keycode.isHex(e.which) || !_keycode.isPrint(e.which); + }); + + inputs.alpha.on('change', function () { + if (/[^a-fA-F0-9]/.test(inputs.alpha)) { + inputs.alpha.val(inputs.alpha.val().replace(/[^a-fA-F0-9]/, '')); + } + }); + + inputs.alpha.on('change keyup', function () { + inst.color.setAlpha(parseInt(inputs.alpha.val(), 16) / 255); + inst._change(); + }); + }; + + this.repaint = function () { + if (!inputs.color.is(':focus')) { + inputs.color.val(inst.color.toHex(true)); + } + + if (!inputs.alpha.is(':focus')) { + inputs.alpha.val(_intToHex(inst.color.getAlpha() * 255)); + } + }; + + this.update = this.repaint; + + this.disable = function (disable) { + $(':input', part).prop('disabled', disable); + }; + }, + + swatches: function (inst) { + var that = this, + part = null, + html = function () { + var html = ''; + + inst._eachSwatch(function (name, color) { + var c = new $.colorpicker.Color(color.r, color.g, color.b), + css = c.toCSS(); + html += '
'; + }); + + return '
' + html + '
'; + }, + onclick = function () { + inst.color = inst._parseColor($(this).css('background-color')) || new $.colorpicker.Color(); + inst._change(); + }; + + this.init = function () { + part = $(html()); + $('.ui-colorpicker-swatches-container', inst.dialog).html(part); + $('.ui-colorpicker-swatch', part).on('click', onclick); + }; + + this.disable = function (disable) { + $('.ui-colorpicker-swatch', part)[disable ? 'off' : 'on']('click', onclick); + }; + }, + + footer: function (inst) { + var that = this, + part = null, + id_transparent = 'ui-colorpicker-special-transparent-' + inst.colorpicker_index, + id_none = 'ui-colorpicker-special-none-' + inst.colorpicker_index, + html = function () { + var html = ''; + + if (inst.options.alpha || (!inst.inline && inst.options.showNoneButton)) { + html += '
'; + + if (inst.options.alpha) { + html += ''; + } + if (!inst.inline && inst.options.showNoneButton) { + html += ''; + } + html += '
'; + } + + if (!inst.inline) { + html += '
'; + if (inst.options.showCancelButton) { + html += ''; + } + html += ''; + html += '
'; + } + + return '
' + html + '
'; + }; + + this.init = function () { + part = $(html()).appendTo(inst.dialog); + + $('.ui-colorpicker-ok', part).button().click(function () { + inst.close(); + }); + + $('.ui-colorpicker-cancel', part).button().click(function () { + inst.close(true); //cancel + }); + + $('.ui-colorpicker-buttonset', part)[$.fn.controlgroup ? 'controlgroup' : 'buttonset'](); + + $('.ui-colorpicker-special-color', part).click(function () { + inst._change(); + }); + + $('#'+id_none, part).click(function () { + inst.color.set = false; + inst._change(); + }); + + $('#'+id_transparent, part).click(function () { + inst.color.setAlpha(0); + inst._change(); + }); + }; + + this.repaint = function () { + $('.ui-colorpicker-special-none', part).prop('checked', !inst.color.set).button('refresh'); + $('.ui-colorpicker-special-transparent', part).prop('checked', inst.color.set && inst.color.getAlpha() === 0).button('refresh'); + $('.ui-colorpicker-ok', part).button(inst.changed ? 'enable' : 'disable'); + }; + + this.update = function () {}; + + this.disable = function (disabled) { + $(':input, :button', part).button(disabled ? 'disable' : 'enable'); + if (!disabled) { + $('.ui-colorpicker-ok', part).button(inst.changed ? 'enable' : 'disable'); + } + }; + } + }; + + this.Color = function () { + var spaces = { rgb: {r: 0, g: 0, b: 0}, + hsv: {h: 0, s: 0, v: 0}, + hsl: {h: 0, s: 0, l: 0}, + lab: {l: 0, a: 0, b: 0}, + cmyk: {c: 0, m: 0, y: 0, k: 1} + }, + a = 1, + illuminant = [0.9504285, 1, 1.0889], // CIE-L*ab D65/2' 1931 + args = arguments, + _clip = function(v) { + if (isNaN(v) || v === null) { + return 0; + } + if (typeof v == 'string') { + v = parseInt(v, 10); + } + return Math.max(0, Math.min(v, 1)); + }, + _hexify = function (number) { + var number = Math.round(number), + digits = '0123456789abcdef', + lsd = number % 16, + msd = (number - lsd) / 16, + hexified = digits.charAt(msd) + digits.charAt(lsd); + return hexified; + }, + _rgb_to_xyz = function(rgb) { + var r = (rgb.r > 0.04045) ? Math.pow((rgb.r + 0.055) / 1.055, 2.4) : rgb.r / 12.92, + g = (rgb.g > 0.04045) ? Math.pow((rgb.g + 0.055) / 1.055, 2.4) : rgb.g / 12.92, + b = (rgb.b > 0.04045) ? Math.pow((rgb.b + 0.055) / 1.055, 2.4) : rgb.b / 12.92; + + return { + x: r * 0.4124 + g * 0.3576 + b * 0.1805, + y: r * 0.2126 + g * 0.7152 + b * 0.0722, + z: r * 0.0193 + g * 0.1192 + b * 0.9505 + }; + }, + _xyz_to_rgb = function(xyz) { + var rgb = { + r: xyz.x * 3.2406 + xyz.y * -1.5372 + xyz.z * -0.4986, + g: xyz.x * -0.9689 + xyz.y * 1.8758 + xyz.z * 0.0415, + b: xyz.x * 0.0557 + xyz.y * -0.2040 + xyz.z * 1.0570 + }; + + rgb.r = (rgb.r > 0.0031308) ? 1.055 * Math.pow(rgb.r, (1 / 2.4)) - 0.055 : 12.92 * rgb.r; + rgb.g = (rgb.g > 0.0031308) ? 1.055 * Math.pow(rgb.g, (1 / 2.4)) - 0.055 : 12.92 * rgb.g; + rgb.b = (rgb.b > 0.0031308) ? 1.055 * Math.pow(rgb.b, (1 / 2.4)) - 0.055 : 12.92 * rgb.b; + + return rgb; + }, + _rgb_to_hsv = function(rgb) { + var minVal = Math.min(rgb.r, rgb.g, rgb.b), + maxVal = Math.max(rgb.r, rgb.g, rgb.b), + delta = maxVal - minVal, + del_R, del_G, del_B, + hsv = { + h: 0, + s: 0, + v: maxVal + }; + + if (delta === 0) { + hsv.h = 0; + hsv.s = 0; + } else { + hsv.s = delta / maxVal; + + del_R = (((maxVal - rgb.r) / 6) + (delta / 2)) / delta; + del_G = (((maxVal - rgb.g) / 6) + (delta / 2)) / delta; + del_B = (((maxVal - rgb.b) / 6) + (delta / 2)) / delta; + + if (rgb.r === maxVal) { + hsv.h = del_B - del_G; + } else if (rgb.g === maxVal) { + hsv.h = (1 / 3) + del_R - del_B; + } else if (rgb.b === maxVal) { + hsv.h = (2 / 3) + del_G - del_R; + } + + if (hsv.h < 0) { + hsv.h += 1; + } else if (hsv.h > 1) { + hsv.h -= 1; + } + } + + return hsv; + }, + _hsv_to_rgb = function(hsv) { + var rgb = { + r: 0, + g: 0, + b: 0 + }, + var_h, + var_i, + var_1, + var_2, + var_3; + + if (hsv.s === 0) { + rgb.r = rgb.g = rgb.b = hsv.v; + } else { + var_h = hsv.h === 1 ? 0 : hsv.h * 6; + var_i = Math.floor(var_h); + var_1 = hsv.v * (1 - hsv.s); + var_2 = hsv.v * (1 - hsv.s * (var_h - var_i)); + var_3 = hsv.v * (1 - hsv.s * (1 - (var_h - var_i))); + + if (var_i === 0) { + rgb.r = hsv.v; + rgb.g = var_3; + rgb.b = var_1; + } else if (var_i === 1) { + rgb.r = var_2; + rgb.g = hsv.v; + rgb.b = var_1; + } else if (var_i === 2) { + rgb.r = var_1; + rgb.g = hsv.v; + rgb.b = var_3; + } else if (var_i === 3) { + rgb.r = var_1; + rgb.g = var_2; + rgb.b = hsv.v; + } else if (var_i === 4) { + rgb.r = var_3; + rgb.g = var_1; + rgb.b = hsv.v; + } else { + rgb.r = hsv.v; + rgb.g = var_1; + rgb.b = var_2; + } + } + + return rgb; + }, + _rgb_to_hsl = function(rgb) { + var minVal = Math.min(rgb.r, rgb.g, rgb.b), + maxVal = Math.max(rgb.r, rgb.g, rgb.b), + delta = maxVal - minVal, + del_R, del_G, del_B, + hsl = { + h: 0, + s: 0, + l: (maxVal + minVal) / 2 + }; + + if (delta === 0) { + hsl.h = 0; + hsl.s = 0; + } else { + hsl.s = hsl.l < 0.5 ? delta / (maxVal + minVal) : delta / (2 - maxVal - minVal); + + del_R = (((maxVal - rgb.r) / 6) + (delta / 2)) / delta; + del_G = (((maxVal - rgb.g) / 6) + (delta / 2)) / delta; + del_B = (((maxVal - rgb.b) / 6) + (delta / 2)) / delta; + + if (rgb.r === maxVal) { + hsl.h = del_B - del_G; + } else if (rgb.g === maxVal) { + hsl.h = (1 / 3) + del_R - del_B; + } else if (rgb.b === maxVal) { + hsl.h = (2 / 3) + del_G - del_R; + } + + if (hsl.h < 0) { + hsl.h += 1; + } else if (hsl.h > 1) { + hsl.h -= 1; + } + } + + return hsl; + }, + _hsl_to_rgb = function(hsl) { + var var_1, + var_2, + hue_to_rgb = function(v1, v2, vH) { + if (vH < 0) { + vH += 1; + } + if (vH > 1) { + vH -= 1; + } + if ((6 * vH) < 1) { + return v1 + (v2 - v1) * 6 * vH; + } + if ((2 * vH) < 1) { + return v2; + } + if ((3 * vH) < 2) { + return v1 + (v2 - v1) * ((2 / 3) - vH) * 6; + } + return v1; + }; + + if (hsl.s === 0) { + return { + r: hsl.l, + g: hsl.l, + b: hsl.l + }; + } + + var_2 = (hsl.l < 0.5) ? hsl.l * (1 + hsl.s) : (hsl.l + hsl.s) - (hsl.s * hsl.l); + var_1 = 2 * hsl.l - var_2; + + return { + r: hue_to_rgb(var_1, var_2, hsl.h + (1 / 3)), + g: hue_to_rgb(var_1, var_2, hsl.h), + b: hue_to_rgb(var_1, var_2, hsl.h - (1 / 3)) + }; + }, + _xyz_to_lab = function(xyz) { + var x = xyz.x / illuminant[0], + y = xyz.y / illuminant[1], + z = xyz.z / illuminant[2]; + + x = (x > 0.008856) ? Math.pow(x, (1/3)) : (7.787 * x) + (16/116); + y = (y > 0.008856) ? Math.pow(y, (1/3)) : (7.787 * y) + (16/116); + z = (z > 0.008856) ? Math.pow(z, (1/3)) : (7.787 * z) + (16/116); + + return { + l: ((116 * y) - 16) / 100, // [0,100] + a: ((500 * (x - y)) + 128) / 255, // [-128,127] + b: ((200 * (y - z)) + 128) / 255 // [-128,127] + }; + }, + _lab_to_xyz = function(lab) { + var lab2 = { + l: lab.l * 100, + a: (lab.a * 255) - 128, + b: (lab.b * 255) - 128 + }, + xyz = { + x: 0, + y: (lab2.l + 16) / 116, + z: 0 + }; + + xyz.x = lab2.a / 500 + xyz.y; + xyz.z = xyz.y - lab2.b / 200; + + xyz.x = (Math.pow(xyz.x, 3) > 0.008856) ? Math.pow(xyz.x, 3) : (xyz.x - 16 / 116) / 7.787; + xyz.y = (Math.pow(xyz.y, 3) > 0.008856) ? Math.pow(xyz.y, 3) : (xyz.y - 16 / 116) / 7.787; + xyz.z = (Math.pow(xyz.z, 3) > 0.008856) ? Math.pow(xyz.z, 3) : (xyz.z - 16 / 116) / 7.787; + + xyz.x *= illuminant[0]; + xyz.y *= illuminant[1]; + xyz.z *= illuminant[2]; + + return xyz; + }, + _rgb_to_cmy = function(rgb) { + return { + c: 1 - (rgb.r), + m: 1 - (rgb.g), + y: 1 - (rgb.b) + }; + }, + _cmy_to_rgb = function(cmy) { + return { + r: 1 - (cmy.c), + g: 1 - (cmy.m), + b: 1 - (cmy.y) + }; + }, + _cmy_to_cmyk = function(cmy) { + var K = 1; + + if (cmy.c < K) { + K = cmy.c; + } + if (cmy.m < K) { + K = cmy.m; + } + if (cmy.y < K) { + K = cmy.y; + } + + if (K === 1) { + return { + c: 0, + m: 0, + y: 0, + k: 1 + }; + } + + return { + c: (cmy.c - K) / (1 - K), + m: (cmy.m - K) / (1 - K), + y: (cmy.y - K) / (1 - K), + k: K + }; + }, + _cmyk_to_cmy = function(cmyk) { + return { + c: cmyk.c * (1 - cmyk.k) + cmyk.k, + m: cmyk.m * (1 - cmyk.k) + cmyk.k, + y: cmyk.y * (1 - cmyk.k) + cmyk.k + }; + }; + + this.set = false; + + this.setAlpha = function(_a) { + if (_a !== null) { + a = _clip(_a); + } + this.set = true; + + return this; + }; + + this.getAlpha = function() { + return a; + }; + + this.setRGB = function(r, g, b) { + spaces = { rgb: this.getRGB() }; + if (r !== null) { + spaces.rgb.r = _clip(r); + } + if (g !== null) { + spaces.rgb.g = _clip(g); + } + if (b !== null) { + spaces.rgb.b = _clip(b); + } + this.set = true; + + return this; + }; + + this.getChannel = function(channel) { + switch (channel) { + case 'h': + case 's': + case 'v': + return this.getHSV()[channel]; + + case 'r': + case 'g': + case 'b': + return this.getRGB()[channel]; + + case 'a': + return this.getAlpha(); + } + + return null; + }; + + this.setChannel = function(channel, value) { + switch (channel) { + case 'h': + return this.setHSV(value, null, null); + + case 's': + return this.setHSV(null, value, null); + + case 'v': + return this.setHSV(null, null, value); + + case 'r': + return this.setRGB(value, null, null); + + case 'g': + return this.setRGB(null, value, null); + + case 'b': + return this.setRGB(null, null, value); + + case 'a': + return this.setAlpha(value); + } + + return this; + }; + + this.setHSV = function(h, s, v) { + spaces = {hsv: this.getHSV()}; + if (h !== null) { + spaces.hsv.h = _clip(h); + } + if (s !== null) { + spaces.hsv.s = _clip(s); + } + if (v !== null) { + spaces.hsv.v = _clip(v); + } + this.set = true; + + return this; + }; + + this.setHSL = function(h, s, l) { + spaces = {hsl: this.getHSL()}; + if (h !== null) { + spaces.hsl.h = _clip(h); + } + if (s !== null) { + spaces.hsl.s = _clip(s); + } + if (l !== null) { + spaces.hsl.l = _clip(l); + } + this.set = true; + + return this; + }; + + this.setLAB = function(l, a, b) { + spaces = {lab: this.getLAB()}; + if (l !== null) { + spaces.lab.l = _clip(l); + } + if (a !== null) { + spaces.lab.a = _clip(a); + } + if (b !== null) { + spaces.lab.b = _clip(b); + } + this.set = true; + + return this; + }; + + this.setCMYK = function(c, m, y, k) { + spaces = {cmyk: this.getCMYK()}; + if (c !== null) { + spaces.cmyk.c = _clip(c); + } + if (m !== null) { + spaces.cmyk.m = _clip(m); + } + if (y !== null) { + spaces.cmyk.y = _clip(y); + } + if (k !== null) { + spaces.cmyk.k = _clip(k); + } + this.set = true; + + return this; + }; + + this.getRGB = function() { + if (!spaces.rgb) { + spaces.rgb = spaces.lab ? _xyz_to_rgb(_lab_to_xyz(spaces.lab)) + : spaces.hsv ? _hsv_to_rgb(spaces.hsv) + : spaces.hsl ? _hsl_to_rgb(spaces.hsl) + : spaces.cmyk ? _cmy_to_rgb(_cmyk_to_cmy(spaces.cmyk)) + : {r: 0, g: 0, b: 0}; + spaces.rgb.r = _clip(spaces.rgb.r); + spaces.rgb.g = _clip(spaces.rgb.g); + spaces.rgb.b = _clip(spaces.rgb.b); + } + return $.extend({}, spaces.rgb); + }; + + this.getHSV = function() { + if (!spaces.hsv) { + spaces.hsv = spaces.lab ? _rgb_to_hsv(this.getRGB()) + : spaces.rgb ? _rgb_to_hsv(spaces.rgb) + : spaces.hsl ? _rgb_to_hsv(this.getRGB()) + : spaces.cmyk ? _rgb_to_hsv(this.getRGB()) + : {h: 0, s: 0, v: 0}; + spaces.hsv.h = _clip(spaces.hsv.h); + spaces.hsv.s = _clip(spaces.hsv.s); + spaces.hsv.v = _clip(spaces.hsv.v); + } + return $.extend({}, spaces.hsv); + }; + + this.getHSL = function() { + if (!spaces.hsl) { + spaces.hsl = spaces.rgb ? _rgb_to_hsl(spaces.rgb) + : spaces.hsv ? _rgb_to_hsl(this.getRGB()) + : spaces.cmyk ? _rgb_to_hsl(this.getRGB()) + : spaces.hsv ? _rgb_to_hsl(this.getRGB()) + : {h: 0, s: 0, l: 0}; + spaces.hsl.h = _clip(spaces.hsl.h); + spaces.hsl.s = _clip(spaces.hsl.s); + spaces.hsl.l = _clip(spaces.hsl.l); + } + return $.extend({}, spaces.hsl); + }; + + this.getCMYK = function() { + if (!spaces.cmyk) { + spaces.cmyk = spaces.rgb ? _cmy_to_cmyk(_rgb_to_cmy(spaces.rgb)) + : spaces.hsv ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : spaces.hsl ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : spaces.lab ? _cmy_to_cmyk(_rgb_to_cmy(this.getRGB())) + : {c: 0, m: 0, y: 0, k: 1}; + spaces.cmyk.c = _clip(spaces.cmyk.c); + spaces.cmyk.m = _clip(spaces.cmyk.m); + spaces.cmyk.y = _clip(spaces.cmyk.y); + spaces.cmyk.k = _clip(spaces.cmyk.k); + } + return $.extend({}, spaces.cmyk); + }; + + this.getLAB = function() { + if (!spaces.lab) { + spaces.lab = spaces.rgb ? _xyz_to_lab(_rgb_to_xyz(spaces.rgb)) + : spaces.hsv ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : spaces.hsl ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : spaces.cmyk ? _xyz_to_lab(_rgb_to_xyz(this.getRGB())) + : {l: 0, a: 0, b: 0}; + spaces.lab.l = _clip(spaces.lab.l); + spaces.lab.a = _clip(spaces.lab.a); + spaces.lab.b = _clip(spaces.lab.b); + } + return $.extend({}, spaces.lab); + }; + + this.getChannels = function() { + return { + r: this.getRGB().r, + g: this.getRGB().g, + b: this.getRGB().b, + a: this.getAlpha(), + h: this.getHSV().h, + s: this.getHSV().s, + v: this.getHSV().v, + c: this.getCMYK().c, + m: this.getCMYK().m, + y: this.getCMYK().y, + k: this.getCMYK().k, + L: this.getLAB().l, + A: this.getLAB().a, + B: this.getLAB().b + }; + }; + + this.getSpaces = function() { + return $.extend(true, {}, spaces); + }; + + this.distance = function(color) { + var space = 'lab', + getter = 'get'+space.toUpperCase(), + a = this[getter](), + b = color[getter](), + distance = 0, + channel; + + for (channel in a) { + distance += Math.pow(a[channel] - b[channel], 2); + } + + return distance; + }; + + this.equals = function(color) { + if (color) { + var a = this.getRGB(), + b = color.getRGB(); + + return this.set === color.set + && this.getAlpha() === color.getAlpha() + && a.r === b.r + && a.g === b.g + && a.b === b.b; + } + return false; + }; + + this.limit = function(steps) { + steps -= 1; + var rgb = this.getRGB(); + this.setRGB( + Math.round(rgb.r * steps) / steps, + Math.round(rgb.g * steps) / steps, + Math.round(rgb.b * steps) / steps + ); + }; + + this.toHex = function() { + var rgb = this.getRGB(); + return _hexify(rgb.r * 255) + _hexify(rgb.g * 255) + _hexify(rgb.b * 255); + }; + + this.toCSS = function() { + return '#' + this.toHex(); + }; + + this.copy = function() { + var color = new $.colorpicker.Color(this.getSpaces(), this.getAlpha()); + color.set = this.set; + return color; + }; + + // Construct + if (args.length === 2) { + spaces = args[0]; + this.setAlpha(args[1] === 0 ? 0 : args[1] || 1); + this.set = true; + } + if (args.length > 2) { + this.setRGB(args[0], args[1], args[2]); + this.setAlpha(args[3] === 0 ? 0 : args[3] || 1); + this.set = true; + } + }; + }(); + + $.widget("vanderlee.colorpicker", { + options: { + alpha: false, // Show alpha controls and mode + altAlpha: true, // change opacity of altField as well? + altField: '', // selector for DOM elements which change background color on change. + altOnChange: true, // true to update on each change, false to update only on close. + altProperties: 'background-color', // comma separated list of any of 'background-color', 'color', 'border-color', 'outline-color' + autoOpen: false, // Open dialog automatically upon creation + buttonClass: null, // If set, the button will get this/these classname(s). + buttonColorize: false, + buttonImage: 'images/ui-colorpicker.png', + buttonImageOnly: false, + buttonText: null, // Text on the button and/or title of button image. + closeOnEscape: true, // Close the dialog when the escape key is pressed. + closeOnOutside: true, // Close the dialog when clicking outside the dialog (not for inline) + color: '#00FF00', // Initial color (for inline only) + colorFormat: 'HEX', // Format string for output color format + disabled: false, // Disable or enable the colorpicker initially + draggable: true, // Make popup dialog draggable if header is visible. + containment: null, // Constrains dragging to within the bounds of the specified element or region. + duration: 'fast', + hideOn: 'button', // 'focus', 'click', 'button', 'alt', 'all' + hsv: true, // Show HSV controls and modes + inline: true, // Show any divs as inline by default + inlineFrame: true, // Show a border and background when inline. + layout: { + map: [0, 0, 1, 5], // Left, Top, Width, Height (in table cells). + bar: [1, 0, 1, 5], + preview: [2, 0, 1, 1], + hsv: [2, 1, 1, 1], + rgb: [2, 2, 1, 1], + alpha: [2, 3, 1, 1], + hex: [2, 4, 1, 1], + lab: [3, 1, 1, 1], + cmyk: [3, 2, 1, 2], + swatches: [4, 0, 1, 5] + }, + limit: '', // Limit color "resolution": '', 'websafe', 'nibble', 'binary', 'name' + modal: false, // Modal dialog? + mode: 'h', // Initial editing mode, h, s, v, r, g, b or a + okOnEnter: false, // Close (with OK) when pressing the enter key + parts: '', // leave empty for automatic selection + part: { + map: { size: 256 }, + bar: { size: 256 } + }, // options per part + position: null, + regional: '', + revert: false, // Revert color upon non + rgb: true, // Show RGB controls and modes + showAnim: 'fadeIn', + showCancelButton: true, + showNoneButton: false, + showCloseButton: true, + showOn: 'focus click alt', // 'focus', 'click', 'button', 'alt', 'all' + showOptions: {}, + swatches: null, // null for default or kv-object or names swatches set + swatchesWidth: 84, // width (in number of pixels) of swatches box. + title: null, + + cancel: null, + close: null, + init: null, + ok: null, + open: null, + select: null, + stop: null + }, + + _create: function () { + var that = this, + text; + + that.colorpicker_index = _colorpicker_index++; + + that.widgetEventPrefix = 'colorpicker'; + + that.opened = false; + that.generated = false; + that.inline = false; + that.changed = false; + + that.dialog = null; + that.button = null; + that.image = null; + that.overlay = null; + + that.events = { + window_resize: null, + document_keydown: null, + document_click_html: null + }; + + that.mode = that.options.mode; + + if (that.element.is('input') || that.options.inline === false) { + // Initial color + that._setColor(that.element.is('input') ? that.element.val() : that.options.color); + that._callback('init'); + + // showOn focus + if (/\bfocus|all|both\b/.test(that.options.showOn)) { + that.element.on('focus', function () { + that.open(); + }); + } + if (/\bfocus|all|both\b/.test(that.options.hideOn)) { + that.element.on('focusout', function (e) { + that.close(); + }); + } + + // showOn click + if (/\bclick|all|both\b/.test(that.options.showOn)) { + that.element.on('click', function (e) { + if (that.opened && /\bclick|all|both\b/.test(that.options.hideOn)) { + that.close(); + } else { + that.open(); + } + }); + } + + // showOn button + if (/\bbutton|all|both\b/.test(that.options.showOn)) { + if (that.options.buttonImage !== '') { + text = that.options.buttonText || that._getRegional('button'); + + that.image = $('').attr({ + 'src': that.options.buttonImage, + 'alt': text, + 'title': text + }); + if (that.options.buttonClass) { + that.image.attr('class', that.options.buttonClass); + } + + that._setImageBackground(); + } + + if (that.options.buttonImageOnly && that.image) { + that.button = that.image; + } else { + that.button = $('').html(that.image || that.options.buttonText).button(); + that.image = that.image ? $('img', that.button).first() : null; + } + that.button.insertAfter(that.element).click(function () { + if (that.opened && /\bbutton|all|both\b/.test(that.options.hideOn)) { + that.close(); + } else { + that.open(); + } + }); + } + + // showOn alt + if (/\balt|all|both\b/.test(that.options.showOn)) { + $(that.options.altField).on('click', function () { + if (that.opened && /\balt|all|both\b/.test(that.options.hideOn)) { + that.close(); + } else { + that.open(); + } + }); + } + + if (that.options.autoOpen) { + that.open(); + } + + } else { + that.inline = true; + + that._generate(); + that.opened = true; + } + + // Disable Widget-style + (that.element.is(':disabled') || that.options.disabled) && that.disable(); + + return this; + }, + + _setOption: function(key, value) { + switch (key) { + case 'disabled': + this[value ? 'disable' : 'enable'](); + break; + + case 'swatches': + this.options.swatches = value; + this.parts.swatches.init(); + break; + } + + $.Widget.prototype._setOption.apply(this, arguments); + }, + + enable: function () { + //$.Widget.prototype.enable.call(this); + this.element && this.element.prop('disabled', false); + this.button && this.button.prop('disabled', false); + this.dialog && this.dialog.removeClass('ui-colorpicker-disabled'); + this.options.disabled = false; + + this.parts && $.each(this.parts, function (index, part) { + part.disable && part.disable(false); + }); + }, + + disable: function () { + //$.Widget.prototype.disable.call(this); + this.element && this.element.prop('disabled', true); + this.button && this.button.prop('disabled', true); + this.dialog && this.dialog.addClass('ui-colorpicker-disabled'); + this.options.disabled = true; + + this.parts && $.each(this.parts, function (index, part) { + part.disable && part.disable(true); + }); + }, + + _setImageBackground: function() { + if (this.image && this.options.buttonColorize) { + this.image.css('background-color', this.color.set? this._formatColor('RGBA', this.color) : ''); + } + }, + + /** + * If an alternate field is specified, set it according to the current color. + */ + _setAltField: function () { + if (this.options.altOnChange && this.options.altField && this.options.altProperties) { + var index, + property, + properties = this.options.altProperties.split(','); + + for (index = 0; index <= properties.length; ++index) { + property = $.trim(properties[index]); + switch (property) { + case 'color': + case 'fill': + case 'stroke': + case 'background-color': + case 'backgroundColor': + case 'outline-color': + case 'border-color': + $(this.options.altField).css(property, this.color.set? this.color.toCSS() : ''); + break; + } + } + + this.options.altAlpha && + $(this.options.altField).css('opacity', this.color.set? this.color.getAlpha() : ''); + } + }, + + _setColor: function(text) { + this.color = this._parseColor(text) || new $.colorpicker.Color(); + this.currentColor = this.color.copy(); + + this._setImageBackground(); + this._setAltField(); + }, + + setColor: function(text) { + this._setColor(text); + this._change(); + }, + + getColor: function(format) { + return this._formatColor(format || this.options.colorFormat, this.color); + }, + + _generateInline: function() { + var that = this; + + $(that.element).html(that.options.inlineFrame ? _container_inlineFrame : _container_inline); + + that.dialog = $('.ui-colorpicker', that.element); + }, + + _generatePopup: function() { + var that = this; + + that.dialog = $(_container_popup).appendTo('body'); + + // Close on clicking outside window and controls + if (that.events.document_click_html === null) { + $(document).on('touchstart click', 'html', that.events.document_click_html = function (event) { + if (!that.opened || event.target === that.element[0] || that.overlay) { + return; + } + + // Check if clicked on any part of dialog + if (that.dialog.is(event.target) || that.dialog.has(event.target).length > 0) { + that.element.blur(); // inside window! + return; + } + + // Check if clicked on known external elements + var p, + parents = $(event.target).parents(); + // add the event.target in case of buttonImageOnly and closeOnOutside both are set to true + parents.push(event.target); + for (p = 0; p <= parents.length; ++p) { + // button + if (that.button !== null && parents[p] === that.button[0]) { + return; + } + // showOn alt + if (/\balt|all|both\b/.test(that.options.showOn) && $(that.options.altField).is(parents[p])) { + return; + } + } + + // no closeOnOutside + if (!that.options.closeOnOutside) { + return; + } + + that.close(that.options.revert); + }); + } + + if (that.events.document_keydown === null) { + $(document).on('keydown', that.events.document_keydown = function (event) { + // close on ESC key + if (that.opened && event.keyCode === 27 && that.options.closeOnEscape) { + that.close(that.options.revert); + } + + // OK on Enter key + if (that.opened && event.keyCode === 13 && that.options.okOnEnter) { + that.close(); + } + }); + } + + // Close (with OK) on tab key in element + that.element.keydown(function (event) { + if (event.keyCode === 9) { + that.close(); + } + }).keyup(function (event) { + var color = that._parseColor(that.element.val()); + if (color && !that.color.equals(color)) { + that.color = color; + that._change(); + } + }); + }, + + _generate: function () { + var that = this, + index, + part, + parts_list, + layout_parts, + table, + classes; + + that._setColor(that.inline || !that.element.is('input') ? that.options.color : that.element.val()); + + that[that.inline ? '_generateInline' : '_generatePopup'](); + + // Determine the parts to include in this colorpicker + if (typeof that.options.parts === 'string') { + if ($.colorpicker.partslists[that.options.parts]) { + parts_list = $.colorpicker.partslists[that.options.parts]; + } else { + // automatic + parts_list = $.colorpicker.partslists[that.inline ? 'inline' : 'popup']; + } + } else { + parts_list = that.options.parts; + } + + // Add any parts to the internal parts list + that.parts = {}; + $.each(parts_list, function(index, part) { + if ($.colorpicker.parts[part]) { + that.parts[part] = new $.colorpicker.parts[part](that); + } + }); + + if (!that.generated) { + layout_parts = []; + + $.each(that.options.layout, function(part, pos) { + if (that.parts[part]) { + layout_parts.push({ + 'part': part, + 'pos': pos + }); + } + }); + + table = $(_layoutTable(layout_parts, function(cell, x, y) { + classes = ['ui-colorpicker-' + cell.part + '-container']; + + if (x > 0) { + classes.push('ui-colorpicker-padding-left'); + } + + if (y > 0) { + classes.push('ui-colorpicker-padding-top'); + } + + return ' 1 ? ' colspan="' + cell.pos[2] + '"' : '') + + (cell.pos[3] > 1 ? ' rowspan="' + cell.pos[3] + '"' : '') + + ' valign="top">'; + })).appendTo(that.dialog); + if (that.options.inlineFrame) { + table.addClass('ui-dialog-content ui-widget-content'); + } + + that._initAllParts(); + that._updateAllParts(); + that.generated = true; + } + }, + + _effectGeneric: function (element, show, slide, fade, callback) { + var that = this; + + if ($.effects && $.effects[that.options.showAnim]) { + element[show](that.options.showAnim, that.options.showOptions, that.options.duration, callback); + } else { + element[(that.options.showAnim === 'slideDown' ? + slide + : (that.options.showAnim === 'fadeIn' ? + fade + : show))]((that.options.showAnim ? that.options.duration : null), callback); + if (!that.options.showAnim || !that.options.duration) { + callback(); + } + } + }, + + _effectShow: function(element, callback) { + this._effectGeneric(element, 'show', 'slideDown', 'fadeIn', callback); + }, + + _effectHide: function(element, callback) { + this._effectGeneric(element, 'hide', 'slideUp', 'fadeOut', callback); + }, + + open: function() { + var that = this, + offset, + bottom, right, + height, width, + x, y, + zIndex, + element, + position; + + if (!that.opened) { + that._generate(); + + if (that.element.is(':hidden')) { + element = $('
').insertBefore(that.element); + } else { + element = that.element; + } + + if (that.element.is(':hidden')) { + element.remove(); + } + + // Automatically find highest z-index. + zIndex = 0; + $(that.element[0]).parents().each(function() { + var z = $(this).css('z-index'); + if ((typeof(z) === 'number' || typeof(z) === 'string') && z !== '' && !isNaN(z)) { + if (z > zIndex) { + zIndex = parseInt(z, 10); + return false; + } + } + else { + $(this).siblings().each(function() { + var z = $(this).css('z-index'); + if ((typeof(z) === 'number' || typeof(z) === 'string') && z !== '' && !isNaN(z)) { + if (z > zIndex) { + zIndex = parseInt(z, 10); + } + } + }); + } + }); + + zIndex += 2; + that.dialog.css('z-index', zIndex); + + if (that.options.modal) { + that.overlay = $('
').appendTo('body').css('z-index', zIndex - 1); + + if (that.events.window_resize !== null) { + $(window).off('resize', that.events.window_resize); + } + + that.events.window_resize = function() { + if (that.overlay) { + that.overlay.width($(document).width()); + that.overlay.height($(document).height()); + } + }, + + $(window).on('resize', that.events.window_resize); + that.events.window_resize(); + } + + that._effectShow(this.dialog); + + if (that.options.position) { + position = $.extend({}, that.options.position); + if (position.of === 'element') { + position.of = element; + } + } else { + position = { + my: 'left top', + at: 'left bottom', + of: element, + collision: 'flip' + }; + } + that.dialog.position(position); + + that.opened = true; + that._callback('open', true); + + // Without waiting for domready the width of the map is 0 and we + // wind up with the cursor stuck in the upper left corner + $(function() { + that._repaintAllParts(); + }); + } + }, + + close: function (cancel) { + var that = this; + + if (!that.opened) { + return; + } + + if (cancel) { + that.color = that.currentColor.copy(); + that._change(); + that._callback('cancel', true); + } else { + that.currentColor = that.color.copy(); + that._callback('ok', true); + } + that.changed = false; + + if (that.overlay) { + $(window).off('resize', that.events.window_resize); + that.overlay.remove(); + } + + // tear down the interface + that._effectHide(that.dialog, function () { + that.dialog.remove(); + that.dialog = null; + that.generated = false; + + that.opened = false; + that._callback('close', true); + }); + }, + + destroy: function() { + var that = this; + if (that.events.document_click_html !== null) { + $(document).off('touchstart click', 'html', that.events.document_click_html); + } + + if (that.events.document_keydown !== null) { + $(document).off('keydown', that.events.document_keydown); + } + + if (that.events.resizeOverlay !== null) { + $(window).off('resize', that.events.resizeOverlay); + } + + this.element.off(); + + if (this.overlay) { + this.overlay.remove(); + } + + if (this.dialog !== null) { + this.dialog.remove(); + } + + if (this.image !== null) { + this.image.remove(); + } + + if (this.button !== null) { + this.button.remove(); + } + }, + + _callback: function (callback, spaces) { + var that = this, + data, + lab; + + if (that.color.set) { + data = { + formatted: that._formatColor(that.options.colorFormat, that.color), + colorPicker: that + }; + + lab = that.color.getLAB(); + lab.a = (lab.a * 2) - 1; + lab.b = (lab.b * 2) - 1; + + if (spaces === true) { + data.a = that.color.getAlpha(); + data.rgb = that.color.getRGB(); + data.hsv = that.color.getHSV(); + data.cmyk = that.color.getCMYK(); + data.hsl = that.color.getHSL(); + data.lab = lab; + } + + return that._trigger(callback, null, data); + } else { + return that._trigger(callback, null, { + formatted: '', + colorPicker: that + }); + } + }, + + _initAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.init) { + part.init(); + } + }); + }, + + _updateAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.update) { + part.update(); + } + }); + }, + + _repaintAllParts: function () { + $.each(this.parts, function (index, part) { + if (part.repaint) { + part.repaint(); + } + }); + }, + + _change: function (stoppedChanging /* = true */) { + // Limit color palette + if (this.color.set && this.options.limit && $.colorpicker.limits[this.options.limit]) { + $.colorpicker.limits[this.options.limit](this.color, this); + } + + // Set changed if different from starting color + this.changed = !this.color.equals(this.currentColor); + + // update input element content + if (!this.inline) { + if (!this.color.set) { + if (this.element.val() !== '') { + this.element.val('').change(); + } + } else if (!this.color.equals(this._parseColor(this.element.val()))) { + this.element.val(this._formatColor(this.options.colorFormat, this.color)).change(); + } + + this._setImageBackground(); + } + + // Set the alt field + this._setAltField(); + + // update color option + this.options.color = this.color.set ? this.color.toCSS() : ''; + + if (this.opened) { + this._repaintAllParts(); + } + + // callbacks + this._callback('select'); + + if (typeof stoppedChanging === 'undefined' ? true : !!stoppedChanging) { + this._callback('stop'); + } + }, + + // This will be deprecated by jQueryUI 1.9 widget + _hoverable: function (e) { + e.hover(function () { + e.addClass("ui-state-hover"); + }, function () { + e.removeClass("ui-state-hover"); + }); + }, + + // This will be deprecated by jQueryUI 1.9 widget + _focusable: function (e) { + e.focus(function () { + e.addClass("ui-state-focus"); + }).blur(function () { + e.removeClass("ui-state-focus"); + }); + }, + + _getRegional: function(name) { + return $.colorpicker.regional[this.options.regional][name] !== undefined ? + $.colorpicker.regional[this.options.regional][name] : $.colorpicker.regional[''][name]; + }, + + _getSwatches: function() { + if (typeof(this.options.swatches) === 'string') { + return $.colorpicker.swatches[this.options.swatches]; + } + + if ($.isPlainObject(this.options.swatches)) { + return this.options.swatches; + } + + return $.colorpicker.swatches.html; + }, + + _eachSwatch: function (callback) { + var currentSwatches = this._getSwatches(), + name; + $.each(currentSwatches, function (nameOrIndex, swatch) { + name = $.isArray(currentSwatches) ? swatch.name : nameOrIndex; + return callback(name, swatch); + }); + }, + + _getSwatch: function(name) { + var swatch = false; + + this._eachSwatch(function(swatchName, current) { + if (swatchName.toLowerCase() == name.toLowerCase()) { + swatch = current; + return false; + } + }); + + return swatch; + }, + + _parseFormat: function(format, text) { + var that = this, + typeRegexps = { + x: function() {return '([0-9a-fA-F]{2})';} + , d: function() {return '([12]?[0-9]{1,2})';} + , f: function() {return '([0-9]*\\.?[0-9]*)';} + , p: function() {return '([0-9]*\\.?[0-9]*)';} + }, + typeConverters = { + x: function(v) {return parseInt(v, 16) / 255.;} + , d: function(v) {return v / 255.;} + , f: function(v) {return v;} + , p: function(v) {return v * 0.01;} + }, + setters = { + r: 'setRGB' + , g: 'setRGB' + , b: 'setRGB' + , h: 'setHSV' + , s: 'setHSV' + , v: 'setHSV' + , c: 'setCMYK' + , m: 'setCMYK' + , y: 'setCMYK' + , k: 'setCMYK' + , L: 'setLAB' + , A: 'setLAB' + , B: 'setLAB' + }, + setterChannels = { + setRGB: [ 'r', 'g', 'b'] + , setHSV: [ 'h', 's', 'v' ] + , setCMYK: [ 'c', 'm', 'y', 'k' ] + , setLAB: [ 'L', 'A', 'B' ] + }, + channels = [], + converters = [], + setter = null, + color, + pattern; + + // Construct pattern + pattern = format.replace(/[()\\^$.|?*+[\]]/g, function(m) { + return '\\'+m; + }); + + + pattern = pattern.replace(/\\?[argbhsvcmykLAB][xdfp]/g, function(variable) { + if (variable.match(/^\\/)) { + return variable.slice(1); + } + + var channel = variable.charAt(0), + type = variable.charAt(1); + + channels.push(channel); + converters.push(typeConverters[type]); + if (setters[channel]) { + setter = setters[channel]; + } + + return typeRegexps[type](); + }); + + if (setter) { + var values = text.match(new RegExp(pattern)); + if (values) { + var args = [], + channelIndex; + + values.shift(); + + $.each(setterChannels[setter], function(index, channel) { + channelIndex = $.inArray(channel, channels); + args[index] = converters[channelIndex](values[channelIndex]); + }); + + color = new $.colorpicker.Color(); + color[setter].apply(color, args); + } + } + + return color; + }, + + _parseColor: function(text) { + var that = this, + color; + + var formats = $.isArray(that.options.colorFormat) + ? that.options.colorFormat + : [ that.options.colorFormat ]; + + $.each(formats, function(index, format) { + if ($.colorpicker.parsers[format]) { + color = $.colorpicker.parsers[format](text, that); + } else { + color = that._parseFormat(format, text); + } + + if (color) { + return false; + } + }); + + if (!color) { + // fallback; check all registered parsers + $.each($.colorpicker.parsers, function(name, parser) { + color = parser(text, that); + if (color) { + return false; + } + }); + } + + if (color) { + return color; + } + + return false; + }, + + _exactName: function(color) { + var name = false; + + this._eachSwatch(function(n, swatch) { + if (color.equals(new $.colorpicker.Color(swatch.r, swatch.g, swatch.b))) { + name = n; + return false; + } + }); + + return name; + }, + + _closestName: function(color) { + var rgb = color.getRGB(), + distance = null, + name = false, + d; + + this._eachSwatch(function(n, swatch) { + d = color.distance(new $.colorpicker.Color(swatch.r, swatch.g, swatch.b)); + if (d < distance || distance === null) { + name = n; + if (d <= 1e-20) { // effectively 0 by maximum rounding error + return false; // can't get much closer than 0 + } + distance = d; // safety net + } + }); + + return name; + }, + + _formatColor: function (formats, color) { + var that = this, + text = null, + types = { 'x': function(v) {return _intToHex(v * 255);} + , 'd': function(v) {return Math.round(v * 255);} + , 'f': function(v) {return v;} + , 'p': function(v) {return v * 100.;} + }, + channels = color.getChannels(); + + if (!$.isArray(formats)) { + formats = [formats]; + } + + $.each(formats, function(index, format) { + if ($.colorpicker.writers[format]) { + text = $.colorpicker.writers[format](color, that); + return (text === false); + } else { + text = format.replace(/\\?[argbhsvcmykLAB][xdfp]/g, function(m) { + if (m.match(/^\\/)) { + return m.slice(1); + } + return types[m.charAt(1)](channels[m.charAt(0)]); + }); + return false; + } + }); + + return text; + } + }); + + return $.vanderlee.colorpicker; +})); diff --git a/src/lib/js/jquery.flot.categories.min.js b/src/lib/js/jquery.flot.categories.min.js new file mode 100644 index 0000000..5bce588 --- /dev/null +++ b/src/lib/js/jquery.flot.categories.min.js @@ -0,0 +1,7 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){var options={xaxis:{categories:null},yaxis:{categories:null}};function processRawData(plot,series,data,datapoints){var xCategories=series.xaxis.options.mode=="categories",yCategories=series.yaxis.options.mode=="categories";if(!(xCategories||yCategories))return;var format=datapoints.format;if(!format){var s=series;format=[];format.push({x:true,number:true,required:true});format.push({y:true,number:true,required:true});if(s.bars.show||s.lines.show&&s.lines.fill){var autoscale=!!(s.bars.show&&s.bars.zero||s.lines.show&&s.lines.zero);format.push({y:true,number:true,required:false,defaultValue:0,autoscale:autoscale});if(s.bars.horizontal){delete format[format.length-1].y;format[format.length-1].x=true}}datapoints.format=format}for(var m=0;mindex)index=categories[v];return index+1}function categoriesTickGenerator(axis){var res=[];for(var label in axis.categories){var v=axis.categories[label];if(v>=axis.min&&v<=axis.max)res.push([v,label])}res.sort(function(a,b){return a[0]-b[0]});return res}function setupCategoriesForAxis(series,axis,datapoints){if(series[axis].options.mode!="categories")return;if(!series[axis].categories){var c={},o=series[axis].options.categories||{};if($.isArray(o)){for(var i=0;i, + * + * // lineWidth + * // default: 2 + * // The width of the dashed line in pixels. + * lineWidth: , + * + * // dashLength + * // default: 10 + * // Controls the length of the individual dashes and the amount of + * // space between them. + * // If this is a number, the dashes and spaces will have that length. + * // If this is an array, it is read as [ dashLength, spaceLength ] + * dashLength: or + * } + * } + * } + */ +(function($){ + var options = { + series: { + dashes: { + show: false, + lineWidth: 2, + dashLength: 10 + } + } + }; + function init(plot) { + plot.hooks.drawSeries.push(function(plot, ctx, series) { + if (!series.dashes.show) return; + + var plotOffset = plot.getPlotOffset(), + axisx = series.xaxis, + axisy = series.yaxis; + + function plotDashes(xoffset, yoffset) { + + var points = series.datapoints.points, + ps = series.datapoints.pointsize, + prevx = null, + prevy = null, + dashRemainder = 0, + dashOn = true, + dashOnLength, + dashOffLength; + + if (series.dashes.dashLength[0]) { + dashOnLength = series.dashes.dashLength[0]; + if (series.dashes.dashLength[1]) { + dashOffLength = series.dashes.dashLength[1]; + } else { + dashOffLength = dashOnLength; + } + } else { + dashOffLength = dashOnLength = series.dashes.dashLength; + } + + ctx.beginPath(); + + for (var i = ps; i < points.length; i += ps) { + + var x1 = points[i - ps], + y1 = points[i - ps + 1], + x2 = points[i], + y2 = points[i + 1]; + + if (x1 == null || x2 == null) continue; + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) continue; // line segment is outside + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) continue; + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) continue; + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) continue; + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 != prevx || y1 != prevy) { + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + } + + var ax1 = axisx.p2c(x1) + xoffset, + ay1 = axisy.p2c(y1) + yoffset, + ax2 = axisx.p2c(x2) + xoffset, + ay2 = axisy.p2c(y2) + yoffset, + dashOffset; + + function lineSegmentOffset(segmentLength) { + + var c = Math.sqrt(Math.pow(ax2 - ax1, 2) + Math.pow(ay2 - ay1, 2)); + + if (c <= segmentLength) { + return { + deltaX: ax2 - ax1, + deltaY: ay2 - ay1, + distance: c, + remainder: segmentLength - c + } + } else { + var xsign = ax2 > ax1 ? 1 : -1, + ysign = ay2 > ay1 ? 1 : -1; + return { + deltaX: xsign * Math.sqrt(Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))), + deltaY: ysign * Math.sqrt(Math.pow(segmentLength, 2) - Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))), + distance: segmentLength, + remainder: 0 + }; + } + } + //-end lineSegmentOffset + + do { + + dashOffset = lineSegmentOffset( + dashRemainder > 0 ? dashRemainder : + dashOn ? dashOnLength : dashOffLength); + + if (dashOffset.deltaX != 0 || dashOffset.deltaY != 0) { + if (dashOn) { + ctx.lineTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY); + } else { + ctx.moveTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY); + } + } + + dashOn = !dashOn; + dashRemainder = dashOffset.remainder; + ax1 += dashOffset.deltaX; + ay1 += dashOffset.deltaY; + + } while (dashOffset.distance > 0); + + prevx = x2; + prevy = y2; + } + + ctx.stroke(); + } + //-end plotDashes + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = 'round'; + + var lw = series.dashes.lineWidth, + sw = series.shadowSize; + + // FIXME: consider another form of shadow when filling is turned on + if (lw > 0 && sw > 0) { + // draw shadow as a thick and thin line with transparency + ctx.lineWidth = sw; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + // position shadow at angle from the mid of line + var angle = Math.PI/18; + plotDashes(Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2)); + ctx.lineWidth = sw/2; + plotDashes(Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4)); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + + if (lw > 0) { + plotDashes(0, 0); + } + + ctx.restore(); + + }); + //-end draw hook + } + //-end init + + $.plot.plugins.push({ + init: init, + options: options, + name: 'dashes', + version: '0.1' + }); + +})(jQuery); diff --git a/src/lib/js/jquery.flot.fillbetween.js b/src/lib/js/jquery.flot.fillbetween.js new file mode 100644 index 0000000..69700e7 --- /dev/null +++ b/src/lib/js/jquery.flot.fillbetween.js @@ -0,0 +1,183 @@ +/* +Flot plugin for computing bottoms for filled line and bar charts. + +The case: you've got two series that you want to fill the area +between. In Flot terms, you need to use one as the fill bottom of the +other. You can specify the bottom of each data point as the third +coordinate manually, or you can use this plugin to compute it for you. + +In order to name the other series, you need to give it an id, like this + + var dataset = [ + { data: [ ... ], id: "foo" } , // use default bottom + { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom + ]; + + $.plot($("#placeholder"), dataset, { line: { show: true, fill: true }}); + +As a convenience, if the id given is a number that doesn't appear as +an id in the series, it is interpreted as the index in the array +instead (so fillBetween: 0 can also mean the first series). + +Internally, the plugin modifies the datapoints in each series. For +line series, extra data points might be inserted through +interpolation. Note that at points where the bottom line is not +defined (due to a null point or start/end of line), the current line +will show a gap too. The algorithm comes from the jquery.flot.stack.js +plugin, possibly some code could be shared. +*/ + +(function ($) { + var options = { + series: { fillBetween: null } // or number + }; + + function init(plot) { + function findBottomSeries(s, allseries) { + var i; + for (i = 0; i < allseries.length; ++i) { + if (allseries[i].id == s.fillBetween) + return allseries[i]; + } + + if (typeof s.fillBetween == "number") { + i = s.fillBetween; + + if (i < 0 || i >= allseries.length) + return null; + + return allseries[i]; + } + + return null; + } + + function computeFillBottoms(plot, s, datapoints) { + if (s.fillBetween == null) + return; + + var other = findBottomSeries(s, plot.getData()); + if (!other) + return; + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + withbottom = ps > 2 && datapoints.format[2].y, + withsteps = withlines && s.lines.steps, + fromgap = true, + i = 0, j = 0, l; + + while (true) { + if (i >= points.length) + break; + + l = newpoints.length; + + if (points[i] == null) { + // copy gaps + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + i += ps; + } + else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + } + i += ps; + } + else if (otherpoints[j] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) + newpoints.push(null); + fromgap = true; + j += otherps; + } + else { + // cases where we actually got two points + px = points[i]; + py = points[i + 1]; + qx = otherpoints[j]; + qy = otherpoints[j + 1]; + bottom = 0; + + if (px == qx) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + //newpoints[l + 1] += qy; + bottom = qy; + + i += ps; + j += otherps; + } + else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + if (withlines && i > 0 && points[i - ps] != null) { + intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px); + newpoints.push(qx); + newpoints.push(intery) + for (m = 2; m < ps; ++m) + newpoints.push(points[i + m]); + bottom = qy; + } + + j += otherps; + } + else { // px < qx + if (fromgap && withlines) { + // if we come from a gap, we just skip this point + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + // we might be able to interpolate a point below, + // this can give us a better y + if (withlines && j > 0 && otherpoints[j - otherps] != null) + bottom = qy + (otherpoints[j - otherps + 1] - qy) * (px - qx) / (otherpoints[j - otherps] - qx); + + //newpoints[l + 1] += bottom; + + i += ps; + } + + fromgap = false; + + if (l != newpoints.length && withbottom) + newpoints[l + 2] = bottom; + } + + // maintain the line steps invariant + if (withsteps && l != newpoints.length && l > 0 + && newpoints[l] != null + && newpoints[l] != newpoints[l - ps] + && newpoints[l + 1] != newpoints[l - ps + 1]) { + for (m = 0; m < ps; ++m) + newpoints[l + ps + m] = newpoints[l + m]; + newpoints[l + 1] = newpoints[l - ps + 1]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push(computeFillBottoms); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'fillbetween', + version: '1.0' + }); +})(jQuery); diff --git a/src/lib/js/jquery.flot.grow.js b/src/lib/js/jquery.flot.grow.js new file mode 100644 index 0000000..488fd45 --- /dev/null +++ b/src/lib/js/jquery.flot.grow.js @@ -0,0 +1,181 @@ +/* + * The MIT License + +Copyright (c) 2010,2011,2012, 2013 by Juergen Marsch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +/* + * Added changerequest from Thodoris Greasidis + * It makes growing more + */ +(function ($){ + "use strict"; + var pluginName = "grow", pluginVersion = "0.4"; + var options = { + series: { + grow: { + active: false, + stepDelay: 20, + steps:100, + growings:[ + { + valueIndex: 1, + stepMode: "linear", + stepDirection: "up" + } + ] + } + } + }; + function init(plot) { + var done = false; + var growfunc; + var plt = plot; + var data = null; + var opt = null; + var serie = null; + var valueIndex; + plot.hooks.bindEvents.push(processbindEvents); + plot.hooks.drawSeries.push(processSeries); + plot.hooks.shutdown.push(shutdown); + function processSeries(plot, canvascontext, series){ + opt = plot.getOptions(); + valueIndex = opt.series.grow.valueIndex; + if(opt.series.grow.active === true){ + if (done === false){ + data = plot.getData(); + data.actualStep = 0; + data.growingIndex = 0; + for (var j = 0; j < data.length; j++){ + data[j].dataOrg = clone(data[j].data); + for (var i = 0; i < data[j].data.length; i++){ data[j].data[i][valueIndex] = 0;} + } + plot.setData(data); + done = true; + } + } + } + function processbindEvents(plot,eventHolder){ + opt = plot.getOptions(); + if (opt.series.grow.active === true){ + var d = plot.getData(); + for (var j = 0; j < data.length; j++) { + opt.series.grow.steps = Math.max(opt.series.grow.steps, d[j].grow.steps); + } + if(opt.series.grow.stepDelay === 0){ opt.series.grow.stepDelay++;} + growingLoop(); + if (isPluginRegistered("resize")) { + plot.getPlaceholder().bind("resize", onResize); + } + } + } + function growingLoop(){ + var growing, startTime = new Date(), timeDiff; + if (data.actualStep < opt.series.grow.steps){ + data.actualStep++; + for(var j = 0; j < data.length; j++){ + for(var g = 0; g < data[j].grow.growings.length; g++){ + growing = data[j].grow.growings[g]; + if (typeof growing.stepMode === "function"){ + growing.stepMode(data[j],data.actualStep,growing); + } + else{ + if (growing.stepMode === "linear"){ growLinear();} + else if (growing.stepMode === "maximum"){ growMaximum();} + else if (growing.stepMode === "delay"){ growDelay();} + else{growNone();} + } + } + } + plt.setData(data); + plt.draw(); + timeDiff = new Date() - startTime; + growfunc = window.setTimeout(growingLoop, Math.max(0,opt.series.grow.stepDelay - timeDiff)); + } + else{ window.clearTimeout(growfunc); growfunc = null; } + function growNone(){ + if (data.actualStep === 1){ + for (var i = 0; i < data[j].data.length; i++){ + data[j].data[i][valueIndex] = data[j].dataOrg[i][growing.valueIndex]; + } + } + } + function growLinear(){ + if (data.actualStep <= data[j].grow.steps){ + for (var i = 0; i < data[j].data.length; i++){ + if (growing.stepDirection === "up"){ + data[j].data[i][growing.valueIndex] = data[j].dataOrg[i][growing.valueIndex] / data[j].grow.steps * data.actualStep; + } + else if(growing.stepDirection === "down"){ + data[j].data[i][growing.valueIndex] = data[j].dataOrg[i][growing.valueIndex] + (data[j].yaxis.max - data[j].dataOrg[i][growing.valueIndex]) / data[j].grow.steps * (data[j].grow.steps - data.actualStep); + } + } + } + } + function growMaximum(){ + if (data.actualStep <= data[j].grow.steps){ + for (var i = 0; i < data[j].data.length; i++){ + if (growing.stepDirection === "up"){ + data[j].data[i][growing.valueIndex] = Math.min(data[j].dataOrg[i][growing.valueIndex], data[j].yaxis.max / data[j].grow.steps * data.actualStep); + } + else if (growing.stepDirection === "down"){ + data[j].data[i][growing.valueIndex] = Math.max(data[j].dataOrg[i][growing.valueIndex], data[j].yaxis.max / data[j].grow.steps * (data[j].grow.steps - data.actualStep) ); + } + } + } + } + function growDelay(){ + if (data.actualStep == data[j].grow.steps){ + for (var i = 0; i < data[j].data.length; i++){ + data[j].data[i][growing.valueIndex] = data[j].dataOrg[i][growing.valueIndex]; + } + } + } + } + function onResize() { + if (growfunc) { window.clearTimeout(growfunc); growfunc = null; } + } + function shutdown(plot, eventHolder) { + plot.getPlaceholder().unbind("resize", onResize); + } + function isPluginRegistered(pluginName) { + var plugins = $.plot.plugins; + for (var i = 0, len = plugins.length; i < len; i++) { + var plug = plugins[i]; + if (plug.name === pluginName) { + return true; + } + } + return false; + } + function clone(obj){ + if(obj === null || typeof(obj) !== 'object'){ return obj;} + var temp = new obj.constructor(); + for(var key in obj){temp[key] = clone(obj[key]); } + return temp; + } + } + $.plot.plugins.push({ + init: init, + options: options, + name: pluginName, + version: pluginVersion + }); +})(jQuery); \ No newline at end of file diff --git a/src/lib/js/jquery.flot.hiddengraphs.js b/src/lib/js/jquery.flot.hiddengraphs.js new file mode 100644 index 0000000..9ede546 --- /dev/null +++ b/src/lib/js/jquery.flot.hiddengraphs.js @@ -0,0 +1,229 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Plugin to hide series in flot graphs. + * + * To activate, set legend.hideable to true in the flot options object. + * To hide one or more series by default, set legend.hidden to an array of + * label strings. + * + * At the moment, this only works with line and point graphs. + * + * Example: + * + * var plotdata = [ + * { + * data: [[1, 1], [2, 1], [3, 3], [4, 2], [5, 5]], + * label: "graph 1" + * }, + * { + * data: [[1, 0], [2, 1], [3, 0], [4, 4], [5, 3]], + * label: "graph 2" + * } + * ]; + * + * plot = $.plot($("#placeholder"), plotdata, { + * series: { + * points: { show: true }, + * lines: { show: true } + * }, + * legend: { + * hideable: true, + * hidden: ["graph 1", "graph 2"] + * } + * }); + * + */ +(function ($) { + var options = { }; + + function init(plot) { + var drawnOnce = false; + + function findPlotSeries(label) { + var plotdata = plot.getData(); + for (var i = 0; i < plotdata.length; i++) { + if (plotdata[i].label == label) { + return plotdata[i]; + } + } + return null; + } + + function plotLabelClicked(label, mouseOut) { + var series = findPlotSeries(label); + if (!series) { + return; + } + + var options = plot.getOptions(); + var switchedOff = false; + + if (typeof series.points.oldShow === "undefined") { + series.points.oldShow = false; + } + if (typeof series.lines.oldShow === "undefined") { + series.lines.oldShow = false; + } + + if (series.points.show && !series.points.oldShow) { + series.points.show = false; + series.points.oldShow = true; + switchedOff = true; + } + if (series.lines.show && !series.lines.oldShow) { + series.lines.show = false; + series.lines.oldShow = true; + switchedOff = true; + } + + if (switchedOff) { + series.oldColor = series.color; + series.color = "#fff"; + setHidden(options, label, true); + } else { + var switchedOn = false; + + if (!series.points.show && series.points.oldShow) { + series.points.show = true; + series.points.oldShow = false; + switchedOn = true; + } + if (!series.lines.show && series.lines.oldShow) { + series.lines.show = true; + series.lines.oldShow = false; + switchedOn = true; + } + + if (switchedOn) { + series.color = series.oldColor; + setHidden(options, label, false); + } + } + } + + function setSetupRedraw () { + // HACK: Reset the data, triggering recalculation of graph bounds + plot.setData(plot.getData()); + + plot.setupGrid(); + plot.draw(); + } + + function setHidden(options, label, hide) { + // Record state to a new variable in the legend option object. + if (!options.legend.hidden) { + options.legend.hidden = []; + } + + var pos = options.legend.hidden.indexOf(label); + + if (hide) { + if (pos < 0) { + options.legend.hidden.push(label); + } + } else { + if (pos > -1) { + options.legend.hidden.splice(pos, 1); + } + } + } + + function setHideAction(elem) { + elem.mouseenter(function() { $(this).css("cursor", "pointer"); }) + .mouseleave(function() { $(this).css("cursor", "default"); }) + .unbind("click").click(function() { + if ($(this).is(".legendColorBox")) { + plotLabelClicked($(this).next('.legendLabel').text()); + } else { + plotLabelClicked($(this).parent().text()); + } + setSetupRedraw(); + }); + } + + function plotLabelHandlers(plot) { + var options = plot.getOptions(); + + if (!options.legend.hideable) { + return; + } + + var p = plot.getPlaceholder(); + + setHideAction(p.find(".graphlabel")); + setHideAction(p.find(".legendColorBox")); + + if (!drawnOnce) { + drawnOnce = true; + if (options.legend.hidden) { + for (var i = 0; i < options.legend.hidden.length; i++) { + plotLabelClicked(options.legend.hidden[i], true); + } + setSetupRedraw(); + } + } + } + + function checkOptions(plot, options) { + if (!options.legend.hideable) { + return; + } + + options.legend.labelFormatter = function(label, series) { + return '' + label + ''; + }; + } + + function hideDatapointsIfNecessary(plot, s, datapoints) { + var options = plot.getOptions(); + + if (!options.legend.hideable) { + return; + } + + if (options.legend.hidden && + options.legend.hidden.indexOf(s.label) > -1) { + var off = false; + + if (s.points.show) { + s.points.show = false; + s.points.oldShow = true; + off = true; + } + if (s.lines.show) { + s.lines.show = false; + s.lines.oldShow = true; + off = true; + } + + if (off) { + s.oldColor = s.color; + s.color = "#fff"; + } + } + + if (!s.points.show && !s.lines.show) { + s.datapoints.format = [ null, null ]; + } + } + + plot.hooks.processOptions.push(checkOptions); + + plot.hooks.draw.push(function (plot, ctx) { + plotLabelHandlers(plot); + }); + + plot.hooks.processDatapoints.push(hideDatapointsIfNecessary); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'hiddenGraphs', + version: '1.1' + }); + +})(jQuery); diff --git a/src/lib/js/jquery.flot.js b/src/lib/js/jquery.flot.js new file mode 100644 index 0000000..86c43ae --- /dev/null +++ b/src/lib/js/jquery.flot.js @@ -0,0 +1,3177 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ + +// first an inline dependency, jquery.colorhelpers.js, we inline it here +// for convenience + +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return valuemax?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); + +// the actual Flot code +(function($) { + + // Cache the prototype hasOwnProperty for faster access + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM + // operation produces the same effect as detach, i.e. removing the element + // without touching its jQuery data. + + // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. + + if (!$.fn.detach) { + $.fn.detach = function() { + return this.each(function() { + if (this.parentNode) { + this.parentNode.removeChild( this ); + } + }); + }; + } + + /////////////////////////////////////////////////////////////////////////// + // The Canvas object is a wrapper around an HTML5 tag. + // + // @constructor + // @param {string} cls List of classes to apply to the canvas. + // @param {element} container Element onto which to append the canvas. + // + // Requiring a container is a little iffy, but unfortunately canvas + // operations don't work unless the canvas is attached to the DOM. + + function Canvas(cls, container) { + + var element = container.children("." + cls)[0]; + + if (element == null) { + + element = document.createElement("canvas"); + element.className = cls; + + $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) + .appendTo(container); + + // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas + + if (!element.getContext) { + if (window.G_vmlCanvasManager) { + element = window.G_vmlCanvasManager.initElement(element); + } else { + throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + } + } + } + + this.element = element; + + var context = this.context = element.getContext("2d"); + + // Determine the screen's ratio of physical to device-independent + // pixels. This is the ratio between the canvas width that the browser + // advertises and the number of pixels actually present in that space. + + // The iPhone 4, for example, has a device-independent width of 320px, + // but its screen is actually 640px wide. It therefore has a pixel + // ratio of 2, while most normal devices have a ratio of 1. + + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + this.pixelRatio = devicePixelRatio / backingStoreRatio; + + // Size the canvas to match the internal dimensions of its container + + this.resize(container.width(), container.height()); + + // Collection of HTML div layers for text overlaid onto the canvas + + this.textContainer = null; + this.text = {}; + + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. + + this._textCache = {}; + } + + // Resizes the canvas to the given dimensions. + // + // @param {number} width New width of the canvas, in pixels. + // @param {number} width New height of the canvas, in pixels. + + Canvas.prototype.resize = function(width, height) { + + if (width <= 0 || height <= 0) { + throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); + } + + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; + + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. + + // Resizing should reset the state (excanvas seems to be buggy though) + + if (this.width != width) { + element.width = width * pixelRatio; + element.style.width = width + "px"; + this.width = width; + } + + if (this.height != height) { + element.height = height * pixelRatio; + element.style.height = height + "px"; + this.height = height; + } + + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. + + context.restore(); + context.save(); + + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. + + context.scale(pixelRatio, pixelRatio); + }; + + // Clears the entire canvas area, not including any overlaid HTML text + + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + // Finishes rendering the canvas, including managing the text overlay. + + Canvas.prototype.render = function() { + + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + + var layer = this.getTextLayer(layerKey), + layerCache = cache[layerKey]; + + layer.hide(); + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var positions = styleCache[key].positions; + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + if (!position.rendered) { + layer.append(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + position.element.detach(); + } + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + + layer.show(); + } + } + }; + + // Creates (if necessary) and returns the text overlay container. + // + // @param {string} classes String of space-separated CSS classes used to + // uniquely identify the text layer. + // @return {object} The jQuery-wrapped text-layer div. + + Canvas.prototype.getTextLayer = function(classes) { + + var layer = this.text[classes]; + + // Create the text layer if it doesn't exist + + if (layer == null) { + + // Create the text layer container, if it doesn't exist + + if (this.textContainer == null) { + this.textContainer = $("
") + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0, + 'font-size': "smaller", + color: "#545454" + }) + .insertAfter(this.element); + } + + layer = this.text[classes] = $("
") + .addClass(classes) + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0 + }) + .appendTo(this.textContainer); + } + + return layer; + }; + + // Creates (if necessary) and returns a text info object. + // + // The object looks like this: + // + // { + // width: Width of the text's wrapper div. + // height: Height of the text's wrapper div. + // element: The jQuery-wrapped HTML div containing the text. + // positions: Array of positions at which this text is drawn. + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // rendered: Flag indicating whether the text is currently visible. + // element: The jQuery-wrapped HTML div containing the text. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + // + // Each position after the first receives a clone of the original element. + // + // The idea is that that the width, height, and general 'identity' of the + // text is constant no matter where it is placed; the placements are a + // secondary property. + // + // Canvas maintains a cache of recently-used text info objects; getTextInfo + // either returns the cached element or creates a new entry. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {string} text Text string to retrieve info for. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @return {object} a text info object. + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = "" + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + // If we can't find a matching element in our cache, create a new one + + if (info == null) { + + var element = $("
").html(text) + .css({ + position: "absolute", + 'max-width': width, + top: -9999 + }) + .appendTo(this.getTextLayer(layer)); + + if (typeof font === "object") { + element.css({ + font: textStyle, + color: font.color + }); + } else if (typeof font === "string") { + element.addClass(font); + } + + info = styleCache[text] = { + width: element.outerWidth(true), + height: element.outerHeight(true), + element: element, + positions: [] + }; + + element.detach(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + // + // The text isn't drawn immediately; it is marked as rendering, which will + // result in its addition to the canvas on the next render pass. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number} x X coordinate at which to draw the text. + // @param {number} y Y coordinate at which to draw the text. + // @param {string} text Text string to draw. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @param {string=} halign Horizontal alignment of the text; either "left", + // "center" or "right". + // @param {string=} valign Vertical alignment of the text; either "top", + // "middle" or "bottom". + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign == "center") { + x -= info.width / 2; + } else if (halign == "right") { + x -= info.width; + } + + if (valign == "middle") { + y -= info.height / 2; + } else if (valign == "bottom") { + y -= info.height; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.clone() : info.element, + x: x, + y: y + }; + + positions.push(position); + + // Move the element to its final position within the container + + position.element.css({ + top: Math.round(y), + left: Math.round(x), + 'text-align': halign // In case the text wraps + }); + }; + + // Removes one or more text strings from the canvas text overlay. + // + // If no parameters are given, all text within the layer is removed. + // + // Note that the text is not immediately removed; it is simply marked as + // inactive, which will result in its removal on the next render pass. + // This avoids the performance penalty for 'clear and redraw' behavior, + // where we potentially get rid of all text on a layer, but will likely + // add back most or all of it later, as when redrawing axes, for example. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number=} x X coordinate of the text. + // @param {number=} y Y coordinate of the text. + // @param {string=} text Text string to remove. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which the text is rotated, in degrees. + // Angle is currently unused, it will be implemented in the future. + + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + for (var i = 0, position; position = positions[i]; i++) { + position.active = false; + } + } + } + } + } + } + } else { + var positions = this.getTextInfo(layer, text, font, angle).positions; + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = false; + } + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. + + function Plot(placeholder, data_, options_, plugins) { + // data is on the form: + // [ series1, series2 ... ] + // where series is either just the data as [ [x1, y1], [x2, y2], ... ] + // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } + + var series = [], + options = { + // the color theme used for graphs + colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], + legend: { + show: true, + noColumns: 1, // number of colums in legend table + labelFormatter: null, // fn: string -> string + labelBoxBorderColor: "#ccc", // border color for the little label boxes + container: null, // container (as jQuery object) to put legend in, null means default on top of graph + position: "ne", // position of default legend container within plot + margin: 5, // distance from grid edge to default legend container within plot + backgroundColor: null, // null means auto-detect + backgroundOpacity: 0.85, // set to 0 to avoid background + sorted: null // default to no legend sorting + }, + xaxis: { + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoscaleMargin: null, // margin in % to add if auto-setting min/max + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of ticks, or "full" for whole line + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null // number or [number, "unit"] + }, + yaxis: { + autoscaleMargin: 0.02, + position: "left" // or "right" + }, + xaxes: [], + yaxes: [], + series: { + points: { + show: false, + radius: 3, + lineWidth: 2, // in pixels + fill: true, + fillColor: "#ffffff", + symbol: "circle" // or callback + }, + lines: { + // we don't put in show: false so we can see + // whether lines were actively disabled + lineWidth: 2, // in pixels + fill: false, + fillColor: null, + steps: false + // Omit 'zero', so we can later default its value to + // match that of the 'fill' option. + }, + bars: { + show: false, + lineWidth: 2, // in pixels + barWidth: 1, // in units of the x axis + fill: true, + fillColor: null, + align: "left", // "left", "right", or "center" + horizontal: false, + zero: true + }, + shadowSize: 3, + highlightColor: null + }, + grid: { + show: true, + aboveData: false, + color: "#545454", // primary color used for outline and labels + backgroundColor: null, // null for transparent, else color + borderColor: null, // set if different from the grid color + tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" + margin: 0, // distance from the canvas edge to the grid + labelMargin: 5, // in pixels + axisMargin: 8, // in pixels + borderWidth: 2, // in pixels + minBorderMargin: null, // in pixels, null means taken from points radius + markings: null, // array of ranges or fn: axes -> array of ranges + markingsColor: "#f4f4f4", + markingsLineWidth: 2, + // interactive stuff + clickable: false, + hoverable: false, + autoHighlight: true, // highlight in case mouse is near + mouseActiveRadius: 10 // how far the mouse can be away to activate an item + }, + interaction: { + redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow + }, + hooks: {} + }, + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, octx = null, + xaxes = [], yaxes = [], + plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, + plotWidth = 0, plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + drawBackground: [], + drawSeries: [], + draw: [], + bindEvents: [], + drawOverlay: [], + shutdown: [] + }, + plot = this; + + // public functions + plot.setData = setData; + plot.setupGrid = setupGrid; + plot.draw = draw; + plot.getPlaceholder = function() { return placeholder; }; + plot.getCanvas = function() { return surface.element; }; + plot.getPlotOffset = function() { return plotOffset; }; + plot.width = function () { return plotWidth; }; + plot.height = function () { return plotHeight; }; + plot.offset = function () { + var o = eventHolder.offset(); + o.left += plotOffset.left; + o.top += plotOffset.top; + return o; + }; + plot.getData = function () { return series; }; + plot.getAxes = function () { + var res = {}, i; + $.each(xaxes.concat(yaxes), function (_, axis) { + if (axis) + res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; + }); + return res; + }; + plot.getXAxes = function () { return xaxes; }; + plot.getYAxes = function () { return yaxes; }; + plot.c2p = canvasToAxisCoords; + plot.p2c = axisToCanvasCoords; + plot.getOptions = function () { return options; }; + plot.highlight = highlight; + plot.unhighlight = unhighlight; + plot.triggerRedrawOverlay = triggerRedrawOverlay; + plot.pointOffset = function(point) { + return { + left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), + top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) + }; + }; + plot.shutdown = shutdown; + plot.destroy = function () { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + highlights = []; + plot = null; + }; + plot.resize = function () { + var width = placeholder.width(), + height = placeholder.height(); + surface.resize(width, height); + overlay.resize(width, height); + }; + + // public attributes + plot.hooks = hooks; + + // initialize + initPlugins(plot); + parseOptions(options_); + setupCanvases(); + setData(data_); + setupGrid(); + draw(); + bindEvents(); + + + function executeHooks(hook, args) { + args = [plot].concat(args); + for (var i = 0; i < hook.length; ++i) + hook[i].apply(this, args); + } + + function initPlugins() { + + // References to key classes, allowing plugins to modify them + + var classes = { + Canvas: Canvas + }; + + for (var i = 0; i < plugins.length; ++i) { + var p = plugins[i]; + p.init(plot, classes); + if (p.options) + $.extend(true, options, p.options); + } + } + + function parseOptions(opts) { + + $.extend(true, options, opts); + + // $.extend merges arrays, rather than replacing them. When less + // colors are provided than the size of the default palette, we + // end up with those colors plus the remaining defaults, which is + // not expected behavior; avoid it by replacing them here. + + if (opts && opts.colors) { + options.colors = opts.colors; + } + + if (options.xaxis.color == null) + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + if (options.yaxis.color == null) + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility + options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; + if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility + options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; + + if (options.grid.borderColor == null) + options.grid.borderColor = options.grid.color; + if (options.grid.tickColor == null) + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + // Fill in defaults for axis options, including any unspecified + // font-spec fields, if a font-spec was provided. + + // If no x/y axis options were provided, create one of each anyway, + // since the rest of the code assumes that they exist. + + var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, + fontDefaults = { + style: placeholder.css("font-style"), + size: Math.round(0.8 * fontSizeDefault), + variant: placeholder.css("font-variant"), + weight: placeholder.css("font-weight"), + family: placeholder.css("font-family") + }; + + axisCount = options.xaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.xaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.xaxis, axisOptions); + options.xaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + axisCount = options.yaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.yaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.yaxis, axisOptions); + options.yaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + // backwards compatibility, to be removed in future + if (options.xaxis.noTicks && options.xaxis.ticks == null) + options.xaxis.ticks = options.xaxis.noTicks; + if (options.yaxis.noTicks && options.yaxis.ticks == null) + options.yaxis.ticks = options.yaxis.noTicks; + if (options.x2axis) { + options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); + options.xaxes[1].position = "top"; + // Override the inherit to allow the axis to auto-scale + if (options.x2axis.min == null) { + options.xaxes[1].min = null; + } + if (options.x2axis.max == null) { + options.xaxes[1].max = null; + } + } + if (options.y2axis) { + options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); + options.yaxes[1].position = "right"; + // Override the inherit to allow the axis to auto-scale + if (options.y2axis.min == null) { + options.yaxes[1].min = null; + } + if (options.y2axis.max == null) { + options.yaxes[1].max = null; + } + } + if (options.grid.coloredAreas) + options.grid.markings = options.grid.coloredAreas; + if (options.grid.coloredAreasColor) + options.grid.markingsColor = options.grid.coloredAreasColor; + if (options.lines) + $.extend(true, options.series.lines, options.lines); + if (options.points) + $.extend(true, options.series.points, options.points); + if (options.bars) + $.extend(true, options.series.bars, options.bars); + if (options.shadowSize != null) + options.series.shadowSize = options.shadowSize; + if (options.highlightColor != null) + options.series.highlightColor = options.highlightColor; + + // save options on axes for future reference + for (i = 0; i < options.xaxes.length; ++i) + getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; + for (i = 0; i < options.yaxes.length; ++i) + getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; + + // add hooks from options + for (var n in hooks) + if (options.hooks[n] && options.hooks[n].length) + hooks[n] = hooks[n].concat(options.hooks[n]); + + executeHooks(hooks.processOptions, [options]); + } + + function setData(d) { + series = parseData(d); + fillInSeriesOptions(); + processData(); + } + + function parseData(d) { + var res = []; + for (var i = 0; i < d.length; ++i) { + var s = $.extend(true, {}, options.series); + + if (d[i].data != null) { + s.data = d[i].data; // move the data instead of deep-copy + delete d[i].data; + + $.extend(true, s, d[i]); + + d[i].data = s.data; + } + else + s.data = d[i]; + res.push(s); + } + + return res; + } + + function axisNumber(obj, coord) { + var a = obj[coord + "axis"]; + if (typeof a == "object") // if we got a real axis, extract number + a = a.n; + if (typeof a != "number") + a = 1; // default to first axis + return a; + } + + function allAxes() { + // return flat array without annoying null entries + return $.grep(xaxes.concat(yaxes), function (a) { return a; }); + } + + function canvasToAxisCoords(pos) { + // return an object with x/y corresponding to all used axes + var res = {}, i, axis; + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) + res["x" + axis.n] = axis.c2p(pos.left); + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) + res["y" + axis.n] = axis.c2p(pos.top); + } + + if (res.x1 !== undefined) + res.x = res.x1; + if (res.y1 !== undefined) + res.y = res.y1; + + return res; + } + + function axisToCanvasCoords(pos) { + // get canvas coords from the first pair of x/y found in pos + var res = {}, i, axis, key; + + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + key = "x" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "x"; + + if (pos[key] != null) { + res.left = axis.p2c(pos[key]); + break; + } + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + key = "y" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "y"; + + if (pos[key] != null) { + res.top = axis.p2c(pos[key]); + break; + } + } + } + + return res; + } + + function getOrCreateAxis(axes, number) { + if (!axes[number - 1]) + axes[number - 1] = { + n: number, // save the number for future reference + direction: axes == xaxes ? "x" : "y", + options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) + }; + + return axes[number - 1]; + } + + function fillInSeriesOptions() { + + var neededColors = series.length, maxIndex = -1, i; + + // Subtract the number of series that already have fixed colors or + // color indexes from the number that we still need to generate. + + for (i = 0; i < series.length; ++i) { + var sc = series[i].color; + if (sc != null) { + neededColors--; + if (typeof sc == "number" && sc > maxIndex) { + maxIndex = sc; + } + } + } + + // If any of the series have fixed color indexes, then we need to + // generate at least as many colors as the highest index. + + if (neededColors <= maxIndex) { + neededColors = maxIndex + 1; + } + + // Generate all the colors, using first the option colors and then + // variations on those colors once they're exhausted. + + var c, colors = [], colorPool = options.colors, + colorPoolSize = colorPool.length, variation = 0; + + for (i = 0; i < neededColors; i++) { + + c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); + + // Each time we exhaust the colors in the pool we adjust + // a scaling factor used to produce more variations on + // those colors. The factor alternates negative/positive + // to produce lighter/darker colors. + + // Reset the variation after every few cycles, or else + // it will end up producing only white or black colors. + + if (i % colorPoolSize == 0 && i) { + if (variation >= 0) { + if (variation < 0.5) { + variation = -variation - 0.2; + } else variation = 0; + } else variation = -variation; + } + + colors[i] = c.scale('rgb', 1 + variation); + } + + // Finalize the series options, filling in their colors + + var colori = 0, s; + for (i = 0; i < series.length; ++i) { + s = series[i]; + + // assign colors + if (s.color == null) { + s.color = colors[colori].toString(); + ++colori; + } + else if (typeof s.color == "number") + s.color = colors[s.color].toString(); + + // turn on lines automatically in case nothing is set + if (s.lines.show == null) { + var v, show = true; + for (v in s) + if (s[v] && s[v].show) { + show = false; + break; + } + if (show) + s.lines.show = true; + } + + // If nothing was provided for lines.zero, default it to match + // lines.fill, since areas by default should extend to zero. + + if (s.lines.zero == null) { + s.lines.zero = !!s.lines.fill; + } + + // setup axes + s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); + s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); + } + } + + function processData() { + var topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + fakeInfinity = Number.MAX_VALUE, + i, j, k, m, length, + s, points, ps, x, y, axis, val, f, p, + data, format; + + function updateAxis(axis, min, max) { + if (min < axis.datamin && min != -fakeInfinity) + axis.datamin = min; + if (max > axis.datamax && max != fakeInfinity) + axis.datamax = max; + } + + $.each(allAxes(), function (_, axis) { + // init axis + axis.datamin = topSentry; + axis.datamax = bottomSentry; + axis.used = false; + }); + + for (i = 0; i < series.length; ++i) { + s = series[i]; + s.datapoints = { points: [] }; + + executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); + } + + // first pass: clean and copy data + for (i = 0; i < series.length; ++i) { + s = series[i]; + + data = s.data; + format = s.datapoints.format; + + if (!format) { + format = []; + // find out how to copy + format.push({ x: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + s.datapoints.format = format; + } + + if (s.datapoints.pointsize != null) + continue; // already filled in + + s.datapoints.pointsize = format.length; + + ps = s.datapoints.pointsize; + points = s.datapoints.points; + + var insertSteps = s.lines.show && s.lines.steps; + s.xaxis.used = s.yaxis.used = true; + + for (j = k = 0; j < data.length; ++j, k += ps) { + p = data[j]; + + var nullify = p == null; + if (!nullify) { + for (m = 0; m < ps; ++m) { + val = p[m]; + f = format[m]; + + if (f) { + if (f.number && val != null) { + val = +val; // convert to number + if (isNaN(val)) + val = null; + else if (val == Infinity) + val = fakeInfinity; + else if (val == -Infinity) + val = -fakeInfinity; + } + + if (val == null) { + if (f.required) + nullify = true; + + if (f.defaultValue != null) + val = f.defaultValue; + } + // extract min/max info + if (f.autoscale !== false) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + + points[k + m] = val; + } + } + + if (nullify) { + for (m = 0; m < ps; ++m) { + val = points[k + m]; + if (val != null) { + f = format[m]; + // extract min/max info + if (f.autoscale !== false) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + points[k + m] = null; + } + } + else { + // a little bit of line specific stuff that + // perhaps shouldn't be here, but lacking + // better means... + if (insertSteps && k > 0 + && points[k - ps] != null + && points[k - ps] != points[k] + && points[k - ps + 1] != points[k + 1]) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) + points[k + ps + m] = points[k + m]; + + // middle point has same y + points[k + 1] = points[k - ps + 1]; + + // we've added a point, better reflect that + k += ps; + } + } + } + } + + // give the hooks a chance to run + for (i = 0; i < series.length; ++i) { + s = series[i]; + + executeHooks(hooks.processDatapoints, [ s, s.datapoints]); + } + + // second pass: find datamax/datamin for auto-scaling + for (i = 0; i < series.length; ++i) { + s = series[i]; + points = s.datapoints.points; + ps = s.datapoints.pointsize; + format = s.datapoints.format; + + var xmin = topSentry, ymin = topSentry, + xmax = bottomSentry, ymax = bottomSentry; + + for (j = 0; j < points.length; j += ps) { + if (points[j] == null) + continue; + + for (m = 0; m < ps; ++m) { + val = points[j + m]; + f = format[m]; + if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) + continue; + + if (f.x) { + if (val < xmin) + xmin = val; + if (val > xmax) + xmax = val; + } + if (f.y) { + if (val < ymin) + ymin = val; + if (val > ymax) + ymax = val; + } + } + } + + if (s.bars.show) { + // make sure we got room for the bar on the dancing floor + var delta; + + switch (s.bars.align) { + case "left": + delta = 0; + break; + case "right": + delta = -s.bars.barWidth; + break; + default: + delta = -s.bars.barWidth / 2; + } + + if (s.bars.horizontal) { + ymin += delta; + ymax += delta + s.bars.barWidth; + } + else { + xmin += delta; + xmax += delta + s.bars.barWidth; + } + } + + updateAxis(s.xaxis, xmin, xmax); + updateAxis(s.yaxis, ymin, ymax); + } + + $.each(allAxes(), function (_, axis) { + if (axis.datamin == topSentry) + axis.datamin = null; + if (axis.datamax == bottomSentry) + axis.datamax = null; + }); + } + + function setupCanvases() { + + // Make sure the placeholder is clear of everything except canvases + // from a previous plot in this container that we'll try to re-use. + + placeholder.css("padding", 0) // padding messes up the positioning + .children().filter(function(){ + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); + + if (placeholder.css("position") == 'static') + placeholder.css("position", "relative"); // for positioning labels and overlay + + surface = new Canvas("flot-base", placeholder); + overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features + + ctx = surface.context; + octx = overlay.context; + + // define which element we're listening for events on + eventHolder = $(overlay.element).unbind(); + + // If we're re-using a plot object, shut down the old one + + var existing = placeholder.data("plot"); + + if (existing) { + existing.shutdown(); + overlay.clear(); + } + + // save in case we get replotted + placeholder.data("plot", plot); + } + + function bindEvents() { + // bind events + if (options.grid.hoverable) { + eventHolder.mousemove(onMouseMove); + + // Use bind, rather than .mouseleave, because we officially + // still support jQuery 1.2.6, which doesn't define a shortcut + // for mouseenter or mouseleave. This was a bug/oversight that + // was fixed somewhere around 1.3.x. We can return to using + // .mouseleave when we drop support for 1.2.6. + + eventHolder.bind("mouseleave", onMouseLeave); + } + + if (options.grid.clickable) + eventHolder.click(onClick); + + executeHooks(hooks.bindEvents, [eventHolder]); + } + + function shutdown() { + if (redrawTimeout) + clearTimeout(redrawTimeout); + + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mouseleave", onMouseLeave); + eventHolder.unbind("click", onClick); + + executeHooks(hooks.shutdown, [eventHolder]); + } + + function setTransformationHelpers(axis) { + // set helper functions on the axis, assumes plot area + // has been computed already + + function identity(x) { return x; } + + var s, m, t = axis.options.transform || identity, + it = axis.options.inverseTransform; + + // precompute how much the axis is scaling a point + // in canvas space + if (axis.direction == "x") { + s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); + m = Math.min(t(axis.max), t(axis.min)); + } + else { + s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); + s = -s; + m = Math.max(t(axis.max), t(axis.min)); + } + + // data point to canvas coordinate + if (t == identity) // slight optimization + axis.p2c = function (p) { return (p - m) * s; }; + else + axis.p2c = function (p) { return (t(p) - m) * s; }; + // canvas coordinate to data point + if (!it) + axis.c2p = function (c) { return m + c / s; }; + else + axis.c2p = function (c) { return it(m + c / s); }; + } + + function measureTickLabels(axis) { + + var opts = axis.options, + ticks = axis.ticks || [], + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; + + for (var i = 0; i < ticks.length; ++i) { + + var t = ticks[i]; + + if (!t.label) + continue; + + var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); + + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); + } + + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; + } + + function allocateAxisBoxFirstPhase(axis) { + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, + axisMargin = options.grid.axisMargin, + padding = options.grid.labelMargin, + innermost = true, + outermost = true, + first = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + if (!found) { + first = false; + } + } + }); + + // The outermost axis on each side has no margin + + if (outermost) { + axisMargin = 0; + } + + // The ticks for the first axis in each direction stretch across + + if (tickLength == null) { + tickLength = first ? "full" : 5; + } + + if (!isNaN(+tickLength)) + padding += +tickLength; + + if (isXAxis) { + lh += padding; + + if (pos == "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { top: surface.height - plotOffset.bottom, height: lh }; + } + else { + axis.box = { top: plotOffset.top + axisMargin, height: lh }; + plotOffset.top += lh + axisMargin; + } + } + else { + lw += padding; + + if (pos == "left") { + axis.box = { left: plotOffset.left + axisMargin, width: lw }; + plotOffset.left += lw + axisMargin; + } + else { + plotOffset.right += lw + axisMargin; + axis.box = { left: surface.width - plotOffset.right, width: lw }; + } + } + + // save for future reference + axis.position = pos; + axis.tickLength = tickLength; + axis.box.padding = padding; + axis.innermost = innermost; + } + + function allocateAxisBoxSecondPhase(axis) { + // now that all axis boxes have been placed in one + // dimension, we can set the remaining dimension coordinates + if (axis.direction == "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } + else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; + } + } + + function adjustLayoutForThingsStickingOut() { + // possibly adjust plot offset to ensure everything stays + // inside the canvas and isn't clipped off + + var minMargin = options.grid.minBorderMargin, + axis, i; + + // check stuff from the plot (FIXME: this should just read + // a value from the series, otherwise it's impossible to + // customize) + if (minMargin == null) { + minMargin = 0; + for (i = 0; i < series.length; ++i) + minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); + } + + var margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; + + // check axis labels, note we don't check the actual + // labels but instead use the overall width/height to not + // jump as much around with replots + $.each(allAxes(), function (_, axis) { + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } + } + }); + + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); + } + + function setupGrid() { + var i, axes = allAxes(), showGrid = options.grid.show; + + // Initialize the plot's offset from the edge of the canvas + + for (var a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; + } + + executeHooks(hooks.processOffset, [plotOffset]); + + // If the grid is visible, add its border width to the offset + + for (var a in plotOffset) { + if(typeof(options.grid.borderWidth) == "object") { + plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; + } + else { + plotOffset[a] += showGrid ? options.grid.borderWidth : 0; + } + } + + $.each(axes, function (_, axis) { + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; + setRange(axis); + }); + + if (showGrid) { + + var allocatedAxes = $.grep(axes, function (axis) { + return axis.show || axis.reserveSpace; + }); + + $.each(allocatedAxes, function (_, axis) { + // make the ticks + setupTickGeneration(axis); + setTicks(axis); + snapRangeToTicks(axis, axis.ticks); + // find labelWidth/Height for axis + measureTickLabels(axis); + }); + + // with all dimensions calculated, we can compute the + // axis bounding boxes, start from the outside + // (reverse order) + for (i = allocatedAxes.length - 1; i >= 0; --i) + allocateAxisBoxFirstPhase(allocatedAxes[i]); + + // make sure we've got enough space for things that + // might stick out + adjustLayoutForThingsStickingOut(); + + $.each(allocatedAxes, function (_, axis) { + allocateAxisBoxSecondPhase(axis); + }); + } + + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + // now we got the proper plot dimensions, we can compute the scaling + $.each(axes, function (_, axis) { + setTransformationHelpers(axis); + }); + + if (showGrid) { + drawAxisLabels(); + } + + insertLegend(); + } + + function setRange(axis) { + var opts = axis.options, + min = +(opts.min != null ? opts.min : axis.datamin), + max = +(opts.max != null ? opts.max : axis.datamax), + delta = max - min; + + if (delta == 0.0) { + // degenerate case + var widen = max == 0 ? 1 : 0.01; + + if (opts.min == null) + min -= widen; + // always widen max if we couldn't widen min to ensure we + // don't fall into min == max which doesn't work + if (opts.max == null || opts.min != null) + max += widen; + } + else { + // consider autoscaling + var margin = opts.autoscaleMargin; + if (margin != null) { + if (opts.min == null) { + min -= delta * margin; + // make sure we don't go below zero if all values + // are positive + if (min < 0 && axis.datamin != null && axis.datamin >= 0) + min = 0; + } + if (opts.max == null) { + max += delta * margin; + if (max > 0 && axis.datamax != null && axis.datamax <= 0) + max = 0; + } + } + } + axis.min = min; + axis.max = max; + } + + function setupTickGeneration(axis) { + var opts = axis.options; + + // estimate number of ticks + var noTicks; + if (typeof opts.ticks == "number" && opts.ticks > 0) + noTicks = opts.ticks; + else + // heuristic based on the model a*sqrt(x) fitted to + // some data points that seemed reasonable + noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); + + var delta = (axis.max - axis.min) / noTicks, + dec = -Math.floor(Math.log(delta) / Math.LN10), + maxDec = opts.tickDecimals; + + if (maxDec != null && dec > maxDec) { + dec = maxDec; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + // special case for 2.5, requires an extra decimal + if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { + size = 2.5; + ++dec; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + + if (opts.minTickSize != null && size < opts.minTickSize) { + size = opts.minTickSize; + } + + axis.delta = delta; + axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); + axis.tickSize = opts.tickSize || size; + + // Time mode was moved to a plug-in in 0.8, and since so many people use it + // we'll add an especially friendly reminder to make sure they included it. + + if (opts.mode == "time" && !axis.tickGenerator) { + throw new Error("Time mode requires the flot.time plugin."); + } + + // Flot supports base-10 axes; any other mode else is handled by a plug-in, + // like flot.time.js. + + if (!axis.tickGenerator) { + + axis.tickGenerator = function (axis) { + + var ticks = [], + start = floorInBase(axis.min, axis.tickSize), + i = 0, + v = Number.NaN, + prev; + + do { + prev = v; + v = start + i * axis.tickSize; + ticks.push(v); + ++i; + } while (v < axis.max && v != prev); + return ticks; + }; + + axis.tickFormatter = function (value, axis) { + + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + var formatted = "" + Math.round(value * factor) / factor; + + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."); + var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } + + return formatted; + }; + } + + if ($.isFunction(opts.tickFormatter)) + axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; + + if (opts.alignTicksWithAxis != null) { + var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis != axis) { + // consider snapping min/max to outermost nice ticks + var niceTicks = axis.tickGenerator(axis); + if (niceTicks.length > 0) { + if (opts.min == null) + axis.min = Math.min(axis.min, niceTicks[0]); + if (opts.max == null && niceTicks.length > 1) + axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); + } + + axis.tickGenerator = function (axis) { + // copy ticks, scaled to this axis + var ticks = [], v, i; + for (i = 0; i < otherAxis.ticks.length; ++i) { + v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); + v = axis.min + v * (axis.max - axis.min); + ticks.push(v); + } + return ticks; + }; + + // we might need an extra decimal since forced + // ticks don't necessarily fit naturally + if (!axis.mode && opts.tickDecimals == null) { + var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), + ts = axis.tickGenerator(axis); + + // only proceed if the tick interval rounded + // with an extra decimal doesn't give us a + // zero at end + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) + axis.tickDecimals = extraDec; + } + } + } + } + + function setTicks(axis) { + var oticks = axis.options.ticks, ticks = []; + if (oticks == null || (typeof oticks == "number" && oticks > 0)) + ticks = axis.tickGenerator(axis); + else if (oticks) { + if ($.isFunction(oticks)) + // generate the ticks + ticks = oticks(axis); + else + ticks = oticks; + } + + // clean up/labelify the supplied ticks, copy them over + var i, v; + axis.ticks = []; + for (i = 0; i < ticks.length; ++i) { + var label = null; + var t = ticks[i]; + if (typeof t == "object") { + v = +t[0]; + if (t.length > 1) + label = t[1]; + } + else + v = +t; + if (label == null) + label = axis.tickFormatter(v, axis); + if (!isNaN(v)) + axis.ticks.push({ v: v, label: label }); + } + } + + function snapRangeToTicks(axis, ticks) { + if (axis.options.autoscaleMargin && ticks.length > 0) { + // snap to ticks + if (axis.options.min == null) + axis.min = Math.min(axis.min, ticks[0].v); + if (axis.options.max == null && ticks.length > 1) + axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); + } + } + + function draw() { + + surface.clear(); + + executeHooks(hooks.drawBackground, [ctx]); + + var grid = options.grid; + + // draw background, if any + if (grid.show && grid.backgroundColor) + drawBackground(); + + if (grid.show && !grid.aboveData) { + drawGrid(); + } + + for (var i = 0; i < series.length; ++i) { + executeHooks(hooks.drawSeries, [ctx, series[i]]); + drawSeries(series[i]); + } + + executeHooks(hooks.draw, [ctx]); + + if (grid.show && grid.aboveData) { + drawGrid(); + } + + surface.render(); + + // A draw implies that either the axes or data have changed, so we + // should probably update the overlay highlights as well. + + triggerRedrawOverlay(); + } + + function extractRange(ranges, coord) { + var axis, from, to, key, axes = allAxes(); + + for (var i = 0; i < axes.length; ++i) { + axis = axes[i]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? xaxes[0] : yaxes[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function drawBackground() { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); + ctx.fillRect(0, 0, plotWidth, plotHeight); + ctx.restore(); + } + + function drawGrid() { + var i, axes, bw, bc; + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // draw markings + var markings = options.grid.markings; + if (markings) { + if ($.isFunction(markings)) { + axes = plot.getAxes(); + // xmin etc. is backwards compatibility, to be + // removed in the future + axes.xmin = axes.xaxis.min; + axes.xmax = axes.xaxis.max; + axes.ymin = axes.yaxis.min; + axes.ymax = axes.yaxis.max; + + markings = markings(axes); + } + + for (i = 0; i < markings.length; ++i) { + var m = markings[i], + xrange = extractRange(m, "x"), + yrange = extractRange(m, "y"); + + // fill in missing + if (xrange.from == null) + xrange.from = xrange.axis.min; + if (xrange.to == null) + xrange.to = xrange.axis.max; + if (yrange.from == null) + yrange.from = yrange.axis.min; + if (yrange.to == null) + yrange.to = yrange.axis.max; + + // clip + if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) + continue; + + xrange.from = Math.max(xrange.from, xrange.axis.min); + xrange.to = Math.min(xrange.to, xrange.axis.max); + yrange.from = Math.max(yrange.from, yrange.axis.min); + yrange.to = Math.min(yrange.to, yrange.axis.max); + + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { + continue; + } + + // then draw + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; + ctx.beginPath(); + ctx.strokeStyle = m.color || options.grid.markingsColor; + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } + ctx.stroke(); + } else { + ctx.fillStyle = m.color || options.grid.markingsColor; + ctx.fillRect(xrange.from, yrange.to, + xrange.to - xrange.from, + yrange.from - yrange.to); + } + } + } + + // draw the ticks + axes = allAxes(); + bw = options.grid.borderWidth; + + for (var j = 0; j < axes.length; ++j) { + var axis = axes[j], box = axis.box, + t = axis.tickLength, x, y, xoff, yoff; + if (!axis.show || axis.ticks.length == 0) + continue; + + ctx.lineWidth = 1; + + // find the edges + if (axis.direction == "x") { + x = 0; + if (t == "full") + y = (axis.position == "top" ? 0 : plotHeight); + else + y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); + } + else { + y = 0; + if (t == "full") + x = (axis.position == "left" ? 0 : plotWidth); + else + x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); + } + + // draw tick bar + if (!axis.innermost) { + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + xoff = yoff = 0; + if (axis.direction == "x") + xoff = plotWidth + 1; + else + yoff = plotHeight + 1; + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") { + y = Math.floor(y) + 0.5; + } else { + x = Math.floor(x) + 0.5; + } + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + ctx.stroke(); + } + + // draw ticks + + ctx.strokeStyle = axis.options.tickColor; + + ctx.beginPath(); + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v; + + xoff = yoff = 0; + + if (isNaN(v) || v < axis.min || v > axis.max + // skip those lying on the axes if we got a border + || (t == "full" + && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) + && (v == axis.min || v == axis.max))) + continue; + + if (axis.direction == "x") { + x = axis.p2c(v); + yoff = t == "full" ? -plotHeight : t; + + if (axis.position == "top") + yoff = -yoff; + } + else { + y = axis.p2c(v); + xoff = t == "full" ? -plotWidth : t; + + if (axis.position == "left") + xoff = -xoff; + } + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") + x = Math.floor(x) + 0.5; + else + y = Math.floor(y) + 0.5; + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + } + + ctx.stroke(); + } + + + // draw border + if (bw) { + // If either borderWidth or borderColor is an object, then draw the border + // line by line instead of as one rectangle + bc = options.grid.borderColor; + if(typeof bw == "object" || typeof bc == "object") { + if (typeof bw !== "object") { + bw = {top: bw, right: bw, bottom: bw, left: bw}; + } + if (typeof bc !== "object") { + bc = {top: bc, right: bc, bottom: bc, left: bc}; + } + + if (bw.top > 0) { + ctx.strokeStyle = bc.top; + ctx.lineWidth = bw.top; + ctx.beginPath(); + ctx.moveTo(0 - bw.left, 0 - bw.top/2); + ctx.lineTo(plotWidth, 0 - bw.top/2); + ctx.stroke(); + } + + if (bw.right > 0) { + ctx.strokeStyle = bc.right; + ctx.lineWidth = bw.right; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); + ctx.lineTo(plotWidth + bw.right / 2, plotHeight); + ctx.stroke(); + } + + if (bw.bottom > 0) { + ctx.strokeStyle = bc.bottom; + ctx.lineWidth = bw.bottom; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); + ctx.lineTo(0, plotHeight + bw.bottom / 2); + ctx.stroke(); + } + + if (bw.left > 0) { + ctx.strokeStyle = bc.left; + ctx.lineWidth = bw.left; + ctx.beginPath(); + ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom); + ctx.lineTo(0- bw.left/2, 0); + ctx.stroke(); + } + } + else { + ctx.lineWidth = bw; + ctx.strokeStyle = options.grid.borderColor; + ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); + } + } + + ctx.restore(); + } + + function drawAxisLabels() { + + $.each(allAxes(), function (_, axis) { + var box = axis.box, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", + tick, x, y, halign, valign; + + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. + + surface.removeText(layer); + + if (!axis.show || axis.ticks.length == 0) + return; + + for (var i = 0; i < axis.ticks.length; ++i) { + + tick = axis.ticks[i]; + if (!tick.label || tick.v < axis.min || tick.v > axis.max) + continue; + + if (axis.direction == "x") { + halign = "center"; + x = plotOffset.left + axis.p2c(tick.v); + if (axis.position == "bottom") { + y = box.top + box.padding; + } else { + y = box.top + box.height - box.padding; + valign = "bottom"; + } + } else { + valign = "middle"; + y = plotOffset.top + axis.p2c(tick.v); + if (axis.position == "left") { + x = box.left + box.width - box.padding; + halign = "right"; + } else { + x = box.left + box.padding; + } + } + + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); + } + }); + } + + function drawSeries(series) { + if (series.lines.show) + drawSeriesLines(series); + if (series.bars.show) + drawSeriesBars(series); + if (series.points.show) + drawSeriesPoints(series); + } + + function drawSeriesLines(series) { + function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + prevx = null, prevy = null; + + ctx.beginPath(); + for (var i = ps; i < points.length; i += ps) { + var x1 = points[i - ps], y1 = points[i - ps + 1], + x2 = points[i], y2 = points[i + 1]; + + if (x1 == null || x2 == null) + continue; + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) + continue; // line segment is outside + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) + continue; + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) + continue; + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) + continue; + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 != prevx || y1 != prevy) + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + + prevx = x2; + prevy = y2; + ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); + } + ctx.stroke(); + } + + function plotLineArea(datapoints, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + bottom = Math.min(Math.max(0, axisy.min), axisy.max), + i = 0, top, areaOpen = false, + ypos = 1, segmentStart = 0, segmentEnd = 0; + + // we process each segment in two turns, first forward + // direction to sketch out top, then once we hit the + // end we go backwards to sketch the bottom + while (true) { + if (ps > 0 && i > points.length + ps) + break; + + i += ps; // ps is negative if going backwards + + var x1 = points[i - ps], + y1 = points[i - ps + ypos], + x2 = points[i], y2 = points[i + ypos]; + + if (areaOpen) { + if (ps > 0 && x1 != null && x2 == null) { + // at turning point + segmentEnd = i; + ps = -ps; + ypos = 2; + continue; + } + + if (ps < 0 && i == segmentStart + ps) { + // done with the reverse sweep + ctx.fill(); + areaOpen = false; + ps = -ps; + ypos = 1; + i = segmentStart = segmentEnd + ps; + continue; + } + } + + if (x1 == null || x2 == null) + continue; + + // clip x values + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (!areaOpen) { + // open area + ctx.beginPath(); + ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); + areaOpen = true; + } + + // now first check the case where both is outside + if (y1 >= axisy.max && y2 >= axisy.max) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); + continue; + } + else if (y1 <= axisy.min && y2 <= axisy.min) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); + continue; + } + + // else it's a bit more complicated, there might + // be a flat maxed out rectangle first, then a + // triangular cutout or reverse; to find these + // keep track of the current x values + var x1old = x1, x2old = x2; + + // clip the y values, without shortcutting, we + // go through all cases in turn + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // if the x value was changed we got a rectangle + // to fill + if (x1 != x1old) { + ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); + // it goes to (x1, y1), but we fill that below + } + + // fill triangular section, this sometimes result + // in redundant points if (x1, y1) hasn't changed + // from previous line to, but we just ignore that + ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + + // fill the other rectangle if it's there + if (x2 != x2old) { + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); + } + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + var lw = series.lines.lineWidth, + sw = series.shadowSize; + // FIXME: consider another form of shadow when filling is turned on + if (lw > 0 && sw > 0) { + // draw shadow as a thick and thin line with transparency + ctx.lineWidth = sw; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + // position shadow at angle from the mid of line + var angle = Math.PI/18; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis); + ctx.lineWidth = sw/2; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); + if (fillStyle) { + ctx.fillStyle = fillStyle; + plotLineArea(series.datapoints, series.xaxis, series.yaxis); + } + + if (lw > 0) + plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); + ctx.restore(); + } + + function drawSeriesPoints(series) { + function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var x = points[i], y = points[i + 1]; + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + continue; + + ctx.beginPath(); + x = axisx.p2c(x); + y = axisy.p2c(y) + offset; + if (symbol == "circle") + ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); + else + symbol(ctx, x, y, radius, shadow); + ctx.closePath(); + + if (fillStyle) { + ctx.fillStyle = fillStyle; + ctx.fill(); + } + ctx.stroke(); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var lw = series.points.lineWidth, + sw = series.shadowSize, + radius = series.points.radius, + symbol = series.points.symbol; + + // If the user sets the line width to 0, we change it to a very + // small value. A line width of 0 seems to force the default of 1. + // Doing the conditional here allows the shadow setting to still be + // optional even with a lineWidth of 0. + + if( lw == 0 ) + lw = 0.0001; + + if (lw > 0 && sw > 0) { + // draw shadow in two steps + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + plotPoints(series.datapoints, radius, null, w + w/2, true, + series.xaxis, series.yaxis, symbol); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + plotPoints(series.datapoints, radius, null, w/2, true, + series.xaxis, series.yaxis, symbol); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + plotPoints(series.datapoints, radius, + getFillStyle(series.points, series.color), 0, false, + series.xaxis, series.yaxis, symbol); + ctx.restore(); + } + + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + var left, right, bottom, top, + drawLeft, drawRight, drawTop, drawBottom, + tmp; + + // in horizontal mode, we start the bar from the left + // instead of from the bottom so it appears to be + // horizontal rather than vertical + if (horizontal) { + drawBottom = drawRight = drawTop = true; + drawLeft = false; + left = b; + right = x; + top = y + barLeft; + bottom = y + barRight; + + // account for negative bars + if (right < left) { + tmp = right; + right = left; + left = tmp; + drawLeft = true; + drawRight = false; + } + } + else { + drawLeft = drawRight = drawTop = true; + drawBottom = false; + left = x + barLeft; + right = x + barRight; + bottom = b; + top = y; + + // account for negative bars + if (top < bottom) { + tmp = top; + top = bottom; + bottom = tmp; + drawBottom = true; + drawTop = false; + } + } + + // clip + if (right < axisx.min || left > axisx.max || + top < axisy.min || bottom > axisy.max) + return; + + if (left < axisx.min) { + left = axisx.min; + drawLeft = false; + } + + if (right > axisx.max) { + right = axisx.max; + drawRight = false; + } + + if (bottom < axisy.min) { + bottom = axisy.min; + drawBottom = false; + } + + if (top > axisy.max) { + top = axisy.max; + drawTop = false; + } + + left = axisx.p2c(left); + bottom = axisy.p2c(bottom); + right = axisx.p2c(right); + top = axisy.p2c(top); + + // fill the bar + if (fillStyleCallback) { + c.fillStyle = fillStyleCallback(bottom, top); + c.fillRect(left, top, right - left, bottom - top) + } + + // draw outline + if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { + c.beginPath(); + + // FIXME: inline moveTo is buggy with excanvas + c.moveTo(left, bottom); + if (drawLeft) + c.lineTo(left, top); + else + c.moveTo(left, top); + if (drawTop) + c.lineTo(right, top); + else + c.moveTo(right, top); + if (drawRight) + c.lineTo(right, bottom); + else + c.moveTo(right, bottom); + if (drawBottom) + c.lineTo(left, bottom); + else + c.moveTo(left, bottom); + c.stroke(); + } + } + + function drawSeriesBars(series) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) + continue; + drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // FIXME: figure out a way to add shadows (for instance along the right edge) + ctx.lineWidth = series.bars.lineWidth; + ctx.strokeStyle = series.color; + + var barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; + plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); + ctx.restore(); + } + + function getFillStyle(filloptions, seriesColor, bottom, top) { + var fill = filloptions.fill; + if (!fill) + return null; + + if (filloptions.fillColor) + return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); + + var c = $.color.parse(seriesColor); + c.a = typeof fill == "number" ? fill : 0.4; + c.normalize(); + return c.toString(); + } + + function insertLegend() { + + if (options.legend.container != null) { + $(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } + + if (!options.legend.show) { + return; + } + + var fragments = [], entries = [], rowStarted = false, + lf = options.legend.labelFormatter, s, label; + + // Build a list of legend entries, with each having a label and a color + + for (var i = 0; i < series.length; ++i) { + s = series[i]; + if (s.label) { + label = lf ? lf(s.label, s) : s.label; + if (label) { + entries.push({ + label: label, + color: s.color + }); + } + } + } + + // Sort the legend using either the default or a custom comparator + + if (options.legend.sorted) { + if ($.isFunction(options.legend.sorted)) { + entries.sort(options.legend.sorted); + } else if (options.legend.sorted == "reverse") { + entries.reverse(); + } else { + var ascending = options.legend.sorted != "descending"; + entries.sort(function(a, b) { + return a.label == b.label ? 0 : ( + (a.label < b.label) != ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + // Generate markup for the list of entries, in their final order + + for (var i = 0; i < entries.length; ++i) { + + var entry = entries[i]; + + if (i % options.legend.noColumns == 0) { + if (rowStarted) + fragments.push(''); + fragments.push(''); + rowStarted = true; + } + + fragments.push( + '
' + + '' + entry.label + '' + ); + } + + if (rowStarted) + fragments.push(''); + + if (fragments.length == 0) + return; + + var table = '' + fragments.join("") + '
'; + if (options.legend.container != null) + $(options.legend.container).html(table); + else { + var pos = "", + p = options.legend.position, + m = options.legend.margin; + if (m[0] == null) + m = [m, m]; + if (p.charAt(0) == "n") + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + else if (p.charAt(0) == "s") + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + if (p.charAt(1) == "e") + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + else if (p.charAt(1) == "w") + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos +';') + '
').appendTo(placeholder); + if (options.legend.backgroundOpacity != 0.0) { + // put in the transparent background + // separately to avoid blended labels and + // label boxes + var c = options.legend.backgroundColor; + if (c == null) { + c = options.grid.backgroundColor; + if (c && typeof c == "string") + c = $.color.parse(c); + else + c = $.color.extract(legend, 'background-color'); + c.a = 1; + c = c.toString(); + } + var div = legend.children(); + $('
').prependTo(legend).css('opacity', options.legend.backgroundOpacity); + } + } + } + + + // interactive features + + var highlights = [], + redrawTimeout = null; + + // returns the data item the mouse is over, or null if none is found + function findNearbyItem(mouseX, mouseY, seriesFilter) { + var maxDistance = options.grid.mouseActiveRadius, + smallestDistance = maxDistance * maxDistance + 1, + item = null, foundPoint = false, i, j, ps; + + for (i = series.length - 1; i >= 0; --i) { + if (!seriesFilter(series[i])) + continue; + + var s = series[i], + axisx = s.xaxis, + axisy = s.yaxis, + points = s.datapoints.points, + mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster + my = axisy.c2p(mouseY), + maxx = maxDistance / axisx.scale, + maxy = maxDistance / axisy.scale; + + ps = s.datapoints.pointsize; + // with inverse transforms, we can't use the maxx/maxy + // optimization, sadly + if (axisx.options.inverseTransform) + maxx = Number.MAX_VALUE; + if (axisy.options.inverseTransform) + maxy = Number.MAX_VALUE; + + if (s.lines.show || s.points.show) { + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1]; + if (x == null) + continue; + + // For points and lines, the cursor must be within a + // certain distance to the data point + if (x - mx > maxx || x - mx < -maxx || + y - my > maxy || y - my < -maxy) + continue; + + // We have to calculate distances in pixels, not in + // data units, because the scales of the axes may be different + var dx = Math.abs(axisx.p2c(x) - mouseX), + dy = Math.abs(axisy.p2c(y) - mouseY), + dist = dx * dx + dy * dy; // we save the sqrt + + // use <= to ensure last point takes precedence + // (last generally means on top of) + if (dist < smallestDistance) { + smallestDistance = dist; + item = [i, j / ps]; + } + } + } + + if (s.bars.show && !item) { // no other point can be nearby + + var barLeft, barRight; + + switch (s.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -s.bars.barWidth; + break; + default: + barLeft = -s.bars.barWidth / 2; + } + + barRight = barLeft + s.bars.barWidth; + + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1], b = points[j + 2]; + if (x == null) + continue; + + // for a bar graph, the cursor must be inside the bar + if (series[i].bars.horizontal ? + (mx <= Math.max(b, x) && mx >= Math.min(b, x) && + my >= y + barLeft && my <= y + barRight) : + (mx >= x + barLeft && mx <= x + barRight && + my >= Math.min(b, y) && my <= Math.max(b, y))) + item = [i, j / ps]; + } + } + } + + if (item) { + i = item[0]; + j = item[1]; + ps = series[i].datapoints.pointsize; + + return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), + dataIndex: j, + series: series[i], + seriesIndex: i }; + } + + return null; + } + + function onMouseMove(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return s["hoverable"] != false; }); + } + + function onMouseLeave(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return false; }); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e, + function (s) { return s["clickable"] != false; }); + } + + // trigger click or hover event (they send the same parameters + // so we share their code) + function triggerClickHoverEvent(eventname, event, seriesFilter) { + var offset = eventHolder.offset(), + canvasX = event.pageX - offset.left - plotOffset.left, + canvasY = event.pageY - offset.top - plotOffset.top, + pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); + + pos.pageX = event.pageX; + pos.pageY = event.pageY; + + var item = findNearbyItem(canvasX, canvasY, seriesFilter); + + if (item) { + // fill in mouse pos for any listeners out there + item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); + item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10); + } + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && + !(item && h.series == item.series && + h.point[0] == item.datapoint[0] && + h.point[1] == item.datapoint[1])) + unhighlight(h.series, h.point); + } + + if (item) + highlight(item.series, item.datapoint, eventname); + } + + placeholder.trigger(eventname, [ pos, item ]); + } + + function triggerRedrawOverlay() { + var t = options.interaction.redrawOverlayInterval; + if (t == -1) { // skip event queue + drawOverlay(); + return; + } + + if (!redrawTimeout) + redrawTimeout = setTimeout(drawOverlay, t); + } + + function drawOverlay() { + redrawTimeout = null; + + // draw highlights + octx.save(); + overlay.clear(); + octx.translate(plotOffset.left, plotOffset.top); + + var i, hi; + for (i = 0; i < highlights.length; ++i) { + hi = highlights[i]; + + if (hi.series.bars.show) + drawBarHighlight(hi.series, hi.point); + else + drawPointHighlight(hi.series, hi.point); + } + octx.restore(); + + executeHooks(hooks.drawOverlay, [octx]); + } + + function highlight(s, point, auto) { + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i == -1) { + highlights.push({ series: s, point: point, auto: auto }); + + triggerRedrawOverlay(); + } + else if (!auto) + highlights[i].auto = false; + } + + function unhighlight(s, point) { + if (s == null && point == null) { + highlights = []; + triggerRedrawOverlay(); + return; + } + + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i != -1) { + highlights.splice(i, 1); + + triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s, p) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s && h.point[0] == p[0] + && h.point[1] == p[1]) + return i; + } + return -1; + } + + function drawPointHighlight(series, point) { + var x = point[0], y = point[1], + axisx = series.xaxis, axisy = series.yaxis, + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); + + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + return; + + var pointRadius = series.points.radius + series.points.lineWidth / 2; + octx.lineWidth = pointRadius; + octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; + x = axisx.p2c(x); + y = axisy.p2c(y); + + octx.beginPath(); + if (series.points.symbol == "circle") + octx.arc(x, y, radius, 0, 2 * Math.PI, false); + else + series.points.symbol(octx, x, y, radius, false); + octx.closePath(); + octx.stroke(); + } + + function drawBarHighlight(series, point) { + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), + fillStyle = highlightColor, + barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + octx.lineWidth = series.bars.lineWidth; + octx.strokeStyle = highlightColor; + + drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, + function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + } + + function getColorOrGradient(spec, bottom, top, defaultColor) { + if (typeof spec == "string") + return spec; + else { + // assume this is a gradient spec; IE currently only + // supports a simple vertical gradient properly, so that's + // what we support too + var gradient = ctx.createLinearGradient(0, top, 0, bottom); + + for (var i = 0, l = spec.colors.length; i < l; ++i) { + var c = spec.colors[i]; + if (typeof c != "string") { + var co = $.color.parse(defaultColor); + if (c.brightness != null) + co = co.scale('rgb', c.brightness); + if (c.opacity != null) + co.a *= c.opacity; + c = co.toString(); + } + gradient.addColorStop(i / (l - 1), c); + } + + return gradient; + } + } + } + + // Add the plot function to the top level of the jQuery object + + $.plot = function(placeholder, data, options) { + //var t0 = new Date(); + var plot = new Plot($(placeholder), data, options, $.plot.plugins); + //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime())); + return plot; + }; + + $.plot.version = "0.8.3"; + + $.plot.plugins = []; + + // Also add the plot function as a chainable property + + $.fn.plot = function(data, options) { + return this.each(function() { + $.plot(this, data, options); + }); + }; + + // round to nearby lower multiple of base + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + +})(jQuery); diff --git a/src/lib/js/jquery.flot.min.js b/src/lib/js/jquery.flot.min.js new file mode 100644 index 0000000..30b5207 --- /dev/null +++ b/src/lib/js/jquery.flot.min.js @@ -0,0 +1,8 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return valuemax?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){var cache=this._textCache;for(var layerKey in cache){if(hasOwnProperty.call(cache,layerKey)){var layer=this.getTextLayer(layerKey),layerCache=cache[layerKey];layer.hide();for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){if(position.active){if(!position.rendered){layer.append(position.element);position.rendered=true}}else{positions.splice(i--,1);if(position.rendered){position.element.detach()}}}if(positions.length==0){delete styleCache[key]}}}}}layer.show()}}};Canvas.prototype.getTextLayer=function(classes){var layer=this.text[classes];if(layer==null){if(this.textContainer==null){this.textContainer=$("
").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)}layer=this.text[classes]=$("
").addClass(classes).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)}return layer};Canvas.prototype.getTextInfo=function(layer,text,font,angle,width){var textStyle,layerCache,styleCache,info;text=""+text;if(typeof font==="object"){textStyle=font.style+" "+font.variant+" "+font.weight+" "+font.size+"px/"+font.lineHeight+"px "+font.family}else{textStyle=font}layerCache=this._textCache[layer];if(layerCache==null){layerCache=this._textCache[layer]={}}styleCache=layerCache[textStyle];if(styleCache==null){styleCache=layerCache[textStyle]={}}info=styleCache[text];if(info==null){var element=$("
").html(text).css({position:"absolute","max-width":width,top:-9999}).appendTo(this.getTextLayer(layer));if(typeof font==="object"){element.css({font:textStyle,color:font.color})}else if(typeof font==="string"){element.addClass(font)}info=styleCache[text]={width:element.outerWidth(true),height:element.outerHeight(true),element:element,positions:[]};element.detach()}return info};Canvas.prototype.addText=function(layer,x,y,text,font,angle,width,halign,valign){var info=this.getTextInfo(layer,text,font,angle,width),positions=info.positions;if(halign=="center"){x-=info.width/2}else if(halign=="right"){x-=info.width}if(valign=="middle"){y-=info.height/2}else if(valign=="bottom"){y-=info.height}for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=true;return}}position={active:true,rendered:false,element:positions.length?info.element.clone():info.element,x:x,y:y};positions.push(position);position.element.css({top:Math.round(y),left:Math.round(x),"text-align":halign})};Canvas.prototype.removeText=function(layer,x,y,text,font,angle){if(text==null){var layerCache=this._textCache[layer];if(layerCache!=null){for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){position.active=false}}}}}}}else{var positions=this.getTextInfo(layer,text,font,angle).positions;for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=false}}}};function Plot(placeholder,data_,options_,plugins){var series=[],options={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false,zero:true},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},surface=null,overlay=null,eventHolder=null,ctx=null,octx=null,xaxes=[],yaxes=[],plotOffset={left:0,right:0,top:0,bottom:0},plotWidth=0,plotHeight=0,hooks={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},plot=this;plot.setData=setData;plot.setupGrid=setupGrid;plot.draw=draw;plot.getPlaceholder=function(){return placeholder};plot.getCanvas=function(){return surface.element};plot.getPlotOffset=function(){return plotOffset};plot.width=function(){return plotWidth};plot.height=function(){return plotHeight};plot.offset=function(){var o=eventHolder.offset();o.left+=plotOffset.left;o.top+=plotOffset.top;return o};plot.getData=function(){return series};plot.getAxes=function(){var res={},i;$.each(xaxes.concat(yaxes),function(_,axis){if(axis)res[axis.direction+(axis.n!=1?axis.n:"")+"axis"]=axis});return res};plot.getXAxes=function(){return xaxes};plot.getYAxes=function(){return yaxes};plot.c2p=canvasToAxisCoords;plot.p2c=axisToCanvasCoords;plot.getOptions=function(){return options};plot.highlight=highlight;plot.unhighlight=unhighlight;plot.triggerRedrawOverlay=triggerRedrawOverlay;plot.pointOffset=function(point){return{left:parseInt(xaxes[axisNumber(point,"x")-1].p2c(+point.x)+plotOffset.left,10),top:parseInt(yaxes[axisNumber(point,"y")-1].p2c(+point.y)+plotOffset.top,10)}};plot.shutdown=shutdown;plot.destroy=function(){shutdown();placeholder.removeData("plot").empty();series=[];options=null;surface=null;overlay=null;eventHolder=null;ctx=null;octx=null;xaxes=[];yaxes=[];hooks=null;highlights=[];plot=null};plot.resize=function(){var width=placeholder.width(),height=placeholder.height();surface.resize(width,height);overlay.resize(width,height)};plot.hooks=hooks;initPlugins(plot);parseOptions(options_);setupCanvases();setData(data_);setupGrid();draw();bindEvents();function executeHooks(hook,args){args=[plot].concat(args);for(var i=0;imaxIndex){maxIndex=sc}}}if(neededColors<=maxIndex){neededColors=maxIndex+1}var c,colors=[],colorPool=options.colors,colorPoolSize=colorPool.length,variation=0;for(i=0;i=0){if(variation<.5){variation=-variation-.2}else variation=0}else variation=-variation}colors[i]=c.scale("rgb",1+variation)}var colori=0,s;for(i=0;iaxis.datamax&&max!=fakeInfinity)axis.datamax=max}$.each(allAxes(),function(_,axis){axis.datamin=topSentry;axis.datamax=bottomSentry;axis.used=false});for(i=0;i0&&points[k-ps]!=null&&points[k-ps]!=points[k]&&points[k-ps+1]!=points[k+1]){for(m=0;mxmax)xmax=val}if(f.y){if(valymax)ymax=val}}}if(s.bars.show){var delta;switch(s.bars.align){case"left":delta=0;break;case"right":delta=-s.bars.barWidth;break;default:delta=-s.bars.barWidth/2}if(s.bars.horizontal){ymin+=delta;ymax+=delta+s.bars.barWidth}else{xmin+=delta;xmax+=delta+s.bars.barWidth}}updateAxis(s.xaxis,xmin,xmax);updateAxis(s.yaxis,ymin,ymax)}$.each(allAxes(),function(_,axis){if(axis.datamin==topSentry)axis.datamin=null;if(axis.datamax==bottomSentry)axis.datamax=null})}function setupCanvases(){placeholder.css("padding",0).children().filter(function(){return!$(this).hasClass("flot-overlay")&&!$(this).hasClass("flot-base")}).remove();if(placeholder.css("position")=="static")placeholder.css("position","relative");surface=new Canvas("flot-base",placeholder);overlay=new Canvas("flot-overlay",placeholder);ctx=surface.context;octx=overlay.context;eventHolder=$(overlay.element).unbind();var existing=placeholder.data("plot");if(existing){existing.shutdown();overlay.clear()}placeholder.data("plot",plot)}function bindEvents(){if(options.grid.hoverable){eventHolder.mousemove(onMouseMove);eventHolder.bind("mouseleave",onMouseLeave)}if(options.grid.clickable)eventHolder.click(onClick);executeHooks(hooks.bindEvents,[eventHolder])}function shutdown(){if(redrawTimeout)clearTimeout(redrawTimeout);eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mouseleave",onMouseLeave);eventHolder.unbind("click",onClick);executeHooks(hooks.shutdown,[eventHolder])}function setTransformationHelpers(axis){function identity(x){return x}var s,m,t=axis.options.transform||identity,it=axis.options.inverseTransform;if(axis.direction=="x"){s=axis.scale=plotWidth/Math.abs(t(axis.max)-t(axis.min));m=Math.min(t(axis.max),t(axis.min))}else{s=axis.scale=plotHeight/Math.abs(t(axis.max)-t(axis.min));s=-s;m=Math.max(t(axis.max),t(axis.min))}if(t==identity)axis.p2c=function(p){return(p-m)*s};else axis.p2c=function(p){return(t(p)-m)*s};if(!it)axis.c2p=function(c){return m+c/s};else axis.c2p=function(c){return it(m+c/s)}}function measureTickLabels(axis){var opts=axis.options,ticks=axis.ticks||[],labelWidth=opts.labelWidth||0,labelHeight=opts.labelHeight||0,maxWidth=labelWidth||(axis.direction=="x"?Math.floor(surface.width/(ticks.length||1)):null),legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=opts.font||"flot-tick-label tickLabel";for(var i=0;i=0;--i)allocateAxisBoxFirstPhase(allocatedAxes[i]);adjustLayoutForThingsStickingOut();$.each(allocatedAxes,function(_,axis){allocateAxisBoxSecondPhase(axis)})}plotWidth=surface.width-plotOffset.left-plotOffset.right;plotHeight=surface.height-plotOffset.bottom-plotOffset.top;$.each(axes,function(_,axis){setTransformationHelpers(axis)});if(showGrid){drawAxisLabels()}insertLegend()}function setRange(axis){var opts=axis.options,min=+(opts.min!=null?opts.min:axis.datamin),max=+(opts.max!=null?opts.max:axis.datamax),delta=max-min;if(delta==0){var widen=max==0?1:.01;if(opts.min==null)min-=widen;if(opts.max==null||opts.min!=null)max+=widen}else{var margin=opts.autoscaleMargin;if(margin!=null){if(opts.min==null){min-=delta*margin;if(min<0&&axis.datamin!=null&&axis.datamin>=0)min=0}if(opts.max==null){max+=delta*margin;if(max>0&&axis.datamax!=null&&axis.datamax<=0)max=0}}}axis.min=min;axis.max=max}function setupTickGeneration(axis){var opts=axis.options;var noTicks;if(typeof opts.ticks=="number"&&opts.ticks>0)noTicks=opts.ticks;else noTicks=.3*Math.sqrt(axis.direction=="x"?surface.width:surface.height);var delta=(axis.max-axis.min)/noTicks,dec=-Math.floor(Math.log(delta)/Math.LN10),maxDec=opts.tickDecimals;if(maxDec!=null&&dec>maxDec){dec=maxDec}var magn=Math.pow(10,-dec),norm=delta/magn,size;if(norm<1.5){size=1}else if(norm<3){size=2;if(norm>2.25&&(maxDec==null||dec+1<=maxDec)){size=2.5;++dec}}else if(norm<7.5){size=5}else{size=10}size*=magn;if(opts.minTickSize!=null&&size0){if(opts.min==null)axis.min=Math.min(axis.min,niceTicks[0]);if(opts.max==null&&niceTicks.length>1)axis.max=Math.max(axis.max,niceTicks[niceTicks.length-1])}axis.tickGenerator=function(axis){var ticks=[],v,i;for(i=0;i1&&/\..*0$/.test((ts[1]-ts[0]).toFixed(extraDec))))axis.tickDecimals=extraDec}}}}function setTicks(axis){var oticks=axis.options.ticks,ticks=[];if(oticks==null||typeof oticks=="number"&&oticks>0)ticks=axis.tickGenerator(axis);else if(oticks){if($.isFunction(oticks))ticks=oticks(axis);else ticks=oticks}var i,v;axis.ticks=[];for(i=0;i1)label=t[1]}else v=+t;if(label===null)label=axis.tickFormatter(v,axis);if(!isNaN(v))axis.ticks.push({v:v,label:label})}}function snapRangeToTicks(axis,ticks){if(axis.options.autoscaleMargin&&ticks.length>0){if(axis.options.min==null)axis.min=Math.min(axis.min,ticks[0].v);if(axis.options.max==null&&ticks.length>1)axis.max=Math.max(axis.max,ticks[ticks.length-1].v)}}function draw(){surface.clear();executeHooks(hooks.drawBackground,[ctx]);var grid=options.grid;if(grid.show&&grid.backgroundColor)drawBackground();if(grid.show&&!grid.aboveData){drawGrid()}for(var i=0;ito){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function drawBackground(){ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.fillStyle=getColorOrGradient(options.grid.backgroundColor,plotHeight,0,"rgba(255, 255, 255, 0)");ctx.fillRect(0,0,plotWidth,plotHeight);ctx.restore()}function drawGrid(){var i,axes,bw,bc;ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var markings=options.grid.markings;if(markings){if($.isFunction(markings)){axes=plot.getAxes();axes.xmin=axes.xaxis.min;axes.xmax=axes.xaxis.max;axes.ymin=axes.yaxis.min;axes.ymax=axes.yaxis.max;markings=markings(axes)}for(i=0;ixrange.axis.max||yrange.toyrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;jaxis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;iaxis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i=y2&&y1>axisy.max){if(y2>axisy.max)continue;x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max){if(y1>axisy.max)continue;x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1<=x2&&x1=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(x1!=prevx||y1!=prevy)ctx.moveTo(axisx.p2c(x1)+xoffset,axisy.p2c(y1)+yoffset);prevx=x2;prevy=y2;ctx.lineTo(axisx.p2c(x2)+xoffset,axisy.p2c(y2)+yoffset)}ctx.stroke()}function plotLineArea(datapoints,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,bottom=Math.min(Math.max(0,axisy.min),axisy.max),i=0,top,areaOpen=false,ypos=1,segmentStart=0,segmentEnd=0;while(true){if(ps>0&&i>points.length+ps)break;i+=ps;var x1=points[i-ps],y1=points[i-ps+ypos],x2=points[i],y2=points[i+ypos];if(areaOpen){if(ps>0&&x1!=null&&x2==null){segmentEnd=i;ps=-ps;ypos=2;continue}if(ps<0&&i==segmentStart+ps){ctx.fill();areaOpen=false;ps=-ps;ypos=1;i=segmentStart=segmentEnd+ps;continue}}if(x1==null||x2==null)continue;if(x1<=x2&&x1=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(!areaOpen){ctx.beginPath();ctx.moveTo(axisx.p2c(x1),axisy.p2c(bottom));areaOpen=true}if(y1>=axisy.max&&y2>=axisy.max){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.max));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.max));continue}else if(y1<=axisy.min&&y2<=axisy.min){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.min));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.min));continue}var x1old=x1,x2old=x2;if(y1<=y2&&y1=axisy.min){x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2=axisy.min){x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max&&y2<=axisy.max){x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max&&y1<=axisy.max){x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1!=x1old){ctx.lineTo(axisx.p2c(x1old),axisy.p2c(y1))}ctx.lineTo(axisx.p2c(x1),axisy.p2c(y1));ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));if(x2!=x2old){ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));ctx.lineTo(axisx.p2c(x2old),axisy.p2c(y2))}}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineJoin="round";var lw=series.lines.lineWidth,sw=series.shadowSize;if(lw>0&&sw>0){ctx.lineWidth=sw;ctx.strokeStyle="rgba(0,0,0,0.1)";var angle=Math.PI/18;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/2),Math.cos(angle)*(lw/2+sw/2),series.xaxis,series.yaxis);ctx.lineWidth=sw/2;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/4),Math.cos(angle)*(lw/2+sw/4),series.xaxis,series.yaxis)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;var fillStyle=getFillStyle(series.lines,series.color,0,plotHeight);if(fillStyle){ctx.fillStyle=fillStyle;plotLineArea(series.datapoints,series.xaxis,series.yaxis)}if(lw>0)plotLine(series.datapoints,0,0,series.xaxis,series.yaxis);ctx.restore()}function drawSeriesPoints(series){function plotPoints(datapoints,radius,fillStyle,offset,shadow,axisx,axisy,symbol){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;iaxisx.max||yaxisy.max)continue;ctx.beginPath();x=axisx.p2c(x);y=axisy.p2c(y)+offset;if(symbol=="circle")ctx.arc(x,y,radius,0,shadow?Math.PI:Math.PI*2,false);else symbol(ctx,x,y,radius,shadow);ctx.closePath();if(fillStyle){ctx.fillStyle=fillStyle;ctx.fill()}ctx.stroke()}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var lw=series.points.lineWidth,sw=series.shadowSize,radius=series.points.radius,symbol=series.points.symbol;if(lw==0)lw=1e-4;if(lw>0&&sw>0){var w=sw/2;ctx.lineWidth=w;ctx.strokeStyle="rgba(0,0,0,0.1)";plotPoints(series.datapoints,radius,null,w+w/2,true,series.xaxis,series.yaxis,symbol);ctx.strokeStyle="rgba(0,0,0,0.2)";plotPoints(series.datapoints,radius,null,w/2,true,series.xaxis,series.yaxis,symbol)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;plotPoints(series.datapoints,radius,getFillStyle(series.points,series.color),0,false,series.xaxis,series.yaxis,symbol);ctx.restore()}function drawBar(x,y,b,barLeft,barRight,fillStyleCallback,axisx,axisy,c,horizontal,lineWidth){var left,right,bottom,top,drawLeft,drawRight,drawTop,drawBottom,tmp;if(horizontal){drawBottom=drawRight=drawTop=true;drawLeft=false;left=b;right=x;top=y+barLeft;bottom=y+barRight;if(rightaxisx.max||topaxisy.max)return;if(leftaxisx.max){right=axisx.max;drawRight=false}if(bottomaxisy.max){top=axisy.max;drawTop=false}left=axisx.p2c(left);bottom=axisy.p2c(bottom);right=axisx.p2c(right);top=axisy.p2c(top);if(fillStyleCallback){c.fillStyle=fillStyleCallback(bottom,top);c.fillRect(left,top,right-left,bottom-top)}if(lineWidth>0&&(drawLeft||drawRight||drawTop||drawBottom)){c.beginPath();c.moveTo(left,bottom);if(drawLeft)c.lineTo(left,top);else c.moveTo(left,top);if(drawTop)c.lineTo(right,top);else c.moveTo(right,top);if(drawRight)c.lineTo(right,bottom);else c.moveTo(right,bottom);if(drawBottom)c.lineTo(left,bottom);else c.moveTo(left,bottom);c.stroke()}}function drawSeriesBars(series){function plotBars(datapoints,barLeft,barRight,fillStyleCallback,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i");fragments.push("");rowStarted=true}fragments.push('
'+''+entry.label+"")}if(rowStarted)fragments.push("");if(fragments.length==0)return;var table=''+fragments.join("")+"
";if(options.legend.container!=null)$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null)m=[m,m];if(p.charAt(0)=="n")pos+="top:"+(m[1]+plotOffset.top)+"px;";else if(p.charAt(0)=="s")pos+="bottom:"+(m[1]+plotOffset.bottom)+"px;";if(p.charAt(1)=="e")pos+="right:"+(m[0]+plotOffset.right)+"px;";else if(p.charAt(1)=="w")pos+="left:"+(m[0]+plotOffset.left)+"px;";var legend=$('
'+table.replace('style="','style="position:absolute;'+pos+";")+"
").appendTo(placeholder);if(options.legend.backgroundOpacity!=0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string")c=$.color.parse(c);else c=$.color.extract(legend,"background-color");c.a=1;c=c.toString()}var div=legend.children();$('
').prependTo(legend).css("opacity",options.legend.backgroundOpacity)}}}var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i]))continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform)maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform)maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;jmaxx||x-mx<-maxx||y-my>maxy||y-my<-maxy)continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight:mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))item=[i,j/ps]}}}if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i}}return null}function onMouseMove(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false})}function onMouseLeave(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return false})}function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false})}function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10)}if(options.grid.autoHighlight){for(var i=0;iaxisx.max||yaxisy.max)return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle")octx.arc(x,y,radius,0,2*Math.PI,false);else series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke()}function drawBarHighlight(series,point){var highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString(),fillStyle=highlightColor,barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,function(){return fillStyle},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth)}function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string")return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY)max){var tmp=min;min=max;max=tmp}if(pr){if(pr[0]!=null&&minpr[1]){max=pr[1]}}var range=max-min;if(zr&&(zr[0]!=null&&range1||zr[1]!=null&&range>zr[1]&&amount<1))return;opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotzoom",[plot,args])};plot.pan=function(args){var delta={x:+args.left,y:+args.top};if(isNaN(delta.x))delta.x=0;if(isNaN(delta.y))delta.y=0;$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min,max,d=delta[axis.direction];min=axis.c2p(axis.p2c(axis.min)+d),max=axis.c2p(axis.p2c(axis.max)+d);var pr=opts.panRange;if(pr===false)return;if(pr){if(pr[0]!=null&&pr[0]>min){d=pr[0]-min;min+=d;max+=d}if(pr[1]!=null&&pr[1]1){options.series.pie.tilt=1}else if(options.series.pie.tilt<0){options.series.pie.tilt=0}}});plot.hooks.bindEvents.push(function(plot,eventHolder){var options=plot.getOptions();if(options.series.pie.show){if(options.grid.hoverable){eventHolder.unbind("mousemove").mousemove(onMouseMove)}if(options.grid.clickable){eventHolder.unbind("click").click(onClick)}}});plot.hooks.processDatapoints.push(function(plot,series,data,datapoints){var options=plot.getOptions();if(options.series.pie.show){processDatapoints(plot,series,data,datapoints)}});plot.hooks.drawOverlay.push(function(plot,octx){var options=plot.getOptions();if(options.series.pie.show){drawOverlay(plot,octx)}});plot.hooks.draw.push(function(plot,newCtx){var options=plot.getOptions();if(options.series.pie.show){draw(plot,newCtx)}});function processDatapoints(plot,series,datapoints){if(!processed){processed=true;canvas=plot.getCanvas();target=$(canvas).parent();options=plot.getOptions();plot.setData(combine(plot.getData()))}}function combine(data){var total=0,combined=0,numCombined=0,color=options.series.pie.combine.color,newdata=[];for(var i=0;ioptions.series.pie.combine.threshold){newdata.push($.extend(data[i],{data:[[1,value]],color:data[i].color,label:data[i].label,angle:value*Math.PI*2/total,percent:value/(total/100)}))}}if(numCombined>1){newdata.push({data:[[1,combined]],color:color,label:options.series.pie.combine.label,angle:combined*Math.PI*2/total,percent:combined/(total/100)})}return newdata}function draw(plot,newCtx){if(!target){return}var canvasWidth=plot.getPlaceholder().width(),canvasHeight=plot.getPlaceholder().height(),legendWidth=target.children().filter(".legend").children().width()||0;ctx=newCtx;processed=false;maxRadius=Math.min(canvasWidth,canvasHeight/options.series.pie.tilt)/2;centerTop=canvasHeight/2+options.series.pie.offset.top;centerLeft=canvasWidth/2;if(options.series.pie.offset.left=="auto"){if(options.legend.position.match("w")){centerLeft+=legendWidth/2}else{centerLeft-=legendWidth/2}if(centerLeftcanvasWidth-maxRadius){centerLeft=canvasWidth-maxRadius}}else{centerLeft+=options.series.pie.offset.left}var slices=plot.getData(),attempts=0;do{if(attempts>0){maxRadius*=REDRAW_SHRINK}attempts+=1;clear();if(options.series.pie.tilt<=.8){drawShadow()}}while(!drawPie()&&attempts=REDRAW_ATTEMPTS){clear();target.prepend("
Could not draw pie with labels contained inside canvas
")}if(plot.setSeries&&plot.insertLegend){plot.setSeries(slices);plot.insertLegend()}function clear(){ctx.clearRect(0,0,canvasWidth,canvasHeight);target.children().filter(".pieLabel, .pieLabelBackground").remove()}function drawShadow(){var shadowLeft=options.series.pie.shadow.left;var shadowTop=options.series.pie.shadow.top;var edge=10;var alpha=options.series.pie.shadow.alpha;var radius=options.series.pie.radius>1?options.series.pie.radius:maxRadius*options.series.pie.radius;if(radius>=canvasWidth/2-shadowLeft||radius*options.series.pie.tilt>=canvasHeight/2-shadowTop||radius<=edge){return}ctx.save();ctx.translate(shadowLeft,shadowTop);ctx.globalAlpha=alpha;ctx.fillStyle="#000";ctx.translate(centerLeft,centerTop);ctx.scale(1,options.series.pie.tilt);for(var i=1;i<=edge;i++){ctx.beginPath();ctx.arc(0,0,radius,0,Math.PI*2,false);ctx.fill();radius-=i}ctx.restore()}function drawPie(){var startAngle=Math.PI*options.series.pie.startAngle;var radius=options.series.pie.radius>1?options.series.pie.radius:maxRadius*options.series.pie.radius;ctx.save();ctx.translate(centerLeft,centerTop);ctx.scale(1,options.series.pie.tilt);ctx.save();var currentAngle=startAngle;for(var i=0;i0){ctx.save();ctx.lineWidth=options.series.pie.stroke.width;currentAngle=startAngle;for(var i=0;i1e-9){ctx.moveTo(0,0)}ctx.arc(0,0,radius,currentAngle,currentAngle+angle/2,false);ctx.arc(0,0,radius,currentAngle+angle/2,currentAngle+angle,false);ctx.closePath();currentAngle+=angle;if(fill){ctx.fill()}else{ctx.stroke()}}function drawLabels(){var currentAngle=startAngle;var radius=options.series.pie.label.radius>1?options.series.pie.label.radius:maxRadius*options.series.pie.label.radius;for(var i=0;i=options.series.pie.label.threshold*100){if(!drawLabel(slices[i],currentAngle,i)){return false}}currentAngle+=slices[i].angle}return true;function drawLabel(slice,startAngle,index){if(slice.data[0][1]==0){return true}var lf=options.legend.labelFormatter,text,plf=options.series.pie.label.formatter;if(lf){text=lf(slice.label,slice)}else{text=slice.label}if(plf){text=plf(text,slice)}var halfAngle=(startAngle+slice.angle+startAngle)/2;var x=centerLeft+Math.round(Math.cos(halfAngle)*radius);var y=centerTop+Math.round(Math.sin(halfAngle)*radius)*options.series.pie.tilt;var html=""+text+"";target.append(html);var label=target.children("#pieLabel"+index);var labelTop=y-label.height()/2;var labelLeft=x-label.width()/2;label.css("top",labelTop);label.css("left",labelLeft);if(0-labelTop>0||0-labelLeft>0||canvasHeight-(labelTop+label.height())<0||canvasWidth-(labelLeft+label.width())<0){return false}if(options.series.pie.label.background.opacity!=0){var c=options.series.pie.label.background.color;if(c==null){c=slice.color}var pos="top:"+labelTop+"px;left:"+labelLeft+"px;";$("
").css("opacity",options.series.pie.label.background.opacity).insertBefore(label)}return true}}}}function drawDonutHole(layer){if(options.series.pie.innerRadius>0){layer.save();var innerRadius=options.series.pie.innerRadius>1?options.series.pie.innerRadius:maxRadius*options.series.pie.innerRadius;layer.globalCompositeOperation="destination-out";layer.beginPath();layer.fillStyle=options.series.pie.stroke.color;layer.arc(0,0,innerRadius,0,Math.PI*2,false);layer.fill();layer.closePath();layer.restore();layer.save();layer.beginPath();layer.strokeStyle=options.series.pie.stroke.color;layer.arc(0,0,innerRadius,0,Math.PI*2,false);layer.stroke();layer.closePath();layer.restore()}}function isPointInPoly(poly,pt){for(var c=false,i=-1,l=poly.length,j=l-1;++i1?options.series.pie.radius:maxRadius*options.series.pie.radius,x,y;for(var i=0;i1?options.series.pie.radius:maxRadius*options.series.pie.radius;octx.save();octx.translate(centerLeft,centerTop);octx.scale(1,options.series.pie.tilt);for(var i=0;i1e-9){octx.moveTo(0,0)}octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle/2,false);octx.arc(0,0,radius,series.startAngle+series.angle/2,series.startAngle+series.angle,false);octx.closePath();octx.fill()}}}var options={series:{pie:{show:false,radius:"auto",innerRadius:0,startAngle:3/2,tilt:1,shadow:{left:5,top:15,alpha:.02},offset:{top:0,left:"auto"},stroke:{color:"#fff",width:1},label:{show:"auto",formatter:function(label,slice){return"
"+label+"
"+Math.round(slice.percent)+"%
"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:.5}}}};$.plot.plugins.push({init:init,options:options,name:"pie",version:"1.1"})})(jQuery); \ No newline at end of file diff --git a/src/lib/js/jquery.flot.resize.min.js b/src/lib/js/jquery.flot.resize.min.js new file mode 100644 index 0000000..7e92aa6 --- /dev/null +++ b/src/lib/js/jquery.flot.resize.min.js @@ -0,0 +1,7 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($,e,t){"$:nomunge";var i=[],n=$.resize=$.extend($.resize,{}),a,r=false,s="setTimeout",u="resize",m=u+"-special-event",o="pendingDelay",l="activeDelay",f="throttleWindow";n[o]=200;n[l]=20;n[f]=true;$.event.special[u]={setup:function(){if(!n[f]&&this[s]){return false}var e=$(this);i.push(this);e.data(m,{w:e.width(),h:e.height()});if(i.length===1){a=t;h()}},teardown:function(){if(!n[f]&&this[s]){return false}var e=$(this);for(var t=i.length-1;t>=0;t--){if(i[t]==this){i.splice(t,1);break}}e.removeData(m);if(!i.length){if(r){cancelAnimationFrame(a)}else{clearTimeout(a)}a=null}},add:function(e){if(!n[f]&&this[s]){return false}var i;function a(e,n,a){var r=$(this),s=r.data(m)||{};s.w=n!==t?n:r.width();s.h=a!==t?a:r.height();i.apply(this,arguments)}if($.isFunction(e)){i=e;return a}else{i=e.handler;e.handler=a}}};function h(t){if(r===true){r=t||1}for(var s=i.length-1;s>=0;s--){var l=$(i[s]);if(l[0]==e||l.is(":visible")){var f=l.width(),c=l.height(),d=l.data(m);if(d&&(f!==d.w||c!==d.h)){l.trigger(u,[d.w=f,d.h=c]);r=t||true}}else{d=l.data(m);d.w=0;d.h=0}}if(a!==null){if(r&&(t==null||t-r<1e3)){a=e.requestAnimationFrame(h)}else{a=setTimeout(h,n[o]);r=false}}}if(!e.requestAnimationFrame){e.requestAnimationFrame=function(){return e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t,i){return e.setTimeout(function(){t((new Date).getTime())},n[l])}}()}if(!e.cancelAnimationFrame){e.cancelAnimationFrame=function(){return e.webkitCancelRequestAnimationFrame||e.mozCancelRequestAnimationFrame||e.oCancelRequestAnimationFrame||e.msCancelRequestAnimationFrame||clearTimeout}()}})(jQuery,this);(function($){var options={};function init(plot){function onResize(){var placeholder=plot.getPlaceholder();if(placeholder.width()==0||placeholder.height()==0)return;plot.resize();plot.setupGrid();plot.draw()}function bindEvents(plot,eventHolder){plot.getPlaceholder().resize(onResize)}function shutdown(plot,eventHolder){plot.getPlaceholder().unbind("resize",onResize)}plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown)}$.plot.plugins.push({init:init,options:options,name:"resize",version:"1.0"})})(jQuery); \ No newline at end of file diff --git a/src/lib/js/jquery.flot.selection.min.js b/src/lib/js/jquery.flot.selection.min.js new file mode 100644 index 0000000..a0154fb --- /dev/null +++ b/src/lib/js/jquery.flot.selection.min.js @@ -0,0 +1,7 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){function init(plot){var selection={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var savedhandlers={};var mouseUpHandler=null;function onMouseMove(e){if(selection.active){updateSelection(e);plot.getPlaceholder().trigger("plotselecting",[getSelection()])}}function onMouseDown(e){if(e.which!=1)return;document.body.focus();if(document.onselectstart!==undefined&&savedhandlers.onselectstart==null){savedhandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&savedhandlers.ondrag==null){savedhandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}setSelectionPos(selection.first,e);selection.active=true;mouseUpHandler=function(e){onMouseUp(e)};$(document).one("mouseup",mouseUpHandler)}function onMouseUp(e){mouseUpHandler=null;if(document.onselectstart!==undefined)document.onselectstart=savedhandlers.onselectstart;if(document.ondrag!==undefined)document.ondrag=savedhandlers.ondrag;selection.active=false;updateSelection(e);if(selectionIsSane())triggerSelectedEvent();else{plot.getPlaceholder().trigger("plotunselected",[]);plot.getPlaceholder().trigger("plotselecting",[null])}return false}function getSelection(){if(!selectionIsSane())return null;if(!selection.show)return null;var r={},c1=selection.first,c2=selection.second;$.each(plot.getAxes(),function(name,axis){if(axis.used){var p1=axis.c2p(c1[axis.direction]),p2=axis.c2p(c2[axis.direction]);r[name]={from:Math.min(p1,p2),to:Math.max(p1,p2)}}});return r}function triggerSelectedEvent(){var r=getSelection();plot.getPlaceholder().trigger("plotselected",[r]);if(r.xaxis&&r.yaxis)plot.getPlaceholder().trigger("selected",[{x1:r.xaxis.from,y1:r.yaxis.from,x2:r.xaxis.to,y2:r.yaxis.to}])}function clamp(min,value,max){return valuemax?max:value}function setSelectionPos(pos,e){var o=plot.getOptions();var offset=plot.getPlaceholder().offset();var plotOffset=plot.getPlotOffset();pos.x=clamp(0,e.pageX-offset.left-plotOffset.left,plot.width());pos.y=clamp(0,e.pageY-offset.top-plotOffset.top,plot.height());if(o.selection.mode=="y")pos.x=pos==selection.first?0:plot.width();if(o.selection.mode=="x")pos.y=pos==selection.first?0:plot.height()}function updateSelection(pos){if(pos.pageX==null)return;setSelectionPos(selection.second,pos);if(selectionIsSane()){selection.show=true;plot.triggerRedrawOverlay()}else clearSelection(true)}function clearSelection(preventEvent){if(selection.show){selection.show=false;plot.triggerRedrawOverlay();if(!preventEvent)plot.getPlaceholder().trigger("plotunselected",[])}}function extractRange(ranges,coord){var axis,from,to,key,axes=plot.getAxes();for(var k in axes){axis=axes[k];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?plot.getXAxes()[0]:plot.getYAxes()[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function setSelection(ranges,preventEvent){var axis,range,o=plot.getOptions();if(o.selection.mode=="y"){selection.first.x=0;selection.second.x=plot.width()}else{range=extractRange(ranges,"x");selection.first.x=range.axis.p2c(range.from);selection.second.x=range.axis.p2c(range.to)}if(o.selection.mode=="x"){selection.first.y=0;selection.second.y=plot.height()}else{range=extractRange(ranges,"y");selection.first.y=range.axis.p2c(range.from);selection.second.y=range.axis.p2c(range.to)}selection.show=true;plot.triggerRedrawOverlay();if(!preventEvent&&selectionIsSane())triggerSelectedEvent()}function selectionIsSane(){var minSize=plot.getOptions().selection.minSize;return Math.abs(selection.second.x-selection.first.x)>=minSize&&Math.abs(selection.second.y-selection.first.y)>=minSize}plot.clearSelection=clearSelection;plot.setSelection=setSelection;plot.getSelection=getSelection;plot.hooks.bindEvents.push(function(plot,eventHolder){var o=plot.getOptions();if(o.selection.mode!=null){eventHolder.mousemove(onMouseMove);eventHolder.mousedown(onMouseDown)}});plot.hooks.drawOverlay.push(function(plot,ctx){if(selection.show&&selectionIsSane()){var plotOffset=plot.getPlotOffset();var o=plot.getOptions();ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var c=$.color.parse(o.selection.color);ctx.strokeStyle=c.scale("a",.8).toString();ctx.lineWidth=1;ctx.lineJoin=o.selection.shape;ctx.fillStyle=c.scale("a",.4).toString();var x=Math.min(selection.first.x,selection.second.x)+.5,y=Math.min(selection.first.y,selection.second.y)+.5,w=Math.abs(selection.second.x-selection.first.x)-1,h=Math.abs(selection.second.y-selection.first.y)-1;ctx.fillRect(x,y,w,h);ctx.strokeRect(x,y,w,h);ctx.restore()}});plot.hooks.shutdown.push(function(plot,eventHolder){eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mousedown",onMouseDown);if(mouseUpHandler)$(document).unbind("mouseup",mouseUpHandler)})}$.plot.plugins.push({init:init,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery); \ No newline at end of file diff --git a/src/lib/js/jquery.flot.spline.min.js b/src/lib/js/jquery.flot.spline.min.js new file mode 100644 index 0000000..8c31537 --- /dev/null +++ b/src/lib/js/jquery.flot.spline.min.js @@ -0,0 +1,217 @@ +/** + * Flot plugin that provides spline interpolation for line graphs + * author: Alex Bardas < alex.bardas@gmail.com > + * modified by: Avi Kohn https://github.com/AMKohn + * based on the spline interpolation described at: + * http://scaledinnovation.com/analytics/splines/aboutSplines.html + * + * Example usage: (add in plot options series object) + * for linespline: + * series: { + * ... + * lines: { + * show: false + * }, + * splines: { + * show: true, + * tension: x, (float between 0 and 1, defaults to 0.5), + * lineWidth: y (number, defaults to 2), + * fill: z (float between 0 .. 1 or false, as in flot documentation) + * }, + * ... + * } + * areaspline: + * series: { + * ... + * lines: { + * show: true, + * lineWidth: 0, (line drawing will not execute) + * fill: x, (float between 0 .. 1, as in flot documentation) + * ... + * }, + * splines: { + * show: true, + * tension: 0.5 (float between 0 and 1) + * }, + * ... + * } + * + */ + +(function($) { + 'use strict' + + /** + * @param {Number} x0, y0, x1, y1: coordinates of the end (knot) points of the segment + * @param {Number} x2, y2: the next knot (not connected, but needed to calculate p2) + * @param {Number} tension: control how far the control points spread + * @return {Array}: p1 -> control point, from x1 back toward x0 + * p2 -> the next control point, returned to become the next segment's p1 + * + * @api private + */ + function getControlPoints(x0, y0, x1, y1, x2, y2, tension) { + + var pow = Math.pow, + sqrt = Math.sqrt, + d01, d12, fa, fb, p1x, p1y, p2x, p2y; + + // Scaling factors: distances from this knot to the previous and following knots. + d01 = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2)); + d12 = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); + + fa = tension * d01 / (d01 + d12); + fb = tension - fa; + + p1x = x1 + fa * (x0 - x2); + p1y = y1 + fa * (y0 - y2); + + p2x = x1 - fb * (x0 - x2); + p2y = y1 - fb * (y0 - y2); + + return [p1x, p1y, p2x, p2y]; + } + + var line = []; + + function drawLine(points, ctx, height, fill, seriesColor) { + var c = $.color.parse(seriesColor); + + c.a = typeof fill == "number" ? fill : .3; + c.normalize(); + c = c.toString(); + + ctx.beginPath(); + ctx.moveTo(points[0][0], points[0][1]); + + var plength = points.length; + + for (var i = 0; i < plength; i++) { + try { + ctx[points[i][3]].apply(ctx, points[i][2]); + } catch(e) { + console.log(e); + break; + } + } + + ctx.stroke(); + + ctx.lineWidth = 0; + ctx.lineTo(points[plength - 1][0], height); + ctx.lineTo(points[0][0], height); + + ctx.closePath(); + + if (fill !== false) { + ctx.fillStyle = c; + ctx.fill(); + } + } + + /** + * @param {Object} ctx: canvas context + * @param {String} type: accepted strings: 'bezier' or 'quadratic' (defaults to quadratic) + * @param {Array} points: 2 points for which to draw the interpolation + * @param {Array} cpoints: control points for those segment points + * + * @api private + */ + function queue(ctx, type, points, cpoints) { + if (type === void 0 || (type !== 'bezier' && type !== 'quadratic')) { + type = 'quadratic'; + } + type = type + 'CurveTo'; + + if (line.length == 0) line.push([points[0], points[1], cpoints.concat(points.slice(2)), type]); + else if (type == "quadraticCurveTo" && points.length == 2) { + cpoints = cpoints.slice(0, 2).concat(points); + + line.push([points[0], points[1], cpoints, type]); + } + else line.push([points[2], points[3], cpoints.concat(points.slice(2)), type]); + } + + /** + * @param {Object} plot + * @param {Object} ctx: canvas context + * @param {Object} series + * + * @api private + */ + + function drawSpline(plot, ctx, series) { + // Not interested if spline is not requested + if (series.splines.show !== true) { + return; + } + + var cp = [], + // array of control points + tension = series.splines.tension || 0.5, + idx, x, y, points = series.datapoints.points, + ps = series.datapoints.pointsize, + plotOffset = plot.getPlotOffset(), + len = points.length, + pts = []; + + line = []; + + // Cannot display a linespline/areaspline if there are less than 3 points + if (len / ps < 4) { + $.extend(series.lines, series.splines); + return; + } + + for (idx = 0; idx < len; idx += ps) { + x = points[idx]; + y = points[idx + 1]; + if (x == null || x < series.xaxis.min || x > series.xaxis.max || y < series.yaxis.min || y > series.yaxis.max) { + continue; + } + + pts.push(series.xaxis.p2c(x) + plotOffset.left, series.yaxis.p2c(y) + plotOffset.top); + } + + len = pts.length; + + // Draw an open curve, not connected at the ends + for (idx = 0; idx < len - 2; idx += 2) { + cp = cp.concat(getControlPoints.apply(this, pts.slice(idx, idx + 6).concat([tension]))); + } + + ctx.save(); + ctx.strokeStyle = series.color; + ctx.lineWidth = series.splines.lineWidth; + + queue(ctx, 'quadratic', pts.slice(0, 4), cp.slice(0, 2)); + + for (idx = 2; idx < len - 3; idx += 2) { + queue(ctx, 'bezier', pts.slice(idx, idx + 4), cp.slice(2 * idx - 2, 2 * idx + 2)); + } + + queue(ctx, 'quadratic', pts.slice(len - 2, len), [cp[2 * len - 10], cp[2 * len - 9], pts[len - 4], pts[len - 3]]); + + drawLine(line, ctx, plot.height() + 10, series.splines.fill, series.color); + + ctx.restore(); + } + + $.plot.plugins.push({ + init: function(plot) { + plot.hooks.drawSeries.push(drawSpline); + }, + options: { + series: { + splines: { + show: false, + lineWidth: 2, + tension: 0.5, + fill: false + } + } + }, + name: 'spline', + version: '0.8.2' + }); +})(jQuery); \ No newline at end of file diff --git a/src/lib/js/jquery.flot.time.min.js b/src/lib/js/jquery.flot.time.min.js new file mode 100644 index 0000000..690eb68 --- /dev/null +++ b/src/lib/js/jquery.flot.time.min.js @@ -0,0 +1,7 @@ +/* Javascript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ +(function($){var options={xaxis:{timezone:null,timeformat:null,twelveHourClock:false,monthNames:null}};function floorInBase(n,base){return base*Math.floor(n/base)}function formatDate(d,fmt,monthNames,dayNames){if(typeof d.strftime=="function"){return d.strftime(fmt)}var leftPad=function(n,pad){n=""+n;pad=""+(pad==null?"0":pad);return n.length==1?pad+n:n};var r=[];var escape=false;var hours=d.getHours();var isAM=hours<12;if(monthNames==null){monthNames=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(dayNames==null){dayNames=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]}var hours12;if(hours>12){hours12=hours-12}else if(hours==0){hours12=12}else{hours12=hours}for(var i=0;i=minSize){break}}var size=spec[i][0];var unit=spec[i][1];if(unit=="year"){if(opts.minTickSize!=null&&opts.minTickSize[1]=="year"){size=Math.floor(opts.minTickSize[0])}else{var magn=Math.pow(10,Math.floor(Math.log(axis.delta/timeUnitSize.year)/Math.LN10));var norm=axis.delta/timeUnitSize.year/magn;if(norm<1.5){size=1}else if(norm<3){size=2}else if(norm<7.5){size=5}else{size=10}size*=magn}if(size<1){size=1}}axis.tickSize=opts.tickSize||[size,unit];var tickSize=axis.tickSize[0];unit=axis.tickSize[1];var step=tickSize*timeUnitSize[unit];if(unit=="second"){d.setSeconds(floorInBase(d.getSeconds(),tickSize))}else if(unit=="minute"){d.setMinutes(floorInBase(d.getMinutes(),tickSize))}else if(unit=="hour"){d.setHours(floorInBase(d.getHours(),tickSize))}else if(unit=="month"){d.setMonth(floorInBase(d.getMonth(),tickSize))}else if(unit=="quarter"){d.setMonth(3*floorInBase(d.getMonth()/3,tickSize))}else if(unit=="year"){d.setFullYear(floorInBase(d.getFullYear(),tickSize))}d.setMilliseconds(0);if(step>=timeUnitSize.minute){d.setSeconds(0)}if(step>=timeUnitSize.hour){d.setMinutes(0)}if(step>=timeUnitSize.day){d.setHours(0)}if(step>=timeUnitSize.day*4){d.setDate(1)}if(step>=timeUnitSize.month*2){d.setMonth(floorInBase(d.getMonth(),3))}if(step>=timeUnitSize.quarter*2){d.setMonth(floorInBase(d.getMonth(),6))}if(step>=timeUnitSize.year){d.setMonth(0)}var carry=0;var v=Number.NaN;var prev;do{prev=v;v=d.getTime();ticks.push(v);if(unit=="month"||unit=="quarter"){if(tickSize<1){d.setDate(1);var start=d.getTime();d.setMonth(d.getMonth()+(unit=="quarter"?3:1));var end=d.getTime();d.setTime(v+carry*timeUnitSize.hour+(end-start)*tickSize);carry=d.getHours();d.setHours(0)}else{d.setMonth(d.getMonth()+tickSize*(unit=="quarter"?3:1))}}else if(unit=="year"){d.setFullYear(d.getFullYear()+tickSize)}else{d.setTime(v+step)}}while(v'); + } + } + else { + expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name '); + } + } + else { + console.log('WARNING: Testing for set authors field in io-package skipped because template adapter'); + console.log(); + } + expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true; + if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') { + console.log('WARNING: titleLang is not existing in io-package.json. Please add'); + console.log(); + } + if ( + ioPackage.common.title.indexOf('yunkong2') !== -1 || + ioPackage.common.title.indexOf('yunkong2') !== -1 || + ioPackage.common.title.indexOf('adapter') !== -1 || + ioPackage.common.title.indexOf('Adapter') !== -1 + ) { + console.log('WARNING: title contains Adapter or yunkong2. It is clear anyway, that it is adapter for yunkong2.'); + console.log(); + } + + if (ioPackage.common.name.indexOf('vis-') !== 0) { + if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) { + console.log('WARNING: Admin3 support is missing! Please add it'); + console.log(); + } + if (ioPackage.common.materialize) { + expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true; + } + } + + var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE'); + var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8'); + if (fileContentReadme.indexOf('## Changelog') === -1) { + console.log('Warning: The README.md should have a section ## Changelog'); + console.log(); + } + expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true; + if (!licenseFileExists) { + console.log('Warning: The License should also exist as LICENSE file'); + console.log(); + } + if (fileContentReadme.indexOf('## License') === -1) { + console.log('Warning: The README.md should also have a section ## License to be shown in Admin3'); + console.log(); + } + done(); + }); +});