I've been working on drawing a simplify animated voyage of James Cook on a map with D3.
Projection is equirectangular. The data is a set of geographical points which I use to create pathLines bewteen two points looping the JSON object.
I animate then for each patLines a ship and draw the line step by step using stroke-dasharray.
NB: I didn't include TopoJSON data on the Jsfiddle.
Here is the jsfiddle: http://jsfiddle.net/yoannlal/16yrfka5/22/
var cook = [
{"name": "Plymouth", "year": 1768, "month": 08, "day": 26, "coordinates": [-4.1397, 50.3706]},
{"name": "Rio de Janeiro", "year": 1768, "month": 12, "day": 06, "coordinates": [-43.2436, -22.9083]},
{"name": "Car horn", "year": 1769, "month": 01, "day": 20, "coordinates": [-67.2717, -55.9797]},
{"name": "Pacific", "year": 1769, "month": 03, "day": 01, "coordinates": [-110.55, -38.733333]},
{"name": "Possession Island", "year": 1770, "month": 09, "day": 22, "coordinates": [142.3959417, -10.7226237]},
{"name": "Cape of Good Hope", "year": 1771, "month": 04, "day": 15, "coordinates": [18.4737341, -34.3570248]},
{"name": "Saint Helena", "year": 1771, "month": 05, "day": 15, "coordinates": [-5.7, -15.9333]},
{"name": "Baleares", "year": 1771, "month": 06, "day": 15, "coordinates": [-25.6, 37.7]},
{"name": "Plymouth", "year": 1771, "month": 07, "day": 13, "coordinates": [-4.1397, 50.3706]}
];
var width = document.getElementById('map').offsetWidth;
var height = document.getElementById('map').offsetHeight;
var projection = d3.geo.equirectangular()
.scale((width/640)*100)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height);
function transition(ship, route, routeNbr, delay) {
var l = route.node().getTotalLength();
var dateStart = new Date(cook[routeNbr].year, cook[routeNbr].month, cook[routeNbr].day);
var dateEnd = new Date(cook[routeNbr+1].year, cook[routeNbr+1].month, cook[routeNbr+1].day);
var journeyDays = d3.time.days(dateStart, dateEnd);
voyageDays[routeNbr] = journeyDays.length;
if(routeNbr === 0){
voyageTransition[0] = ship.transition() .duration(voyageDays[routeNbr]*coef)
.ease("linear")
.attrTween("transform", tweenCustom(ship, route, journeyDays));
}
else{
voyageTransition[routeNbr] = voyageTransition[routeNbr-1].transition() .duration(voyageDays[routeNbr]*coef)
.delay(delay)
.ease("linear")
.attrTween("transform", tweenCustom(ship, route, journeyDays));
}
delay += (voyageDays[routeNbr]*coef);
routeNbr++;
if(routeNbr < cook.length-1){
discover(ship, routeNbr, cook[routeNbr], cook[routeNbr+1], delay);
}
function tweenCustom(ship, route, journeyDays){
var header = d3.select(".header");
var n = 0;
return function(i) {
return function(t) {
var l = route.node().getTotalLength();
var p = route.node().getPointAtLength(t * l);
interpolate = d3.interpolateString("0," + l, l + "," + l);
route.style("stroke-dasharray", interpolate(t));
return "translate(" + (p.x - 10) + "," + (p.y - 10) + "), scale(0.1)";
}
}
}
}
function discover(ship, routeNbr, startPoint, endPoint, delay){
var route = svg.append("path")
.attr("class","route")
.datum({type: "LineString", coordinates: [startPoint.coordinates, endPoint.coordinates]})
.attr("d", path)
.attr("fill","none")
.attr("stroke", "#5f4c4c")
.style('stroke-dasharray', function(d) {
var l = d3.select(this).node().getTotalLength();
return "0, "+l;
});
transition(ship, route, routeNbr, delay);
}
var ship = svg.append("path")
.attr("d", "M 93,0 L 0,81 L 0,82 L 37,104 L 32,108 L 54,128 L 182,128 L 182,118 L 183,115 L 189,112 L 192,105 L 191,92 L 191,87 L 193,81 L 153,30 L 156,20 L 156,19 L 146,21 L 133,4 L 131,3 L 95,0 L 93,0 z M 93,1 L 93,21 L 71,26 L 71,27 C 67,37 67,49 73,59 L 73,61 C 69,70 71,80 76,88 L 74,88 L 70,92 C 52,64 53,37 69,22 C 84,8 93,1 93,1 z M 95,1 L 131,4 L 131,24 L 112,29 L 112,30 L 113,30 L 110,44 C 105,37 109,26 113,19 L 113,18 L 95.5,20.5 L 95,1 z M 133,5 L 145,21 L 133.5,23.5 L 133,5 z M 109,20 L 95.5,25 L 95.5,22.5 L 109,20 z M 154,20.5 L 148,23 L 147,22 L 154,20.5 z M 146,22.5 L 147,23.5 L 133.5,28 L 133.5,25.5 L 146,22.5 z M 93,23 L 93,25 C 88,27 82,28 77,26 L 93,23 z M 131,26 L 131,28 L 118,29 L 131,26 z M 153,31 L 192,81 L 168,85 L 161,90 C 157,80 159,68 162,58 L 163,58 L 163,56 L 162,56 C 155,49 151,41 153,31 z M 109,53 L 97,55 L 97,54 L 109,53 z M 94,54 L 94,55.5 L 76,59 C 81.130294,54.824798 88.927822,54.383689 94,54 z M 111,54.5 L 97,59 L 97,57 L 111,54.5 z M 94,57.5 L 94,60 C 89,61 83,61 78,60 L 94,57.5 z M 158,57 L 136,60 L 136,58 C 143,56.5 150.5,57 158,57 z M 160,58 C 152.5,62 144.5,64.5 136,65 L 136,62 L 160,58 z M 132,59 L 132,60.5 L 122,63 L 132,59 z M 114,62 L 116,65 L 113,73 C 113,73 112,66 114,62 z M 132,62.5 L 132,65 L 119,65 L 132,62.5 z M 69,92 C 61,102 51.5,105 40,100 L 2,81 C 2,81 5,77 9,75 C 31,62.5 52,81 69,92 z M 95,86 L 95,88 L 82,89 C 86,87.5 90.5,86.5 95,86 z M 98,86 L 112,87 L 98,88 L 98,86 z M 112,88 C 112.5,92.5 115.31835,98.819349 116,100 L 116,102 L 134,101 L 134,113 C 120,115 114,108 109,96 L 103,95 L 102,91 L 98,91 L 98,89 L 112,88 z M 95,89 L 95,90 L 88.5,89.5 L 95,89 z M 134,96 L 134,99 L 121,100 L 134,96 z M 137,96 L 154,97 L 137,99 L 137,96 z M 154,99 C 154,110 147,113.5 137,113 L 137,101 L 154,99 z ")
.attr("class", "ship");
var routeNbr = 0;
// Coef pour multplication des durées d'animation
var coef = 20;
var voyageTransition = [];
var voyageDays = [];
var delay = 0;
discover(ship, routeNbr, cook[routeNbr], cook[routeNbr+1], delay);
One issue:
When the path has to cross the earth edge (on the pacific, from Tahiti to NZ for example), the tween function seems to loose smoothness. The timer (t) inside the tween is slower and takes less values. Plus, stroke-dasharray starts on two points and draw an unwanted line on the middle of the pathline.
One solution was to analyse the pathline and split it on each L on the pathSegList[i], create two suPath and send it to the animation, but my code lines are doubled with that one.
Any better solution to propose or explanation why the timer and stroke-dasharray are working that way on this example ?
One question:
One the same example, I'm trying to link the animation timer and the date. I'm calculating the days difference between two points and use it to control the current pathline animation duration. Any idea how can I link this number to the timer (t) inside the tween function that I can have the dates display on the map and the correct location ?
Thanks a lot !
Yoann
I'm building a site that has an svg map of the United States using the very easy usmap jquery plugin which uses Raphael. I have a click event that fires if you click an individual state.
On that occasion, I go to the same US States object to render a single state. The problem is that the paths for each state in the list are relative to each other as rendered in the entire US map of states.
But my requirements are that I need to render each state about the same size as each other when I'm viewing a single state.
I know I can put a multiplier on the path parameters and the overall state will increase/decrease, but I'm looking for a method to determine this multiplier dynamically.
I also tried to use setViewBox, hoping it would increase/decrease the <path> to fill the area. But it didn't work, as far as I could tell.
So, either I need to make the <path> fill the space or I need to figure out a multiplier to apply to scale the <path>
// state coords pulled from All states svg file
var statePolygon = "M 93.573239,6.3617734 L 97.938071,7.8167177 L 107.6377,10.564946 L 116.2057,12.504871 L 136.2516,18.162988 L 159.20739,23.821104 L 174.36801,27.215777 L 173.36373,31.099829 L 169.27051,44.909503 L 164.81238,65.714155 L 161.63584,81.854036 L 161.28429,91.232806 L 148.10315,87.33877 L 132.53264,83.955591 L 118.86585,84.551329 L 117.28528,83.01913 L 111.95881,84.916253 L 107.9821,84.665645 L 105.2606,82.904814 L 103.68223,83.430208 L 99.476903,83.201576 L 97.601755,81.829846 L 92.824862,80.093194 L 91.382778,79.886558 L 86.397035,78.560984 L 84.614222,80.069004 L 78.922841,79.726077 L 74.101997,75.931831 L 74.30643,75.131651 L 74.374575,67.197996 L 72.248826,63.31142 L 68.133618,62.57938 L 67.768708,60.225014 L 65.2543,59.597968 L 62.372763,59.063086 L 60.594498,60.033049 L 58.331251,57.123161 L 58.654572,54.213272 L 61.4028,53.889951 L 63.019405,49.84844 L 60.432837,48.716816 L 60.594498,44.998625 L 64.959331,44.351984 L 62.211103,41.603756 L 60.756158,34.490695 L 61.4028,31.580807 L 61.4028,23.659444 L 59.624535,20.426234 L 61.887782,11.049927 L 63.989368,11.534908 L 66.414275,14.444797 L 69.162503,17.031364 L 72.395712,18.97129 L 76.922205,21.072876 L 79.993756,21.719518 L 82.903645,23.174462 L 86.298518,24.144425 L 88.561764,23.982765 L 88.561764,21.557857 L 89.855048,20.426234 L 91.956634,19.13295 L 92.279955,20.264574 L 92.603276,22.042839 L 90.340029,22.52782 L 90.016708,24.629406 L 91.794974,26.084351 L 92.926597,28.509258 L 93.573239,30.449183 L 95.028183,30.287523 L 95.189843,28.994239 L 94.219881,27.700955 L 93.734899,24.467746 L 94.543201,22.689481 L 93.89656,21.234537 L 93.89656,18.97129 L 95.674825,15.41476 L 94.543201,12.828192 L 92.118294,7.9783781 L 92.441615,7.1700758 z M 84.116548,12.340738 L 86.137312,12.179078 L 86.622294,13.553197 L 88.158073,11.936582 L 90.502155,11.936582 L 91.310458,13.472361 L 89.774678,15.169801 L 90.42133,15.978114 L 89.693853,17.998875 L 88.319734,18.403021 C 88.319734,18.403021 87.430596,18.483857 87.430596,18.160536 C 87.430596,17.837215 88.885551,15.573958 88.885551,15.573958 L 87.188111,15.008141 L 86.86479,16.463095 L 86.137312,17.109737 L 84.60153,14.84648 z";
var width = 175,
height = 125,
paper = Raphael(document.getElementById("statemap"), 350, 250);
paper.setViewBox(0, 0, width, height, true);
// paper.canvas.setAttribute('preserveAspectRatio', true);
paper.path(statePolygon);
Anyone have any ideas?
Update
So, I figured out (thanks, Jordan) that you can get a "size" dimension by capturing the difference between all of the X coord (can be done with y, if you'd rather.) By calculating the diff between the lowest X and the highest X you can get a size.
If you then figure out what a 'normal' size would be, you can then determine a multiplier to apply to each state as a fraction of the state's size relative to the 'normal' one.
In my example, the diff in Kansas is 128. CT is 29, so CT needs a multiplier of 4.41 to bring it up to the relative size of Kansas. TX is 242, so it needs a 0.53 multiplier to bring it down.
This normalizes the sizes of the states. If you then, using Raphael, need to increase/decrease this, you can use the transform function:
p = paper.path(statePolygonNew);
var scale = 1.5;
p.transform("t" + scale*52 + "," + scale*32 + " s" + scale + "");
Thanks,
Scott
There are a number of different ways of approaching this. Here are two of them.
Match the viewbox to the existing path
You used this method incorrectly when you were first seeking a solution. The viewbox is essentially a mechanism for dynamically scaling the way that coordinates in the SVG are translated into coordinates on a screen. By setting the viewbox to the dimensions of the svg in screen coordinates, you are effectively telling it to do nothing -- that's what it does by default.
Instead, try setting the viewbox to the bounding box of the target path:
var statePathString = "..."; // your path here
var statePath = paper.path( statePathString ).attr( { /* your attributes */ } );
var bbox = statePath.getBBox();
paper.setViewBox( bbox.x, bbox.y, bbox.width, bbox.height, true );
This instantiates the path for the state, calculates its dimensions, and zooms the viewbox in to look at just that range of the SVG's coordinate systems. You may need to add additional logic to preserve aspect ratios and add margin, but this is definitely the easiest approach.
Transform the path to fit your existing viewbox
If you do opt to avoid viewbox manipulation -- there are a few valid reasons -- then you can adjust the path to match the default viewing rectangle using a handful of Raphael's built-in utility functions. Here's the approach I'd use, given existing variables width and height reflecting the dimensions of your paper:
var bbox = Raphael.pathBBox( statePathString ); // Handy function to retrieve a bounding box without instantiating a path
// Calculate larger of the two dimensional quotients
var scale = Math.max( bbox.width / width, bbox.height / height );
// Finally, transform the path such that it is translated to have its origin at 0,0 and scaled in such a way that it will fill the SVG
var transformedPathString = Raphael.transformPath( statePathString,
[ "T", 0 - bbox.x, 0 - bbox.y, /* Shift up and left so upper-left extent corresponds to 0,0 */
"S", 1.0 / scale, 1.0 / scale, 0, 0 ] );
At this point you can do whatever you'd like to do with transformedPathString -- presumably, pass it to paper.path and style it up.
I have seen several threads that adress this question but nothing that really solves my problem. I have a SVG file with Finland counties.. What I want to do is map like this: http://raphaeljs.com/australia.html.
I converted the SVG file to Raphael JS in here http://www.irunmywebsite.com/raphael/SVGTOHTML_LIVE.php and I'm tryig to sink that converted code into html page, but it just doesn't seem to work.. The question is why it isn't working..? Everything is supposed to be correct but it just don't draw anything. I also tryed to make exactly the same code as in raphael australia with those different paths from the map of Finland though (and tryed dirrerent converters as well).. But still nothing..
I'm pretty new with JavaScript and I have studyed and spended a lot of time with this SVG file as well.. so I'm getting little bit frustrated.. Can someone please help me..? I post the code on here under:
<!DOCTYPE HTML>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Raphaël - Finland</title>
<style type="text/css" media="screen">
#canvas { height: 480px; margin: 0 auto; text-align: left; width: 640px; }
</style>
<script src="raphael.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
window.onload = function () {
paper.setStart();
pohj_pohjanmaa=paper.path('M 148.9 256.5 L 149.8 256.1 L 150.6 256.8 L 150.6 257.7 L 148.7 258.4 L 146.9 257.2 L 145.4 257.6 L 146.4 261 L 145.1 261.9 L 143.5 260.9 L 141.8 261.4 L 140.3 257.7 L 141.2 256.1 L 146.2 254.9 L 147.6 256.5Z');
pohj_pohjanmaa.attr({'stroke-width':'1.9','stroke-miterlimit':'4','fill':'#000000','stroke':'none','stroke-opacity':'1'});
lappi=paper.path('M 215.6 213.7 L 218.3 212.3 L 221 213.1 L 221.9 212.4 L 221.8 209.9 L 219.9 208.6 L 220 206 L 221.4 205.7 L 222.1 201 L 219.3 199.9 L 217.4 195.8 L 218.1 193.1 L 220.4 192.2 L 220.3 189.7 L 231.4 192.3 L 238.2 191.4 L 236.4 186.6 L 226.8 170.3 L 227.9 166.6 L 242.6 139 L 243.2 132.2 L 236.2 127.1 L 229.1 112.6 L 218.3 108.2 L 214.6 92.9 L 219 85.1 L 219.9 78.1 L 218.7 76.1 L 213.8 76.1 L 221.9 69.3 L 220.3 63.9 L 220.9 58.8 L 228.6 48.7 L 224.2 37.5 L 211.1 31 L 210.8 28.2 L 206.8 25.7 L 202.7 19.9 L 200.3 21.4 L 198 20.6 L 196.4 23 L 190 28 L 182.6 26.1 L 178.4 27.6 L 175.8 33.8 L 171.4 37.7 L 169.2 41.1 L 170.1 43.5 L 168.6 46.1 L 165.9 61.8 L 166.5 71.1 L 165 76.4 L 161.9 75.6 L 159.1 77.3 L 155.4 82.8 L 155.8 88.2 L 153.2 88.1 L 152.3 90 L 148.7 85.6 L 142.1 82.7 L 135.9 78.1 L 132.8 79.8 L 131.1 82.7 L 127 84.2 L 122.6 86.1 L 121.6 84 L 116.8 83.5 L 112.2 80.1 L 109.5 81.3 L 109.8 76.1 L 99.3 54.8 L 93.1 52.7 L 89.3 54.6 L 86.7 57.7 L 88.2 61.7 L 87.4 64.4 L 82.5 60.6 L 79 64 L 83.5 69.7 L 83.8 73.7 L 87.2 74.6 L 92.1 84.8 L 95.6 85.9 L 96.9 89.1 L 100.3 90.8 L 101.6 94.7 L 106.5 95.8 L 113 98.8 L 120 105.3 L 120.1 109.6 L 121 112.2 L 123.1 111.9 L 124 116.1 L 128 120.3 L 126.3 122.2 L 125 124.4 L 125 127.2 L 125.2 135.7 L 122.9 141.5 L 124.6 144.6 L 128.8 145.4 L 127.7 147.7 L 128.5 150.5 L 125 152.3 L 124.8 157 L 131.9 173.5 L 129.3 176.4 L 128.8 184.8 L 126.1 187.1 L 125.4 189.5 L 124.5 192.2 L 125.2 194.7 L 124.5 196.5 L 125.6 202.4 L 128.7 205.3 L 128.8 208.4 L 131.3 212.5 L 131.6 215.5 L 133.1 219.6 L 133.1 222.9 L 134.8 222.7 L 136 220.8 L 137.4 222.6 L 140.5 223.7 L 141.5 225.2 L 140.4 227.5 L 141.2 228.4 L 142.7 227.4 L 143.3 229.3 L 144.6 229.2 L 145.6 228.3 L 147.7 228.6 L 148.9 230.3 L 150.3 230.1 L 151.2 231.1 L 151.2 231.2 L 153.4 228.9 L 156.6 227.3 L 157.1 225.1 L 165.1 225.5 L 172 221.1 L 172.6 225.6 L 186.3 226.8 L 191 225.2 L 197.4 214.9 L 199.4 215.8 L 201 215.1 L 203 220.2 L 213.2 221.8 L 217.6 219.9 L 217.8 217Z');
lappi.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
pohj_pohjanmaa2=paper.path('M 244.1 234.8 L 245 232 L 243.4 229.3 L 247.6 226.5 L 250.5 226.2 L 249.2 217.1 L 244.8 204.4 L 241 199 L 238.2 191.4 L 231.4 192.3 L 220.3 189.7 L 220.4 192.2 L 218.1 193.1 L 217.4 195.8 L 219.3 199.9 L 222.1 201 L 221.4 205.7 L 220 206 L 219.9 208.6 L 221.8 209.9 L 221.9 212.4 L 221 213.1 L 218.3 212.3 L 215.6 213.7 L 217.8 217 L 217.6 219.9 L 213.2 221.8 L 203 220.2 L 201 215.1 L 199.4 215.8 L 197.4 214.9 L 191 225.2 L 186.3 226.8 L 172.6 225.6 L 172 221.1 L 165.1 225.5 L 157.1 225.1 L 156.6 227.3 L 153.4 228.9 L 151.2 231.1 C 151.3 231.2 151.4 231.3 151.5 231.4 L 151.6 233.4 L 152.7 233.4 L 153.3 232.7 L 156.2 237.7 L 156 239.6 L 154.8 240.9 L 154.8 243.1 L 153.8 244.2 L 154.7 245.7 L 154.6 250.4 L 153.3 252.2 L 154 253.6 L 155.9 254.7 L 156.6 256.1 L 157.1 259.2 L 158.5 260.7 L 158.4 261.5 L 157.5 261.5 L 155.3 259.7 L 153.3 259.6 L 152.9 260.6 L 153.1 261.8 L 156 264.8 L 156.6 266.5 L 155.9 267.2 L 154.5 267.1 L 154.2 265.5 L 151.3 263.8 L 148.6 263.8 L 147.1 264.9 L 143.9 265 L 142.8 265.9 L 142.2 267.1 L 140.4 267.3 L 139.6 271.2 L 136.7 273.2 L 135.2 279.7 L 133.3 281.2 L 133.2 282.2 L 130.6 283.9 L 127.5 287.2 L 127.1 288.3 L 125.9 290.2 L 125.9 292.4 L 125 292.9 L 123.8 292.1 L 122.5 294.1 L 121.4 295 L 120.3 296.7 L 118.8 299 L 118.6 302.5 L 121.6 306.6 L 123.4 306.6 L 124.8 307.8 L 126 307.2 L 124.7 305.4 L 125.9 303.1 L 129 302.5 L 130.4 308.2 L 132 309 L 132.7 312.1 L 135 313 L 137.4 320.4 L 146.7 331.7 L 149.3 331.4 L 150.3 325.3 L 152.5 324.4 L 159.5 329.2 L 163 329.2 L 164.5 330.4 L 165.8 333.3 L 170.4 333.2 L 172.8 326.4 L 174.1 325.6 L 173 314.3 L 180.4 307.4 L 185.6 305.7 L 184 303.6 L 184 293.1 L 181.6 291.5 L 179.9 291.8 L 177.7 289.9 L 178 287.8 L 176.9 285.3 L 174.9 284 L 178.7 280.2 L 180.7 279.6 L 181.4 277.2 L 185.7 275.1 L 187.2 270.8 L 191.1 268.9 L 191.2 267.8 L 195.8 268.9 L 196.6 266.6 L 196.2 260.4 L 193.7 258.3 L 195.6 255.2 L 199.8 255.2 L 201.9 253.5 L 204.4 253.9 L 206.5 255.3 L 207.4 249.7 L 209.6 248.3 L 220.5 246.4 L 221 241.4 L 227.1 238.5 L 228.4 239.5 L 230.6 238.9 L 232.5 234.9 L 233.4 235.6 L 238.6 235.9 L 244.1 234.8Z');
pohj_pohjanmaa2.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
kainuu=paper.path('M 250.7 277.9 L 252.4 276.5 L 252.5 273.5 L 250.9 271.5 L 251.6 269.1 L 244 267.5 L 241.8 259 L 242.6 256 L 245.5 255 L 246.6 252.7 L 245.5 251.3 L 246.8 248.6 L 245.6 247.2 L 241.7 246.9 L 243.3 241.3 L 243.7 236.5 L 244.2 234.7 L 238.6 235.9 L 233.4 235.6 L 232.5 234.9 L 230.6 238.9 L 228.4 239.5 L 227.1 238.5 L 221 241.4 L 220.5 246.4 L 209.6 248.3 L 207.4 249.7 L 206.5 255.3 L 204.3 253.9 L 201.9 253.5 L 199.8 255.2 L 195.6 255.1 L 193.7 258.3 L 196.2 260.4 L 196.6 266.6 L 195.8 268.9 L 191.2 267.8 L 191.1 268.9 L 187.2 270.8 L 185.7 275.1 L 181.4 277.2 L 180.7 279.6 L 178.7 280.2 L 174.9 284 L 176.9 285.3 L 178 287.8 L 177.7 289.9 L 179.9 291.8 L 181.6 291.5 L 184 293.1 L 184 303.6 L 185.6 305.7 L 192.1 308.1 L 199.7 308.7 L 209 314.6 L 215 321.6 L 219 312.3 L 229.1 314.2 L 244.1 311.5 L 247.3 319.5 L 249.3 317.2 L 253.1 317.6 L 252.8 317.3 L 257.6 313.9 L 262.8 300.5 L 261.2 293.1 L 253.1 287.6 L 250.7 281.3Z');
kainuu.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
etela_karjala=paper.path('M 225.9 363.5 L 224 364 L 226.6 369.9 L 228.5 370.5 L 232.6 374.3 L 232.9 375.9 L 235.1 377.7 L 234.2 379.8 L 236.3 381.3 L 238.4 380.1 L 239.6 381.6 L 239.6 384.1 L 242.4 388.7 L 244.1 397.8 L 247 399 L 248.1 401.7 L 247.2 402.9 L 248.9 406.3 L 247 411.8 L 260.4 404.6 L 263.1 401.8 L 269 391.3 L 273.4 384.7 L 276.2 383.6 L 281.5 373.8 L 287.7 354.1 L 285.9 349.5 L 280.6 345.2 L 278.9 339.3 L 275.1 336.7 L 270.4 332.9 L 263.7 329.9 L 261 326.1 L 253 317.6 L 249.3 317.3 L 247.2 319.5 L 244.1 311.5 L 229.1 314.2 L 219 312.4 L 216.6 317.8 L 219.6 321 L 221.9 321.2 L 222.5 326 L 223.8 327 L 222.8 328.5 L 223.4 334 L 225.7 335.3 L 225.7 338.6 L 223.7 342.3 L 225.3 343.8 L 228.8 351.1 L 233.6 353.6 L 230.4 355.9 L 233 359.5 L 230.3 363.3 L 226.5 361.7Z');
etela_karjala.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
etela_savo=paper.path('M 173.8 428.4 L 173.9 430.3 L 176.1 432.3 L 177.4 432.5 L 177.6 434.9 L 179.2 434.2 L 181.6 438 L 183.9 436.9 L 183.9 434.5 L 186.9 434.6 L 186.9 438.6 L 191.1 440.7 L 193.5 439.9 L 196.8 439.1 L 199.2 435 L 201.5 434.8 L 202.9 431.9 L 205.6 432 L 207.1 430.1 L 209.6 430.6 L 217 429.9 L 220.8 425.2 L 222 422.4 L 224.1 424.1 L 229.7 424 L 230.4 421.5 L 235 421.7 L 239.6 420.2 L 242.4 415.5 L 246.1 414.3 L 246.9 411.9 L 247 411.8 L 248.9 406.3 L 247.2 402.9 L 248.1 401.7 L 247 399 L 244.1 397.8 L 242.4 388.7 L 239.6 384.1 L 239.6 381.6 L 238.4 380.1 L 236.3 381.3 L 234.2 379.8 L 235.1 377.7 L 232.9 375.9 L 232.6 374.3 L 228.5 370.5 L 226.6 369.9 L 225.1 370.3 L 221.2 374.2 L 219.2 374.2 L 219.2 378.6 L 217.4 378.4 L 216 380.7 L 217.6 381.9 L 216.7 383.8 L 219.4 383.7 L 219.5 386 L 222 385.4 L 225.5 389.7 L 224.4 392.3 L 217.5 389.6 L 213.2 390.1 L 210.6 387.8 L 206.8 387.6 L 204.6 383.8 L 197 377.1 L 193.3 379.6 L 191.7 377.6 L 188.5 378.4 L 187.7 379.6 L 185.5 378.7 L 183.1 379.9 L 181.5 381 L 184 383.8 L 181.8 384.6 L 180.5 390.1 L 177.9 388.7 L 174.2 391 L 172.1 395.2 L 175.4 401.3 L 174.5 402.8 L 175.2 410.9 L 178.4 415.6 L 177.6 418.5 L 174.8 417.6 L 174.4 418.6 L 172.9 422.6 L 172.4 427.4Z');
etela_savo.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
pohj_savo=paper.path('M 222.8 328.5 L 223.8 327 L 222.5 326 L 221.9 321.2 L 219.6 321 L 216.6 317.8 L 215 321.6 L 209 314.6 L 199.7 308.7 L 192.1 308.1 L 185.6 305.7 L 180.4 307.4 L 173 314.3 L 174.1 325.6 L 172.8 326.4 L 170.4 333.2 L 169.4 337.1 L 171 339.3 L 171.5 347.2 L 174.5 351.5 L 172.7 352.7 L 174.1 354.1 L 172.9 356.1 L 168.6 356.7 L 174.8 364.5 L 176.7 364.1 L 179.3 368.1 L 180 372.4 L 177.1 375.6 L 177.1 376.9 L 180.5 379 L 182.1 378.8 L 183.1 379.9 L 185.5 378.7 L 187.7 379.6 L 188.5 378.4 L 191.7 377.6 L 193.3 379.6 L 197 377.1 L 204.6 383.8 L 206.8 387.6 L 210.6 387.8 L 213.2 390.1 L 217.5 389.6 L 224.4 392.3 L 225.5 389.7 L 222 385.4 L 219.5 386 L 219.4 383.7 L 216.7 383.8 L 217.6 381.9 L 216 380.7 L 217.4 378.4 L 219.2 378.6 L 219.2 374.2 L 221.2 374.2 L 225.1 370.3 L 226.6 369.9 L 224 364 L 225.9 363.5 L 226.5 361.7 L 230.3 363.3 L 233 359.5 L 230.4 355.9 L 233.6 353.6 L 228.8 351.1 L 225.3 343.8 L 223.7 342.3 L 225.7 338.6 L 225.7 335.3 L 223.4 334Z');
pohj_savo.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
kanta_hame=paper.path('M 105.8 445.3 L 103.7 443.7 L 102.1 444.6 L 102.1 445.9 L 103.9 447 L 102.7 449.8 L 100.5 450.3 L 100.3 452.3 L 101.6 453.8 L 100.5 454.7 L 100.7 456.5 L 104.5 458.4 L 107.3 457 L 112.7 461.1 L 117.4 462.6 L 124.2 463.8 L 125.1 465.7 L 126.7 464.5 L 128.3 465.3 L 128.8 466.8 L 132.9 466 L 132.8 463.8 L 133.9 462.2 L 136.6 462.6 L 141 462 L 142.5 461.4 L 145.5 462.3 L 145.3 460.9 L 147.3 459.5 L 145.9 458.5 L 144.6 459.7 L 145 457.8 L 146.6 457.3 L 145.9 455.7 L 144.9 453.6 L 146.5 452.3 L 143.8 449.1 L 144.9 444.6 L 149.1 442.1 L 148.7 436.5 L 146.5 434.8 L 144.8 435.6 L 145.3 433.8 L 141.6 432.3 L 138.9 433.5 L 137.2 431.7 L 136.4 433.6 L 132.6 432.1 L 128.4 435.5 L 127.6 435 L 127.1 435.8 L 127.2 436.7 L 127.7 437.3 L 126.3 438.9 L 116 442.8 L 116.7 447.7 L 115.9 448.4 L 112.8 445.1 L 108.3 446.8 L 106.2 446.8Z');
kanta_hame.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
paijat_hame=paper.path('M 164.2 410.7 L 167 412.1 L 170.1 416.9 L 174.5 418.7 L 173 422.7 L 172.4 427.5 L 173.9 428.5 L 174 430.4 L 176.1 432.4 L 177.4 432.6 L 177.6 434.9 L 176.2 435.7 L 175 438.8 L 171.9 440.9 L 168.6 440.9 L 168 442.9 L 168.9 444.8 L 169.6 448.2 L 167.7 448.1 L 166.9 449.6 L 169.3 450.7 L 168.1 452.9 L 168.2 455.4 L 170.3 456.8 L 170.6 459.1 L 171.2 459.4 L 171 461.5 L 169 462.6 L 167.1 460.9 L 164.1 461.5 L 164 459.5 L 162 460.9 L 160.7 460.7 L 156.5 462 L 155.5 460.7 L 155.2 460.8 L 154.2 457 L 153.5 456.3 L 151.1 458.8 L 148 455.1 L 145.9 455.7 L 144.9 453.6 L 146.5 452.3 L 143.8 449.1 L 144.9 444.6 L 149.1 442.1 L 148.7 436.5 L 146.5 434.8 L 144.8 435.6 L 145.3 433.8 L 141.6 432.3 L 141.2 424.4 L 142.5 425.2 L 154.1 424.1 L 156.4 415.7 L 159.9 414.1 L 161.8 415Z');
paijat_hame.attr({'stroke':'#000000','stroke-width':'1.88','stroke-miterlimit':'4','fill':'#000000','stroke-opacity':'1'});
ahvenanmaa=paper.path('M 47.7 465.5 L 48.9 464.8 L 50.1 466.6 L 49.7 468.3 L 48.5 468.9 L 47.5 466.7Z M 49.9 469.4 L 51.5 468.1 L 52.5 469.3 L 52.1 471.5 L 51.3 472.2 L 50.3 471.6Z M 47.9 472.4 L 46.7 472.8 L 45.9 471.9 L 46.4 470.4 L 47.9 471Z M 44.4 472.6 L 43.3 472.9 L 42.9 472.4 L 42.9 472.3 L 43.3 471 L 44.2 470.4 L 44.9 471.1Z M 45.7 475.8 L 44.2 477.2 L 43.5 476.7 L 43.3 476 L 43.3 474.7 L 44.6 474.1 L 45.4 475.2Z M 42.5 477.7 L 42.7 478.7 L 41.2 478.7 L 40.7 476.9 L 41.2 476.1 L 42.2 476.3 L 42.5 477.1Z M 41.2 479.6 L 42.1 481.6 L 41.9 482 L 41.8 482.8 L 40.1 482.7 L 39.7 480.9 L 38.9 480 L 39.7 478.7Z M 36.3 471.5 L 33 471.2 L 33 470.2 L 33.9 469.5 L 36.3 470.7Z M 34.5 473.3 L 35.3 472.6 L 35.9 473.5 L 35.4 474.6 L 36.2 475.8 L 35 477.5 L 34.2 477.5 L 34.3 475.3 L 33.4 474.3Z M 37.9 484.5 L 38.7 485.4 L 37.7 486.6 L 34.6 487.5 L 32.3 487.5 L 31.9 486.7 L 33.9 485 L 35.1 484.1Z M 36.1 482.3 L 36.8 481.5 L 37.6 481.7 L 38.6 482.7 L 38.7 483.4 L 36.9 483.2Z M 31.5 481.6 L 32 482.7 L 30.4 482.7 L 30.1 480.4 L 31.6 478.7 L 32.1 478.8 L 32.4 480Z M 30.2 482.7 L 30.2 483.7 L 29.7 484.8 L 30.6 485.7 L 30.4 486.9 L 28.9 487.9 L 28.6 486.3 L 27.6 486.5 L 26.9 484.9 L 24.8 483.4 L 23 483.8 L 22.8 482.3 L 22.1 481.4 L 20.6 481.2 L 19.8 480.3 L 19.5 478.4 L 18.1 476.8 L 17.1 476.8 L 16.3 476.6 L 15.9 478 L 14.8 478.1 L 14 476.3 L 14.4 474.3 L 13.6 473.5 L 14.1 472.2 L 17 470.9 L 18.3 471.4 L 19.7 471.1 L 20.8 469.7 L 22 470.5 L 21.7 472.7 L 22.6 473 L 23.4 472.1 L 23.1 471.4 L 23.1 470.5 L 22.4 469.3 L 20.3 469 L 22.2 466.5 L 24 465.7 L 26.4 468 L 28.5 468.4 L 29.5 470 L 30.8 470.6 L 31 472.1 L 32.5 474 L 31.3 477.2 L 28.7 477.6 L 27.1 475.8 L 26.1 475.7 L 25.2 477.2 L 26.7 478.3 L 25.4 481.3 L 25.8 481.8 L 27 481.8 L 27.8 481.3Z M 44.4 490.4 L 46.4 489.5 L 47 489.9 L 48.2 490.5 L 47.8 491 L 47.6 491.8 L 46.7 491.8 L 45.9 493 L 44 491.5Z');
ahvenanmaa.attr({'fill':'#000000','stroke':'none'});
/*
...and so on..
*/
var st = paper.setFinish();
/*********************************************************************************
The below lines use the set to transform your SVG to:
(1)Translate (Move) your image to the top left of the paper.
(2)Scale your vector image to fit inside the the paper.
Remove this comment and alter or remove the code below it.
*********************************************************************************/
var translate='t'+(-1*st.getBBox().x)+','+(-1*st.getBBox().y);
st.transform(translate+'s0.91,0.91,0,0');
/*********************************************************************************
The below lines use the set to add event handlers.
As you mouseover the above code window vectors they change colour.
If your trying to locate a path, click on the vector image above...
Remove this comment and alter or remove the code below it.
*********************************************************************************/
function callback(member)
{
member.mouseover(function (e) { this.ofill=this.attr('fill');this.attr({fill:'#ffffff'}); });
member.mouseout(function (e) { this.attr({fill:this.ofill}); });
member.click(function (e) { var thisPath=this.attr('path');alert('You just clicked on Element #'+this.id+'.To help you find it in the code its path starts with......'+thisPath); });
}
st.forEach(callback);
}
</script>
</head>
<body>
<div id="canvas">
<div id="paper"></div>
<div id="pohj_pohjanmaa"></div>
<div id="lappi"></div>
<div id="pohj_pohjanmaa2"></div>
<div id="kainuu"></div>
<div id="etela-karjala"></div>
<div id="etela-savo"></div>
<div id="pohj_savo"></div>
<div id="kanta_hame"></div>
<div id="paijat_hame"></div>
<div id="ahvenanmaa"></div>
<div id="varsinais-suomi"></div>
<div id="etela_pohjanmaa"></div>
<div id="keski_suomi"></div>
<div id="pirkanmaa"></div>
<div id="satakunta"></div>
<div id="kymenlaakso"></div>
<div id="keski_pohjanmaa"></div>
<div id="uusimaa"></div>
<div id="etela_karjala"></div>
<div id="pohjanmaa"></div>
</div>
</body>
</html>
The biggest thing that the converter did was pull that the path data from the SVG files that you fed it. My suggestion is to use that data, but with other code.
In order to simplify and keep things as DRY as possible, you will want to create two objects. One will contain path data for each county and the other will contain counties attribute data. With these objects you can run a simple for loop and build your map that way. I hope the following code helps.
note that pathData represents the path strings such as 'M 192.9 S 9494 ...290 Z'
Javascript
//create Raphael county map
var countyMap = Raphael("canvas", 640, 480);
//create county map object to hold extracted path data
var finlandCounty = {
pohj_pohjanmaa:'pathData',
lappi: 'pathData',
kainuu: 'pathData',
etela_karjala: 'pathData',
etela_savo: 'pathData'
};
//create attribute object
var countyAttr = {
'stroke-width':1.9,
'stroke-miterlimit':4,
fill:'#000000',
stroke:'none',
'stroke-opacity':1
};
//loop through county object list and create the map
for (var county in finlandCounty) {
county = countyMap.path(county).attr(countyAttr);
//set click event
county.click(function(){
alert('You just clicked on Element '+this.id);
}
//set hover event
county.hover(
function () {
this.animate({fill: "#ffffff"}, 400);
},function () {
this.animate({fill:countyAttr.fill}, 400);
});
}
}
HTML
<body>
<div id="canvas></div>
</body>
The biggest problem with your code is that I don't see anywhere where you actually create the paper object. You simply use the variable paper assuming that it's a Raphael paper object but from your code it actually looks like it's undefined.
You need to create a paper object:
var paper = Raphael('paper');
If you look at Jon Black's answer he calls his paper countyMap and it's initialized on this line:
var countyMap = Raphael("canvas", 640, 480);
The paper doesn't have to be called paper and the variable paper is not a special magic variable that will automatically create a Raphael paper object. You need to create the paper object yourself and you can name it anything you like.
I strongly encourage that you write your code by using another name (like canvas for example) instead of paper for the Raphael paper object just to get comfortable with how things really work and avoid confusing yourself.