Leaflet/OpenLayers3 change size animation with velocity.js - leaflet

I'm trying to make an animation with velocity.js of a map. I tried 2 different libraries: leaflet, and openlayers3.
Here are the jsfiddles: leaflet, openlayers3
The leaflet animation is smooth on my chrome, but not on firefox, edge, or even qt webview.
I know that invalidateSize()/updateSize() just change the position of the tiles and download new ones but I want them to produce a smooth animation.
wish somebody have seen this kind of animation. Or know how could I solve the issue, thanks.
leaflet
$(document).ready(function() {
var position = {
lat: 43.180176,
lng: 13.792964,
zoomLevel: 4
};
var swBound = L.latLng(-90, -180);
var neBound = L.latLng(90, 180);
var maxBounds = L.latLngBounds(swBound, neBound);
var entityMap = L.map($("#smallMapContainer")[0], {
minZoom: 2,
maxBounds: maxBounds,
zoomControl: false
});
var streetMapURL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
L.tileLayer(streetMapURL, {
maxZoom: 18
}).addTo(entityMap);
//entityMap.fitWorld();
entityMap.setView(L.latLng(position.lat, position.lng), position.zoomLevel);
var nextIndexes = 0;
var aaa = function() {
var smallMapPosition = $("#smallMapContainer").position();
var newW = $("body").width() - 90;
var newH = $("body").height() - 90;
var newX = smallMapPosition.top + newH / 2 - 100;
var newY = smallMapPosition.left + newW / 2 - 150;
$("#smallMapContainer").velocity({
top: newX,
left: newY
}, {
duration: 500,
complete: function() {
$("#smallMapContainer").velocity({
width: newW,
height: newH,
top: smallMapPosition.top,
left: smallMapPosition.left
}, {
duration: 1000,
progress: function() {
entityMap.invalidateSize();
},
complete: function() {
if (nextIndexes++ % 2 == 0) { // with animation
entityMap.setView(L.latLng(55.751674, 37.637059), position.zoomLevel);
} else {
entityMap.setView(L.latLng(43.180176, 13.792964), position.zoomLevel);
}
$("#smallMapContainer").velocity({
width: 300,
height: 200,
top: newX,
left: newY
}, {
delay: 1000,
duration: 1000,
progress: function() {
entityMap.invalidateSize();
},
complete: function() {
$("#smallMapContainer").velocity({
top: smallMapPosition.top,
left: smallMapPosition.left
}, {
duration: 1000
});
}
});
}
});
}
});
}
aaa();
setTimeout(function() {
aaa();
}, 10000);});
openlayers
$(document).ready(function() {
var view = new ol.View({
// the view's initial state
center: ol.proj.fromLonLat([13.792964, 43.180176]),
zoom: 4
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
preload: 4,
source: new ol.source.OSM()
})
],
loadTilesWhileAnimating: true,
target: 'smallMapContainer',
controls: ol.control.defaults({
attributionOptions: ({
collapsible: false
})
}),
view: view
});
nextIndexes = 0;
var animateMap = function() {
var smallMapPosition = $("#smallMapContainer").position();
var newW = $("body").width() - 90;
var newH = $("body").height() - 90;
var newX = smallMapPosition.top + newH / 2 - 100;
var newY = smallMapPosition.left + newW / 2 - 150;
$("#smallMapContainer").velocity({
top: newX,
left: newY
}, {
duration: 500,
complete: function() {
$("#smallMapContainer").velocity({
width: newW,
height: newH,
top: smallMapPosition.top,
left: smallMapPosition.left
}, {
duration: 1000,
progress: function() {
map.updateSize();
},
complete: function() {
if (nextIndexes++ % 2 == 0) {
var pan = ol.animation.pan({
duration: 1000,
source: /** #type {ol.Coordinate} */ (view.getCenter())
});
map.beforeRender(pan);
view.setCenter(ol.proj.fromLonLat([37.637059, 55.751674]));
} else {
var pan = ol.animation.pan({
duration: 1000,
source: /** #type {ol.Coordinate} */ (view.getCenter())
});
map.beforeRender(pan);
view.setCenter(ol.proj.fromLonLat([13.792964, 43.180176]));
}
$("#smallMapContainer").velocity({
width: 300,
height: 200,
top: newX,
left: newY
}, {
delay: 1000,
duration: 1000,
progress: function() {
map.updateSize();
},
complete: function() {
$("#smallMapContainer").velocity({
top: smallMapPosition.top,
left: smallMapPosition.left
}, {
duration: 1000
});
}
});
}
});
}
});
}
animateMap();});

Disclaimer: If you're adament on using Velocity this is in no means a validate answer but i thought i'de throw it in here because i think it's unnecessary to pull in an entire animation library to accomplish something that can easily be done with standard CSS.
You can accomplish the same effect by using CSS keyframe animation, it will run much smoother than using an external animation library:
#leaflet {
width: 300px;
height: 200px;
position: absolute;
top: 55px;
left: 45px;
animation-name: move;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-direction: normal;
animation-timing-function: linear;
}
#keyframes move {
0% {
top: 55px;
left: 45px;
}
25% {
top: calc(50% - (200px / 2));
left: calc(50% - (300px / 2));
width: 300px;
height: 200px;
}
50% {
top: calc(5%);
left: calc(5%);
width: 90%;
height: 90%;
}
75% {
top: calc(50% - (200px / 2));
left: calc(50% - (300px / 2));
width: 300px;
height: 200px;
}
100% {
top: 55px;
left: 45px;
}
}
The only drawback/problem is that somehow (got to look further into this, but i'm low on time at the moment) L.Map's 'resize' event doesn't seem to fire when resizing the map container through CSS animation. So i've used ResizeSensor from CSS Element Queries to be able to call invalidateSize on the map instance when the container gets resized.
Here's a working example on Plunker: http://plnkr.co/edit/EyQFbm?p=preview

Related

Optimize simple CSS / WebAnimation, eg scale()

I've tried different solutions to animate a sidenav bar rise from bottom right corner. This is the last solution, maybe the best one ( because i'm animating the transform scale() ) in the previous ( width / height ) but the animation still sluggish on the cut corner... with the cut line acting with strange squared forms during the animation ... so i'm looking to solve!
Here the scale() example on glitch
https://glitch.com/edit/#!/heady-grey-lantern
Even on w3schools site the simple animation of Side Navigation is little shimmy and flicker
https://www.w3schools.com/howto/howto_js_sidenav.asp
Here the core of animation
// css code
.sidenav {
width: 200vw;
height: 200vh;
width: 200dvw;
height: 200dvh;
position: fixed;
bottom: 0;
/* left: 0; */
right: 0;
/* cut corner */
--cutting: max(100vw, 100vh);
--cutting: max(150dvw, 150dvh);
clip-path: polygon(0 var(--cutting), var(--cutting) 0,100% 0,100% 100%,0 100%);
/* z-index: 1; */
background-color: #111;
/* overflow-x: hidden; */
will-change: transform;
transform: scale(0);
transform-origin: bottom right;
}
// Js code
const sidenav = document.getElementById("mySidenav")
const duration = 500
const openSidenav = [
{ transform: 'scaleX(0) scaleY(0)' },
{ transform: 'scaleX(1) scaleY(1)' }
]
const closeSidenav = [
{ transform: 'scaleX(1) scaleY(1)' },
{ transform: 'scaleX(0) scaleY(0)' }
]
const openNav = () => {
console.log('#NAV >> Open')
// document.getElementById("mySidenav").style.width = '175vw'
// document.getElementById("mySidenav").style.height = '175vh'
sidenav.animate(
openSidenav, {
duration,
iterations: 1,
easing: 'ease-in',
fill: 'forwards'
}
)
}
const closeNav = () => {
console.log('#NAV >> Close')
// document.getElementById("mySidenav").style.width = '0'
// document.getElementById("mySidenav").style.height = '0'
sidenav.animate(
closeSidenav, {
duration,
iterations: 1,
easing: 'ease-in',
fill: 'forwards'
}
)
}
Last, better one!
/* css */
#sidenav {
width: 100vw;
height: 100vh;
width: 100dvw;
height: 100dvh;
position: fixed;
/* cut corner */
--cutting: max(100vw, 100vh);
clip-path: polygon(0 var(--cutting), var(--cutting) 0,100% 0,100% 100%,0 100%);
/* set transition as in WebAnimation API */
transition: all 0.5s;
will-change: transform;
transform: scale(0);
transform-origin: bottom right;
z-index: 11;
background-color: var(--surface1);
display: grid;
justify-items: center;
align-items: center;
/* justify-items: end;
align-items: end; */
}
#sidenav[active] {
--cutting: 0;
transition: all 0.5s;
}
/* --------------- Mobile Nav -------------- */
nav {
/* TODO fallback inline-size: 75vw;
block-size: 75vh; */
inline-size: 75dvw;
block-size: 75dvh;
display: block;
flex-direction: column;
background-color: crimson;
}
// javascript animations
const openSidenav = [
{ transform: 'scale(0)' },
{ transform: 'scale(0.25)' },
{ transform: 'scale(0.5)' },
{ transform: 'scale(0.75)' },
{ transform: 'scale(1)' }
]
const closeSidenav = [
{ transform: 'scale(1)' },
{ transform: 'scale(0.75)' },
{ transform: 'scale(0.5)' },
{ transform: 'scale(0.25)' },
{ transform: 'scale(0)' }
]
const slideIn = [
{ transform: 'translateX(100%)' },
{ transform: 'translateX(0)', opacity: 1 }
]
const slideOut = [
{ transform: 'translateX(0)' },
{ transform: 'translateX(100%)', opacity: 0 }
]
// duration animation
const openSidenavDuration = 500
const closeSidenavDuration = 300
// duration animation per a tag
const slideInDuration = 200
const slideOutDuration = 100
// javascript
openNav (e) {
const sidenav =
this.renderRoot.getElementById('sidenav')
this.sidenavIsOpen = true
const openAnimation = sidenav.animate(
openSidenav, {
duration: openSidenavDuration,
iterations: 1,
easing: 'ease-in',
fill: 'forwards'
}
)
openAnimation.addEventListener('finish', (e) => {
// console.log('#EVENT >> ', e.type)
sidenav.setAttribute('active', '')
// sidenav.style.setProperty('--cutting', 0)
})
}
closeNav (e) {
const sidenav =
this.renderRoot.getElementById('sidenav')
this.sidenavIsOpen = false
sidenav.animate(
closeSidenav, {
duration: closeSidenavDuration,
iterations: 1,
easing: 'ease-in',
fill: 'forwards',
delay: slideOutDuration * 3
}
)
sidenav.removeAttribute('active')
}

ol4 + ol-ext problem with ol.featureAnimation.Zoom and ol.layer.AnimatedCluster

When I clicked over cluster, the features not show correctly, I tried stopping the animation but it didn't work. Is another option to show animation for each feature?
// Cluster Source
clusterSource = new ol.source.Cluster({
distance: distanceFt,
source: new ol.source.Vector()
});
// Animated cluster layer
clusterLayer = new ol.layer.AnimatedCluster({
name: 'Cluster',
source: clusterSource,
animationDuration: 700, //$("#animatecluster").prop('checked') ? 700 : 0,
// Cluster style
style: getStyle
});
// Transparent style to handle click on animation
var transparent = [0, 0, 0, 0.01];
var filltransparent = [0, 0, 0, 0];
var transparentStyle =
[new ol.style.Style(
{
image: new ol.style.RegularShape({ radius: 10, radius2: 5, points: 5, fill: new ol.style.Fill({ color: transparent }) }),
stroke: new ol.style.Stroke({ color: transparent, width: 2 }),
fill: new ol.style.Fill({ color: filltransparent })
})
];
// animation
var animacion = new ol.featureAnimation.Zoom({
fade: ol.easing.easeOut,
duration: 2000,
easing: ol.easing["easeOut"],
repeat: 100,
hiddenStyle: transparentStyle
});
ft_animados[idx] = vector_anim.animateFeature(anim_ft[i], animacion(anim_ft[i]));
I have two function:
function ft_animacion(f) {
//var style = f.getStyle();
var efecto = new ol.style.Style({
image: new ol.style["Circle"]({
radius: 30,
points: 4,
stroke: new ol.style.Stroke({ color: 'red', width: 2 })
})
});
f.setStyle(efecto);
return f;
}
function addFeatures(ffs, centrar) {
// some code lines
for (var i = 0; i < ffs.length; i++) {
features[i] = new ol.Feature();
features[i].setProperties(ffs[i]);
var geometry = new ol.geom.Point(transform([parseFloat(ffs[i].lon), parseFloat(ffs[i].lat)]));
features[i].setGeometry(geometry);
if (ffs[i].content.ind) {
if (ffs[i].content.ind.includes("Pendiente")) {
anim_ft.push(ft_animacion(features[i]));
}
}
}
// some code lines
}
I resolve my problem using feature.clone().
So edit the line anim_ft.push(ft_animacion(features[i])) to anim_ft.push(ft_animacion(features[i].clone()))
I dont noticed that when I use the function ft_animacion I was overwriting the style of feature.

OpenLayers 5: move marker smoothly

I use
https://openlayers.org/en/latest/examples/feature-move-animation.html
code snippet:
// This long string is placed here due to jsFiddle limitations.
// It is usually loaded with AJAX.
var polyline = [
'hldhx#lnau`BCG_EaC??cFjAwDjF??uBlKMd#}#z#??aC^yk#z_#se#b[wFdE??wFfE}N',
'fIoGxB_I\\gG}#eHoCyTmPqGaBaHOoD\\??yVrGotA|N??o[N_STiwAtEmHGeHcAkiA}^',
'aMyBiHOkFNoI`CcVvM??gG^gF_#iJwC??eCcA]OoL}DwFyCaCgCcCwDcGwHsSoX??wI_E',
'kUFmq#hBiOqBgTwS??iYse#gYq\\cp#ce#{vA}s#csJqaE}{#iRaqE{lBeRoIwd#_T{]_',
'Ngn#{PmhEwaA{SeF_u#kQuyAw]wQeEgtAsZ}LiCarAkVwI}D??_}RcjEinPspDwSqCgs#',
'sPua#_OkXaMeT_Nwk#ob#gV}TiYs[uTwXoNmT{Uyb#wNg]{Nqa#oDgNeJu_#_G}YsFw]k',
'DuZyDmm#i_#uyIJe~#jCg|#nGiv#zUi_BfNqaAvIow#dEed#dCcf#r#qz#Egs#{Acu#mC',
'um#yIey#gGig#cK_m#aSku#qRil#we#{mAeTej#}Tkz#cLgr#aHko#qOmcEaJw~C{w#ka',
'i#qBchBq#kmBS{kDnBscBnFu_Dbc#_~QHeU`IuyDrC_}#bByp#fCyoA?qMbD}{AIkeAgB',
'k_A_A{UsDke#gFej#qH{o#qGgb#qH{`#mMgm#uQus#kL{_#yOmd#ymBgwE}x#ouBwtA__',
'DuhEgaKuWct#gp#cnBii#mlBa_#}|Asj#qrCg^eaC}L{dAaJ_aAiOyjByH{nAuYu`GsAw',
'Xyn#ywMyOyqD{_#cfIcDe}#y#aeBJmwA`CkiAbFkhBlTgdDdPyiB`W}xDnSa}DbJyhCrX',
'itAhT}x#bE}Z_#qW_Kwv#qKaaAiBgXvIm}A~JovAxCqW~WanB`XewBbK{_A`K}fBvAmi#',
'xBycBeCauBoF}}#qJioAww#gjHaPopA_NurAyJku#uGmi#cDs[eRaiBkQstAsQkcByNma',
'CsK_uBcJgbEw#gkB_#ypEqDoqSm#eZcDwjBoGw`BoMegBaU_`Ce_#_uBqb#ytBwkFqiT_',
'fAqfEwe#mfCka#_eC_UmlB}MmaBeWkkDeHwqAoX}~DcBsZmLcxBqOwqE_DkyAuJmrJ\\o',
'~CfIewG|YibQxBssB?es#qGciA}RorAoVajA_nAodD{[y`AgPqp#mKwr#ms#umEaW{dAm',
'b#umAw|#ojBwzDaaJsmBwbEgdCsrFqhAihDquAi`Fux#}_Dui#_eB_u#guCuyAuiHukA_',
'lKszAu|OmaA{wKm}#clHs_A_rEahCssKo\\sgBsSglAqk#yvDcS_wAyTwpBmPc|BwZknF',
'oFscB_GsaDiZmyMyLgtHgQonHqT{hKaPg}Dqq#m~Hym#c`EuiBudIabB{hF{pWifx#snA',
'w`GkFyVqf#y~BkoAi}Lel#wtc#}`#oaXi_C}pZsi#eqGsSuqJ|Lqeb#e]kgPcaAu}SkDw',
'zGhn#gjYh\\qlNZovJieBqja#ed#siO{[ol\\kCmjMe\\isHorCmec#uLebB}EqiBaCg}',
'#m#qwHrT_vFps#kkI`uAszIrpHuzYxx#e{Crw#kpDhN{wBtQarDy#knFgP_yCu\\wyCwy',
'A{kHo~#omEoYmoDaEcPiuAosDagD}rO{{AsyEihCayFilLaiUqm#_bAumFo}DgqA_uByi',
'#swC~AkzDlhA}xEvcBa}Cxk#ql#`rAo|#~bBq{#``Bye#djDww#z_C_cAtn#ye#nfC_eC',
'|gGahH~s#w}#``Fi~FpnAooC|u#wlEaEedRlYkrPvKerBfYs}Arg#m}AtrCkzElw#gjBb',
'h#woBhR{gCwGkgCc[wtCuOapAcFoh#uBy[yBgr#c#iq#o#wvEv#sp#`FajBfCaq#fIipA',
'dy#ewJlUc`ExGuaBdEmbBpBssArAuqBBg}#s#g{AkB{bBif#_bYmC}r#kDgm#sPq_BuJ_',
's#{X_{AsK_d#eM{d#wVgx#oWcu#??aDmOkNia#wFoSmDyMyCkPiBePwAob#XcQ|#oNdCo',
'SfFwXhEmOnLi\\lbAulB`X_d#|k#au#bc#oc#bqC}{BhwDgcD`l#ed#??bL{G|a#eTje#',
'oS~]cLr~Bgh#|b#}Jv}EieAlv#sPluD{z#nzA_]`|KchCtd#sPvb#wSb{#ko#f`RooQ~e',
'[upZbuIolI|gFafFzu#iq#nMmJ|OeJn^{Qjh#yQhc#uJ~j#iGdd#kAp~BkBxO{#|QsAfY',
'gEtYiGd]}Jpd#wRhVoNzNeK`j#ce#vgK}cJnSoSzQkVvUm^rSgc#`Uql#xIq\\vIgg#~k',
'Dyq[nIir#jNoq#xNwc#fYik#tk#su#neB}uBhqEesFjoGeyHtCoD|D}Ed|#ctAbIuOzqB',
'_}D~NgY`\\um#v[gm#v{Cw`G`w#o{AdjAwzBh{C}`Gpp#ypAxn#}mAfz#{bBbNia#??jI',
'ab#`CuOlC}YnAcV`#_^m#aeB}#yk#YuTuBg^uCkZiGk\\yGeY}Lu_#oOsZiTe[uWi[sl#',
'mo#soAauAsrBgzBqgAglAyd#ig#asAcyAklA}qAwHkGi{#s~#goAmsAyDeEirB_{B}IsJ',
'uEeFymAssAkdAmhAyTcVkFeEoKiH}l#kp#wg#sj#ku#ey#uh#kj#}EsFmG}Jk^_r#_f#m',
'~#ym#yjA??a#cFd#kBrCgDbAUnAcBhAyAdk#et#??kF}D??OL'
].join('');
var route = /** #type {module:ol/geom/LineString~LineString} */ (new ol.format.Polyline({
factor: 1e6
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
}));
var routeCoords = route.getCoordinates();
var routeLength = routeCoords.length;
var routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
var geoMarker = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(routeCoords[0])
});
var startMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[0])
});
var endMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[routeLength - 1])
});
var styles = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8]
})
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png'
})
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({ // CircleStyle({
radius: 7,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2
})
})
})
};
var animating = false;
var speed, now;
var speedInput = document.getElementById('speed');
var startButton = document.getElementById('start-animation');
var vectorLayer = new ol.layer.Vector({ // VectorLayer({
source: new ol.source.Vector({ // VectorSource({
features: [routeFeature, geoMarker, startMarker, endMarker]
}),
style: function(feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
return null;
}
return styles[feature.get('type')];
}
});
var center = [-5639523.95, -3501274.52];
var map = new ol.Map({
target: document.getElementById('map'),
loadTilesWhileAnimating: true,
view: new ol.View({
center: center,
zoom: 9,
minZoom: 2,
maxZoom: 19
}),
layers: [
new ol.layer.Tile({ // TileLayer({
source: new ol.source.OSM()
}),
vectorLayer
]
});
var moveFeature = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating) {
var elapsedTime = frameState.time - now;
// here the trick to increase speed is to jump some indexes
// on lineString coordinates
var index = Math.round(speed * elapsedTime / 1000);
if (index >= routeLength) {
stopAnimation(true);
return;
}
var currentPoint = new ol.geom.Point(routeCoords[index]);
var feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
// tell OpenLayers to continue the postcompose animation
map.render();
};
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
now = new Date().getTime();
speed = speedInput.value;
startButton.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker.setStyle(null);
// just in case you pan somewhere else
map.getView().setCenter(center);
map.on('postcompose', moveFeature);
map.render();
}
}
/**
* #param {boolean} ended end of animation.
*/
function stopAnimation(ended) {
animating = false;
startButton.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
var coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
/** #type {module:ol/geom/Point~Point} */
(geoMarker.getGeometry())
.setCoordinates(coord);
//remove listener
map.un('postcompose', moveFeature);
}
startButton.addEventListener('click', startAnimation, false);
html,
body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
.map {
height: 90%;
width: 100%;
}
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.1.3/build/ol.js"></script>
<div id="map" class="map"></div>
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation">Start Animation</button>
but I need to move marker smoothly between two point (or many)
See ol-ext : featureAnimation
example from that library's documentation
code snippet (example from the OpenLayers documentation using ol-ext):
// use window.onload so can move encoded polyline definition to bottom
window.onload = function() {
var route = /** #type {module:ol/geom/LineString~LineString} */ (new ol.format.Polyline({
factor: 1e6
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
}));
var routeCoords = route.getCoordinates();
var routeLength = routeCoords.length;
var routePts = new ol.Feature({
type: 'route',
geometry: new ol.geom.MultiPoint(routeCoords)
});
var routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
var geoMarker = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(routeCoords[0])
});
var startMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[0])
});
var endMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[routeLength - 1])
});
var styles = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8]
}),
image: new ol.style.Circle({
radius: 1,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'red'
})
})
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png'
})
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({ // CircleStyle({
radius: 7,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2
})
})
})
};
var animating = false;
var speed, now;
var speedInput = document.getElementById('speed');
var startButton = document.getElementById('start-animation');
var vectorLayer = new ol.layer.Vector({ // VectorLayer({
source: new ol.source.Vector({ // VectorSource({
features: [routePts, routeFeature, geoMarker, startMarker, endMarker]
}),
style: function(feature) {
return styles[feature.get('type')];
}
});
var center = [-5639523.95, -3501274.52];
var map = new ol.Map({
target: document.getElementById('map'),
loadTilesWhileAnimating: true,
view: new ol.View({
center: center,
zoom: 9,
minZoom: 2,
maxZoom: 19
}),
layers: [
new ol.layer.Tile({ // TileLayer({
source: new ol.source.OSM()
}),
vectorLayer
]
});
console.log("init speed=" + speedInput.value / 100);
function startAnimation() {
if (animating) animating.stop();
console.log("update speed=" + Number(speedInput.value) / 100);
// anim.set("speed", Number(speedInput.value)/10);
var anim = new ol.featureAnimation.Path({
path: route,
easing: ol.easing.linear,
speed: Number(speedInput.value) / 100
});
animating = vectorLayer.animateFeature(geoMarker, anim);
}
geoMarker.on('change', function() {
map.getView().setCenter(geoMarker.getGeometry().getCoordinates());
});
startButton.addEventListener('click', startAnimation, false);
}
// This long string is placed here due to jsFiddle limitations.
// It is usually loaded with AJAX.
var polyline = [
'hldhx#lnau`BCG_EaC??cFjAwDjF??uBlKMd#}#z#??aC^yk#z_#se#b[wFdE??wFfE}N',
'fIoGxB_I\\gG}#eHoCyTmPqGaBaHOoD\\??yVrGotA|N??o[N_STiwAtEmHGeHcAkiA}^',
'aMyBiHOkFNoI`CcVvM??gG^gF_#iJwC??eCcA]OoL}DwFyCaCgCcCwDcGwHsSoX??wI_E',
'kUFmq#hBiOqBgTwS??iYse#gYq\\cp#ce#{vA}s#csJqaE}{#iRaqE{lBeRoIwd#_T{]_',
'Ngn#{PmhEwaA{SeF_u#kQuyAw]wQeEgtAsZ}LiCarAkVwI}D??_}RcjEinPspDwSqCgs#',
'sPua#_OkXaMeT_Nwk#ob#gV}TiYs[uTwXoNmT{Uyb#wNg]{Nqa#oDgNeJu_#_G}YsFw]k',
'DuZyDmm#i_#uyIJe~#jCg|#nGiv#zUi_BfNqaAvIow#dEed#dCcf#r#qz#Egs#{Acu#mC',
'um#yIey#gGig#cK_m#aSku#qRil#we#{mAeTej#}Tkz#cLgr#aHko#qOmcEaJw~C{w#ka',
'i#qBchBq#kmBS{kDnBscBnFu_Dbc#_~QHeU`IuyDrC_}#bByp#fCyoA?qMbD}{AIkeAgB',
'k_A_A{UsDke#gFej#qH{o#qGgb#qH{`#mMgm#uQus#kL{_#yOmd#ymBgwE}x#ouBwtA__',
'DuhEgaKuWct#gp#cnBii#mlBa_#}|Asj#qrCg^eaC}L{dAaJ_aAiOyjByH{nAuYu`GsAw',
'Xyn#ywMyOyqD{_#cfIcDe}#y#aeBJmwA`CkiAbFkhBlTgdDdPyiB`W}xDnSa}DbJyhCrX',
'itAhT}x#bE}Z_#qW_Kwv#qKaaAiBgXvIm}A~JovAxCqW~WanB`XewBbK{_A`K}fBvAmi#',
'xBycBeCauBoF}}#qJioAww#gjHaPopA_NurAyJku#uGmi#cDs[eRaiBkQstAsQkcByNma',
'CsK_uBcJgbEw#gkB_#ypEqDoqSm#eZcDwjBoGw`BoMegBaU_`Ce_#_uBqb#ytBwkFqiT_',
'fAqfEwe#mfCka#_eC_UmlB}MmaBeWkkDeHwqAoX}~DcBsZmLcxBqOwqE_DkyAuJmrJ\\o',
'~CfIewG|YibQxBssB?es#qGciA}RorAoVajA_nAodD{[y`AgPqp#mKwr#ms#umEaW{dAm',
'b#umAw|#ojBwzDaaJsmBwbEgdCsrFqhAihDquAi`Fux#}_Dui#_eB_u#guCuyAuiHukA_',
'lKszAu|OmaA{wKm}#clHs_A_rEahCssKo\\sgBsSglAqk#yvDcS_wAyTwpBmPc|BwZknF',
'oFscB_GsaDiZmyMyLgtHgQonHqT{hKaPg}Dqq#m~Hym#c`EuiBudIabB{hF{pWifx#snA',
'w`GkFyVqf#y~BkoAi}Lel#wtc#}`#oaXi_C}pZsi#eqGsSuqJ|Lqeb#e]kgPcaAu}SkDw',
'zGhn#gjYh\\qlNZovJieBqja#ed#siO{[ol\\kCmjMe\\isHorCmec#uLebB}EqiBaCg}',
'#m#qwHrT_vFps#kkI`uAszIrpHuzYxx#e{Crw#kpDhN{wBtQarDy#knFgP_yCu\\wyCwy',
'A{kHo~#omEoYmoDaEcPiuAosDagD}rO{{AsyEihCayFilLaiUqm#_bAumFo}DgqA_uByi',
'#swC~AkzDlhA}xEvcBa}Cxk#ql#`rAo|#~bBq{#``Bye#djDww#z_C_cAtn#ye#nfC_eC',
'|gGahH~s#w}#``Fi~FpnAooC|u#wlEaEedRlYkrPvKerBfYs}Arg#m}AtrCkzElw#gjBb',
'h#woBhR{gCwGkgCc[wtCuOapAcFoh#uBy[yBgr#c#iq#o#wvEv#sp#`FajBfCaq#fIipA',
'dy#ewJlUc`ExGuaBdEmbBpBssArAuqBBg}#s#g{AkB{bBif#_bYmC}r#kDgm#sPq_BuJ_',
's#{X_{AsK_d#eM{d#wVgx#oWcu#??aDmOkNia#wFoSmDyMyCkPiBePwAob#XcQ|#oNdCo',
'SfFwXhEmOnLi\\lbAulB`X_d#|k#au#bc#oc#bqC}{BhwDgcD`l#ed#??bL{G|a#eTje#',
'oS~]cLr~Bgh#|b#}Jv}EieAlv#sPluD{z#nzA_]`|KchCtd#sPvb#wSb{#ko#f`RooQ~e',
'[upZbuIolI|gFafFzu#iq#nMmJ|OeJn^{Qjh#yQhc#uJ~j#iGdd#kAp~BkBxO{#|QsAfY',
'gEtYiGd]}Jpd#wRhVoNzNeK`j#ce#vgK}cJnSoSzQkVvUm^rSgc#`Uql#xIq\\vIgg#~k',
'Dyq[nIir#jNoq#xNwc#fYik#tk#su#neB}uBhqEesFjoGeyHtCoD|D}Ed|#ctAbIuOzqB',
'_}D~NgY`\\um#v[gm#v{Cw`G`w#o{AdjAwzBh{C}`Gpp#ypAxn#}mAfz#{bBbNia#??jI',
'ab#`CuOlC}YnAcV`#_^m#aeB}#yk#YuTuBg^uCkZiGk\\yGeY}Lu_#oOsZiTe[uWi[sl#',
'mo#soAauAsrBgzBqgAglAyd#ig#asAcyAklA}qAwHkGi{#s~#goAmsAyDeEirB_{B}IsJ',
'uEeFymAssAkdAmhAyTcVkFeEoKiH}l#kp#wg#sj#ku#ey#uh#kj#}EsFmG}Jk^_r#_f#m',
'~#ym#yjA??a#cFd#kBrCgDbAUnAcBhAyAdk#et#??kF}D??OL'
].join('');
html,
body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
.map {
height: 90%;
width: 100%;
}
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.1.3/build/ol.js"></script>
<script src="https://cdn.rawgit.com/Viglino/ol-ext/master/dist/ol-ext.js"></script>
<button id="start-animation">Start Animation</button>
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="4999" step="10" value="500">
</label>
<div id="map" class="map"></div>
The OpenLayers example doesn't move smoothly as the only coordinates it uses are the points where the linestring changes direction. Therefore long straights are traversed much faster than the curved sections. The ol-ext method breaks the linestring into small equal length segments, but it seems to be animating the view to keep up with the marker instead of simply animating the marker. By reusing the splitLineString function from the second part of the answer to this question https://gis.stackexchange.com/questions/306976/add-image-along-the-linestring to finely divide the linestring and setting only one icon style based on a timer based index it is possible to achieve a smooth movement independently of the view (best seen in a full screen window) and also allows the icon to stay aligned with the direction of travel.
// This long string is placed here due to jsFiddle limitations.
// It is usually loaded with AJAX.
var polyline = [
'hldhx#lnau`BCG_EaC??cFjAwDjF??uBlKMd#}#z#??aC^yk#z_#se#b[wFdE??wFfE}N',
'fIoGxB_I\\gG}#eHoCyTmPqGaBaHOoD\\??yVrGotA|N??o[N_STiwAtEmHGeHcAkiA}^',
'aMyBiHOkFNoI`CcVvM??gG^gF_#iJwC??eCcA]OoL}DwFyCaCgCcCwDcGwHsSoX??wI_E',
'kUFmq#hBiOqBgTwS??iYse#gYq\\cp#ce#{vA}s#csJqaE}{#iRaqE{lBeRoIwd#_T{]_',
'Ngn#{PmhEwaA{SeF_u#kQuyAw]wQeEgtAsZ}LiCarAkVwI}D??_}RcjEinPspDwSqCgs#',
'sPua#_OkXaMeT_Nwk#ob#gV}TiYs[uTwXoNmT{Uyb#wNg]{Nqa#oDgNeJu_#_G}YsFw]k',
'DuZyDmm#i_#uyIJe~#jCg|#nGiv#zUi_BfNqaAvIow#dEed#dCcf#r#qz#Egs#{Acu#mC',
'um#yIey#gGig#cK_m#aSku#qRil#we#{mAeTej#}Tkz#cLgr#aHko#qOmcEaJw~C{w#ka',
'i#qBchBq#kmBS{kDnBscBnFu_Dbc#_~QHeU`IuyDrC_}#bByp#fCyoA?qMbD}{AIkeAgB',
'k_A_A{UsDke#gFej#qH{o#qGgb#qH{`#mMgm#uQus#kL{_#yOmd#ymBgwE}x#ouBwtA__',
'DuhEgaKuWct#gp#cnBii#mlBa_#}|Asj#qrCg^eaC}L{dAaJ_aAiOyjByH{nAuYu`GsAw',
'Xyn#ywMyOyqD{_#cfIcDe}#y#aeBJmwA`CkiAbFkhBlTgdDdPyiB`W}xDnSa}DbJyhCrX',
'itAhT}x#bE}Z_#qW_Kwv#qKaaAiBgXvIm}A~JovAxCqW~WanB`XewBbK{_A`K}fBvAmi#',
'xBycBeCauBoF}}#qJioAww#gjHaPopA_NurAyJku#uGmi#cDs[eRaiBkQstAsQkcByNma',
'CsK_uBcJgbEw#gkB_#ypEqDoqSm#eZcDwjBoGw`BoMegBaU_`Ce_#_uBqb#ytBwkFqiT_',
'fAqfEwe#mfCka#_eC_UmlB}MmaBeWkkDeHwqAoX}~DcBsZmLcxBqOwqE_DkyAuJmrJ\\o',
'~CfIewG|YibQxBssB?es#qGciA}RorAoVajA_nAodD{[y`AgPqp#mKwr#ms#umEaW{dAm',
'b#umAw|#ojBwzDaaJsmBwbEgdCsrFqhAihDquAi`Fux#}_Dui#_eB_u#guCuyAuiHukA_',
'lKszAu|OmaA{wKm}#clHs_A_rEahCssKo\\sgBsSglAqk#yvDcS_wAyTwpBmPc|BwZknF',
'oFscB_GsaDiZmyMyLgtHgQonHqT{hKaPg}Dqq#m~Hym#c`EuiBudIabB{hF{pWifx#snA',
'w`GkFyVqf#y~BkoAi}Lel#wtc#}`#oaXi_C}pZsi#eqGsSuqJ|Lqeb#e]kgPcaAu}SkDw',
'zGhn#gjYh\\qlNZovJieBqja#ed#siO{[ol\\kCmjMe\\isHorCmec#uLebB}EqiBaCg}',
'#m#qwHrT_vFps#kkI`uAszIrpHuzYxx#e{Crw#kpDhN{wBtQarDy#knFgP_yCu\\wyCwy',
'A{kHo~#omEoYmoDaEcPiuAosDagD}rO{{AsyEihCayFilLaiUqm#_bAumFo}DgqA_uByi',
'#swC~AkzDlhA}xEvcBa}Cxk#ql#`rAo|#~bBq{#``Bye#djDww#z_C_cAtn#ye#nfC_eC',
'|gGahH~s#w}#``Fi~FpnAooC|u#wlEaEedRlYkrPvKerBfYs}Arg#m}AtrCkzElw#gjBb',
'h#woBhR{gCwGkgCc[wtCuOapAcFoh#uBy[yBgr#c#iq#o#wvEv#sp#`FajBfCaq#fIipA',
'dy#ewJlUc`ExGuaBdEmbBpBssArAuqBBg}#s#g{AkB{bBif#_bYmC}r#kDgm#sPq_BuJ_',
's#{X_{AsK_d#eM{d#wVgx#oWcu#??aDmOkNia#wFoSmDyMyCkPiBePwAob#XcQ|#oNdCo',
'SfFwXhEmOnLi\\lbAulB`X_d#|k#au#bc#oc#bqC}{BhwDgcD`l#ed#??bL{G|a#eTje#',
'oS~]cLr~Bgh#|b#}Jv}EieAlv#sPluD{z#nzA_]`|KchCtd#sPvb#wSb{#ko#f`RooQ~e',
'[upZbuIolI|gFafFzu#iq#nMmJ|OeJn^{Qjh#yQhc#uJ~j#iGdd#kAp~BkBxO{#|QsAfY',
'gEtYiGd]}Jpd#wRhVoNzNeK`j#ce#vgK}cJnSoSzQkVvUm^rSgc#`Uql#xIq\\vIgg#~k',
'Dyq[nIir#jNoq#xNwc#fYik#tk#su#neB}uBhqEesFjoGeyHtCoD|D}Ed|#ctAbIuOzqB',
'_}D~NgY`\\um#v[gm#v{Cw`G`w#o{AdjAwzBh{C}`Gpp#ypAxn#}mAfz#{bBbNia#??jI',
'ab#`CuOlC}YnAcV`#_^m#aeB}#yk#YuTuBg^uCkZiGk\\yGeY}Lu_#oOsZiTe[uWi[sl#',
'mo#soAauAsrBgzBqgAglAyd#ig#asAcyAklA}qAwHkGi{#s~#goAmsAyDeEirB_{B}IsJ',
'uEeFymAssAkdAmhAyTcVkFeEoKiH}l#kp#wg#sj#ku#ey#uh#kj#}EsFmG}Jk^_r#_f#m',
'~#ym#yjA??a#cFd#kBrCgDbAUnAcBhAyAdk#et#??kF}D??OL'
].join('');
function splitLineString(geometry, minSegmentLength, options) {
function calculatePointsDistance(coord1, coord2) {
var dx = coord1[0] - coord2[0];
var dy = coord1[1] - coord2[1];
return Math.sqrt(dx * dx + dy * dy);
};
function calculateSplitPointCoords(startNode, nextNode, distanceBetweenNodes, distanceToSplitPoint) {
var d = distanceToSplitPoint / distanceBetweenNodes;
var x = nextNode[0] + (startNode[0] - nextNode[0]) * d;
var y = nextNode[1] + (startNode[1] - nextNode[1]) * d;
return [x, y];
};
function calculateAngle(startNode, nextNode, alwaysUp) {
var x = (startNode[0] - nextNode[0]);
var y = (startNode[1] - nextNode[1]);
var angle = Math.atan(x/y);
if (!alwaysUp) {
angle = y > 0 ? angle + Math.PI : x < 0 ? angle + Math.PI*2 : angle;
}
return angle;
};
var splitPoints = [];
var coords = geometry.getCoordinates();
var coordIndex = 0;
var startPoint = coords[coordIndex];
var nextPoint = coords[coordIndex + 1];
var angle = calculateAngle(startPoint, nextPoint, options.alwaysUp);
var n = Math.ceil(geometry.getLength()/minSegmentLength);
var segmentLength = geometry.getLength() / n;
var currentSegmentLength = options.midPoints ? segmentLength/2 : segmentLength;
for (var i = 0; i <= n; i++) {
var distanceBetweenPoints = calculatePointsDistance(startPoint, nextPoint);
currentSegmentLength += distanceBetweenPoints;
if (currentSegmentLength < segmentLength) {
coordIndex++;
if(coordIndex < coords.length - 1) {
startPoint = coords[coordIndex];
nextPoint = coords[coordIndex + 1];
angle = calculateAngle(startPoint, nextPoint, options.alwaysUp);
i--;
continue;
} else {
if (!options.midPoints) {
var splitPointCoords = nextPoint;
splitPointCoords.push(angle);
splitPoints.push(splitPointCoords);
}
break;
}
} else {
var distanceToSplitPoint = currentSegmentLength - segmentLength;
var splitPointCoords = calculateSplitPointCoords(startPoint, nextPoint, distanceBetweenPoints, distanceToSplitPoint);
startPoint = splitPointCoords.slice();
splitPointCoords.push(angle);
splitPoints.push(splitPointCoords);
currentSegmentLength = 0;
}
}
return splitPoints;
};
var route = new ol.format.Polyline({
factor: 1e6
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
var routeCoords = route.getCoordinates();
var routeLength = routeCoords.length;
var routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
var startMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[0])
});
var endMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords[routeLength - 1])
});
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var repeat = false;
var timer = -1;
var style = function(feature, resolution) {
if (feature.get('type') == 'route') {
var styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8],
})
})
];
if (timer < 0) {
feature.unset('splitPoints', true);
} else {
var splitPoints = feature.get('splitPoints');
if (!splitPoints) {
splitPoints = splitLineString(feature.getGeometry(), 2 * resolution, {alwaysUp: false, midPoints: true});
feature.set('splitPoints', splitPoints, true);
}
if (!repeat && timer >= splitPoints.length) {
stopAnimation(true);
} else {
var index = timer % splitPoints.length;
var point = splitPoints[index];
styles.push(
new ol.style.Style({
geometry: new ol.geom.Point([point[0],point[1]]),
image: new ol.style.Icon({
src: 'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
rotation: point[2]
}),
zIndex: 1
})
);
}
}
return styles;
} else {
return [
new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/v4.6.5/examples/data/icon.png',
})
})
];
}
}
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, startMarker, endMarker]
}),
style: style
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-5639523.95, -3501274.52],
zoom: 10
})
});
var animating = false;
var token;
var speedInput = document.getElementById('speed');
var startButton = document.getElementById('start-animation');
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
startButton.textContent = 'Cancel Animation';
token = setInterval( function(){
timer++;
vector.setStyle(style);
}, 6000/speedInput.value);
}
}
function stopAnimation(ended) {
animating = false;
startButton.textContent = 'Start Animation';
clearInterval(token);
timer = -1;
if (!ended) {
vector.setStyle(style);
}
}
startButton.addEventListener('click', startAnimation, false);
html,
body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
.map {
height: 90%;
width: 100%;
}
<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="200">
</label>
<button id="start-animation">Start Animation</button>

Axes Range change dynamically

Does anybody know how can I change axis range in plotly's scatter3D via button click. I use relayout but it doesn't work
function updatet() {
Plotly.relayout(‘myDiv’, ‘zaxis.range’, [[0, 100]]);
}
Nothing happens (my range is still [0,1800])
For 3D plots zaxis.range needs to be inside scene in order to work.
Note: Your ticks look like some copy&paste/autoformat problem.
Plotly.d3.csv('https://raw.githubusercontent.com/plotly/datasets/master/3d-scatter.csv', function(err, rows) {
function unpack(rows, key) {
return rows.map(function(row) {
return row[key];
});
}
var trace1 = {
x: unpack(rows, 'x1'),
y: unpack(rows, 'y1'),
z: unpack(rows, 'z1'),
mode: 'markers',
marker: {
size: 12,
line: {
color: 'rgba(217, 217, 217, 0.14)',
width: 0.5
},
opacity: 0.8
},
type: 'scatter3d'
};
var trace2 = {
x: unpack(rows, 'x2'),
y: unpack(rows, 'y2'),
z: unpack(rows, 'z2'),
mode: 'markers',
marker: {
color: 'rgb(127, 127, 127)',
size: 12,
symbol: 'circle',
line: {
color: 'rgb(204, 204, 204)',
width: 1
},
opacity: 0.9
},
type: 'scatter3d'
};
var data = [trace1, trace2];
var layout = {
margin: {
l: 0,
r: 0,
b: 0,
t: 0,
}
};
Plotly.newPlot('myDiv', data, layout);
});
document.getElementById('updateButton').addEventListener('click', function() {
Plotly.relayout('myDiv', 'scene.zaxis.range', [0, 10 * Math.random()]);
});
<script src="https://cdn.plot.ly/plotly-latest.min.js">
</script>
<div id="myDiv" style="width:100%;height:100%"></div>
<button id='updateButton'>Change axis
</button>

KineticJS dynamically change the position of an object when other object is moved

I have a vertical and a horizontal lines and a circle on my stage, trying to keep the circle centered on the corssoing of the two lines when I move either line, here is my script that does not work:
var cy = 512;
var cx = 512;
var gy = 0;
var gx = 0;
var stage1 = new Kinetic.Stage({
container: 'container',
width: 1024,
height: 1024
});
var layer = new Kinetic.Layer();
var circle = new Kinetic.Layer();
var circle1 = new Kinetic.Circle({
x: cx + gx,
y: cy + gy,
radius: 140,
stroke: '#00ffff',
strokeWidth: 4,
opacity: 0.5
});
circle.add(circle1);
var GreenLine1 = new Kinetic.Line({
points: [0, 512, 1024, 512],
stroke: 'green',
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round',
opacity: 0.3
});
var BlueLine1 = new Kinetic.Line({
points: [512, 0, 512, 1024],
stroke: '#0080c0',
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round',
opacity: 0.5
});
var bgroup1 = new Kinetic.Group({
draggable: true,
dragBoundFunc: function (pos) {
return {
x: pos.x,
y: this.getAbsolutePosition().y
}
}
});
var ggroup1 = new Kinetic.Group({
draggable: true,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
}
}
});
bgroup1.add(BlueLine1);
ggroup1.add(GreenLine1);
layer.add(bgroup1);
layer.add(ggroup1);
stage1.add(circle);
stage1.add(layer);
BlueLine1.on('mouseover', function () {
document.body.style.cursor = 'e-resize';
});
BlueLine1.on('mouseout', function () {
document.body.style.cursor = 'default';
});
GreenLine1.on('mouseover', function () {
document.body.style.cursor = 'n-resize';
});
GreenLine1.on('mouseout', function () {
document.body.style.cursor = 'default';
});
ggroup1.on('dragend', function (event) {
var gy = ggroup1.getPosition().y;
circle.draw();
});
ggroup1.on('dragstart', function (event) {
circle1.moveTo(ggroup1);
});
bgroup1.on('dragstart', function (event) {
circle1.moveTo(bgroup1);
});
bgroup1.on('dragend', function (event) {
var gx = bgroup1.getPosition().x;
circle.draw();
});
I would appreciate your suggetions, thanks in advance
Keeping your circle in your crosshairs
May I suggest a simpler version of your code?
Instead of maintaining 2 groups and moving the circle between the 2 groups, how about just coding the circle to automatically redraw itself at the intersection of the 2 lines.
So when the user moves your GreenLine1 or BlueLine1, just move your circle1 to the intersection of your “crosshairs”.
First, add a custom drawFunc to your circle1 that causes it to always draw in the crosshairs:
drawFunc: function(canvas) {
var context = canvas.getContext();
var centerX=BlueLine1.getPosition().x;
var centerY=GreenLine1.getPosition().y;
context.beginPath();
context.arc(centerX, centerY, this.getRadius(), 0, 2 * Math.PI, false);
context.lineWidth = this.getStrokeWidth();
context.strokeStyle = this.getStroke();
context.stroke();
},
Then, whenever the user drags either line, just trigger circle1 to redraw itself:
// keep circle in center of crosshairs
stage1.getDragLayer().afterDraw(function() {
layer.draw();
});
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/cgF8y/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
function init(){
var cy = 512/2;
var cx = 512/2;
var gy = 0;
var gx = 0;
var stage1 = new Kinetic.Stage({
container: 'container',
width: 1024/2,
height: 1024/2
});
var layer = new Kinetic.Layer();
stage1.add(layer);
var circle1 = new Kinetic.Circle({
drawFunc: function(canvas) {
var context = canvas.getContext();
var centerX=BlueLine1.getPosition().x;
var centerY=GreenLine1.getPosition().y;
context.beginPath();
context.arc(centerX, centerY, this.getRadius(), 0, 2 * Math.PI, false);
context.lineWidth = this.getStrokeWidth();
context.strokeStyle = this.getStroke();
context.stroke();
},
x: cx + gx,
y: cy + gy,
radius: 140/2,
stroke: '#00ffff',
strokeWidth: 4,
opacity: 0.5
});
layer.add(circle1);
var GreenLine1 = new Kinetic.Line({
points: [0, 512/2, 1024/2, 512/2],
stroke: 'green',
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round',
opacity: 0.3,
draggable:true
});
layer.add(GreenLine1);
var BlueLine1 = new Kinetic.Line({
points: [512/2, 0, 512/2, 1024/2],
stroke: '#0080c0',
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round',
opacity: 0.5,
draggable:true
});
layer.add(BlueLine1);
// keep circle in center of crosshairs
stage1.getDragLayer().afterDraw(function() {
layer.draw();
});
BlueLine1.on('mouseover', function () {
document.body.style.cursor = 'e-resize';
});
BlueLine1.on('mouseout', function () {
document.body.style.cursor = 'default';
});
GreenLine1.on('mouseover', function () {
document.body.style.cursor = 'n-resize';
});
GreenLine1.on('mouseout', function () {
document.body.style.cursor = 'default';
});
layer.draw();
} // end init();
init();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>