Add mobx. Add scratchpad

This commit is contained in:
Alfred Melch 2019-04-30 14:06:37 +02:00
parent b82dc913a6
commit a23905c826
15 changed files with 2043 additions and 276 deletions

View File

@ -2,6 +2,10 @@
# pylint: disable=invalid-name
import os
import io
import base64
from urllib.parse import urlparse
from PIL import Image
from flask import Blueprint, render_template, session, redirect, url_for, \
request, flash, current_app, abort, send_from_directory
@ -59,12 +63,22 @@ def create_tile(z, x, y):
if not valid_tile(z, x, y):
return abort(404)
if 'file' not in request.files:
image_bytes = None
# try to read file from request.files (byte-stream)
if 'file' in request.files:
image_bytes = request.files['file'].stream
# try to read file from form (base64 encoded dataURL)
if image_bytes is None and ('file' in request.form):
parsed_url = urlparse(request.form['file'])
head, data = parsed_url.path.split(',', 1)
image_bytes = io.BytesIO(base64.b64decode(data))
if image_bytes is None:
flash('No file part')
return redirect(url_for('index'))
file = request.files['file']
try:
image = Image.open(file.stream)
image = Image.open(image_bytes)
image = image.resize((256, 256))
except OSError:
flash('cannot read image')

File diff suppressed because one or more lines are too long

View File

@ -27,3 +27,15 @@ main {
.flex > *[main] {
flex: 1;
}
.tile-image {
border: 2px solid black;
box-shadow: 5px 5px 10px 0px rgba(0,0,0,0.5);
width: 256px;
height: 256px;
}
.current-tile-upload {
display: flex;
justify-content: space-around;
}

View File

@ -2,18 +2,23 @@
{% block body %}
<h1>Wundertile - A collaborative TileLayer</h1>
<section class="intro">
<h1>Wundertile - A collaborative TileLayer</h1>
<p>Hello Friend, this Website Lorem ipsum dolor sit amet consectetur adipisicing elit. Corrupti adipisci est quo libero odit modi iste corporis debitis tenetur sunt similique alias consequuntur, cupiditate suscipit impedit maiores, recusandae fugiat. Obcaecati?</p>
</section>
<p>Hello Friend, this Website Lorem ipsum dolor sit amet consectetur adipisicing elit. Corrupti adipisci est quo libero odit modi iste corporis debitis tenetur sunt similique alias consequuntur, cupiditate suscipit impedit maiores, recusandae fugiat. Obcaecati?</p>
<section class="map">
<div id="map"></div>
</section>
<section id="currentTile">
</section>
<section class="about">
<h2>About</h2>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Iusto sed vero, doloribus, dolor laborum cumque ab quo odio dolorem voluptas asperiores debitis reiciendis? Sint aut, iusto sapiente eaque ipsa dolorum.</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Error veniam consectetur accusamus distinctio fugit, omnis voluptas. Iure voluptatum omnis unde quas voluptates suscipit neque libero a recusandae quisquam, dolorum voluptate?</p>
</section>
<div id="map"></div>
<h2>Current tile</h2>
<div id="currentTile"></div>
<h2>About</h2>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Iusto sed vero, doloribus, dolor laborum cumque ab quo odio dolorem voluptas asperiores debitis reiciendis? Sint aut, iusto sapiente eaque ipsa dolorum.</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Error veniam consectetur accusamus distinctio fugit, omnis voluptas. Iure voluptatum omnis unde quas voluptates suscipit neque libero a recusandae quisquam, dolorum voluptate?</p>
<script src="{{ url_for('static', filename='bundle.js') }}"></script>
{% endblock %}

15
web/.babelrc Normal file
View File

@ -0,0 +1,15 @@
{
"presets": [
["@babel/preset-env", {
"modules": false,
"targets": {
"browsers": ["last 2 versions", "IE >= 9"]
},
}]
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
["@babel/plugin-transform-react-jsx", {"pragma": "h"}]
]
}

View File

@ -1,4 +1,5 @@
{
"extends": "standard"
"extends": ["standard", "standard-preact"],
"parser": "babel-eslint"
}

View File

@ -1,4 +1,3 @@
import './src/map.js'
import './src/currentTile.js'
console.log('Hello World')
console.log('lala')

1819
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,19 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.4.4",
"@babel/core": "^7.4.4",
"@babel/plugin-proposal-class-properties": "^7.4.4",
"@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@babel/preset-env": "^7.4.4",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
"babel-plugin-jsx-pragmatic": "^1.0.2",
"css-loader": "^2.1.1",
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-config-standard-preact": "^1.1.6",
"eslint-plugin-import": "^2.17.2",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.1.1",
@ -28,6 +38,9 @@
"webpack-dev-server": "^3.3.1"
},
"dependencies": {
"leaflet": "^1.4.0"
"leaflet": "^1.4.0",
"mobx": "^5.9.4",
"mobx-preact": "^3.0.0",
"preact": "^8.4.2"
}
}

View File

@ -1,12 +1,69 @@
import { Component, h, render } from 'preact'
import { observer } from 'mobx-preact'
import { coordsToPath } from './util.js'
import state from './state.js'
import { Scratchpad } from './scratchpad.js'
const root = document.getElementById('currentTile')
export const render = (coords) => {
root.innerHTML = `
<div class="flex">
<img src="/tiles${coordsToPath(coords)}">
</div>
Hello World! ${JSON.stringify(coords)}
`
}
@observer
class CurrentTileComponent extends Component {
render () {
let coordsPath = '/tiles/' + coordsToPath(state.coords)
return (
<div>
<h2>Current Tile: {coordsToPath(state.coords)}</h2>
<div className='current-tile-upload'>
<SubmitDrawingForm tilePath={coordsPath} />
<UploadForm tilePath={coordsPath} />
<img src={coordsPath} className='tile-image' />
</div>
</div>
)
}
handleClick (e) {
console.log(this.scratchpad.image)
}
}
class SubmitDrawingForm extends Component {
render (props) {
console.log('submDrawing', props)
return (
(
<div className='uploadForm'>
<Scratchpad ref={s => { this.scratchpad = s }} />
<form
action={props.tilePath}
method='POST'
enctype='multipart/form-data'
onSubmit={(e) => this.handleSubmit(e)}>
<input type='hidden' name='file' ref={f => { this.file = f }} />
<input type='submit' value='Upload Scratch' />
</form>
</div>
)
)
}
handleSubmit (e) {
console.log(this.file, this.scratchpad)
this.file.value = this.scratchpad.image
}
}
class UploadForm extends Component {
render (props) {
console.log(props)
return (
<div className='uploadForm'>
<form action={props.tilePath} method='POST' enctype='multipart/form-data'>
<input type='file' name='file' /><br />
<input type='submit' value='Upload' />
</form>
</div>
)
}
}
export const CurrentTile = render(<CurrentTileComponent />, root)

View File

@ -1,7 +1,7 @@
import { map as LMap, tileLayer } from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { render } from './currentTile'
import state from './state.js'
export const map = LMap('map')
map.setView([0, 0], 1)
@ -28,6 +28,5 @@ const getTileCoords = (lat, lon, zoom) => {
// demo: how to get tile coords on click
map.on('click', (e) => {
let coords = getTileCoords(e.latlng.lat, e.latlng.lng, map.getZoom())
render(coords)
state.coords = getTileCoords(e.latlng.lat, e.latlng.lng, map.getZoom())
})

47
web/src/scratchpad.js Normal file
View File

@ -0,0 +1,47 @@
import { Component, h } from 'preact'
export class Scratchpad extends Component {
draw = false
render () {
return (
<div>
<canvas
width='256' height='256'
className='tile-image'
onMouseDown={(e) => this.handleMouseDown(e)}
onMouseMove={(e) => this.handleMouseMove(e)}
onMouseUp={(e) => this.handleMouseUp(e)}
onMouseOut={(e) => this.handleMouseOut(e)}
ref={c => { this.canvas = c }}
/>
</div>
)
}
get ctx () {
return this.canvas.getContext('2d')
}
get image () {
return this.canvas.toDataURL()
}
handleMouseDown (e) {
this.draw = true
this.ctx.beginPath()
this.ctx.moveTo(e.layerX, e.layerY)
}
handleMouseMove (e) {
if (this.draw === true) {
this.ctx.lineTo(e.layerX, e.layerY)
this.ctx.stroke()
}
}
handleMouseUp (e) {
this.draw = false
}
handleMouseOut (e) {
}
}

11
web/src/state.js Normal file
View File

@ -0,0 +1,11 @@
import { observable } from 'mobx'
class State {
@observable coords = { x: 0, y: 0, z: 0 }
setState (newState) {
this.state = { ...this.state, ...newState }
}
}
export default new State()

View File

@ -1 +1 @@
export const coordsToPath = coords => `/${coords.z}/${coords.x}/${coords.y}`
export const coordsToPath = coords => `${coords.z}/${coords.x}/${coords.y}`

View File

@ -8,6 +8,9 @@ module.exports = {
},
module: {
rules: [{
test: /\.js$/,
use: ['babel-loader']
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader']
}, {