开发者

Complex JS onclick events from multiple elements

Ok ( the title may be misleading ) however it is the best i can come up with.

What we want to achieve ?

Ok we have an svg map, of Australia.

On click of a state on that map, the map state changes colour to selected. ( in our case Pink ) At the same time ( a useless button ) which is on page load blank, changes its value to that of the state. Simultaneously a drop down menu, with the state names in, which on page load has the value , Please Select , changes its value to that of the state.

So : here is what happens.

User visits page and sees map. They also see drop down select box.

They can choose to either click the select dropdown, or click the map.

Scenario 1. They click the map, and click on the state QUEENSLAND , which has a value of QLD.

On clicking the state, the state changes from grey to pink. The select drop down, changes from Please select, to Queensland The gray button changes from blank to QLD

Here is an image:

Complex JS onclick events from multiple elements

Ok what we have working is.

The map click events work, and propagate the grey button values, so thats all fine. The select element works, in so far as if we select a state on the map it changes select box value.

What we dont have working is.

  1. on click of map, we cannot propagate BOTH the select drop down and the gray button values.
  2. we cannot on using the select drop down box, change the "select" state of the map , ie, doesnt change from grey to pink. Also it doesnt change the value of the button from its current value.

So here is some code:

Its SVG so here is the wrap element for the map.

<a xlink:href="javascript:void goToOption(document.australia.state,'WA')" target="_top">
    <path
        id="WA"
        class="territory"
        fill="#a9a9a9"
        onmouseup="clickTerritory(evt)"
        d="m 38.318056,168.24244 c -4.79245,0.99662 -8.64245,1.61598 l -7,1.12612 -8.18526,4.91727 -8.18526,4.91727 -5.31474,-0.0902 c -2.92311,-0.0496 -6.88974,-0.54005 -8.81474,-1.08988 z"/></a>

Here is the JS that controls the map click events:

function prepare(){}
function ready(){
    svgdoc = document.sv.getSVGDocument();
    svgRoot = svgdoc.documentElement;
}
function onTerritoryClick(territory){
    document.getElementById("territory-name").innerHTML=territory;
}

var selected_territory = "None";

  function init(evt) {
    if (window.svgDocument == null)
    {
        svgDocument = evt.target.ownerDocument;
    }
  }

  function clickTerritory(evt) {
    var clicked_territory;

    if (evt.target.parentNode.getAttributeNS(null, "id") != "australia-map")
    {
        // Hack to deal with groups
        clicked_territory = evt.target.parentNode;
    } else {
        clicked_territory = evt.target;
    }

    if (selected_territory != clicked_territory) {
        if (selected_territory != "None") {
            // Unselect previous territory
            selected_territory.setAttributeNS(null, "fill", "#a9a9a9");
        }
        selected_territory = clicked_territory;
        selected_territory.setAttributeNS(null, "fill", "#ec008c");
        top.onTerritoryClick(selected_territory.getAttributeNS(null, "id"));
    } 
  }

Here is the JS to handle the select box, which fires the href.

function goToOption(sel, val) {
  var opt, o = 0;
  while (opt = sel[o++]) if (opt.value == val) sel.selectedIndex = o - 1;
}

Here is the button html:

<div class="selected-state left">
    <button id="territory-name" class="mystate grayNohover button" style="position:absolute;top:250px;left:50px">ALL</button> 
</div>

Here is the select menu html:

<select name="state" id="speedF" style="width:180px;">开发者_JAVA技巧
<option value="">Please Select</option>
<option value="QLD">Queensland</option>
<option value="NT">Northern Territory</option>
<option value="WA">Western Australia</option>                           
<option value="SA">South Australia</option>
<option value="NSW">New South Wales</option>
<option value="VIC">Victoria</option>
<option value="ACT">A.C.T.</option>
<option value="TAS">Tasmania</option>
</select>

sample: http://sitehelp.com.au/demos/svgmap2/

Version 2: http://dev.30.com.au/422-svg/


Well, I sort of got it to work hackily by adding this function and invoking this function when the select box value changes as,

<select onchange="selectChanged(this)">

Here's the function,

function selectChanged(el) {
    var selectedState = el.value;

    var event = document.createEvent('MouseEvents');
    event.initMouseEvent("mouseup", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

    var groups = document.getElementsByTagName('g');
    for (var i = 0; i < groups.length; i++) {
        if (groups[i].id == selectedState) {
            var path = groups[i].getElementsByTagName('path')[0];
            path.dispatchEvent(event);
            return;
        }
    }
}

It creates a mouseup event programmatically and triggers it against the <path> element that represents that state.

However, this is a very bad way to keep things in-sync. You might want to look into custom-events. With custom events, think of the DOM items as self-contained components that respond to events. The only event of interest here is the changing the state. So, the high-level interactions would be,

  • when select box changes, fire the stateChanged event with the value of the selected state
  • when user clicks on a map, fire the stateChanged event with the value of the selected state

Now the map, the gray button, and the select box, all listen to the stateChanged event. Whenever the state changes, they update themselves with the selected state. You could also provide yourself with programmatic access to change the state easily.

function changeState(newState) {
    // update map
    // update button
    // update select list
}

// add an app level event handler to listen for change of a state
app.handleEvent('stateChanged', changeState);

Then hook the map click, and select change actions back into this changeState function.

map.onclick = function(event) {
    var stateId = // get state-code of clicked portion
    app.triggerEvent('stateChanged', stateId);
}

selectList.onchange = function(event) {
    var stateId = this.value;
    app.triggerEvent('stateChanged', stateId);
}


For problem 2: add an onchange event to the dropdown.

<select onchange="handlechange()">

The handlechange function can get the value and use it to call clickterritory()

I'm not seeing question 1, as it appears to be working for me in your demos.


I'm not an expert in dealing with events, but this sounds like it requires expert knowledge of event bubbling and capturing.

So here is a page that might lead you in the right direction: http://www.quirksmode.org/js/events_order.html

I also happen to know that there is a whole chapter (12) in Nicholas Zakas' book Professional Javascript for Web Developers devoted to explaining events.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜