Skip to content

Commit

Permalink
Change PlotlyJS to PlotlyBase
Browse files Browse the repository at this point in the history
Update README, remove DateFrames dependency, work on Plotly stuff.

Fix server for query parameters

Small changes to README.

Return nothing from block
  • Loading branch information
EricForgy committed Mar 31, 2018
1 parent ae6527c commit 6b18731
Show file tree
Hide file tree
Showing 16 changed files with 261 additions and 130 deletions.
64 changes: 58 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,38 @@

[![][travis-img]][travis-url] [![][appveyor-img]][appveyor-url]

This a package designed to help get started with web APIs some basic interaction between Julia and a browser.
This is a package designed to help get started with web APIs and some basic interaction between Julia and a browser.

## Installation

To get the latest tagged version, try:

~~~julia
julia> Pkg.add("Pages")
~~~

However, this package is still in early development and is likely to change often. To get the latest, try:

~~~julia
julia> Pkg.checkout("Pages")
~~~

Beware this version is likely going to depend on untagged versions of other packages.

## Introduction

To get started, try the following:

~~~julia
julia> using Pages

julia> @async Pages.start();
Listening on 0.0.0.0:8000...
~~~

When launched, Pages starts a server that is listening at http://localhost:8000 and exposes a few methods.
This starts a server that is listening at http://localhost:8000 and exposes the `EndPoint` type with a few methods.

The first:
To create an `EndPoint`, try:

~~~julia
julia> Endpoint("/hello") do request::Request
Expand All @@ -30,7 +42,9 @@ julia> Endpoint("/hello") do request::Request
Endpoint created at /hello.
~~~

creates a web page at http://localhost:8000/hello that says `Hello world`. A dictionary of endpoints is contained in
This creates a web page at http://localhost:8000/hello that says `Hello world`.

You can see all current endpoints in

~~~julia
julia> Pages.pages
Expand All @@ -41,7 +55,7 @@ Dict{String,Pages.Endpoint} with 2 entries:

Note there are two endpoints already. The one we just added plus `/pages.js`. This endpoint is special and is part of Pages. It contains the JavaScript library that allows interaction between Julia and the browser. We'll discuss this in more detail below.

One nice thing about using Pages is that we can create pages whenever and wherever we want in our Julia code. The remaining dictionaries and methods are probably best explained by way of an example.
One nice thing about using `Pages` is that we can create pages whenever and wherever we want in our Julia code.

## Examples

Expand All @@ -53,7 +67,45 @@ julia> Pages.examples()

This will start a server and launch a browser open to a page with links to some examples.

To be continued...
Current examples include:

- `Plotly` - Dynamically insert plotly.js plots into a browser
- `Requests` - Send GET and POST requests from the browser to Julia and print the contents to the REPL.
- `Blank Page` - You can use this for experimemntation, e.g. use `Pages.add_library` to insert your favorite JavaScript library.

You can reconstruct the `Plotly` example from the `Blank Page` via:

```julia
> Pages.add_library("https://cdn.plot.ly/plotly-1.16.1.min.js")
> Pages.add_library("https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.1/d3.min.js")
> Pages.example_plotly()
```

## Callbacks

`Pages` comes with a small JavaScript library `pages.js` that allows communication between Julia and the browser as well as communication between browsers, e.g. chat, using WebSockets.

For example, consider the function

```julia
function add_library(url)
name = basename(url)
block(name) do
Pages.broadcast("script","""
var script = document.createElement("script");
script.charset = "utf-8";
script.type = "text/javascript";
script.src = "$(url)";
script.onload = function() {
Pages.notify("$(name)");
};
document.head.appendChild(script);
""")
end
end
```

This adds a library to the head of any connected web pages. However, Julia execution is blocked until the JavaScript library is successfully loaded and sends a notification back to Julia via a callback.

## Acknowledgements

Expand Down
3 changes: 1 addition & 2 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
julia 0.6
HTTP
JSON
DataFrames
PlotlyJS
PlotlyBase
2 changes: 1 addition & 1 deletion examples/examples.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ul>
<li><a href="/examples/plot.ly">Plotly</a></li>
<li><a href="/examples/requests">Requests</a></li>
<li><a href="/examples/mwe">Websockets MWE</a></li>
<li><a href="/examples/pages">Blank page</a></li>
</ul>

</body>
Expand Down
4 changes: 4 additions & 0 deletions examples/examples.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ Endpoint("/examples") do request::HTTP.Request
readstring(joinpath(dirname(@__FILE__),"examples.html"))
end

Endpoint("/examples/pages") do request::HTTP.Request
readstring(joinpath(dirname(@__FILE__),"pages.html"))
end

include("plotly.jl")
include("requests.jl")
# include("mwe.jl")
Expand Down
8 changes: 5 additions & 3 deletions examples/pages.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta charset="UTF-8">
<script src="/pages.js"></script>
<script src="/libs/d3/4.2.1/d3.min.js"></script>
<script src="/libs/plotly/1.16.1/plotly.min.js"></script>
</head>
<body>
</body>
</html>

<script>
Pages.start(window.location.href)
</script>
4 changes: 4 additions & 0 deletions examples/plotly.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
Try running Pages.example_plotly() repeatedly from the REPL.
</body>
</html>

<script>
Pages.start(window.location.href)
</script>
10 changes: 5 additions & 5 deletions examples/plotly.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using PlotlyJS
using PlotlyBase

Endpoint("/libs/plotly/1.16.1/plotly.min.js") do request::HTTP.Request
readstring(joinpath(dirname(@__FILE__),"libs","plotly","v1.16.1","plotly.min.js"))
Expand All @@ -22,7 +22,7 @@ layout = Layout(;title = "Create a new <div> and plot a single trace",
)
id = "Plot1"
Pages.add(Pages.Element(id=id))
Pages.broadcast("/examples/plot.ly","script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")
Pages.broadcast("script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")

trace1 = scatter(;x = 1:n, y = rand(n))
trace2 = scatter(;x = 1:n, y = rand(n))
Expand All @@ -33,7 +33,7 @@ layout = Layout(;title = "Create a new <div> and plot an array of traces",
)
id = "Plot2"
Pages.add(Pages.Element(id=id))
Pages.broadcast("/examples/plot.ly","script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")
Pages.broadcast("script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")

trace1 = scatter(;
x = [1, 2, 3, 4],
Expand All @@ -59,7 +59,7 @@ layout = Layout(;

id = "Plot3"
Pages.add(Pages.Element(id=id))
Pages.broadcast("/examples/plot.ly","script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")
Pages.broadcast("script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")

country = ["Switzerland (2011)", "Chile (2013)", "Japan (2014)",
"United States (2012)", "Slovenia (2014)", "Canada (2011)",
Expand Down Expand Up @@ -104,7 +104,7 @@ layout = Layout(Dict{Symbol,Any}(:paper_bgcolor => "rgb(254, 247, 234)",

id = "Plot4"
Pages.add(Pages.Element(id=id))
Pages.broadcast("/examples/plot.ly","script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")
Pages.broadcast("script","""Plotly.newPlot("$(id)",$(data),$(layout),{displayModeBar: false});""")

end

Expand Down
37 changes: 32 additions & 5 deletions examples/requests.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,55 @@
<meta charset="UTF-8">
</head>
<body>
Send a POST request and receive an echo of the body. The body is printed to the Julia REPL.<br><br>
<input type="text" placeholder="POST data" id="postData" value="Hello!"><br>
<button type="button" onclick="post()">POST</button>
<button type="button" onclick="post()">POST</button><br><br>
<div id="postResponse"></div><br><br>
Send a GET request and receive an echo of the request parameter. The parameters are printed to the Julia REPL.<br><br>
<input type="text" placeholder="GET parameters" id="getData" value="?id=1"><br>
<button type="button" onclick="get()">GET</button><br><br>
<div id="getResponse"></div><br><br>
</body>
</html>

<script>
var echoPath = window.location.href+"/echo"

function post() {
var postData = document.getElementById("postData").value
console.log(postData)
fetch(window.location.href, {
method: 'post',
fetch(echoPath, {
method: "post",
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: postData
})
.then(res => res.json())
.then(function (data) {
console.log('Request succeeded with JSON response', data);
document.getElementById("postResponse").innerHTML = "POST request succeeded with JSON response: "+JSON.stringify(data);
})
.catch(function (error) {
document.getElementById("postResponse").innerHTML = "POST request failed: "+JSON.stringify(error);
});
}

function get() {
var getData = document.getElementById("getData").value
console.log(postData)
fetch(echoPath+getData, {
method: "get",
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
})
.then(res => res.json())
.then(function (data) {
document.getElementById("getResponse").innerHTML = "GET request succeeded with JSON response: "+JSON.stringify(data);
})
.catch(function (error) {
console.log('Request failed', error);
document.getElementById("getResponse").innerHTML = "GET request failed: "+JSON.stringify(error);
});
}

</script>
11 changes: 8 additions & 3 deletions examples/requests.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
using JSON

Endpoint("/examples/requests") do request::HTTP.Request
readstring(joinpath(dirname(@__FILE__),"requests.html"))
end

Endpoint("/examples/requests/echo") do request::HTTP.Request
if request.method == "GET"
response = readstring(joinpath(dirname(@__FILE__),"requests.html"))
params = HTTP.queryparams(HTTP.URI(request.target).query)
println("Body: $(params)")
response = JSON.json(params)
elseif request.method == "POST"
data = String(request.body)
println(data)
println("Parameters: $(data)")
response = JSON.json(Dict(:data => data))
end
response
end


# Endpoint("/api/math/rand") do request::HTTP.Request
# uri = URI(request.resource)
# if request.method == "GET"
Expand Down
7 changes: 5 additions & 2 deletions src/Pages.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
__precompile__()

module Pages

using HTTP, JSON, DataFrames
using HTTP, JSON

import HTTP.WebSockets.WebSocket

export Endpoint, Callback
export Endpoint, Callback, Plotly

mutable struct Endpoint
handler::Function
Expand All @@ -27,6 +29,7 @@ const pages = Dict{String,Endpoint}() # url => page
include("callbacks.jl")
include("server.jl")
include("api.jl")
include("displays/plotly.jl")
# include("ijulia.jl")

include("../examples/examples.jl")
Expand Down
Loading

0 comments on commit 6b18731

Please sign in to comment.