-
-
Save drfloob/5938266 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>The Pirate Puzzle></title> | |
<style> | |
.island { | |
stroke: blue; | |
stroke-width: 3; | |
fill: transparent; | |
} | |
.tree { | |
stroke: green; | |
fill: green; | |
} | |
.grave { | |
stroke: black; | |
fill: black; | |
} | |
.flag { | |
stroke: red; | |
fill: red; | |
} | |
.treasure { | |
stroke: yellow; | |
fill: yellow; | |
} | |
.flag-path { | |
stroke: black; | |
fill: none; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script type="text/javascript"> | |
(function (){ | |
var width = 960, | |
height = 600, | |
// our svg container | |
svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height), | |
// a group within our container that will hold our map features | |
features = svg.append('g'), | |
// a group within our features group that will hold some paths to explain the geometries | |
geometries = features.append('g'), | |
islandRadius = 300, | |
featureLength = 30, | |
treeOffset = 210, | |
trees = [ | |
{ | |
x: treeOffset, | |
y: treeOffset | |
}, | |
{ | |
x: islandRadius - treeOffset, | |
y: treeOffset+120 | |
}], | |
grave = {x: islandRadius, y: islandRadius}, | |
// helper function for generating path values for lines | |
line = d3.svg.line() | |
.x(function(d) { return d.x; }) | |
.y(function(d) { return d.y; }); | |
// create a mask to keep features from displaying off of the island | |
svg.append('g') | |
.append('clipPath') | |
.attr('id','island-mask') | |
.append('circle') | |
.attr('r', islandRadius) | |
.attr('cx', islandRadius) | |
.attr('cy', islandRadius); | |
// apply it to the features group | |
features.attr('clip-path', 'url(#island-mask)'); | |
// create the island on top of everything. If we draw our features "over top" | |
// of the island then they will interfere with our event handling | |
svg.append('circle') | |
.attr('r', islandRadius) | |
.attr('cx', islandRadius) | |
.attr('cy', islandRadius) | |
.classed('island', true); | |
// create the trees - these are static so only draw them once | |
features.selectAll('.tree') | |
.data(trees) | |
.enter().append('image') | |
.attr('xlink:href', 'tree.svg') | |
.attr('width', featureLength) | |
.attr('height', featureLength) | |
.attr('x', getX) | |
.attr('y', getY) | |
.classed('tree', true); | |
// dynamic draw function for things that react to moving the grave position | |
function draw() { | |
// calculate positions | |
var flags = getFlagPositions(trees, grave), | |
treasure = getTreasurePosition(flags), | |
paths = getPathPoints(trees, flags, grave); | |
// draw the grave | |
features.selectAll('.grave') | |
.data([grave]) | |
.attr('x', getX) | |
.attr('y', getY) | |
.enter().append('image') | |
.attr('xlink:href', 'grave.svg') | |
.classed('grave', true) | |
.attr('height', featureLength) | |
.attr('width', featureLength) | |
.attr('x', getX) | |
.attr('y', getY); | |
// draw the flags | |
features.selectAll('.flag') | |
.data(flags) | |
.attr('x', getX) | |
.attr('y', getY) | |
.enter().append('image') | |
.attr('xlink:href', 'flag.svg') | |
.classed('flag', true) | |
.attr('height', featureLength) | |
.attr('width', featureLength) | |
.attr('x', getX) | |
.attr('y', getY); | |
// draw the treasure location | |
features.selectAll('.treasure') | |
.data([treasure]) | |
.attr('x', getX) | |
.attr('y', getY) | |
.enter().append('image') | |
.attr('xlink:href', 'treasure_chest.svg') | |
.classed('treasure', true) | |
.attr('height', featureLength) | |
.attr('width', featureLength) | |
.attr('x', getX) | |
.attr('y', getY); | |
// draw triangles showing the flag calculations | |
// these are in the geometries group so they appear underneath the other features | |
geometries.selectAll('.flag-path') | |
.data(paths) | |
.attr('d', line) | |
.enter().append('path') | |
.classed('flag-path', true) | |
.attr('d', line); | |
} | |
// move grave location to wherever the mouse is | |
svg.select('.island') | |
.on('mousemove', function() { | |
// 15 is a magic number to make things look nice, on my screen at least. | |
var mousePosition = d3.mouse(this); | |
grave.x = mousePosition[0] - 5; | |
grave.y = mousePosition[1] - 5; | |
draw(); | |
}); | |
// calculate the positions of the flags | |
function getFlagPositions(treePositions, gravePosition) { | |
var leftTree, rightTree, rise, run, leftFlag, rightFlag, | |
flagPositions, leftTreeIdx, rightTreeIdx; | |
// XXX assume grave position is either above or below both, | |
// i.e. y positions are equal for both trees | |
// this code determines which tree is "left" and which is "right" based | |
// on the location of the grave | |
if ( | |
(treePositions[0].x < treePositions[1].x && treePositions[0].y < grave.y) || | |
(treePositions[0].x > treePositions[1].x && treePositions[0].y > grave.y) | |
) { | |
leftTreeIdx = 0; | |
rightTreeIdx = 1; | |
} else { | |
leftTreeIdx = 1; | |
rightTreeIdx = 0; | |
} | |
leftTree = treePositions[leftTreeIdx]; | |
rightTree = treePositions[rightTreeIdx]; | |
// get left flag position | |
rise = gravePosition.y - leftTree.y; | |
run = gravePosition.x - leftTree.x; | |
// turn 90 to the left | |
leftFlag = { | |
x: leftTree.x - rise, | |
y: leftTree.y + run | |
}; | |
// get right flag position | |
rise = gravePosition.y - rightTree.y; | |
run = gravePosition.x - rightTree.x; | |
// turn 90 to the right | |
rightFlag = { | |
x: rightTree.x + rise, | |
y: rightTree.y - run | |
}; | |
flagPositions = []; | |
// use these indexes to keep the order of our flags consistent with the order | |
// of our trees in the trees array | |
flagPositions[leftTreeIdx] = leftFlag; | |
flagPositions[rightTreeIdx] = rightFlag; | |
return flagPositions; | |
} | |
function getTreasurePosition(flagPositions) { | |
// averages the x and y values of the two flag positions | |
return { | |
x: (flagPositions[0].x + flagPositions[1].x) / 2, | |
y: (flagPositions[0].y + flagPositions[1].y) / 2 | |
} | |
} | |
function getPathPoints(treePositions, flagPositions, grave) { | |
// create two lines, grave -> tree -> flag -> grave for each tree | |
return [ | |
[ | |
grave, | |
treePositions[0], | |
flagPositions[0], | |
grave | |
], | |
[ | |
grave, | |
treePositions[1], | |
flagPositions[1], | |
grave | |
] | |
] | |
} | |
// helper functions for positioning | |
function getX(d) { | |
return d.x - featureLength/2; | |
} | |
function getY(d) { | |
return d.y - featureLength/2; | |
} | |
})(); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- http://thenounproject.com/noun/tree/#icon-No17078 James Keunning from The Noun Project --> | |
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="100" height="100" viewBox="0 0 80 80" version="1.1" id="svg2" inkscape:version="0.48.2 r9819" sodipodi:docname="blank.svg"> | |
<metadata id="metadata10"> | |
<rdf:RDF> | |
<cc:Work rdf:about=""> | |
<dc:format>image/svg+xml</dc:format> | |
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> | |
<dc:title/> | |
</cc:Work> | |
</rdf:RDF> | |
</metadata> | |
<defs id="defs8"> | |
<inkscape:path-effect is_visible="true" id="path-effect5043" effect="spiro"/> | |
<inkscape:path-effect is_visible="true" id="path-effect5065" effect="spiro"/> | |
</defs> | |
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1366" inkscape:window-height="706" id="namedview6" showgrid="true" inkscape:zoom="3.0561717" inkscape:cx="49.557734" inkscape:cy="43.363027" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg2" inkscape:snap-grids="false"> | |
<inkscape:grid type="xygrid" id="grid3807"/> | |
</sodipodi:namedview> | |
<path style="fill:green;stroke:green;stroke-width:0.01269767" d="m 35.978884,10.741135 c 0.49616,1.98221 -0.55017,-1.0092398 -1.23252,0.71785 l 0.41987,0.25733 c -2.26061,2.46704 -5.56265,0.20425 -7.47639,2.23818 -1.80212,0.0143 -2.02847,0.39941 -2.91538,1.84201 -2.38121,-1.03864 -3.19447,2.94552 -4.98087,3.26076 -1.49215,-0.38928 -4.84335,-2.01183 -5.54296,0.60949 0.40715,1.92673 -2.29955,0.50062 -1.21559,1.42214 -1.98999,-0.15151 1.21539,1.36802 -0.921,0.63657 1.91974,1.06763 0.96083,3.21919 1.97745,4.25287 2.5486,0.60195 2.7629,1.34894 5.34995,1.00566 0.49894,0.98156 3.94233,1.78342 4.76416,2.73593 -0.95902,3.80025 -2.55178,0.72861 -4.5847,-0.27427 0.14506,0.5225 -2.44004,-1.62965 -2.51922,-0.32168 -0.3942,2.8797 -5.05804,3.28214 -6.27434,3.92443 1.06103,0.44388 -0.45477,1.37459 -0.52822,1.19527 -0.4819402,0.20389 -2.2551002,0.64864 -1.7776802,1.25961 0.15564,0.66003 -3.47493,0.95502 -1.96052,2.33976 -2.61207,0.82602 -0.51134,6.0746 1.61176,3.64338 4.3232702,0.73757 5.9014002,-0.49268 10.0802502,-1.0666 4.72303,-0.24294 -3.33303,4.9328 -3.48424,2.6919 -1.51664,0.26439 -1.72678,0.33121 -1.80137,1.15465 -3.1048902,-0.29477 -5.7681602,0.94091 -8.9662502,-0.5587 -0.0544,0.1069 -5.29372,2.10198 -2.15352,4.25287 -1.17462999,-1.23065 0.5909,-0.45763 1.05644,-0.18962 -1.92123999,2.87755 4.45264,6.13765 5.26869,4.46958 2.1006102,0.73792 3.8985902,0.0821 4.4018602,2.13998 -1.84268,1.13215 -3.9322902,0.69688 -3.8330102,1.09031 -0.29085,1.62414 -5.13155,0.90883 -5.57343,2.57339 -1.27849,0.45764 2.48727,3.29198 2.20093,1.71334 1.31709,1.15127 0.51443,-0.54171 1.54065,0.0643 3.1693402,-0.93903 2.79459,2.79537 5.1671102,1.88602 1.85737,1.93758 -0.70021,0.56617 -1.75059,2.61403 1.24074,-1.24463 0.12694,0.93221 1.29347,1.00227 -1.8729102,0.59908 -1.09307,2.81228 0.79234,3.3725 0.24272,-1.41801 2.21577,-0.16984 3.96844,-0.77879 1.19112,-1.24024 2.78535,-1.75861 4.7811,-1.84878 0.5736,0.62237 4.39755,-0.19525 4.34768,-0.88037 2.43122,-1.50854 4.58751,-1.39679 6.98541,-1.76075 3.59852,-0.60328 1.92976,3.06188 2.17723,5.43799 -0.015,2.81073 0.5853,6.61644 -2.96279,7.5712 -4.61335,1.15132 1.85409,0.71551 3.40636,1.78444 3.43274,0.58652 6.3464,-2.05192 8.9053,-1.26638 1.72139,-1.46024 -4.27606,-0.41754 -4.52714,-2.77655 -0.2319,-2.6016 -1.51132,-7.75597 0.73815,-8.94932 0.62327,2.21995 2.85212,-0.89822 2.17723,1.42214 -1.72427,2.45362 1.97078,-0.54947 1.65239,1.31378 2.1553,0.52014 4.51364,1.38644 6.82965,0.61626 0.97914,-1.44267 4.17662,-0.47822 3.11855,-2.0621 1.98707,-2.90797 6.44327,2.40366 8.94932,-0.38939 2.03196,-0.24404 6.71754,-0.53216 3.86009,-3.6637 1.85627,-1.22051 -3.65096,-0.48579 -1.22914,-1.21221 2.50853,-2.51018 4.73527,2.63069 6.64004,0.27089 1.7296,-1.01663 3.56574,0.21849 5.60052,-1.04968 3.00608,-1.33701 0.19913,-5.2586 0.47404,-6.06779 -2.10033,0.20795 0.99287,-1.48035 -1.00227,-0.4605 -1.08797,-3.17115 -5.38516,0.58015 -6.5012,-0.69753 2.05578,-0.50247 2.98434,-2.30527 0.0135,-2.76978 2.77803,-0.75985 -0.36534,-2.99155 -1.82169,-1.80138 -3.4519,0.15132 1.04645,0.11201 0.19639,-1.55419 -2.17249,-1.09184 0.46801,-1.59009 2.05194,-0.99889 3.46386,0.90569 6.63393,-1.9007 4.73031,-4.64904 0.79194,-0.79204 -1.38014,-1.60725 -0.69414,-2.48197 0.74356,-0.8876 -3.1577,-4.26752 -6.12536,-4.92331 -3.04775,-2.1219 -2.3513,4.53961 -3.6874,1.36119 -1.95166,1.02213 -0.62165,-0.28725 -1.11739,-1.07337 1.26253,-3.02597 -9.03224,-1.65402 -3.86687,-3.64 0.0226,-2.85107 3.05272,-2.77464 4.22579,-3.75174 1.70886,0.95782 1.81951,0.25135 3.0068,0.4368 -0.27377,-0.16661 2.00439,-2.39831 0.31152,-2.02147 0.0649,0.0172 -6.13849,-3.34644 -2.67159,-3.60614 2.9885,0.2512 0.36725,-2.40369 1.3578,-2.9357 -1.99133,-3.09581 -4.19357,2.60542 -6.41994,0.0271 2.21463,-2.95275 -2.59925,0.48965 -4.06325,-0.29797 0.37856,2.01339 -2.94112,1.91188 -2.07226,3.15579 -1.87052,-1.30468 -5.63411,0.79022 -5.21451,-2.2551 0.86696,0.19688 5.29148,0.54118 4.68629,-1.68625 -0.27509,-2.14163 -1.87843,-2.08718 -4.37477,-2.11289 -0.2452,1.60711 -5.20366,-1.32709 -0.64335,-1.5305 1.43582,-1.5886 -2.95705,-1.71385 -4.34091,-2.47858 0.88043,2.45346 -4.81145,2.02114 -2.15353,1.02936 -0.63428,-2.00386 -2.2364,-1.42723 -4.45603,-0.86683 -1.13433,-1.61456 -0.73259,0.59628 -1.67948,-1.08354 z m 31.73401,16.66273 c 0.0152,0.009 0.0358,0.0144 0.0677,0.0102 -0.0238,-0.004 -0.0448,-0.007 -0.0677,-0.0102 z m -57.41377,6.83981 c 0.13122,-0.0555 0.17338,-0.0938 0.0406,-0.11174 -0.0383,0.0549 -0.0493,0.0905 -0.0406,0.11174 z m 17.174415,27.002777 c 0.35628,-1.67912 5.598092,-0.88762 4.593632,-0.913787 -0.664859,-0.01732 -4.524904,1.517395 -4.593632,0.913787 z m 15.402715,0.268433 c 2.11999,-0.003 0.71358,2.82556 -1.63884,2.07903 -3.32224,0.0944 0.32647,-2.19871 0.86344,-1.98084 0.29757,-0.0681 0.5561,-0.0979 0.7754,-0.0982 z" id="path3008" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccscccccc"/> | |
</svg> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment