Commit 157e1b4e authored by Klaus Stein's avatar Klaus Stein
Browse files

Add anchor point edits to ImageMap

parent b79689de
...@@ -14,7 +14,8 @@ import 'leaflet/dist/leaflet.css'; ...@@ -14,7 +14,8 @@ import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet.markercluster/dist/MarkerCluster.css' import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css' import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet-toolbar/dist/leaflet.toolbar.css'
import 'leaflet-distortableimage/dist/leaflet.distortableimage.css'
import '../leaflet-plugins/leaflet-providers' import '../leaflet-plugins/leaflet-providers'
...@@ -22,6 +23,7 @@ import '../leaflet-plugins/leaflet-providers' ...@@ -22,6 +23,7 @@ import '../leaflet-plugins/leaflet-providers'
import "../src/overview-map" import "../src/overview-map"
import "../src/example-map" import "../src/example-map"
import "../src/place-map" import "../src/place-map"
import "../src/imagemap-map"
import "../src/datatable" import "../src/datatable"
Rails.start() Rails.start()
......
import L from 'leaflet';
import 'leaflet-defaulticon-compatibility';
import 'leaflet-toolbar'; // needed for distortableimage
import 'leaflet-distortableimage';
function mapWithImagemap(mapdiv) {
const input = document.getElementById('image_map_anchors');
const map = L.map(mapdiv,
{
center: [50.5,10],
zoom: 5,
zoomSnap: 0.25,
zoomDelta: 0.25
});
L.tileLayer.provider('OpenStreetMap.DE').addTo(map);
if(mapdiv.dataset.anchors){
const anchors = JSON.parse(mapdiv.dataset.anchors);
// this is only for debugging
/*
L.geoJSON(anchors, {
pointToLayer: function(f,latlng) {
return L.circleMarker(latlng, { radius: 1, color: '#c00' });
}
}).addTo(map);
*/
if(mapdiv.dataset.image) {
const corners = anchors.coordinates.map(c => L.latLng(c[1],c[0]));
const img = L.distortableImageOverlay(mapdiv.dataset.image, {
corners: corners
});
window.di = img;
img.on('add',(evt) => {
console.log(evt.layer);
const bounds = img.getBounds(corners);
// alert(JSON.stringify(img.getCorners()));
map.fitBounds(corners);
});
img.on('update',(evt) => {
input.value = 'LINESTRING (' +
img.getCorners().map(ll => `${ll.lng} ${ll.lat}`) + ')';
});
img.addTo(map);
}
}
}
document.addEventListener("turbolinks:load", function(event) {
for(let mapdiv of document.querySelectorAll(".imagemap-map[data-image]")) {
mapWithImagemap(mapdiv);
}
});
import L from 'leaflet'; import L from 'leaflet';
import 'leaflet-defaulticon-compatibility'; import 'leaflet-defaulticon-compatibility';
import 'leaflet.markercluster'; import 'leaflet.markercluster';
import "Leaflet.Deflate" import "Leaflet.Deflate";
// //
const bamberg = L.latLng(49.9, 10.9); const bamberg = L.latLng(49.9, 10.9);
......
...@@ -43,7 +43,7 @@ function mapWithPlace(mapdiv) { ...@@ -43,7 +43,7 @@ function mapWithPlace(mapdiv) {
} }
document.addEventListener("turbolinks:load", function(event) { document.addEventListener("turbolinks:load", function(event) {
for(let mapdiv of document.querySelectorAll("[data-geojsonurl]")) { for(let mapdiv of document.querySelectorAll(".place-map[data-geojsonurl]")) {
mapWithPlace(mapdiv); mapWithPlace(mapdiv);
} }
}); });
.image_map.edit {
figure.map {
order: 99;
margin-right: 0px;
width: 80%;
min-width: 200px;
.imagemap-map {
height: 80vh;
border: 1px solid grey;
margin-bottom: 1px;
box-sizing: border-box;
}
}
input {
width: 90%;
}
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
@import "main"; @import "main";
@import "place"; @import "place";
@import "map"; @import "map";
@import "image_map";
@import "examples"; @import "examples";
@import "overview"; @import "overview";
@import "maps"; @import "maps";
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Table name: image_maps # Table name: image_maps
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# anchors :geometry multipoint, 0 # anchors :geometry geometry, 0
# clip :geometry polygon, 0 # clip :geometry polygon, 0
# name :string # name :string
# created_at :datetime not null # created_at :datetime not null
...@@ -37,6 +37,66 @@ class ImageMap < ApplicationRecord ...@@ -37,6 +37,66 @@ class ImageMap < ApplicationRecord
# image_map.image.variant(resize_to_limit: [50, 50]).processed # image_map.image.variant(resize_to_limit: [50, 50]).processed
# https://edgeapi.rubyonrails.org/classes/ActiveStorage/Variant.html # https://edgeapi.rubyonrails.org/classes/ActiveStorage/Variant.html
# we predefine some variants
def image_preview
if image?
self.image.variant(resize_to_limit: [10000, 200],
auto_orient: true,
format: :jpg).processed
end
end
def image_thumbnail
if image?
self.image.variant(resize_to_limit: [50, 50],
auto_orient: true,
format: :jpg).processed
end
end
def image_hd
if image?
self.image.variant(resize_to_limit: [1920, 1200],
auto_orient: true,
format: :jpg).processed
end
end
def image?
image.attached?
end
def position
if anchors
anchors.convex_hull.centroid
else
map.place.centerpoint
end
end
DX = 0.08
DY = 0.05
# if no anchors are given use a bounding box
def anchors_or_buffer
return anchors if anchors
# ok, we take the place centerpoint
cp = map.place.centerpoint
# we fetch its factory
f = cp.factory
d = 0.1
# and create a linestring object
# (as a multipoint object is unsorted)
f.line_string([cp,
f.point(cp.x + DX, cp.y),
f.point(cp.x, cp.y - DY),
f.point(cp.x + DX, cp.y - DY)])
# f.line_string([f.point(1,1), f.point(2,1), f.point(1,0), f.point(2,0)])
end
# converting uses up huge system resources # converting uses up huge system resources
# we have to increase values in /etc/ImageMagick-6/policy.xml # we have to increase values in /etc/ImageMagick-6/policy.xml
# see e.g. https://github.com/ImageMagick/ImageMagick/issues/396#issuecomment-326849298git diff # see e.g. https://github.com/ImageMagick/ImageMagick/issues/396#issuecomment-326849298git diff
......
<%= form_with(model: image_map) do |form| %> <div class="image_map edit">
<%= form_with(model: image_map) do |form| %>
<% if image_map.errors.any? %> <% if image_map.errors.any? %>
<div id="error_explanation"> <div id="error_explanation">
<h2><%= pluralize(image_map.errors.count, "error") %> prohibited this image_map from being saved:</h2> <h2><%= pluralize(image_map.errors.count, "error") %> prohibited this image_map from being saved:</h2>
...@@ -11,6 +12,11 @@ ...@@ -11,6 +12,11 @@
</div> </div>
<% end %> <% end %>
<figure class="map">
<div class="imagemap-map" data-image="<%= url_for(image_map.image_hd) %>" data-anchors="<%= RGeo::GeoJSON.encode(image_map.anchors_or_buffer).to_json %>" data-clip="<%= RGeo::GeoJSON.encode(image_map.clip).to_json %>"></div>
<label>Position: <input type="text" readonly="readonly" value="<%= image_map.position %>"></input></label>
</figure>
<div class="field"> <div class="field">
<%= form.label :name %> <%= form.label :name %>
<%= form.text_field :name %> <%= form.text_field :name %>
...@@ -40,3 +46,4 @@ ...@@ -40,3 +46,4 @@
<%= form.submit %> <%= form.submit %>
</div> </div>
<% end %> <% end %>
</div>
...@@ -6,10 +6,8 @@ json.properties do ...@@ -6,10 +6,8 @@ json.properties do
json.place image_map.map.place.name json.place image_map.map.place.name
json.place_url url_for(image_map.map.place) json.place_url url_for(image_map.map.place)
if image_map.image.variable? if image_map.image.variable?
json.img url_for(image_map.image.variant(resize_to_limit: [50, 50], json.img url_for(image_map.image_thumbnail)
auto_orient: true,
format: :jpg).processed)
end end
json.map_url url_for(image_map.map) json.map_url url_for(image_map.map)
end end
json.geometry RGeo::GeoJSON.encode(image_map.map.place.centerpoint) json.geometry RGeo::GeoJSON.encode(image_map.position)
<p id="notice"><%= notice %></p> <p id="notice"><%= notice %></p>
<p> <table>
<strong>Name:</strong> <tr>
<%= @image_map.name %> <th>Name:</th>
</p> <td><%= @image_map.name %></td>
</tr>
<p>
<strong>Image:</strong> <tr>
<%= image_tag @image_map.image %><br /> <th>Image:</th>
<%= url_for(@image_map.image) %> <td><% img = @image_map.image_preview %>
</p> <%= image_tag img %><br />
<%= url_for(@image_map.image) %></td>
</tr>
<p> <tr>
<strong>Anchors:</strong> <th>Position:</th>
<%= @image_map.anchors %> <td><%= @image_map.position %></td>
</p> </tr>
<tr>
<th>Anchors:</th>
<td><%= @image_map.anchors %></td>
<p> </tr>
<strong>Clip:</strong>
<%= @image_map.clip %>
</p>
<tr>
<p> <th>Clip:</th>
<strong>Map:</strong> <td><%= @image_map.clip %></td>
<%= @image_map.map_id %> </tr>
</p>
<tr>
<th>Map:</th>
<td><%= @image_map.map_id %></td>
</tr>
</table>
<%= link_to 'Edit', edit_image_map_path(@image_map) %> | <%= link_to 'Edit', edit_image_map_path(@image_map) %> |
<%= link_to 'Back', image_maps_path %> <%= link_to 'Back', image_maps_path %>
<table class="nested-form-wrapper imgupload" data-new-record="<%= form.object.new_record? %>"> <table class="nested-form-wrapper imgupload" data-new-record="<%= form.object.new_record? %>">
<tr> <tr>
<td class="img"><%= <td class="img"><%=
im=form.object.image image_map = form.object
if im.attached? if image_map.image?
image_tag im.variant(resize_to_limit: [10000, 200], image_tag image_map.image_preview
auto_orient: true, else
format: :jpg).processed form.file_field :image, direct_upload: true
else end
form.file_field :image, direct_upload: true %></td>
end
%></td>
<td><button type="button" data-action="nested-form#remove"> <td><button type="button" data-action="nested-form#remove">
Remove image Remove image
</button></td> </button></td>
......
...@@ -34,9 +34,7 @@ ...@@ -34,9 +34,7 @@
<div class="previews"> <div class="previews">
<% @map.image_maps.each do |im| %> <% @map.image_maps.each do |im| %>
<figure> <figure>
<%= link_to image_tag(im.image.variant(resize_to_limit: [10000, 200], <%= link_to image_tag(im.image_preview,
auto_orient: true,
format: :jpg).processed,
class: 'preview', alt: im.name), class: 'preview', alt: im.name),
rails_blob_path(im.image), target: '_blank', title: im.name %> rails_blob_path(im.image), target: '_blank', title: im.name %>
<figcaption><%= im.sizeinfo_s %></figcaption> <figcaption><%= im.sizeinfo_s %></figcaption>
......
class ChangeImageMapAnchorsToGeometry < ActiveRecord::Migration[6.1]
def change
change_column :image_maps, :anchors, :geometry
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_08_18_091114) do ActiveRecord::Schema.define(version: 2021_11_16_120511) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "adminpack" enable_extension "adminpack"
...@@ -83,7 +83,7 @@ ActiveRecord::Schema.define(version: 2021_08_18_091114) do ...@@ -83,7 +83,7 @@ ActiveRecord::Schema.define(version: 2021_08_18_091114) do
create_table "image_maps", force: :cascade do |t| create_table "image_maps", force: :cascade do |t|
t.string "name" t.string "name"
t.geometry "anchors", limit: {:srid=>0, :type=>"multi_point"} t.geometry "anchors", limit: {:srid=>0, :type=>"geometry"}
t.geometry "clip", limit: {:srid=>0, :type=>"st_polygon"} t.geometry "clip", limit: {:srid=>0, :type=>"st_polygon"}
t.bigint "map_id", null: false t.bigint "map_id", null: false
t.datetime "created_at", precision: 6, null: false t.datetime "created_at", precision: 6, null: false
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Table name: image_maps # Table name: image_maps
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# anchors :geometry multipoint, 0 # anchors :geometry geometry, 0
# clip :geometry polygon, 0 # clip :geometry polygon, 0
# name :string # name :string
# created_at :datetime not null # created_at :datetime not null
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Table name: image_maps # Table name: image_maps
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# anchors :geometry multipoint, 0 # anchors :geometry geometry, 0
# clip :geometry polygon, 0 # clip :geometry polygon, 0
# name :string # name :string
# created_at :datetime not null # created_at :datetime not null
......
...@@ -3023,6 +3023,11 @@ execa@^1.0.0: ...@@ -3023,6 +3023,11 @@ execa@^1.0.0:
signal-exit "^3.0.0" signal-exit "^3.0.0"
strip-eof "^1.0.0" strip-eof "^1.0.0"
exif-js@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/exif-js/-/exif-js-2.3.0.tgz#9d10819bf571f873813e7640241255ab9ce1a814"
integrity sha1-nRCBm/Vx+HOBPnZAJBJVq5zhqBQ=
expand-brackets@^2.1.4: expand-brackets@^2.1.4:
version "2.1.4" version "2.1.4"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
...@@ -3420,6 +3425,11 @@ getpass@^0.1.1: ...@@ -3420,6 +3425,11 @@ getpass@^0.1.1:
dependencies: dependencies:
assert-plus "^1.0.0" assert-plus "^1.0.0"
glfx@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/glfx/-/glfx-0.0.4.tgz#1b776dc748c081994624b0af3b5638403de78f4d"
integrity sha1-G3dtx0jAgZlGJLCvO1Y4QD3nj00=
glob-parent@^3.1.0: glob-parent@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
...@@ -4370,6 +4380,21 @@ leaflet-defaulticon-compatibility@^0.1.1: ...@@ -4370,6 +4380,21 @@ leaflet-defaulticon-compatibility@^0.1.1:
resolved "https://registry.yarnpkg.com/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.1.tgz#ab72257b3da66fb48dab69a10c3824012a15a20a" resolved "https://registry.yarnpkg.com/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.1.tgz#ab72257b3da66fb48dab69a10c3824012a15a20a"
integrity sha512-vDBFdlUAwjSEGep9ih8kfJilf6yN8V9zTbF5NC/1ZwLeGko3RUQepspPnGCRMFV51dY3Lb3hziboicrFz+rxQA== integrity sha512-vDBFdlUAwjSEGep9ih8kfJilf6yN8V9zTbF5NC/1ZwLeGko3RUQepspPnGCRMFV51dY3Lb3hziboicrFz+rxQA==
leaflet-distortableimage@^0.21.7:
version "0.21.7"
resolved "https://registry.yarnpkg.com/leaflet-distortableimage/-/leaflet-distortableimage-0.21.7.tgz#3b78227d51615bff17b0e5269e7b9563c067ca7e"
integrity sha512-hy6MGbbJTic/iDjTvmn/hAVrZ9wkJ6Vs1yXOxk066YxC4675kswkTfmMKGllO8wYxEadoSCD+Xqgqwq0Xyce7A==
dependencies:
exif-js "^2.3.0"
glfx "0.0.4"
leaflet-toolbar "0.4.0-alpha.2"
webgl-distort "0.0.2"
leaflet-toolbar@0.4.0-alpha.2, leaflet-toolbar@^0.4.0-alpha.2:
version "0.4.0-alpha.2"
resolved "https://registry.yarnpkg.com/leaflet-toolbar/-/leaflet-toolbar-0.4.0-alpha.2.tgz#ab58092d65b3dd158fb874c3f7e36b7ebdb994f8"
integrity sha512-g1KeU3DYGUOwXTS0vKIgJ8KgY0h/2B0qENNQUSYMFtSY2yzwaHWMbDyhDbk+aO8LgJ1iOX4fUt2bh1sYZbpmmQ==
leaflet.markercluster@^1.5.0: leaflet.markercluster@^1.5.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.0.tgz#54db42485da32fc3d92c7ae22d0d7982879e0b67" resolved "https://registry.yarnpkg.com/leaflet.markercluster/-/leaflet.markercluster-1.5.0.tgz#54db42485da32fc3d92c7ae22d0d7982879e0b67"
...@@ -7665,6 +7690,11 @@ wbuf@^1.1.0, wbuf@^1.7.3: ...@@ -7665,6 +7690,11 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies: dependencies:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
webgl-distort@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/webgl-distort/-/webgl-distort-0.0.2.tgz#80d2f61efc4aece28e7a1ff1375e14aac6d06f36"
integrity sha1-gNL2HvxK7OKOeh/xN14UqsbQbzY=
webpack-assets-manifest@^3.1.1: webpack-assets-manifest@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de" resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment