export default part => { let { Point, points, Path, paths, options } = part.shorthand(); /** * Returs the value passed to it randomized with a given tolerance */ const about = (value, tolerance = 5) => { let randomized = (tolerance / 100) * Math.random() * value; let fixed = (1 - tolerance / 100) * value; return fixed + randomized; }; /** * like about, but also randomly makes value negative * This is for degrees */ const nabout = (value, tolerance = 5) => { if (Math.random() > 0.5) return about(value, tolerance); else return -1 * about(value, tolerance); }; /** * Draws a w*h box that's randomized by tolerance to give it * that hand-drawn look. * * Returns a Path object */ const box = (name, origin, width, height, tolerance = 10) => { let base = height; if (width < height) base = width; let t = base * (tolerance / 100); points[name + "TopLeft"] = new Point( about(origin.x, t), about(origin.y, t) ); points[name + "BottomLeft"] = new Point( about(origin.x, t), about(origin.y + height, t) ); points[name + "BottomRight"] = new Point( about(origin.x + width, t), about(origin.y + height, t) ); points[name + "TopRight"] = new Point( about(origin.x + width, t), about(origin.y, t) ); points[name + "Mid"] = points[name + "TopLeft"].shiftFractionTowards( points[name + "BottomRight"], 0.5 ); points[name + "Mid"].y += 3; let f = 0.3; let r = tolerance / 2; points[name + "TopLeftCp1"] = points[name + "TopLeft"] .shiftFractionTowards(points[name + "BottomLeft"], about(f)) .rotate(nabout(r), points[name + "TopLeft"]); points[name + "TopLeftCp2"] = points[name + "TopLeft"] .shiftFractionTowards(points[name + "TopRight"], about(f)) .rotate(nabout(r), points[name + "TopLeft"]); points[name + "BottomLeftCp1"] = points[name + "BottomLeft"] .shiftFractionTowards(points[name + "TopLeft"], about(f)) .rotate(nabout(r), points[name + "BottomLeft"]); points[name + "BottomLeftCp2"] = points[name + "BottomLeft"] .shiftFractionTowards(points[name + "BottomRight"], about(f)) .rotate(nabout(r), points[name + "BottomLeft"]); points[name + "BottomRightCp1"] = points[name + "BottomRight"] .shiftFractionTowards(points[name + "BottomLeft"], about(f)) .rotate(nabout(r), points[name + "BottomRight"]); points[name + "BottomRightCp2"] = points[name + "BottomRight"] .shiftFractionTowards(points[name + "TopRight"], about(f)) .rotate(nabout(r), points[name + "BottomRight"]); points[name + "TopRightCp1"] = points[name + "TopRight"] .shiftFractionTowards(points[name + "BottomRight"], about(f)) .rotate(nabout(r), points[name + "TopRight"]); points[name + "TopRightCp2"] = points[name + "TopRight"] .shiftFractionTowards(points[name + "TopLeft"], about(f)) .rotate(nabout(r), points[name + "TopRight"]); return new Path() .move(points[name + "TopLeft"]) .curve( points[name + "TopLeftCp1"], points[name + "BottomLeftCp1"], points[name + "BottomLeft"] ) .curve( points[name + "BottomLeftCp2"], points[name + "BottomRightCp1"], points[name + "BottomRight"] ) .curve( points[name + "BottomRightCp2"], points[name + "TopRightCp1"], points[name + "TopRight"] ) .curve( points[name + "TopRightCp2"], points[name + "TopLeftCp2"], points[name + "TopLeft"] ) .close() .attr("class", options.focus === name ? "note" : "fabric"); }; /** * Draws an arrow from to * Returns a Path object */ const arrow = (name, text = "", tolerance = 10) => { let from = points[name + "From"]; let to = points[name + "To"]; from = from.shiftTowards(to, 3); to = to.shiftTowards(from, 3); let base = from.dist(to); let t = base * (tolerance / 100); from.x = about(from.x, t); from.x = about(from.x, t); to.x = about(to.x, t); to.x = about(to.x, t); let f = 0.3; let r = tolerance / 2; points[name + "FromCp"] = from .shiftFractionTowards(to, about(f)) .rotate(nabout(r), from); points[name + "ToCp"] = to .shiftFractionTowards(from, about(f)) .rotate(nabout(r), to); points[name + "Tip1"] = to .shiftTowards(from, about(3.8)) .rotate(about(15), to); points[name + "Tip2"] = to .shiftTowards(from, about(3.5)) .rotate(about(-15), to); let path = new Path() .move(from) .curve(points[name + "FromCp"], points[name + "ToCp"], to) .move(points[name + "Tip1"]) .line(to) .line(points[name + "Tip2"]) .attr("class", "fabric"); if (options.focus === name) path = path.attr("class", "note"); if (text) return path .attr("data-text", " " + text) .attr("data-text-class", "scribble") .attr("data-text-class", options.focus === name ? "fill-note" : ""); else return path; }; const drawBox = (name, x, y, width, height, tolerance = 5, text = true) => { points[name + "Origin"] = new Point(x, y); paths[name] = box(name, points[name + "Origin"], width, height, tolerance); if (text) { points[name + "Mid"] .attr("data-text", name) .attr("data-text-class", "center scribble"); if (options.focus === name) points[name + "Mid"].attr("data-text-class", "fill-note"); } }; const svgLogo = (anchor, size = 1) => { points.svg15 = anchor .shift(45, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg3 = anchor .shift(0, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg45 = anchor .shift(-45, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg6 = anchor .shift(-90, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg75 = anchor .shift(-135, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg9 = anchor .shift(180, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg105 = anchor .shift(135, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svg12 = anchor .shift(90, 4 * size) .attr("data-circle", 1.2 * size) .attr("data-circle-class", "fill-fabric"); points.svgText = anchor .clone() .attr("data-text", "SVG") .attr("data-text-class", "text-xl scribble"); points.svgText.x += size * 7; points.svgText.y += 6; paths.svgLogo = new Path() .move(points.svg15) .line(points.svg75) .move(points.svg3) .line(points.svg9) .move(points.svg45) .line(points.svg105) .move(points.svg6) .line(points.svg12) .attr("class", "stroke-l"); }; const reactLogo = (anchor, size = 1) => { h = 3 * size; w = 6 * size; points.reactTop1 = anchor.shift(45, w); points.reactBottom1 = anchor.shift(-135, w); points.reactTop1Cp1 = points.reactTop1.shift(135, h); points.reactTop1Cp2 = points.reactTop1.shift(-45, h); points.reactBottom1Cp1 = points.reactBottom1.shift(135, h); points.reactBottom1Cp2 = points.reactBottom1.shift(-45, h); points.reactTop2 = points.reactTop1.rotate(60, anchor); points.reactBottom2 = points.reactBottom1.rotate(60, anchor); points.reactTop2Cp1 = points.reactTop1Cp1.rotate(60, anchor); points.reactTop2Cp2 = points.reactTop1Cp2.rotate(60, anchor); points.reactBottom2Cp1 = points.reactBottom1Cp1.rotate(60, anchor); points.reactBottom2Cp2 = points.reactBottom1Cp2.rotate(60, anchor); points.reactTop3 = points.reactTop1.rotate(-60, anchor); points.reactBottom3 = points.reactBottom1.rotate(-60, anchor); points.reactTop3Cp1 = points.reactTop1Cp1.rotate(-60, anchor); points.reactTop3Cp2 = points.reactTop1Cp2.rotate(-60, anchor); points.reactBottom3Cp1 = points.reactBottom1Cp1.rotate(-60, anchor); points.reactBottom3Cp2 = points.reactBottom1Cp2.rotate(-60, anchor); points.svgLogo = anchor .clone() .attr("data-circle", 1 * size) .attr("data-circle-class", "fill-fabric"); points.reactText = anchor .clone() .attr("data-text", "React") .attr("data-text-class", "text-xl scribble"); points.reactText.x += size * 7; points.reactText.y += 6; paths.reactLogo = new Path() .move(points.reactTop1) .curve(points.reactTop1Cp1, points.reactBottom1Cp1, points.reactBottom1) .curve(points.reactBottom1Cp2, points.reactTop1Cp2, points.reactTop1) .close() .move(points.reactTop2) .curve(points.reactTop2Cp1, points.reactBottom2Cp1, points.reactBottom2) .curve(points.reactBottom2Cp2, points.reactTop2Cp2, points.reactTop2) .close() .move(points.reactTop3) .curve(points.reactTop3Cp1, points.reactBottom3Cp1, points.reactBottom3) .curve(points.reactBottom3Cp2, points.reactTop3Cp2, points.reactTop3) .close(); }; // Other parts first so they're behind drawBox("Part4", 4, -19, 40, 65, 5, false); drawBox("Part3", 1, -16, 40, 65, 5, false); drawBox("Part2", -2, -13, 40, 65, 5, false); drawBox("Part", -5, -10, 40, 65, 5); paths.Part4.attr("class", "fill-bg"); paths.Part3.attr("class", "fill-bg"); paths.Part2.attr("class", "fill-bg"); paths.Part.attr("class", "fill-bg"); points.PartMid.y = points.PartTopLeft.y + 9; let x = 0; let y = 0; let w = 30; let h = 15; drawBox("Points", x, y, w, h); y += 18; drawBox("Paths", x, y, w, h); y += 18; drawBox("Snippets", x, y, w, h); x = -35; y = -3; w = 25; h = 20; drawBox("config", x, y, w, h); y += 23; drawBox("Store", x, y, w, h); x = -40; y = -30; drawBox("Pattern", x, y, 90, 90); points.PatternMid.y = points.PatternTopLeft.y + 9; drawBox("settings", -100, 6, 40, 20); drawBox("draft", 80, 3, 20, 25); points.arrow1From = points.settingsTopRight.shiftFractionTowards( points.settingsBottomRight, 0.5 ); points.arrow1To = points.PatternTopLeft.shiftFractionTowards( points.PatternBottomLeft, 0.5 ); paths.arrow1 = arrow("arrow1"); points.arrow2From = points.PatternTopRight.shiftFractionTowards( points.PatternBottomRight, 0.5 ); points.arrow2To = points.draftTopLeft.shiftFractionTowards( points.draftBottomLeft, 0.5 ); paths.arrow2 = arrow("arrow2", "draft()"); svgLogo(points.draftMid.shift(70, 50)); reactLogo(points.draftMid.shift(-80, 36)); points.arrow3From = points.draftTopLeft.shiftFractionTowards( points.draftTopRight, 0.5 ); points.arrow3To = points.svgText.clone(); paths.arrow3 = arrow("arrow3", "render()"); points.arrow4From = points.draftBottomLeft.shiftFractionTowards( points.draftBottomRight, 0.5 ); points.arrow4To = points.reactText.clone().shift(40, 15); paths.arrow4 = arrow("arrow4"); paths.extend = new Path() .move(points.draftTopRight) .line(points.draftTopRight.shift(0, 40)) .attr("class", "hidden"); return part; };