Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
pony
tsview
Commits
eb5ebcbf7800
Commit
60c1f161
authored
Aug 06, 2019
by
André Espaze
Browse files
Move to a Plotly web component for pure Elm rendering
parent
76eb8832076e
Changes
3
Hide whitespace changes
Inline
Side-by-side
elm/Plot.elm
View file @
eb5ebcbf
port
module
Plot
exposing
(
main
)
module
Plot
exposing
(
main
)
import
Browser
import
Common
exposing
(
classes
)
import
Dict
import
Either
exposing
(
Either
)
import
Html
.
Styled
exposing
(
..
)
import
Html
.
Styled
.
Attributes
as
A
import
Html
.
Styled
.
Events
exposing
(
onClick
)
import
Http
import
Json
.
Decode
as
Decode
exposing
(
Decoder
)
import
Json
.
Encode
as
Encode
import
KeywordMultiSelector
import
KeywordSelector
import
LruCache
exposing
(
LruCache
)
...
...
@@ -24,6 +26,7 @@ type alias Model =
,
searchString
:
String
,
searchedSeries
:
List
String
,
selectedSeries
:
List
String
,
selectedNamedSeries
:
List
NamedSerie
,
activeSelection
:
Bool
,
cache
:
SeriesCache
}
...
...
@@ -56,8 +59,6 @@ type Msg
|
ToggleItem
String
|
SearchSeries
String
|
MakeSearch
|
OnApply
|
GotPlot
(
Result
Http
.
Error
String
)
|
RenderPlot
(
Result
String
(
SeriesCache
,
List
NamedSerie
))
...
...
@@ -70,6 +71,17 @@ type alias Trace =
}
encodeTrace
:
Trace
->
Encode
.
Value
encodeTrace
t
=
Encode
.
object
[
(
"
type"
,
Encode
.
string
t
.
type_
)
,
(
"
name"
,
Encode
.
string
t
.
name
)
,
(
"
x"
,
Encode
.
list
Encode
.
string
t
.
x
)
,
(
"
y"
,
Encode
.
list
Encode
.
float
t
.
y
)
,
(
"
mode"
,
Encode
.
string
t
.
mode
)
]
type
alias
TraceArgs
=
String
->
List
String
->
List
Float
->
String
->
Trace
...
...
@@ -80,21 +92,22 @@ scatterPlot =
type
alias
PlotArgs
=
{
data
:
List
Trace
{
div
:
String
,
data
:
List
Trace
}
port
renderPlot
:
PlotArgs
->
Cmd
msg
type
alias
RenderArgs
=
{
plotlyResponse
:
String
,
selectedSeries
:
List
String
,
permalinkQuery
:
String
}
encodePlotArgs
:
PlotArgs
->
Encode
.
Value
encodePlotArgs
x
=
Encode
.
object
[
(
"
div"
,
Encode
.
string
x
.
div
)
,
(
"
data"
,
Encode
.
list
encodeTrace
x
.
data
)
]
port
renderPlotly
:
RenderArgs
->
Cmd
msg
plotFigure
:
List
(
Attribute
msg
)
->
List
(
Html
msg
)
->
Html
msg
plotFigure
=
node
"
plot-figure"
fetchSeries
:
List
String
->
Model
->
Task
String
(
SeriesCache
,
List
NamedSerie
)
...
...
@@ -194,11 +207,6 @@ update msg model =
else
KeywordSelector
.
select
xm
xs
|>
List
.
take
20
plotUrl
=
UB
.
crossOrigin
model
.
urlPrefix
[
"
tsplot"
]
(
List
.
map
(
\
x
->
UB
.
string
"
series"
x
)
model
.
selectedSeries
)
in
case
msg
of
CatalogReceived
(
Ok
x
)
->
...
...
@@ -234,19 +242,7 @@ update msg model =
newModel
{
model
|
searchedSeries
=
keywordMatch
model
.
searchString
model
.
series
}
RenderPlot
(
Ok
(
cache
,
namedSeries
))
->
let
vals
=
List
.
map
(
\
(
name
,
serie
)
->
scatterPlot
name
(
Dict
.
keys
serie
)
(
Dict
.
values
serie
)
"
lines"
)
namedSeries
in
(
{
model
|
cache
=
cache
}
,
renderPlot
<|
PlotArgs
vals
)
(
{
model
|
cache
=
cache
,
selectedNamedSeries
=
namedSeries
}
,
Cmd
.
none
)
RenderPlot
(
Err
x
)
->
let
...
...
@@ -255,32 +251,6 @@ update msg model =
in
newModel
model
OnApply
->
(
model
,
Http
.
get
{
url
=
plotUrl
,
expect
=
Http
.
expectString
GotPlot
}
)
GotPlot
(
Ok
x
)
->
let
validUrl
=
Common
.
maybe
(
"
http://dummy"
++
plotUrl
)
(
always
plotUrl
)
(
Url
.
fromString
plotUrl
)
q
=
validUrl
|>
Url
.
fromString
|>
Maybe
.
map
(
.
query
>>
Maybe
.
withDefault
"
"
)
|>
Maybe
.
withDefault
"
"
in
(
model
,
renderPlotly
<|
RenderArgs
x
model
.
selectedSeries
q
)
GotPlot
(
Err
x
)
->
let
_
=
Debug
.
log
"
Error on GotPlot"
x
in
newModel
model
selectorConfig
:
KeywordMultiSelector
.
Config
Msg
selectorConfig
=
...
...
@@ -292,12 +262,7 @@ selectorConfig =
,
toggleMsg
=
ToggleItem
}
,
actionSelector
=
{
action
=
Just
{
attrs
=
[
classes
[
T
.
white
,
T
.
bg_dark_blue
]
]
,
html
=
text
"
Apply"
,
clickMsg
=
OnApply
}
{
action
=
Nothing
,
defaultText
=
text
"
"
,
toggleMsg
=
ToggleItem
}
...
...
@@ -309,27 +274,54 @@ selectorConfig =
view
:
Model
->
Html
Msg
view
model
=
let
cls
=
classes
[
T
.
pb2
,
T
.
f4
,
T
.
fw6
,
T
.
db
,
T
.
navy
,
T
.
link
,
T
.
dim
]
plotDiv
=
"
plotly_div"
args
=
let
data
=
List
.
map
(
\
(
name
,
serie
)
->
scatterPlot
name
(
Dict
.
keys
serie
)
(
Dict
.
values
serie
)
"
lines"
)
model
.
selectedNamedSeries
in
PlotArgs
plotDiv
data
|>
encodePlotArgs
|>
Encode
.
encode
0
children
=
[
a
[
cls
,
onClick
ToggleSelection
]
[
text
"
Series selection"
]
]
selector
=
let
cls
=
classes
[
T
.
pb2
,
T
.
f4
,
T
.
fw6
,
T
.
db
,
T
.
navy
,
T
.
link
,
T
.
dim
]
ctx
=
KeywordMultiSelector
.
Context
model
.
searchString
model
.
searchedSeries
model
.
selectedSeries
in
div
[
classes
[
T
.
center
,
T
.
pt4
,
T
.
w_90
]
]
(
if
model
.
activeSelection
then
List
.
append
children
[
KeywordMultiSelector
.
view
selectorConfig
ctx
]
children
=
[
a
[
cls
,
onClick
ToggleSelection
]
[
text
"
Series selection"
]
]
else
children
)
ctx
=
KeywordMultiSelector
.
Context
model
.
searchString
model
.
searchedSeries
model
.
selectedSeries
in
form
[
classes
[
T
.
center
,
T
.
pt4
,
T
.
w_90
]
]
(
if
model
.
activeSelection
then
List
.
append
children
[
KeywordMultiSelector
.
view
selectorConfig
ctx
]
else
children
)
in
div
[
classes
[
T
.
bg_light_blue
]
]
[
header
[]
[
selector
]
,
div
[
A
.
id
plotDiv
]
[]
,
plotFigure
[
A
.
attribute
"
args"
args
]
[]
,
footer
[]
[]
]
main
:
Program
String
Model
Msg
...
...
@@ -352,7 +344,7 @@ main =
c
=
LruCache
.
empty
100
in
(
Model
p
[]
"
"
[]
[]
True
c
,
initialGet
p
)
(
Model
p
[]
"
"
[]
[]
[]
True
c
,
initialGet
p
)
sub
model
=
if
model
.
activeSelection
then
...
...
tsview/tsview_templates/tsbase.html
View file @
eb5ebcbf
...
...
@@ -28,6 +28,27 @@
<link
rel=
"stylesheet"
href=
"./tsview_static/style.css"
>
<script
src=
"./tsview_static/util.js"
></script>
<script
src=
"https://unpkg.com/@webcomponents/custom-elements@1.2.1/custom-elements.min.js"
>
</script>
<script>
class
PlotFigure
extends
HTMLElement
{
static
get
observedAttributes
()
{
return
[
'
args
'
];
}
attributeChangedCallback
(
name
,
old_value
,
new_value
)
{
if
(
name
==
'
args
'
)
{
let
args
=
JSON
.
parse
(
new_value
);
Plotly
.
newPlot
(
args
.
div
,
args
.
data
,
{
showlegend
:
true
},
{
displaylogo
:
false
,
modeBarButtonsToRemove
:
[
"
sendDataToCloud
"
]}
);
}
}
}
window
.
customElements
.
define
(
"
plot-figure
"
,
PlotFigure
);
</script>
</head>
{% block body %}
...
...
tsview/tsview_templates/tsview.html
View file @
eb5ebcbf
...
...
@@ -2,45 +2,14 @@
{% block body %}
<form
id=
"tsviewform"
class=
"form-inline"
>
<div
id=
"series_selector"
></div>
<script
src=
"./tsview_static/plot_elm.js"
></script>
<script>
<div
id=
"app"
></div>
<script
src=
"./tsview_static/plot_elm.js"
></script>
<script>
const
baseurl
=
"
{{ homeurl }}
"
var
app
=
Elm
.
Plot
.
init
({
node
:
document
.
getElementById
(
"
series_selector
"
),
node
:
document
.
getElementById
(
"
app
"
),
flags
:
baseurl
});
app
.
ports
.
renderPlot
.
subscribe
(
function
(
args
)
{
Plotly
.
newPlot
(
"
plot
"
,
args
.
data
.
map
(
function
(
o
)
{
o
.
type
=
o
.
type_
;
return
o
;
}),
{
showlegend
:
true
},
{
displaylogo
:
false
,
modeBarButtonsToRemove
:
[
"
sendDataToCloud
"
]}
)
});
app
.
ports
.
renderPlotly
.
subscribe
(
function
(
args
)
{
let
$target
=
$
(
'
#output
'
)
$target
.
html
(
args
.
plotlyResponse
)
$target
.
append
(
`<a href="tsview?
${
args
.
permalinkQuery
}
">Permalink</a>`
)
args
.
selectedSeries
.
forEach
(
function
(
name
){
$target
.
append
(
`<br/> <a href="tshistory/
${
name
}
" target=_blank>View
${
name
}
history</a>`
)
});
});
</script>
</form>
<div
id=
"plot"
class=
"plotly-graph-div"
></div>
<div
id=
"output"
style=
"margin-top: 1em; padding-bottom:2em;"
>
No data yet.
</div>
<script>
init_form
(
'
tsviewform
'
,
'
tsplot
'
);
</script>
{% endblock %}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment