Klikk på en av grønne tekstene eller blå boksene,
og klikk en gang til for å fjerne markeringen. Markeringene skal overleve scroll, rezise og toggling av menyen til venstre
Jeg har 5 barn med forskjellig plassering
Jeg har negativ margin
Jeg er relativ
Jeg er absolute
Jeg er fixed (sorry)
Jeg bare er her
Vi er i en flex-box
alle
fire
Jeg bruker navnene markable og marked i klasselista til de markerbare elementene.
Disse to klassenavnene brukes bare til angivelse av status, og representerer ikke noe stilbeskrivelse. (Det er selvsagt her vi
kunne løst oppgaven svært enkelt, ved ganske enkelå toggle marked)
I utgangspunktet er det en enkel måte å finne et elements plassering i vinduet.
var rect = element.getBoundingClientRect();
der rect har properties: left, top, right, bottom. Problemet er at dette
ikke holder dersom plasseringsegenskapen til elementet ikke er fixed
og vi har scrollet vinduet eller endret størrelse på det.
For å få kontroll over dette kan vi bruke følgende funksjon for å finne top og left.
(fra kirupa
[1]
)
function getOffset( elt ) {
var x = 0;
var y = 0;
while( elt && !isNaN( elt.offsetLeft ) && !isNaN( elt.offsetTop ) ) {
x += elt.offsetLeft - elt.scrollLeft;
y += elt.offsetTop - elt.scrollTop;
elt = elt.offsetParent;
}
return { top: y, left: x };
}
Jeg benytter meg også av funksjonen:
window.getComputedStyle()
for å finne ut hva som er den aktuelle egenskapen til
et element. Dette er altså det samme som utviklerverktøyet i nettleseren viser
når vi ber om å få se den effektive (computed) verdien for stilegenskapene til et element.
Se MSD
[2]
for en bedre forklaring.
Javascriptet
// get element position and
// set/update/remove markerimage
var targets=[];
// object with element and image pair
function Marker(mE,mM){
this.mE=mE;// element to be marked
this.mM=mM;// marker image
this.getElement=function(){return this.mE;}
this.getMarker=function(){return this.mM;}
this.setMarker=function(m){this.mM=m;}
this.removeMarker=function(){
this.mM.parentNode.removeChild(this.mM);
this.mM=null;
}
this.updateMarker=function(){
if(!this.mM)
return;
var pos=getComputedStyles(this.mE,"position");
if(pos && (pos=="fixed")){
// not subject to scroll
var r=this.mE.getBoundingClientRect();
this.mM.setAttribute("style",
"position:fixed;top:"+r.top+"px;left:"+r.left+"px;");
}
else{
// must calculate
var where=getOffset( this.mE);
this.mM.setAttribute("style",
"position:absolute;top:"+where.top+"px;left:"+where.left+"px;");
}
}
}
// establish list of marakable elements and plant events
function setUp(){
targets=[];
var tList=document.querySelectorAll(".markable");
for(var i=0;i<tList.length;i++){
tList[i].addEventListener("click", toggleMarkerElt,false);
targets.push(new Marker(tList[i],null));
}
// when something happens to the window
window.addEventListener("scroll", updatePosition, false);
window.addEventListener("resize", updatePosition, false);
}
//mark/unmark
function toggleMarkerElt(e){
e.stopPropagation();
// find in targets
for(var i=0; i < targets.length; i++){
if(targets[i].getElement()==e.target){
if(targets[i].getMarker()!=null){
// remove
targets[i].removeMarker();
}
else{
// etablish
var im=document.createElement("img");
targets[i].setMarker(im);
im.setAttribute("src","marker.png");
im.setAttribute("alt","X");
im.setAttribute("class","markim");
// hang marker on body
var root=document.getElementsByTagName('body')[0];
root.appendChild(im);
im.addEventListener("click", removeImage, false);
e.target.classList.add("marked");
targets[i].updateMarker();
}
}
}
}
// we have clicke an image we want to remove
function removeImage(e){
for(var ix=0; ix < targets.length; ix++){
if(targets[ix].getMarker()==e.target){
targets[ix].removeMarker();
return;
}
}
}
// update all markers
function updatePosition(e){
for(var i=0;i< targets.length;i++){
targets[i].updateMarker();
}
}
// calc pos according to scroll
function getOffset( elt ) {
var x = 0;
var y = 0;
while( elt && !isNaN( elt.offsetLeft ) && !isNaN( elt.offsetTop ) ) {
x += elt.offsetLeft - elt.scrollLeft;
y += elt.offsetTop - elt.scrollTop;
elt = elt.offsetParent;
}
return { top: y, left: x };
}
// what is a style, used for position
function getComputedStyles(elt,prop) {
var cs = window.getComputedStyle(elt,null);
return cs.getPropertyValue(prop);
}
Stilsettet
/* the yellow box with the 5 children*/
.yellowbox{background-color:yellow;
border-style:solid;border-width:thin;color:green;
font-weight:bold;margin-left:70px;width:120px;
}
.box0,.box1,.box2,.box3,.box4{width:50px}
.box1{margin-left:-45px}
.box2{position:relative;left:150px; top:0px;}
.box3{position:absolute;left:350px; top:460px;}
.box4{position:fixed;left:400px; top:500px; }
/* a marker image, compensated for geeral image frame*/
.markim{width:20px;margin-left:-7px;margin-top:-7px}
/* the flexcontainer */
.container{
display: flex;
display: -webkit-flex;
flex-flow: row;
-webkit-flex-flow: row;
justify-content: space-around;
-webkit-justify-content: space-around;
min-height: 50px;
margin-top:30px;
}
.container > div{border-style:solid;border-width:thin;border-color:blue;padding:7px}