├── ex ├── fullVertical.PNG ├── halfVertical.PNG ├── fullHorizontal.PNG └── halfHorizontal.PNG ├── assets ├── css │ └── rink-style.css └── js │ └── rinkPlot.js ├── README.md └── rinks.html /ex/fullVertical.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/war-on-ice/icerink/HEAD/ex/fullVertical.PNG -------------------------------------------------------------------------------- /ex/halfVertical.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/war-on-ice/icerink/HEAD/ex/halfVertical.PNG -------------------------------------------------------------------------------- /ex/fullHorizontal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/war-on-ice/icerink/HEAD/ex/fullHorizontal.PNG -------------------------------------------------------------------------------- /ex/halfHorizontal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/war-on-ice/icerink/HEAD/ex/halfHorizontal.PNG -------------------------------------------------------------------------------- /assets/css/rink-style.css: -------------------------------------------------------------------------------- 1 | .blue-line{ 2 | fill: blue; 3 | } 4 | 5 | .red-line{ 6 | fill: red; 7 | } 8 | 9 | .red-faceoff{ 10 | stroke: red; 11 | } 12 | 13 | .rink-face{ 14 | stroke: gray; 15 | fill: white; 16 | } 17 | 18 | .goal-crease{ 19 | fill: lightblue; 20 | stroke: red; 21 | } 22 | 23 | .center-line{ 24 | fill: red; 25 | } 26 | 27 | .neutral-faceoff{ 28 | stroke: blue; 29 | } 30 | 31 | .danger-line{ 32 | stroke: gray; 33 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # icerink 2 | Ice rink generated via d3.js 3 | 4 | This is intended to be used for any hockey visualizations. The rink is modeled after the current NHL regulation rink markings. 5 | 6 | It's configurable to allow for full or half rinks, vertical or horizontal stylings. You can also configure the sizing. Example usage is located in rinks.html. 7 | 8 | ## Full Rink, Vertical 9 | ![Full, Vertical](ex/fullVertical.PNG) 10 | 11 | ## Full Rink, Horizontal 12 | ![Full, Horizontal](ex/fullHorizontal.PNG) 13 | 14 | ## Half Rink, Vertical 15 | ![Half, Vertical](ex/halfVertical.PNG) 16 | 17 | ## Half Rink, Horizontal 18 | ![Half, Horizontal](ex/halfHorizontal.PNG) -------------------------------------------------------------------------------- /rinks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rink Plots 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Rink Plots

13 |

Full Rink, Horizontal

14 |
15 |

Full Rink, Vertical

16 |
17 |

Half Rink, Horizontal

18 |
19 |

Half Rink, Vertial

20 |
21 | 22 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /assets/js/rinkPlot.js: -------------------------------------------------------------------------------- 1 | var RINK_MAP = function RinkMap(config){ 2 | 3 | // all distances are in FT 4 | var RINK_CONFIG = 5 | { 6 | RINK_LENGTH: 200, 7 | RINK_WIDTH: 85, 8 | BLUE_LINE_WIDTH: 1, 9 | BOARDS_RADIUS: 28, 10 | RED_TO_BOARDS: 11, 11 | RED_TO_FACEOFF: 20, 12 | FACEOFF_RADIUS: 15, 13 | FACEOFF_DOT_RADIUS: 1, 14 | ZONE_LINE_WIDTH: (2/12), 15 | CREASE_RADIUS: 6, 16 | ZONE_LENGTH: 75, 17 | ZONE_TO_NEUTRAL_DOT: 5, 18 | CENTER_TO_NEUTRAL_DOT: 22, 19 | REF_CREASE_RADIUS: 10, 20 | CREASE_HEIGHT: 4, 21 | FACEOFF_HOR_LENGTH: 3, 22 | FACEOFF_VER_LENGTH: 4, 23 | FACEOFF_HOR_DIST_CEN: 2, 24 | FACEOFF_VER_DIST_CEN: (9/12), 25 | FACEOFF_OUT_MARK_LENGTH: 2, 26 | FACEOFF_OUT_MARK_DIST_BW: 5 + (7/12), 27 | TRAPEZOID_TOP: 22, 28 | TRAPEZOID_BOTTOM: 28 29 | }; 30 | 31 | var RINK_COLOR = 32 | { 33 | BLUE_LINE: "blue", 34 | RINK_FILL: "white", 35 | GOAL_FILL: "lightblue" 36 | } 37 | 38 | var DANGER_ZONES = [{x1: -9.11, y1: 89.1}, 39 | {x1: -22.1, y1: 68.9}, {x1: -22.1, y1: 53.9}, 40 | {x1: -9.11, y1: 53.9}, {x1: -9.11, y1: 43.9}, 41 | {x1: 9.11, y1: 43.9}, {x1: 9.11, y1: 53.9}, 42 | {x1: 22.1, y1: 53.9}, {x1: 22.1, y1: 68.9}, 43 | {x1: 9.11, y1: 89.1}, {x1: -9.11, y1: 89.1}, 44 | {x1: -9.11, y1: 68.9}, {x1: 9.11, y1: 68.9}, 45 | {x1: 9.11, y1: 89.1}, {x1: -9.11, y1: 89.1}]; 46 | 47 | var p = 48 | { 49 | chartsize: {width: 500, height: 500}, 50 | margins: {top: 30, bottom: 5, left: 10, right: 10}, 51 | showDanger: false, 52 | horizontal: true, 53 | fullRink: true, 54 | watermark: "" 55 | } 56 | 57 | if (config !== "undefined"){ 58 | for (var property in config){ 59 | p[property] = config[property]; 60 | } 61 | } 62 | 63 | // Get rink scale, scale all rink config distances 64 | var rinkScale = p.desiredWidth / RINK_CONFIG.RINK_WIDTH; 65 | for (var param in RINK_CONFIG){ 66 | RINK_CONFIG[param] = rinkScale * RINK_CONFIG[param]; 67 | } 68 | 69 | // CREATE CHART 70 | function chart() { 71 | 72 | function rinkLine(x, group, type){ 73 | var lineWidth = RINK_CONFIG.BLUE_LINE_WIDTH; 74 | if (type === "center-line"){ 75 | var lineWidth = RINK_CONFIG.BLUE_LINE_WIDTH/2; 76 | } 77 | group 78 | .append("rect") 79 | .attr("x", x - lineWidth) 80 | .attr("y", 0) 81 | .attr("width", lineWidth) 82 | .attr("height", RINK_CONFIG.RINK_WIDTH) 83 | .attr("class", type); 84 | } 85 | 86 | function rinkOutLine(group){ 87 | 88 | group.append("path") 89 | .attr("d", rounded_rect(0,0, RINK_CONFIG.RINK_LENGTH *0.5, RINK_CONFIG.RINK_WIDTH, RINK_CONFIG.BOARDS_RADIUS, true, false, true, false)) 90 | .attr("class", "rink-face") 91 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 92 | 93 | } 94 | 95 | // From stackOverflow http://stackoverflow.com/questions/12115691/svg-d3-js-rounded-corner-on-one-corner-of-a-rectangle 96 | // r -> radius, tl/tr/bl/br - top left/bottom right TRUE/FALSE for posessing rounded corner 97 | function rounded_rect(x, y, w, h, r, tl, tr, bl, br) { 98 | var retval; 99 | retval = "M" + (x + r) + "," + y; 100 | retval += "h" + (w - 2*r); 101 | if (tr) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + r; } 102 | else { retval += "h" + r; retval += "v" + r; } 103 | retval += "v" + (h - 2*r); 104 | if (br) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + r; } 105 | else { retval += "v" + r; retval += "h" + -r; } 106 | retval += "h" + (2*r - w); 107 | if (bl) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + -r; } 108 | else { retval += "h" + -r; retval += "v" + -r; } 109 | retval += "v" + (2*r - h); 110 | if (tl) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + -r; } 111 | else { retval += "v" + -r; retval += "h" + r; } 112 | retval += "z"; 113 | return retval; 114 | } 115 | 116 | // Create goal crease with center at point (x,y) and width d 117 | function goalCrease(xPos, group){ 118 | 119 | var creaseData = [ {"x": xPos, "y": (RINK_CONFIG.RINK_WIDTH/2 ) - RINK_CONFIG.CREASE_HEIGHT , "type": "M"}, 120 | {"x": xPos + RINK_CONFIG.CREASE_HEIGHT, "y":(RINK_CONFIG.RINK_WIDTH/2 ) - RINK_CONFIG.CREASE_HEIGHT, "type": "L"}, 121 | {"x": xPos + RINK_CONFIG.CREASE_HEIGHT, "y": (RINK_CONFIG.RINK_WIDTH/2 ) + RINK_CONFIG.CREASE_HEIGHT, "type": "A", "radius": RINK_CONFIG.CREASE_RADIUS}, 122 | {"x": xPos, "y": (RINK_CONFIG.RINK_WIDTH/2 ) + RINK_CONFIG.CREASE_HEIGHT, "type": "L"}]; 123 | 124 | var creaseFunction = function(input){ 125 | var dStr = ""; 126 | for (var i=0; i < input.length; i++){ 127 | if (input[i]["type"] === "M" || input[i]["type"] === "L"){ 128 | dStr += input[i]["type"] + input[i]["x"] + "," + input[i]["y"]; 129 | } 130 | else if (input[i]["type"] === "A"){ 131 | dStr += input[i]["type"] + input[i]["radius"] + "," + input[i]["radius"] + ",0,0,1," + input[i]["x"] + "," + input[i]["y"]; 132 | } 133 | } 134 | return dStr; 135 | } 136 | 137 | group 138 | .append("path") 139 | .attr("d", creaseFunction(creaseData)) 140 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 141 | .attr("class", "goal-crease"); 142 | } 143 | 144 | // Create red-line at xPos to scale 145 | function redLine(x, group){ 146 | var yDistance = RINK_CONFIG.BOARDS_RADIUS - Math.sqrt((2 * RINK_CONFIG.RED_TO_BOARDS * RINK_CONFIG.BOARDS_RADIUS) - (RINK_CONFIG.RED_TO_BOARDS * RINK_CONFIG.RED_TO_BOARDS)); 147 | group 148 | .append("rect") 149 | .attr("x", x) 150 | .attr("y", yDistance) 151 | .attr("width", RINK_CONFIG.ZONE_LINE_WIDTH) 152 | .attr("height", RINK_CONFIG.RINK_WIDTH - 2 * yDistance) 153 | .attr("class", "red-line"); 154 | } 155 | 156 | function faceOffDot(x,y, group){ 157 | group 158 | .append("circle") 159 | .attr("cx", x) 160 | .attr("cy", y) 161 | .attr("r", RINK_CONFIG.FACEOFF_DOT_RADIUS) 162 | .attr("class", "red-line"); 163 | } 164 | 165 | // Create face-off circule with radius r at point (x,y) 166 | function faceOffCircle(x, y, group){ 167 | var faceOff = group.append("g") 168 | .attr("class", "faceoff"); 169 | 170 | 171 | // outer face-off circle 172 | faceOff.append("circle") 173 | .attr("cx", x) 174 | .attr("cy", y) 175 | .attr("r", RINK_CONFIG.FACEOFF_RADIUS) 176 | .style("fill", RINK_COLOR.RINK_FILL) 177 | .attr("class", "red-faceoff") 178 | .style("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH); 179 | 180 | // face-off dot 181 | faceOff 182 | .append("circle") 183 | .attr("cx", x) 184 | .attr("cy", y) 185 | .attr("r", RINK_CONFIG.FACEOFF_DOT_RADIUS) 186 | .attr("class", "red-line"); 187 | 188 | // Function/data to create four face-off markers 189 | var faceOffLineFunction = d3.svg.line() 190 | .x(function(d) {return RINK_CONFIG.FACEOFF_HOR_DIST_CEN + d.x; }) 191 | .y(function(d) {return RINK_CONFIG.FACEOFF_VER_DIST_CEN + d.y; }) 192 | .interpolate("linear"); 193 | var faceOffLineData = [ {"x": RINK_CONFIG.FACEOFF_VER_LENGTH, "y": 0} ,{"x": 0, "y": 0},{"x": 0, "y": RINK_CONFIG.FACEOFF_HOR_LENGTH}]; 194 | 195 | // Create four markers, each translated appropriately off-of (x,y) 196 | faceOff 197 | .append("path") 198 | .attr("d", faceOffLineFunction(faceOffLineData)) 199 | .attr("class", "red-faceoff") 200 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 201 | .attr("fill", "none") 202 | .attr("transform", "translate(" + x + " , " + y + ")scale(-1, -1)"); 203 | faceOff 204 | .append("path") 205 | .attr("d", faceOffLineFunction(faceOffLineData)) 206 | .attr("class", "red-faceoff") 207 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 208 | .attr("fill", "none") 209 | .attr("transform", "translate(" + x + " , " + y + ")scale(1,-1)"); 210 | faceOff 211 | .append("path") 212 | .attr("d", faceOffLineFunction(faceOffLineData)) 213 | .attr("class", "red-faceoff") 214 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 215 | .attr("fill", "none") 216 | .attr("transform", "translate(" + x + " , " + y + ")"); 217 | faceOff 218 | .append("path") 219 | .attr("d", faceOffLineFunction(faceOffLineData)) 220 | .attr("class", "red-faceoff") 221 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 222 | .attr("fill", "none") 223 | .attr("transform", "translate(" + x + " , " + y + ")scale(-1, 1)"); 224 | 225 | // Create two hash on outside of circle (each side) 226 | // Function/data to create outside line markers 227 | var outsideLineFunction = d3.svg.line() 228 | .x(function(d) {return d.x; }) 229 | .y(function(d) {return d.y; }) 230 | .interpolate("linear"); 231 | var xStartOutsideLine = 0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW * Math.tan(Math.acos(0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW/RINK_CONFIG.FACEOFF_RADIUS)); 232 | var outsideLineData = [ {"x": 0, "y": xStartOutsideLine} ,{"x": 0, "y": xStartOutsideLine + RINK_CONFIG.FACEOFF_OUT_MARK_LENGTH}]; 233 | faceOff 234 | .append("path") 235 | .attr("d", outsideLineFunction(outsideLineData)) 236 | .attr("class", "red-faceoff") 237 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 238 | .attr("fill", "none") 239 | .attr("transform", "translate(" + (x - 0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW) + " , " + y + ")"); 240 | faceOff 241 | .append("path") 242 | .attr("d", outsideLineFunction(outsideLineData)) 243 | .attr("class", "red-faceoff") 244 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 245 | .attr("fill", "none") 246 | .attr("transform", "translate(" + (x + 0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW) + " , " + y + ")"); 247 | faceOff 248 | .append("path") 249 | .attr("d", outsideLineFunction(outsideLineData)) 250 | .attr("class", "red-faceoff") 251 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 252 | .attr("fill", "none") 253 | .attr("transform", "translate(" + (x + 0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW) + " , " + y + "), scale(1,-1)"); 254 | faceOff 255 | .append("path") 256 | .attr("d", outsideLineFunction(outsideLineData)) 257 | .attr("class", "red-faceoff") 258 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 259 | .attr("fill", "none") 260 | .attr("transform", "translate(" + (x - 0.5 * RINK_CONFIG.FACEOFF_OUT_MARK_DIST_BW) + " , " + y + "), scale(1,-1)"); 261 | 262 | } 263 | 264 | function trapezoid(xPos, group){ 265 | 266 | var trapezoidFunction = d3.svg.line() 267 | .x(function(d) {return RINK_CONFIG.RED_TO_BOARDS + d.x; }) 268 | .y(function(d) {return (0.5 * (RINK_CONFIG.RINK_WIDTH - RINK_CONFIG.CENTER_TO_NEUTRAL_DOT)) + d.y; }) 269 | .interpolate("linear"); 270 | 271 | var trapezoidData = [ {"x": -1 * RINK_CONFIG.RED_TO_BOARDS, "y": -0.5 * (RINK_CONFIG.TRAPEZOID_BOTTOM - RINK_CONFIG.TRAPEZOID_TOP)} ,{"x":0 , "y": 0}]; 272 | 273 | group 274 | .append("path") 275 | .attr("d", trapezoidFunction(trapezoidData)) 276 | .attr("class", "red-faceoff") 277 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 278 | .attr("fill", "none") 279 | .attr("transform", "translate(" + xPos + " ,0)"); 280 | group 281 | .append("path") 282 | .attr("d", trapezoidFunction(trapezoidData)) 283 | .attr("class", "red-faceoff") 284 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 285 | .attr("fill", "none") 286 | .attr("transform", "scale(1,-1),translate(" + xPos + "," + (-1 * RINK_CONFIG.RINK_WIDTH) + ")"); 287 | } 288 | 289 | function neutralCircle(x, y, group){ 290 | 291 | var circleData = [ {"x": x, "y": y - RINK_CONFIG.FACEOFF_RADIUS, "type": "M"}, 292 | {"x": x, "y": y + RINK_CONFIG.FACEOFF_RADIUS, "type": "A", "radius": RINK_CONFIG.FACEOFF_RADIUS, "dir": 0}]; 293 | 294 | group 295 | .append("path") 296 | .attr("d", dStringCreator(circleData)) 297 | .attr("class", "neutral-faceoff") 298 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 299 | .attr("fill", "none"); 300 | } 301 | 302 | var dStringCreator = function(input){ 303 | var dStr = ""; 304 | for (var i=0; i < input.length; i++){ 305 | if (input[i]["type"] === "M" || input[i]["type"] === "L"){ 306 | dStr += input[i]["type"] + input[i]["x"] + " " + input[i]["y"]; 307 | } 308 | else if (input[i]["type"] === "A"){ 309 | dStr += input[i]["type"] + input[i]["radius"] + "," + input[i]["radius"] + ",0,0," + input[i]["dir"] + "," + input[i]["x"] + "," + input[i]["y"]; 310 | } 311 | else{ 312 | "neither"; 313 | } 314 | } 315 | return dStr; 316 | } 317 | 318 | function refereeCrease(xPos, group){ 319 | var creaseData = [ {"x": xPos - RINK_CONFIG.REF_CREASE_RADIUS, "y": RINK_CONFIG.RINK_WIDTH, "type": "M"}, 320 | {"x": xPos, "y": RINK_CONFIG.RINK_WIDTH - RINK_CONFIG.REF_CREASE_RADIUS, "type": "A", "radius": RINK_CONFIG.REF_CREASE_RADIUS, "dir": 1}]; 321 | 322 | group 323 | .append("path") 324 | .attr("d", dStringCreator(creaseData)) 325 | .attr("class", "red-faceoff") 326 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 327 | .attr("fill", "none"); 328 | } 329 | 330 | function dangerZones(zoneCoords, group){ 331 | var dangerZoneGroup = group.append("g").attr("class","danger-zone"); 332 | var dangerData = []; 333 | 334 | dangerData[0] = {"type": "M", "x": (0.5 * RINK_CONFIG.RINK_LENGTH - zoneCoords[0]["y1"] * rinkScale), "y": (0.5 * RINK_CONFIG.RINK_WIDTH +zoneCoords[0]["x1"] * rinkScale)}; 335 | 336 | var i = 1; 337 | for (coord in zoneCoords){ 338 | dangerData[i] = {}; 339 | dangerData[i]["x"] = 0.5 * RINK_CONFIG.RINK_LENGTH - zoneCoords[coord]["y1"] * rinkScale; 340 | dangerData[i]["y"] = 0.5 * RINK_CONFIG.RINK_WIDTH + zoneCoords[coord]["x1"] * rinkScale; 341 | dangerData[i]["type"] = "L"; 342 | i++; 343 | } 344 | 345 | dangerZoneGroup 346 | .append("path") 347 | .attr("d", dStringCreator(dangerData)) 348 | .attr("class", "danger-line") 349 | .attr("stroke-width", RINK_CONFIG.ZONE_LINE_WIDTH) 350 | .style("stroke-dasharray", "10,10") 351 | .attr("fill", "none"); 352 | } 353 | 354 | function waterMark(xPos, yPos, waterMarkText, group){ 355 | group 356 | .append("text") 357 | .style("fill", "lightgray") 358 | .style("font-size", "18px") 359 | .style("text-anchor", "middle") 360 | .style("alignment-baseline", "middle") 361 | .attr("transform", "translate(" + xPos +"," + yPos + ") rotate(90)") 362 | .text(waterMarkText); 363 | } 364 | 365 | var zones = p.parent.append("g").attr("class", "zones"); 366 | 367 | // RINK CONFIGURATON -- BOTH ZONES 368 | var zone1 = zones.append("g") 369 | .attr("class", "zone1"); 370 | var zone1Elements = zone1.append("g").attr("class", "rinkElements"); 371 | generateRinkElements(zone1Elements); 372 | 373 | function generateRinkElements(zoneGroup){ 374 | // RINK OUT LINE, CENTER LINE 375 | rinkOutLine(zoneGroup); 376 | rinkLine(0.5 * RINK_CONFIG.RINK_LENGTH, zoneGroup, "center-line"); 377 | 378 | // NEUTRAL ZONE 379 | refereeCrease(0.5 * RINK_CONFIG.RINK_LENGTH, zoneGroup); 380 | neutralCircle(0.5 * RINK_CONFIG.RINK_LENGTH, 0.5 * RINK_CONFIG.RINK_WIDTH, zoneGroup); 381 | 382 | faceOffDot(RINK_CONFIG.ZONE_LENGTH + RINK_CONFIG.ZONE_TO_NEUTRAL_DOT, (RINK_CONFIG.RINK_WIDTH/2 - RINK_CONFIG.CENTER_TO_NEUTRAL_DOT), zoneGroup); 383 | faceOffDot(RINK_CONFIG.ZONE_LENGTH + RINK_CONFIG.ZONE_TO_NEUTRAL_DOT, (RINK_CONFIG.RINK_WIDTH/2 + RINK_CONFIG.CENTER_TO_NEUTRAL_DOT), zoneGroup); 384 | 385 | // O-ZONE 386 | rinkLine(RINK_CONFIG.ZONE_LENGTH, zoneGroup, "blue-line"); 387 | faceOffCircle(RINK_CONFIG.RED_TO_BOARDS + RINK_CONFIG.RED_TO_FACEOFF, RINK_CONFIG.RINK_WIDTH/2 - RINK_CONFIG.CENTER_TO_NEUTRAL_DOT, zoneGroup); 388 | faceOffCircle(RINK_CONFIG.RED_TO_BOARDS + RINK_CONFIG.RED_TO_FACEOFF, RINK_CONFIG.RINK_WIDTH/2 + RINK_CONFIG.CENTER_TO_NEUTRAL_DOT, zoneGroup); 389 | 390 | //GOAL LINES 391 | redLine(RINK_CONFIG.RED_TO_BOARDS, zoneGroup); 392 | trapezoid(0, zoneGroup); 393 | goalCrease(RINK_CONFIG.RED_TO_BOARDS, zoneGroup); 394 | 395 | // Show danger if flagged 396 | if (p.showDanger){ 397 | dangerZones(DANGER_ZONES, zoneGroup); 398 | } 399 | 400 | waterMark(RINK_CONFIG.RED_TO_BOARDS /2, RINK_CONFIG.RINK_WIDTH/2, p.watermark, zoneGroup); 401 | 402 | } 403 | 404 | // FULL RINK. Generate second zone. 405 | if (p.fullRink){ 406 | zoneName = "zone2"; 407 | var zone2 = zones.append("g") 408 | .attr("class", zoneName); 409 | 410 | var zone2Elements = zone2.append("g").attr("class", "rinkElements"); 411 | 412 | generateRinkElements(zone2Elements); 413 | // FULL RINK, HORIZONTAL. Rotate second zone. 414 | if (p.horizontal){ 415 | p.parent.selectAll(".zone2") 416 | .attr("transform", "scale(-1, 1)translate(" + (-1 * (RINK_CONFIG.RINK_LENGTH)) + ",0)"); 417 | 418 | } 419 | // FULL RINK, VERTICAL. rotate/move both zones. 420 | else{ 421 | p.parent.selectAll(".zone1") 422 | .attr("transform", "rotate(-90)translate(" + (-1 * (RINK_CONFIG.RINK_LENGTH)) +",0)"); 423 | p.parent.selectAll(".zone2") 424 | .attr("transform", "scale(-1,1)rotate(90)"); 425 | } 426 | } 427 | else{ 428 | // HALF RINK, VERTICAL. 429 | if (!p.horizontal){ 430 | p.parent.selectAll(".zone1") 431 | .attr("transform", "rotate(-90)translate(" + (-1*(RINK_CONFIG.RINK_LENGTH/2)) +",0)"); 432 | 433 | } 434 | } 435 | // move for margins 436 | p.parent.selectAll(".zones").attr("transform", "translate(" + p.margins.left + "," + p.margins.top + ")"); 437 | 438 | } 439 | return chart; 440 | }; 441 | 442 | --------------------------------------------------------------------------------