Add mobx. Add scratchpad
This commit is contained in:
parent
b82dc913a6
commit
a23905c826
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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
15
web/.babelrc
Normal 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"}]
|
||||
]
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"extends": "standard"
|
||||
"extends": ["standard", "standard-preact"],
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
@ -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
1819
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
47
web/src/scratchpad.js
Normal 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
11
web/src/state.js
Normal 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()
|
@ -1 +1 @@
|
||||
export const coordsToPath = coords => `/${coords.z}/${coords.x}/${coords.y}`
|
||||
export const coordsToPath = coords => `${coords.z}/${coords.x}/${coords.y}`
|
||||
|
@ -8,6 +8,9 @@ module.exports = {
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js$/,
|
||||
use: ['babel-loader']
|
||||
}, {
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader']
|
||||
}, {
|
||||
|
Loading…
Reference in New Issue
Block a user