trollio_maps 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +73 -0
- data/README.md +5 -0
- data/assets/Inter-Regular.ttf +0 -0
- data/bin/trollio-maps +32 -0
- data/mapreversegeocode.gif +0 -0
- data/src/config.rb +13 -0
- data/src/map/control.rb +79 -0
- data/src/map/error.rb +3 -0
- data/src/map/geo/crs/EPSG3857.rb +18 -0
- data/src/map/geo/crs/earth.rb +25 -0
- data/src/map/geo/crs.rb +51 -0
- data/src/map/geo/lat_lng.rb +57 -0
- data/src/map/geo/lat_lng_bounds.rb +59 -0
- data/src/map/geo/projections/lon_lat.rb +0 -0
- data/src/map/geo/projections/mercator.rb +0 -0
- data/src/map/geo/projections/spherical_mercator.rb +32 -0
- data/src/map/geo.rb +4 -0
- data/src/map/geometry/bounds.rb +101 -0
- data/src/map/geometry/bounds_collection.rb +61 -0
- data/src/map/geometry/point.rb +105 -0
- data/src/map/geometry/tile_bounds.rb +110 -0
- data/src/map/geometry/transform.rb +26 -0
- data/src/map/geometry.rb +5 -0
- data/src/map/layers/marker_layer.rb +30 -0
- data/src/map/layers/tile_layer.rb +176 -0
- data/src/map/layers.rb +2 -0
- data/src/map.rb +239 -0
- metadata +95 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
module Mapa
|
2
|
+
class Point
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
def self.convert(str)
|
6
|
+
case str
|
7
|
+
when String
|
8
|
+
coords = str.gsub(/\[|\]/, '').split(",").map(&:to_f)
|
9
|
+
new(coords[0], coords[1])
|
10
|
+
when Array
|
11
|
+
new(str[0], str[1])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?(x, y)
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :x, :y
|
20
|
+
|
21
|
+
def initialize(x, y, round = false)
|
22
|
+
raise Error.new("Invalid point") unless valid?(x, y)
|
23
|
+
|
24
|
+
@x = round ? x.round : x
|
25
|
+
@y = round ? y.round : y
|
26
|
+
end
|
27
|
+
|
28
|
+
def add!(point)
|
29
|
+
self.x += point.x
|
30
|
+
self.y += point.y
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def <=>(point)
|
36
|
+
if x < point.x && y < point.y
|
37
|
+
-1
|
38
|
+
elsif x > point.x && y > point.y
|
39
|
+
1
|
40
|
+
else
|
41
|
+
0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def +(point)
|
46
|
+
Point.new(x + point.x, y + point.y)
|
47
|
+
end
|
48
|
+
|
49
|
+
def -(point)
|
50
|
+
Point.new(x - point.x, y - point.y)
|
51
|
+
end
|
52
|
+
|
53
|
+
def subtract(num)
|
54
|
+
Point.new(x - num, y - num)
|
55
|
+
end
|
56
|
+
|
57
|
+
def /(num)
|
58
|
+
Point.new(x / num.x, y / num.y)
|
59
|
+
end
|
60
|
+
|
61
|
+
def *(num)
|
62
|
+
Point.new(x * num.x, y * num.y)
|
63
|
+
end
|
64
|
+
|
65
|
+
def scale(point)
|
66
|
+
Point.new(x * point.x, y * point.y)
|
67
|
+
end
|
68
|
+
|
69
|
+
def unscale(point)
|
70
|
+
Point.new(x / point.x, y / point.y)
|
71
|
+
end
|
72
|
+
|
73
|
+
def round
|
74
|
+
Point.new(x.round, y.round)
|
75
|
+
end
|
76
|
+
|
77
|
+
def floor
|
78
|
+
Point.new(x.floor, y.floor)
|
79
|
+
end
|
80
|
+
|
81
|
+
def ceil
|
82
|
+
Point.new(x.ceil, y.ceil)
|
83
|
+
end
|
84
|
+
|
85
|
+
def distance_to(point)
|
86
|
+
xx = point.x - x
|
87
|
+
yy = point.y - y
|
88
|
+
|
89
|
+
Math.sqrt(xx ** xx + yy ** yy)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ==(point)
|
93
|
+
point.x == x && point.y == y
|
94
|
+
end
|
95
|
+
|
96
|
+
def contains(point)
|
97
|
+
Math.abs(point.x) <= Math.abs(x) &&
|
98
|
+
Math.abs(point.y) <= Math.abs(y)
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_s
|
102
|
+
"Point(#{x}, #{y})"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Mapa
|
2
|
+
class TileBounds
|
3
|
+
TILE_SIZE = 256
|
4
|
+
|
5
|
+
attr_reader :center, :screen_bounds, :crs
|
6
|
+
attr_accessor :drag_offset, :screen_bounds, :center
|
7
|
+
|
8
|
+
def initialize(crs, latlng, screen_bounds)
|
9
|
+
@crs = crs
|
10
|
+
@center = latlng
|
11
|
+
@screen_bounds = screen_bounds
|
12
|
+
@tiles = {}
|
13
|
+
@drag_offset = Point.new(0, 0)
|
14
|
+
end
|
15
|
+
|
16
|
+
def geo_bounds(bounds, zoom)
|
17
|
+
bounds.to_lat_lng_bounds(crs, zoom)
|
18
|
+
end
|
19
|
+
|
20
|
+
def offset(zoom)
|
21
|
+
collection(zoom).offset
|
22
|
+
end
|
23
|
+
|
24
|
+
def coords_at(point, zoom)
|
25
|
+
collection = collection(zoom)
|
26
|
+
tile = collection.contains(point)
|
27
|
+
offset = collection.offset
|
28
|
+
|
29
|
+
point.x = point.x - tile.screen.center.x + offset.x
|
30
|
+
point.y = point.y - tile.screen.center.y + offset.y
|
31
|
+
|
32
|
+
# click point x / screen width = ratio
|
33
|
+
nx = (point.x) / (tile.screen.max.x - tile.screen.min.x)
|
34
|
+
# click poidnt y / screen_height = ratio
|
35
|
+
ny = (point.y) / (tile.screen.max.y - tile.screen.min.y)
|
36
|
+
|
37
|
+
mbx = (tile.map.max.x - tile.map.min.x) * nx
|
38
|
+
mby = (tile.map.max.y - tile.map.min.y) * ny
|
39
|
+
|
40
|
+
ax = (tile.map.min.x + mbx)
|
41
|
+
ay = (tile.map.min.y + mby)
|
42
|
+
|
43
|
+
x = Point.new(ax, ay)
|
44
|
+
crs.point_to_lat_lng(x, zoom)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def collection(zoom)
|
49
|
+
collection = BoundsProxyCollection.new
|
50
|
+
tile_center = crs.lat_lng_to_point(center, zoom)
|
51
|
+
screen_center = screen_bounds.center + drag_offset
|
52
|
+
|
53
|
+
offx = tile_center.x.modulo(1)
|
54
|
+
offy = tile_center.y.modulo(1)
|
55
|
+
|
56
|
+
collection.offset = Point.new(offx * TILE_SIZE, offy * TILE_SIZE)
|
57
|
+
|
58
|
+
sx = screen_center.x
|
59
|
+
sy = screen_center.y
|
60
|
+
|
61
|
+
tile_center = tile_center.floor
|
62
|
+
mx = tile_center.x
|
63
|
+
my = tile_center.y
|
64
|
+
|
65
|
+
tp = Point.new(TILE_SIZE, TILE_SIZE)
|
66
|
+
mp = Point.new(1, 1)
|
67
|
+
|
68
|
+
# find top left...
|
69
|
+
tl = Point.new(screen_center.x - (TILE_SIZE / 2), screen_center.y - (TILE_SIZE / 2))
|
70
|
+
mtl = Point.new(tile_center.x, tile_center.y)
|
71
|
+
|
72
|
+
while tl.x >= screen_bounds.min.x || tl.y >= screen_bounds.min.y
|
73
|
+
tl = tl - tp
|
74
|
+
mtl = mtl - mp
|
75
|
+
end
|
76
|
+
|
77
|
+
sx = tl.x
|
78
|
+
sy = tl.y
|
79
|
+
mx = mtl.x
|
80
|
+
my = mtl.y
|
81
|
+
|
82
|
+
# populate tiles
|
83
|
+
while sx <= screen_bounds.max.x + TILE_SIZE
|
84
|
+
sy = tl.y
|
85
|
+
my = mtl.y
|
86
|
+
|
87
|
+
while sy <= screen_bounds.max.y + TILE_SIZE
|
88
|
+
sb = Bounds.new(
|
89
|
+
Point.new(sx, sy),
|
90
|
+
Point.new(sx + tp.x, sy + tp.y)
|
91
|
+
)
|
92
|
+
|
93
|
+
mb = Bounds.new(
|
94
|
+
Point.new(mx, my),
|
95
|
+
Point.new(mx + mp.x, my + mp.y)
|
96
|
+
)
|
97
|
+
|
98
|
+
collection << BoundsProxy.new(sb, mb)
|
99
|
+
my += 1
|
100
|
+
sy += TILE_SIZE
|
101
|
+
end
|
102
|
+
|
103
|
+
mx += 1
|
104
|
+
sx += TILE_SIZE
|
105
|
+
end
|
106
|
+
|
107
|
+
collection
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Mapa
|
2
|
+
class Transformation
|
3
|
+
attr_reader :a, :b, :c, :d
|
4
|
+
|
5
|
+
def initialize(a, b, c, d)
|
6
|
+
@a = a
|
7
|
+
@b = b
|
8
|
+
@c = c
|
9
|
+
@d = d
|
10
|
+
end
|
11
|
+
|
12
|
+
def transform(point, scale = 1)
|
13
|
+
Point.new(
|
14
|
+
scale * (a * point.x + b),
|
15
|
+
scale * (c * point.y + d)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def untransform(point, scale = 1)
|
20
|
+
Point.new(
|
21
|
+
(point.x / scale - b) / a,
|
22
|
+
(point.y / scale - d) / c
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/src/map/geometry.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Mapa
|
2
|
+
class MarkerLayer < Hokusai::Block
|
3
|
+
template <<~EOF
|
4
|
+
[template]
|
5
|
+
virtual
|
6
|
+
EOF
|
7
|
+
|
8
|
+
computed :marker, default: nil
|
9
|
+
|
10
|
+
inject :zoom
|
11
|
+
inject :center
|
12
|
+
inject :container_size
|
13
|
+
inject :tile_bounds
|
14
|
+
|
15
|
+
def on_mounted
|
16
|
+
node.meta.set_prop(:z, "3")
|
17
|
+
node.meta.set_prop(:ztarget, "parent")
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(canvas)
|
21
|
+
return if marker.nil?
|
22
|
+
|
23
|
+
draw do
|
24
|
+
circle(marker.x, marker.y, 5) do |command|
|
25
|
+
command.color = Hokusai::Color.new(44, 68, 224)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "rest-client"
|
3
|
+
module Mapa
|
4
|
+
class TileLayer < Hokusai::Block
|
5
|
+
template <<~EOF
|
6
|
+
[template]
|
7
|
+
empty {
|
8
|
+
@mousedown="start_drag"
|
9
|
+
@mousemove="drag"
|
10
|
+
@mouseup="end_drag"
|
11
|
+
}
|
12
|
+
EOF
|
13
|
+
|
14
|
+
uses(
|
15
|
+
empty: Hokusai::Blocks::Empty
|
16
|
+
)
|
17
|
+
|
18
|
+
computed! :url
|
19
|
+
computed :tile_size, default: 256, convert: proc(&:to_i)
|
20
|
+
computed :min_zoom, default: 0, convert: proc(&:to_i)
|
21
|
+
computed :max_zoom, default: 18, convert: proc(&:to_i)
|
22
|
+
computed :subdomains, default: ['a', 'b', 'c']
|
23
|
+
computed :error_tile_url, default: ''
|
24
|
+
computed :zoom_offset, default: 9, convert: proc(&:to_i)
|
25
|
+
computed :tms, default: false
|
26
|
+
computed :zoom_reverse, default: false
|
27
|
+
computed :detect_retina, default: false
|
28
|
+
computed :cross_origin, default: false
|
29
|
+
computed :referrer_policy, default: false
|
30
|
+
|
31
|
+
inject :zoom
|
32
|
+
inject :center
|
33
|
+
inject :container_size
|
34
|
+
inject :tile_bounds
|
35
|
+
|
36
|
+
attr_reader :tiles, :levels, :size, :update_interval, :dragging
|
37
|
+
|
38
|
+
def initialize(**args)
|
39
|
+
super
|
40
|
+
|
41
|
+
@tiles = {}
|
42
|
+
@dragging = false
|
43
|
+
@drag_start = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_drag(event)
|
47
|
+
pp ["Started drag"]
|
48
|
+
if !@dragging && event.left.down
|
49
|
+
@dragging = true
|
50
|
+
@drag_start = Point.new(event.pos.x, event.pos.y)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def drag(event)
|
55
|
+
if event.left.down && dragging
|
56
|
+
tile_bounds.drag_offset = Point.new(event.pos.x, event.pos.y) - @drag_start
|
57
|
+
# @last = tile_bounds.coords_at(tile_bounds.screen_bounds.center, zoom)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def end_drag(event)
|
62
|
+
if dragging && event.left.up
|
63
|
+
@dragging = false
|
64
|
+
if tile_bounds.drag_offset.x > 5 || tile_bounds.drag_offset.y > 5
|
65
|
+
|
66
|
+
collection = tile_bounds.collection(zoom)
|
67
|
+
off = tile_bounds.drag_offset
|
68
|
+
|
69
|
+
pp [collection.offset]
|
70
|
+
|
71
|
+
c = tile_bounds.screen_bounds.center
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
center = tile_bounds.coords_at(c, zoom)
|
76
|
+
|
77
|
+
pp ["unset drag offset", center]
|
78
|
+
|
79
|
+
|
80
|
+
tile_bounds.drag_offset = Point.new(0, 0)
|
81
|
+
tile_bounds.center = center
|
82
|
+
|
83
|
+
emit("update", center)
|
84
|
+
end
|
85
|
+
|
86
|
+
@drag_start = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def downloads
|
91
|
+
FileUtils.mkdir_p "#{__dir__}/downloads"
|
92
|
+
|
93
|
+
"#{__dir__}/downloads"
|
94
|
+
end
|
95
|
+
|
96
|
+
def fetch_download(url)
|
97
|
+
path = "#{downloads}/#{url.gsub("/", "-")}"
|
98
|
+
|
99
|
+
if File.exist?(path)
|
100
|
+
@tiles[url] = path
|
101
|
+
path
|
102
|
+
else
|
103
|
+
Thread.new do
|
104
|
+
block = proc do |res|
|
105
|
+
File.open(path, "wb") do |io|
|
106
|
+
res.read_body do |chunk|
|
107
|
+
io.write chunk
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
@tiles[url] = path
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
RestClient::Request.execute(method: :get, url: url, block_response: block)
|
116
|
+
end
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def subdomain(coords)
|
122
|
+
index = (coords.x + coords.y % subdomains.size).abs
|
123
|
+
subdomains[index]
|
124
|
+
end
|
125
|
+
|
126
|
+
def zoom_for_url
|
127
|
+
if zoom_reverse
|
128
|
+
max_zoom - zoom
|
129
|
+
else
|
130
|
+
zoom + zoom_offset
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
|
135
|
+
def tile_url(coords)
|
136
|
+
opts = {
|
137
|
+
s: subdomain(coords),
|
138
|
+
z: zoom_for_url,
|
139
|
+
x: coords.x.to_i,
|
140
|
+
y: coords.y.to_i,
|
141
|
+
r: ''
|
142
|
+
}
|
143
|
+
|
144
|
+
url.gsub(/\{ *([\w_ -]+) *\}/) do |match|
|
145
|
+
opts[match[1].to_sym]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def before_updated
|
150
|
+
if @throttled
|
151
|
+
if (Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - @ttime) > 200
|
152
|
+
@throttled = false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def render(canvas)
|
158
|
+
# @canvas = canvas
|
159
|
+
collection = tile_bounds.collection(zoom)
|
160
|
+
offx = collection.offset.x
|
161
|
+
offy = collection.offset.y
|
162
|
+
|
163
|
+
|
164
|
+
draw do
|
165
|
+
collection.each_with_index do |item, i|
|
166
|
+
# next if i.odd?
|
167
|
+
if file = fetch_download(tile_url(item.map.center))
|
168
|
+
image(file, item.screen.center.x - offx, item.screen.center.y - offy, tile_size, tile_size)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
yield canvas
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/src/map/layers.rb
ADDED
data/src/map.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
require "hokusai"
|
2
|
+
require "hokusai/backends/raylib"
|
3
|
+
require_relative "./map/error"
|
4
|
+
require_relative "./map/geo"
|
5
|
+
require_relative "./map/layers"
|
6
|
+
require_relative "./map/geometry"
|
7
|
+
require_relative "./map/control"
|
8
|
+
require_relative "./config"
|
9
|
+
|
10
|
+
module Mapa
|
11
|
+
class Map < Hokusai::Block
|
12
|
+
template <<~EOF
|
13
|
+
[template]
|
14
|
+
vblock
|
15
|
+
slot
|
16
|
+
EOF
|
17
|
+
|
18
|
+
uses(vblock: Hokusai::Blocks::Vblock)
|
19
|
+
|
20
|
+
attr_reader :size
|
21
|
+
attr_accessor :sdrag
|
22
|
+
|
23
|
+
provide :zoom, :zoom
|
24
|
+
provide :center, :center
|
25
|
+
provide :container_size, :size
|
26
|
+
provide :tile_bounds, :tile_bounds
|
27
|
+
|
28
|
+
computed! :center
|
29
|
+
computed :crs, default: "EPSG3857"
|
30
|
+
computed :zoom, default: 1
|
31
|
+
computed :min_zoom, default: nil
|
32
|
+
computed :max_zoom, default: nil
|
33
|
+
computed :update_center, default: nil
|
34
|
+
|
35
|
+
def before_updated
|
36
|
+
if update_center
|
37
|
+
@bounds = TileBounds.new(Mapa::EPSG3857, update_center, size)
|
38
|
+
emit("clear_update_center")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_drag(event)
|
43
|
+
if event.left.down && !@started
|
44
|
+
self.sdrag = [event.pos.x.clone, event.pos.y.clone]
|
45
|
+
@started = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_resize(canvas)
|
50
|
+
@size = Bounds.new([canvas.x, canvas.y], [canvas.x + canvas.width, canvas.y + canvas.height])
|
51
|
+
@bounds = TileBounds.new(Mapa::EPSG3857, center, size)
|
52
|
+
end
|
53
|
+
|
54
|
+
def center_point
|
55
|
+
Mapa::EPSG3857.lat_lng_to_point(center, zoom)
|
56
|
+
end
|
57
|
+
|
58
|
+
def alert_latlng(event)
|
59
|
+
if sdrag && ((event.pos.x - sdrag[0]).abs > 5 || (event.pos.y - sdrag[1]).abs > 5)
|
60
|
+
@started = false
|
61
|
+
self.sdrag = nil
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
if event.left.released
|
66
|
+
point = Point.new(event.pos.x, event.pos.y)
|
67
|
+
clicked = Point.new(event.pos.x, event.pos.y)
|
68
|
+
emit("change", tile_bounds.coords_at(point, zoom), clicked)
|
69
|
+
@started = false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def tile_bounds
|
74
|
+
@bounds ||= TileBounds.new(Mapa::EPSG3857, center, size)
|
75
|
+
end
|
76
|
+
|
77
|
+
def render(canvas)
|
78
|
+
if @size.nil?
|
79
|
+
on_resize(canvas)
|
80
|
+
end
|
81
|
+
|
82
|
+
yield canvas
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class App < Hokusai::Block
|
88
|
+
style <<~EOF
|
89
|
+
[style]
|
90
|
+
tileStyle {
|
91
|
+
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
92
|
+
zoom_offset: 8;
|
93
|
+
}
|
94
|
+
box {
|
95
|
+
background: rgb(48, 48, 48);
|
96
|
+
height: 100.0;
|
97
|
+
padding: padding(20.0, 0.0, 30.0, 0.0);
|
98
|
+
}
|
99
|
+
|
100
|
+
input {
|
101
|
+
background: rgb(255,255,255);
|
102
|
+
color: rgb(22,22,22);
|
103
|
+
padding: padding(5.0, 15.0, 5.0, 15.0);
|
104
|
+
outline: outline(1.0, 1.0, 1.0, 1.0)
|
105
|
+
outline_color: rgb(33,33,33);
|
106
|
+
height: 50.0;
|
107
|
+
rounding: 0.2;
|
108
|
+
}
|
109
|
+
|
110
|
+
label {
|
111
|
+
color: rgb(255,255,255);
|
112
|
+
}
|
113
|
+
|
114
|
+
zstyle {
|
115
|
+
z: 2;
|
116
|
+
ztarget: "parent";
|
117
|
+
reverse: true;
|
118
|
+
}
|
119
|
+
EOF
|
120
|
+
|
121
|
+
template <<~EOF
|
122
|
+
[template]
|
123
|
+
vblock
|
124
|
+
map {
|
125
|
+
@change="update_latlng"
|
126
|
+
@clear_update_center="clear_update_center"
|
127
|
+
:update_center="update_center"
|
128
|
+
cursor="pointer"
|
129
|
+
:center="center"
|
130
|
+
:zoom="zoom"
|
131
|
+
}
|
132
|
+
tile_layer {
|
133
|
+
...tileStyle
|
134
|
+
}
|
135
|
+
marker_layer {:marker="marker"}
|
136
|
+
hblock { ...zstyle }
|
137
|
+
control {
|
138
|
+
@zoomin="zoom_in"
|
139
|
+
@zoomout="zoom_out"
|
140
|
+
:height="80.0" :width="65.0"
|
141
|
+
}
|
142
|
+
empty
|
143
|
+
vblock { padding="10.0,0.0,0.0,10.0"}
|
144
|
+
input { @mousedown="stop" @change="search" ...input }
|
145
|
+
EOF
|
146
|
+
|
147
|
+
uses(
|
148
|
+
hblock: Hokusai::Blocks::Hblock,
|
149
|
+
vblock: Hokusai::Blocks::Vblock,
|
150
|
+
label: Hokusai::Blocks::Label,
|
151
|
+
input: Hokusai::Blocks::Input,
|
152
|
+
empty: Hokusai::Blocks::Empty,
|
153
|
+
control: Mapa::Control,
|
154
|
+
button: Hokusai::Blocks::Button,
|
155
|
+
map: Mapa::Map,
|
156
|
+
tile_layer: Mapa::TileLayer,
|
157
|
+
marker_layer: Mapa::MarkerLayer
|
158
|
+
)
|
159
|
+
|
160
|
+
attr_reader :drag_offset, :update_center
|
161
|
+
|
162
|
+
def stop(event)
|
163
|
+
event.stop
|
164
|
+
end
|
165
|
+
|
166
|
+
def point
|
167
|
+
@point || "no point"
|
168
|
+
end
|
169
|
+
|
170
|
+
def initialize(**args)
|
171
|
+
super
|
172
|
+
|
173
|
+
@dragging = false
|
174
|
+
end
|
175
|
+
|
176
|
+
def marker
|
177
|
+
@marker
|
178
|
+
end
|
179
|
+
|
180
|
+
def search(term)
|
181
|
+
begin
|
182
|
+
res = JSON.parse RestClient.get("https://geoffrey.skinnyjames.net/api/v1/us/geocode/#{CGI.escapeURIComponent(term)}").body, symbolize_names: true
|
183
|
+
res = res.first
|
184
|
+
pp res
|
185
|
+
@update_center = Mapa::LatLng.new(res[:latitude], res[:longitude])
|
186
|
+
@marker = Mapa::Point.new(400, 400)
|
187
|
+
rescue
|
188
|
+
pp ["point can't be located"]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def update_latlng(latlng, point)
|
193
|
+
pp ["changing"]
|
194
|
+
@marker = point.clone
|
195
|
+
add = latlng.reverse_geo
|
196
|
+
@point = <<~EOF
|
197
|
+
#{latlng}
|
198
|
+
#{add[:address_number]} #{add[:street_name]} #{add[:street_posttype]}
|
199
|
+
#{add[:postal_community]}, #{add[:state]} #{add[:zip_code]}
|
200
|
+
EOF
|
201
|
+
end
|
202
|
+
|
203
|
+
def clear_update_center
|
204
|
+
@update_center = nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def zoom_out
|
208
|
+
@marker = nil
|
209
|
+
@zoom -= 1
|
210
|
+
end
|
211
|
+
|
212
|
+
def zoom
|
213
|
+
@zoom ||= 1
|
214
|
+
end
|
215
|
+
|
216
|
+
def center
|
217
|
+
@center ||= Mapa::LatLng.new(39.9612, -82.9988)
|
218
|
+
end
|
219
|
+
|
220
|
+
def zoom_in
|
221
|
+
@marker = nil
|
222
|
+
|
223
|
+
@zoom += 1
|
224
|
+
end
|
225
|
+
end
|
226
|
+
#
|
227
|
+
# 1 = 9
|
228
|
+
# 2 = 10
|
229
|
+
# 3 = 11
|
230
|
+
#
|
231
|
+
#
|
232
|
+
|
233
|
+
# latlng = Mapa::LatLng.new(39.9612, -82.9988)
|
234
|
+
# point = Mapa::EPSG3857.lat_lng_to_point(latlng, 4)
|
235
|
+
# new_lat_lng = Mapa::EPSG3857.point_to_lat_lng(point, 4)
|
236
|
+
|
237
|
+
# map = Mapa::EPSG3857
|
238
|
+
|
239
|
+
# pp map.projection.project(map.projection.unproject(Mapa::Point.new(0, 0)))
|