-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransform.html
320 lines (291 loc) · 16.1 KB
/
transform.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
<!DOCTYPE html>
<html>
<head>
<!--
Copyright (c) 2016-2018 Jean-Marc VIGLINO,
released under CeCILL-B (french BSD like) licence: http://www.cecill.info/
-->
<title>ol-ext: Transform interaction</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="transform interaction for OL3" />
<meta name="keywords" content="ol, openlayers, vector, transform, rotate, scale, stretch" />
<!-- <link rel="stylesheet" href="./style.css" /> -->
<!-- jQuery -->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<!-- FontAwesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Openlayers -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@latest/ol.css" />
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ol@latest/dist/ol.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL,Object.assign"></script>
<!-- ol-ext -->
<!-- <link rel="stylesheet" href="./dist/ol-ext.css" /> -->
<script type="text/javascript" src="./dist/ol-ext.js"></script>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
</head>
<body >
<a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>
<a href="../../index.html">
<h1>ol-ext: Transform interaction</h1>
</a>
<div class="info">
<!-- force font to load -->
<i class="fa fa-rotate-left" style="position:absolute; top:-1000px;"></i>
<b>ol.interaction.Transform</b> is an interaction to transform features (scale, translate, rotate).
Handles are drawn on the map to manipulate the features
<ul><li>
Properties can be set to select transforming operations.
</li><li>
Handles can be styled with ol.style.
</li><li>
ol.event are thrown to control the transformation (to set an angle propertie on point features to use with ol.style for example)
</li>
</li></ul>
</div>
<!-- Map div -->
<div id="map" style="width:600px; height:400px;"></div>
<div class="options" >
<h2>Options:</h2>
<ul>
<li>
<input id="style" type="checkbox" onchange="setHandleStyle()" /><label for="style"> styles transform handles (using fontawesome)</label>
</li><li>
<input id="scale" type="checkbox" onchange="setPropertie(this.id);" checked="checked" /><label for="scale"> enable scale</label>
</li><li>
<input id="stretch" type="checkbox" onchange="setPropertie(this.id);" checked="checked" /><label for="stretch"> enable stretch</label>
</li><li>
<input id="rotate" type="checkbox" onchange="setPropertie(this.id);" checked="checked" /><label for="rotate"> enable rotate</label>
</li><li>
<input id="translate" type="checkbox" onchange="setPropertie(this.id);" checked="checked" /><label for="translate"> enable translate</label>
</li><li>
<input id="translateFeature" type="checkbox" onchange="setPropertie(this.id);" /><label for="translateFeature"> translate when click on feature</label>
</li><li>
<input id="keepAspectRatio" type="checkbox" onchange="setAspectRatio(this.id);" /><label for="keepAspectRatio"> force keepAspectRatio (default use <i>Shift</i>)</label>
</li><li>
<input id="enableRotatedTransform" type="checkbox" onchange="setPropertie(this.id);" /><label for="enableRotatedTransform"> force matching the map rotation</label>
</li><li>
SetRotateCenter:
<button onclick='firstPoint=false; interaction.setCenter(); addfeature()'>objects</button>
<button onclick='firstPoint=false; interaction.setCenter(map.getView().getCenter())'>view center</button>
<button onclick='firstPoint=true;'>first point</button>
</li><li>
<hr/>
Use <i>Shift</i> to add object to tranform
<hr/>
Use <i>Shift</i> key to preserve proportions when scaling (see keepAspectRatio).
<br />
Use <i>Ctrl</i> key to modify the center when scaling.
</li>
</ul>
<div style="background:white; padding:0 0.45em;"><span id="info"></span> </div>
</div>
<script type="text/javascript">
// Layers
var layers = [
new ol.layer.Tile({
title:'terrain-background',
source: new ol.source.StadiaMaps({ layer: 'stamen_terrain' })
})
]
// The map
var map = new ol.Map({
target: 'map',
view: new ol.View({
zoom: 5,
center: [261720, 5951081]
}),
layers: layers
});
// Style
function getStyle(feature) {
return [ new ol.style.Style({
image: new ol.style.RegularShape({
fill: new ol.style.Fill({ color: [0,0,255,0.4]}),
stroke: new ol.style.Stroke({color: [0,0,255,1],width: 1}),
radius: feature.get('radius') ||10,
points: 3,
angle: feature.get('angle')||0
}),
fill: new ol.style.Fill({color: [0,0,255,0.4]}),
stroke: new ol.style.Stroke({color: [0,0,255,1],width: 1})
})];
}
// New vector layer
var vector = new ol.layer.Vector({
name: 'Vecteur',
source: new ol.source.Vector({ wrapX: false }),
style: getStyle
})
map.addLayer(vector);
function addfeature() {
vector.getSource().addFeature(new ol.Feature(new ol.geom.Polygon([[[34243, 6305749], [-288626, 5757848], [210354, 5576845], [300000, 6000000], [34243, 6305749]]])));
vector.getSource().addFeature(new ol.Feature(new ol.geom.LineString([[406033, 5664901], [689767, 5718712], [699551, 6149206], [425601, 6183449]])));
vector.getSource().addFeature(new ol.Feature(new ol.geom.Point( [269914, 6248592])));
vector.getSource().addFeature(new ol.Feature(new ol.geom.Circle( [500000, 6400000], 100000 )));
}
// Set cursor style
ol.interaction.Transform.prototype.Cursors['rotate'] = 'url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXAgMAAACdRDwzAAAAAXNSR0IArs4c6QAAAAlQTFRF////////AAAAjvTD7AAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH2wwSEgUFmXJDjQAAAEZJREFUCNdjYMAOuCCk6goQpbp0GpRSAFKcqdNmQKgIILUoNAxIMUWFhoKosNDQBKDgVAilCqcaQBogFFNoGNjsqSgUTgAAM3ES8k912EAAAAAASUVORK5CYII=\') 5 5, auto';
ol.interaction.Transform.prototype.Cursors['rotate0'] = 'url(\'data:image/png;base64,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\') 5 5, auto';
/** Style the transform handles for the current interaction
*/
function setHandleStyle(){
if (!interaction instanceof ol.interaction.Transform) return;
// if ($("#style").prop('checked')) {
// // Style the rotate handle
// var circle = new ol.style.RegularShape({
// fill: new ol.style.Fill({color:[255,255,255,0.01]}),
// stroke: new ol.style.Stroke({width:1, color:[0,0,0,0.01]}),
// radius: 8,
// points: 10
// });
// interaction.setStyle ('rotate',
// new ol.style.Style({
// text: new ol.style.Text ({
// text:'\uf0e2',
// font:"16px Fontawesome",
// textAlign: "left",
// fill:new ol.style.Fill({color:'red'})
// }),
// image: circle
// }));
// // Center of rotation
// interaction.setStyle ('rotate0',
// new ol.style.Style({
// text: new ol.style.Text ({
// text:'\uf0e2',
// font:"20px Fontawesome",
// fill: new ol.style.Fill({ color:[255,255,255,0.8] }),
// stroke: new ol.style.Stroke({ width:2, color:'red' })
// }),
// }));
// // Style the move handle
// interaction.setStyle('translate',
// new ol.style.Style({
// text: new ol.style.Text ({
// text:'\uf047',
// font:"20px Fontawesome",
// fill: new ol.style.Fill({ color:[255,255,255,0.8] }),
// stroke: new ol.style.Stroke({ width:2, color:'red' })
// })
// }));
// // Style the strech handles
// /* uncomment to style * /
// interaction.setStyle ('scaleh1',
// new ol.style.Style({
// text: new ol.style.Text ({
// text:'\uf07d',
// font:"bold 20px Fontawesome",
// fill: new ol.style.Fill({ color:[255,255,255,0.8] }),
// stroke: new ol.style.Stroke({ width:2, color:'red' })
// })
// }));
// interaction.style.scaleh3 = interaction.style.scaleh1;
// interaction.setStyle('scalev',
// new ol.style.Style({
// text: new ol.style.Text ({
// text:'\uf07e',
// font:"bold 20px Fontawesome",
// fill: new ol.style.Fill({ color:[255,255,255,0.8] }),
// stroke: new ol.style.Stroke({ width:2, color:'red' })
// })
// }));
// interaction.style.scalev2 = interaction.style.scalev;
// /**/
// } else {
// interaction.setDefaultStyle ();
// }
// // Refresh
// interaction.set('translate', interaction.get('translate'));
};
/** Set properties
*/
function setPropertie (p) {
interaction.set(p, $("#"+p).prop('checked'));
if (!$("#scale").prop("checked")) $("#stretch").prop('disabled', true);
else $("#stretch").prop('disabled', false);
}
function setAspectRatio (p) {
// if ($("#"+p).prop('checked')) interaction.set("keepAspectRatio", ol.events.condition.always);
// else interaction.set("keepAspectRatio", function(e){ return e.originalEvent.shiftKey });
}
var interaction = new ol.interaction.Transform ({
enableRotatedTransform: false,
/* Limit interaction inside bbox * /
condition: function(e, features) {
return ol.extent.containsXY([-465960, 5536486, 1001630, 6514880], e.coordinate[0], e.coordinate[1]);
},
/* */
// addCondition: ol.events.condition.shiftKeyOnly,
// filter: function(f,l) { return f.getGeometry().getType()==='Polygon'; },
// layers: [vector],
hitTolerance: 2,
translateFeature: false,
scale: true,
rotate: true,
keepAspectRatio: ol.events.condition.always,
keepRectangle: false,
translate: false,
stretch: false,
// Get scale on points
pointRadius: function(f) {
var radius = f.get('radius') || 10;
return [radius, radius];
}
});
map.addInteraction(interaction);
// Style handles
setHandleStyle();
// Events handlers
var startangle = 0;
var startRadius = 10;
var d=[0,0];
// Handle rotate on first point
var firstPoint = false;
interaction.on (['select'], function(e) {
if (firstPoint && e.features && e.features.getLength()) {
interaction.setCenter(e.features.getArray()[0].getGeometry().getFirstCoordinate());
}
});
interaction.on (['rotatestart','translatestart','scalestart'], function(e){
// Rotation
startangle = e.feature.get('angle')||0;
// radius
startRadius = e.feature.get('radius')||10;
// Translation
d=[0,0];
});
interaction.on('rotating', function (e){
$('#info').text("rotate: "+((e.angle*180/Math.PI -180)%360+180).toFixed(2));
// Set angle attribute to be used on style !
e.feature.set('angle', startangle - e.angle);
});
interaction.on('translating', function (e){
d[0]+=e.delta[0];
d[1]+=e.delta[1];
$('#info').text("translate: "+d[0].toFixed(2)+","+d[1].toFixed(2));
if (firstPoint) {
interaction.setCenter(e.features.getArray()[0].getGeometry().getFirstCoordinate());
}
});
interaction.on('scaling', function (e){
$('#info').text("scale: "+e.scale[0].toFixed(2)+","+e.scale[1].toFixed(2));
if (firstPoint) {
interaction.setCenter(e.features.getArray()[0].getGeometry().getFirstCoordinate());
}
if (e.features.getLength() === 1) {
var feature = e.features.item(0);
feature.set('radius', startRadius * Math.abs(e.scale[0]));
}
});
interaction.on(['rotateend', 'translateend', 'scaleend'], function (e) {
$('#info').text("");
});
/* * /
map.addInteraction(new ol.interaction.Snap({
source: vector.getSource()
}))
/* */
</script>
</body>
</html>