diff --git a/examples.html b/examples.html index cec2858d1..91cd165c3 100644 --- a/examples.html +++ b/examples.html @@ -90,8 +90,9 @@ -

Map with some plotted cities and area labels (France)

+

Refreshable map of France with coloured cities and areas labels and zoom buttons

+
Alternative content for the map
diff --git a/examples.js b/examples.js index 2ca1d7ff7..84c16a651 100644 --- a/examples.js +++ b/examples.js @@ -15,10 +15,15 @@ $(function(){ , zoom: { enabled: true } + , defaultPlot : { + attrs : { + opacity : 0.6 + } + } }, areas: { "department-56" : { - text : "56", + text : {content : "56"}, tooltip: {content : "Morbihan (56)"} } }, @@ -33,9 +38,9 @@ $(function(){ latitude :45.758888888889, longitude: 4.8413888888889, value : 700000, - href : "#", + href : "http://fr.wikipedia.org/wiki/Lyon", tooltip: {content : "City : Lyon"}, - text : "Lyon" + text : {content : "Lyon"} }, 'rennes' : { type :"square", @@ -43,12 +48,61 @@ $(function(){ latitude : 48.114166666667, longitude: -1.6808333333333, tooltip: {content : "City : Rennes"}, - text : "Rennes", - attrs : {href : "#"} + text : {content : "Rennes"}, + href : "http://fr.wikipedia.org/wiki/Rennes" } } }); + $('#refreshmaparea2').on('click', function() { + + // Update some plots and areas attributes ... + var updatedOptions = {'areas' : {}, 'plots' : {}}; + updatedOptions.areas["department-56"] = { + tooltip : { + content : "Morbihan (56) (2)" + }, + attrs: { + fill : "#0088db" + }, + text : {content : "56 (2)"} + }; + updatedOptions.plots["rennes"] = { + tooltip : { + content : "Rennes (2)" + }, + attrs: { + fill : "#f38a03" + } + , text : {position : "top"} + , size : 5 + }; + + // add some new plots ... + var newPlots = { + "Limoge" : { + latitude : 45.834444, + longitude : 1.261667, + text : {content : "Limoge"}, + tooltip : {content : "Limoge"} + } + , "Dijon" : { + size:60, + latitude : 47.323056, + longitude : 5.041944, + text : { + content : "Dijon", + position : "left", + margin : 5 + } + } + } + + // and delete some others ... + var deletedPlots = ["paris", "lyon"]; + $(".maparea2").trigger('update', [updatedOptions, newPlots, deletedPlots, {animDuration : 1000}]); + }); + // Example #3 $(".maparea3").mapael({ map : { @@ -65,13 +119,15 @@ $(function(){ attrsHover : { animDuration:0 }, - textAttrs : { - cursor: "pointer", - "font-size" : 10, - fill :"#000" - }, - textAttrsHover : { - animDuration:0 + text : { + attrs : { + cursor: "pointer", + "font-size" : 10, + fill :"#000" + }, + attrsHover : { + animDuration : 0 + } }, eventHandlers : { click: function(e, id, mapElem, textElem) { @@ -89,18 +145,17 @@ $(function(){ } }; } - $(".maparea3").trigger('update', [newData, false, false, 0]); + $(".maparea3").trigger('update', [newData]); } } } }, areas: { "department-29" : { - text : "dblclick", + text : {content : "dblclick", position : "top"}, attrs : { fill :"#0088db" }, - textPosition: "top", tooltip: {content : "Finistère (29)"}, eventHandlers : { click: function() {}, diff --git a/js/jquery.mapael.js b/js/jquery.mapael.js index 1f0c1b6c6..0a85f54ee 100644 --- a/js/jquery.mapael.js +++ b/js/jquery.mapael.js @@ -24,7 +24,6 @@ , mapConf = $.fn.mapael.maps[options.map.name] , paper = new Raphael($container[0], mapConf.width, mapConf.height) , elemOptions = {} - , coords = {} , resizeTO = 0 , areas = {} , plots = {} @@ -43,34 +42,21 @@ , options.legend.area ); areas[id] = {'mapElem' : paper.path(mapConf.elems[id]).attr(elemOptions.attrs)}; + } + + // Init map areas in a second loop (prevent texts to be hidden by map elements) + for (id in mapConf.elems) { + elemOptions = $.fn.mapael.getElemOptions( + options.map.defaultArea + , (options.areas[id] ? options.areas[id] : {}) + , options.legend.area + ); $.fn.mapael.initElem(paper, areas[id], elemOptions, $tooltip, id); } // Draw plots for (id in options.plots) { - elemOptions = $.fn.mapael.getElemOptions( - options.map.defaultPlot - , (options.plots[id] ? options.plots[id] : {}) - , options.legend.plot - ); - - if (elemOptions.x && elemOptions.y) - coords = {x : elemOptions.x, y : elemOptions.y}; - else - coords = mapConf.getCoords(elemOptions.latitude, elemOptions.longitude); - - if ("square" == elemOptions.type) { - plots[id] = {'mapElem' : paper.rect( - coords.x - (elemOptions.size / 2) - , coords.y - (elemOptions.size / 2) - , elemOptions.size - , elemOptions.size - ).attr(elemOptions.attrs)}; - } else { // Default = circle - plots[id] = {'mapElem' : paper.circle(coords.x, coords.y, elemOptions.size / 2).attr(elemOptions.attrs)}; - } - - $.fn.mapael.initElem(paper, plots[id], elemOptions, $tooltip, id); + plots[id] = $.fn.mapael.drawPlot(id, options, mapConf, paper, $tooltip); } // Enable zoom @@ -85,35 +71,73 @@ * * Update the current map * Refresh attributes and tooltips for areas and plots - * @param options options to refresh - * @param resetAreas true to reset previous areas options - * @param resetPlots true to reset previous plots options - * @param animDuration animation duration in ms - * @param easing easing type + * @param updatedOptions options to update for plots and areas + * @param newPlots new plots to add to the map + * @param deletedPlotsplots to delete from the map + * @param opt option for the refresh : + * opt.resetAreas true to reset previous areas options + * opt.resetPlots true to reset previous plots options */ - $(this).on('update', function(e, updateOptions, resetAreas, resetPlots, animDuration, easing) { - var elemOptions = {} - , legend = {} + $(this).on('update', function(e, updatedOptions, newPlots, deletedPlots, opt) { + var i = 0 , id = 0 - , bbox = {} - , textPosition = {} - , plotOffset = 0 + , animDuration = 0 + , elemOptions = {} , resetHiddenElem = function(el) { if(typeof el.hidden != "undefined" && el.hidden == true) { $(el.node).trigger('click'); } }; - if (typeof animDuration == "undefined") animDuration = 300; - if (!easing) easing = 'linear'; - if (resetAreas) options.areas = {}; - if (resetPlots) options.plots = {}; - - $.extend(true, options, updateOptions); - areaLegend.forEach && areaLegend.forEach(resetHiddenElem); plotLegend.forEach && plotLegend.forEach(resetHiddenElem); + if (typeof opt != 'undefined') { + (opt.resetAreas) && (options.areas = {}); + (opt.resetPlots) && (options.plots = {}); + (opt.animDuration) && (animDuration = opt.animDuration); + } + + $.extend(true, options, updatedOptions); + + // Delete plots + if (typeof deletedPlots == 'object') { + for (;i < deletedPlots.length; i++) { + if (typeof plots[deletedPlots[i]] != 'undefined') { + if (animDuration > 0) { + (function(plot) { + plot.mapElem.animate({'opacity':0}, animDuration, 'linear', function() {plot.mapElem.remove();}); + if (plot.textElem) { + plot.textElem.animate({'opacity':0}, animDuration, 'linear', function() {plot.textElem.remove();}); + } + })(plots[deletedPlots[i]]); + } else { + plots[deletedPlots[i]].mapElem.remove(); + if (plots[deletedPlots[i]].textElem) { + plots[deletedPlots[i]].textElem.remove(); + } + } + delete plots[deletedPlots[i]]; + } + } + } + + // New plots + if (typeof newPlots == 'object') { + for (id in newPlots) { + if (typeof plots[id] == 'undefined') { + options.plots[id] = newPlots[id]; + plots[id] = $.fn.mapael.drawPlot(id, options, mapConf, paper, $tooltip); + if (animDuration > 0) { + plots[id].mapElem.attr({opacity : 0}); + plots[id].textElem.attr({opacity : 0}); + plots[id].mapElem.animate({'opacity': (typeof plots[id].mapElem.originalAttrs.opacity != 'undefined') ? plots[id].mapElem.originalAttrs.opacity : 1}, animDuration); + plots[id].textElem.animate({'opacity': (typeof plots[id].textElem.originalAttrs.opacity != 'undefined') ? plots[id].textElem.originalAttrs.opacity : 1}, animDuration); + } + } + } + } + // Update areas attributes and tooltips for (id in areas) { elemOptions = $.fn.mapael.getElemOptions( @@ -122,18 +146,7 @@ , options.legend.area ); - if (typeof elemOptions.value != "undefined") - areas[id].value = elemOptions.value; - - $.fn.mapael.setHoverOptions(areas[id].mapElem, elemOptions.attrs, areas[id].mapElem.attrsHover); - areas[id].mapElem.animate(elemOptions.attrs, animDuration, easing); - - if (elemOptions.tooltip && elemOptions.tooltip.content) { - areas[id].mapElem.tooltipContent = elemOptions.tooltip.content; - if (areas[id].textElem) { - areas[id].textElem.tooltipContent = elemOptions.tooltip.content; - } - } + $.fn.mapael.updateElem(elemOptions, areas[id], $tooltip, animDuration); } // Update plots attributes and tooltips @@ -144,38 +157,17 @@ , options.legend.plot ); - if (typeof elemOptions.value != "undefined") - plots[id].value = elemOptions.value; - - // Update text position - if (plots[id].textElem) { - bbox = plots[id].mapElem.getBBox(); - plotOffset = (elemOptions.size - bbox.height) / 2; - bbox.x -= plotOffset; - bbox.x2 += plotOffset; - bbox.y -= plotOffset; - bbox.y2 += plotOffset; - textPosition = $.fn.mapael.getTextPosition(bbox, elemOptions.textPosition); - plots[id].textElem.animate({x : textPosition.x, y : textPosition.y}, animDuration, easing); - } - // Update plot size if ("square" == elemOptions.type) { elemOptions.attrs.width = elemOptions.size; elemOptions.attrs.height = elemOptions.size; + elemOptions.attrs.x = plots[id].mapElem.attrs.x - (elemOptions.size - plots[id].mapElem.attrs.width) / 2; + elemOptions.attrs.y = plots[id].mapElem.attrs.y - (elemOptions.size - plots[id].mapElem.attrs.height) / 2; } else { // Default : circle elemOptions.attrs.r = elemOptions.size / 2; } - $.fn.mapael.setHoverOptions(plots[id].mapElem, elemOptions.attrs, plots[id].mapElem.attrsHover); - plots[id].mapElem.animate(elemOptions.attrs, animDuration, easing); - - if (elemOptions.tooltip && elemOptions.tooltip.content) { - plots[id].mapElem.tooltipContent = elemOptions.tooltip.content; - if (plots[id].textElem) { - plots[id].textElem.tooltipContent = elemOptions.tooltip.content; - } - } + $.fn.mapael.updateElem(elemOptions, plots[id], $tooltip, animDuration); } }); @@ -213,26 +205,19 @@ }; /** - * Init the element of the map (drawing, setting attributes, events, tooltip, ...) - * @param paper - * @param elem - * @param params - * @param $tooltip - * @param id + * Init the element 'elem' on the map (drawing, setting attributes, events, tooltip, ...) */ $.fn.mapael.initElem = function(paper, elem, options, $tooltip, id) { var bbox = {}, textPosition = {}; $.fn.mapael.setHoverOptions(elem.mapElem, options.attrs, options.attrsHover); - options.href && $.fn.mapael.setHref(elem.mapElem, options.href); - if (options.text) { + if (options.text && typeof options.text.content !='undefined') { // Set a text label in the area bbox = elem.mapElem.getBBox(); - textPosition = $.fn.mapael.getTextPosition(bbox, options.textPosition); - options.textAttrs['text-anchor'] = textPosition.textAnchor; - elem.textElem = paper.text(textPosition.x, textPosition.y, options.text).attr(options.textAttrs); - options.href && $.fn.mapael.setHref(elem.textElem, options.href); - $.fn.mapael.setHoverOptions(elem.textElem, options.textAttrs, options.textAttrsHover); + textPosition = $.fn.mapael.getTextPosition(bbox, options.text.position, options.text.margin); + options.text.attrs['text-anchor'] = textPosition.textAnchor; + elem.textElem = paper.text(textPosition.x, textPosition.y, options.text.content).attr(options.text.attrs); + $.fn.mapael.setHoverOptions(elem.textElem, options.text.attrs, options.text.attrsHover); $.fn.mapael.setHover(paper, elem.mapElem, elem.textElem); options.eventHandlers && $.fn.mapael.setEventHandlers(id, options, elem.mapElem, elem.textElem); $(elem.textElem.node).attr('data-id', id); @@ -245,26 +230,127 @@ elem.mapElem.tooltipContent = options.tooltip.content; $.fn.mapael.setTooltip(elem.mapElem, $tooltip); - if (options.text) { + if (options.text && typeof options.text.content !='undefined') { elem.textElem.tooltipContent = options.tooltip.content; $.fn.mapael.setTooltip(elem.textElem, $tooltip); } } + if (options.href) { + elem.mapElem.href = options.href; + $.fn.mapael.setHref(elem.mapElem); + + if (options.text && typeof options.text.content !='undefined') { + elem.textElem.href = options.href; + $.fn.mapael.setHref(elem.textElem); + } + } + if (typeof options.value != "undefined") elem.value = options.value; $(elem.mapElem.node).attr('data-id', id); } + + /** + * Update the element 'elem' on the map with the new elemOptions options + */ + $.fn.mapael.updateElem = function(elemOptions, elem, $tooltip, animDuration) { + var bbox, textPosition, plotOffset; + if (typeof elemOptions.value != "undefined") + elem.value = elemOptions.value; + + // Update text + if (elem.textElem) { + if (typeof elemOptions.text != 'undefined' && typeof elemOptions.text.content != 'undefined' && elemOptions.text.content != elem.textElem.attrs.text) + elem.textElem.attr({text : elemOptions.text.content}); + + bbox = elem.mapElem.getBBox(); + if (elemOptions.size) { + plotOffset = (elemOptions.size - bbox.height) / 2; + bbox.x -= plotOffset; + bbox.x2 += plotOffset; + bbox.y -= plotOffset; + bbox.y2 += plotOffset; + } + textPosition = $.fn.mapael.getTextPosition(bbox, elemOptions.text.position, elemOptions.text.margin); + if (textPosition.x != elem.textElem.attrs.x || textPosition.y != elem.textElem.attrs.y) { + if (animDuration > 0) { + elem.textElem.attr({'text-anchor' : textPosition.textAnchor}); + elem.textElem.animate({x : textPosition.x, y : textPosition.y}, animDuration); + } else { + elem.textElem.attr({x : textPosition.x, y : textPosition.y, 'text-anchor' : textPosition.textAnchor}); + } + } + } + + $.fn.mapael.setHoverOptions(elem.mapElem, elemOptions.attrs, elem.mapElem.attrsHover); + if (animDuration > 0) { + elem.mapElem.animate(elemOptions.attrs, animDuration); + } else { + elem.mapElem.attr(elemOptions.attrs); + } + + if (elemOptions.tooltip && typeof elemOptions.tooltip.content != 'undefined') { + if (typeof elem.mapElem.tooltipContent == "undefined") { + $.fn.mapael.setTooltip(elem.mapElem, $tooltip); + (elem.textElem) && $.fn.mapael.setTooltip(elem.textElem, $tooltip); + } + elem.mapElem.tooltipContent = elemOptions.tooltip.content; + (elem.textElem) && (elem.textElem.tooltipContent = elemOptions.tooltip.content); + } + + if (typeof elemOptions.href != 'undefined') { + if (typeof elem.mapElem.href == "undefined") { + $.fn.mapael.setHref(elem.mapElem); + (elem.textElem) && $.fn.mapael.setHref(elem.textElem); + } + elem.mapElem.href = elemOptions.href; + (elem.textElem) && (elem.textElem.href = elemOptions.href); + } + } /** - * + * Draw the plot */ - $.fn.mapael.setHref = function(elem, href) { + $.fn.mapael.drawPlot = function(id, options, mapConf, paper, $tooltip) { + var plot = {} + , coords = {} + , elemOptions = $.fn.mapael.getElemOptions( + options.map.defaultPlot + , (options.plots[id] ? options.plots[id] : {}) + , options.legend.plot + ); + + if (elemOptions.x && elemOptions.y) + coords = {x : elemOptions.x, y : elemOptions.y}; + else + coords = mapConf.getCoords(elemOptions.latitude, elemOptions.longitude); + + if ("square" == elemOptions.type) { + plot = {'mapElem' : paper.rect( + coords.x - (elemOptions.size / 2) + , coords.y - (elemOptions.size / 2) + , elemOptions.size + , elemOptions.size + ).attr(elemOptions.attrs)}; + } else { // Default = circle + plot = {'mapElem' : paper.circle(coords.x, coords.y, elemOptions.size / 2).attr(elemOptions.attrs)}; + } + + $.fn.mapael.initElem(paper, plot, elemOptions, $tooltip, id); + + return plot; + }; + + /** + * Set target link on elem + */ + $.fn.mapael.setHref = function(elem) { elem.attr({cursor : 'pointer'}); $(elem.node).bind('click', function() { - if (!$.fn.mapael.panning) - window.location = href; + if (!$.fn.mapael.panning && elem.href) + window.location = elem.href; }); } @@ -278,7 +364,12 @@ var tooltipTO = 0; $(elem.node).on("mouseover", function() { - tooltipTO = setTimeout(function() {$tooltip.html(elem.tooltipContent).css("display", "block");}, 120); + tooltipTO = setTimeout( + function() { + elem.tooltipContent && $tooltip.html(elem.tooltipContent).css("display", "block"); + } + , 120 + ); }).on("mouseout", function() { clearTimeout(tooltipTO); $tooltip.css("display", "none"); @@ -579,7 +670,7 @@ * @param bbox the boundary box of the element * @param textPosition the wanted text position (inner, right, left, top or bottom) */ - $.fn.mapael.getTextPosition = function(bbox, textPosition) { + $.fn.mapael.getTextPosition = function(bbox, textPosition, margin) { var textX = 0 , textY = 0 , textAnchor = ''; @@ -587,21 +678,21 @@ switch (textPosition) { case 'bottom' : textX = (bbox.x + bbox.x2) / 2; - textY = bbox.y2 + 15; + textY = bbox.y2 + margin; textAnchor = "middle"; break; case 'top' : textX = (bbox.x + bbox.x2) / 2; - textY = bbox.y - 15; + textY = bbox.y - margin; textAnchor = "middle"; break; case 'left' : - textX = bbox.x - 10; + textX = bbox.x - margin; textY = (bbox.y + bbox.y2) / 2; textAnchor = "end"; break; case 'right' : - textX = bbox.x2 + 10; + textX = bbox.x2 + margin; textY = (bbox.y + bbox.y2) / 2; textAnchor = "start"; break; @@ -648,14 +739,17 @@ fill : "#f38a03" , animDuration : 300 } - , textPosition : 'inner' - , textAttrs : { - "font-size" : 15 - , fill : "#c7c7c7" - } - , textAttrsHover : { - fill : "#eaeaea" - , "animDuration" : 300 + , text : { + position : 'inner' + , margin : 10 + , attrs : { + "font-size" : 15 + , fill : "#c7c7c7" + } + , attrsHover : { + fill : "#eaeaea" + , "animDuration" : 300 + } } } , defaultPlot : { @@ -671,14 +765,17 @@ "stroke-width" : 3 , animDuration : 300 } - , textPosition : 'right' - , textAttrs : { - "font-size" : 15 - , fill : "#c7c7c7" - }, - textAttrsHover : { - fill : "#eaeaea" - , animDuration : 300 + , text : { + position : 'right' + , margin : 10 + , attrs : { + "font-size" : 15 + , fill : "#c7c7c7" + } + , attrsHover : { + fill : "#eaeaea" + , animDuration : 300 + } } } , zoom : {