{"__browser":{"country":"US","device":"unknown_device","mobile":false,"name":"unknown browser","platform":"unknown_platform","version":"0"},"__constants":{},"__CPDATA":{"domain_iframe":"https://cdpn.io","environment":"production","host":"codepen.io","iframe_allow":"accelerometer *; ambient-light-sensor *; camera *; display-capture *; encrypted-media *; geolocation *; gyroscope *; microphone *; midi *; payment *; vr *; web-share *; serial *; xr-spatial-tracking *","iframe_sandbox":"allow-downloads allow-forms allow-modals allow-pointer-lock allow-popups-to-escape-sandbox allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation"},"__graphql":{"data":{"data":{"sessionUser":{"id":"VoDkNZ","name":"Captain Anonymous","title":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","currentContext":{"id":"VoDkNZ","title":"Captain Anonymous","name":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","username":"anon","__typename":"User"},"currentTeamId":null,"username":"anon","admin":false,"anon":true,"pro":false,"verified":false,"featureFlags":[],"teams":[],"__typename":"User"}}},"url":"https://codepen.io/graphql","api":"cprails"},"__user":{"anon":true,"base_url":"/anon/","cohorts":[],"current_team_hashid":null,"current_team_id":0,"hashid":"VoDkNZ","id":1,"itemType":"user","name":"Captain Anonymous","paid":false,"tier":0,"username":"anon","created_at":null,"email_verified":null,"collections_count":0,"collections_private_count":0,"followers_count":0,"followings_count":0,"pens_count":0,"pens_private_count":0,"projects_count":0,"projects_private_count":0},"__firebase":{"config":{"apiKey":"AIzaSyBgLAe7N_MdFpuVofMkcQLGwwhUu5tuxls","authDomain":"codepen-store-production.firebaseapp.com","databaseURL":"https://codepen-store-production.firebaseio.com","disabled":false,"projectId":"codepen-store-production"},"token":"eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsImNsYWltcyI6eyJvd25lcklkIjoiVm9Ea05aIiwiYWRtaW4iOmZhbHNlfSwiZXhwIjoxNzI5MDAwODEwLCJpYXQiOjE3Mjg5OTcyMTAsImlzcyI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInN1YiI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInVpZCI6IlZvRGtOWiJ9.lctz0akGl3QvUjlFodBod2w8baMnBupMu4G1pBNK9CSvXfyicRz59vbAGVOA6jMsxxL8mVhN2d0ZOJSpXR42Fw-3Ojb2uYDS6OW0utlLrW15fN1KMl9rzIn3pd7zbO-KWAroill8FNc8YrsrykqlDE0uEzBIRh-40rVYwDD0urAy9x2R5-qqiPAOtqwRLB_szTD2R9nHypjxW61fd7h9neS5xIdzVlDx56R-j2I-VRNs5X7iyX0p9m2M8pmv34qgonTd61Xm5yd1Wf5cl9a05q1oUvm9HPflNOJ0LcRUSApVBbuu7Zqwkh60Vu0Ok2Co01m6fEoYBbXlKIA72yNU0Q"},"__pay_stripe_public_key":"pk_live_2GndomDfiklqpSNQn8FrGuwZSMIMzha7DkLJqlYe7IR0ihKAlKdiHg68JJc5eVPt68rzAjzAAVXcUwjySHRCsgjQQ00gtRBUFNH","__pay_braintree_env":"production","__item":"{\"id\":61429065,\"user_id\":6132269,\"html\":\"<div class=\\\"wrapper\\\">\\n <h1>FabUnit Visualizer<\\/h1>\\n<canvas id=\\\"canvas\\\"><\\/canvas>\\n<fieldset>\\n <legend>Size<\\/legend>\\n <label>\\n Min\\n <input type=\\\"number\\\" id=\\\"sizeMin\\\" value=\\\"16\\\"\\/>\\n <\\/label>\\n <div><\\/div>\\n <label>\\n Opt\\n <input type=\\\"number\\\" id=\\\"sizeOpt\\\" value=\\\"22\\\"\\/>\\n <\\/label>\\n <label>\\n Max\\n <input type=\\\"number\\\" id=\\\"sizeMax\\\" disabled\\/>\\n <\\/label>\\n<\\/fieldset>\\n<fieldset>\\n <legend>Screen<\\/legend>\\n <label>\\n Min\\n <input type=\\\"number\\\" id=\\\"screenMin\\\" value=\\\"375\\\"\\/>\\n <\\/label>\\n <label>\\n Opt-Start\\n <input type=\\\"number\\\" id=\\\"screenOptStart\\\" value=\\\"1024\\\"\\/>\\n <\\/label>\\n <label>\\n Opt-End\\n <input type=\\\"number\\\" id=\\\"screenOptEnd\\\" value=\\\"1440\\\"\\/>\\n <\\/label>\\n <label>\\n Max\\n <input type=\\\"number\\\" id=\\\"screenMax\\\" value=\\\"1800\\\"\\/>\\n <\\/label>\\n<\\/fieldset>\\n <h5>by fabummzack<\\/h5>\\n <\\/div>\",\"css\":\"@import url('https:\\/\\/fonts.googleapis.com\\/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');\\n* {\\n box-sizing: border-box;\\n margin: 0;\\n padding: 0;\\n}\\n\\nbody {\\n background-color: #000011;\\n color: white;\\n font-family: Inter, sans-serif;\\n display: grid;\\n place-items: center;\\n min-height: 100vh;\\n padding: 0 5%;\\n font-size: clamp(10px, 3vw, 36px);\\n}\\n\\nh1 {\\n margin: 0 0 .4ch;\\n}\\n\\nlegend {\\n color: rgba(220, 240, 255, .5);\\n font-size: clamp(8px, 2vw, 12px);\\n text-transform: uppercase;\\n letter-spacing: .12em;\\n}\\n\\nfieldset {\\n margin: 20px auto;\\n border: 1px dashed #FFFFFF33;\\n padding: 25px;\\n display: grid;\\n grid-template-columns: repeat(4, minmax(0, 1fr));\\n border-radius: 7px;\\n}\\n\\nlabel {\\n color: rgba(220, 240, 255, .5);\\n font-size: clamp(8px, 3vw, 14px);\\n}\\n\\ninput {\\n font-family: inherit;\\n padding: 0;\\n margin: .5px 2px .5px -3px;\\n background-color: transparent;\\n border: none;\\n color: white;\\n font-size: clamp(18px, 5vw, 50px);\\n display: block;\\n outline: 0;\\n width: 6ch;\\n font-variant-numeric: tabular-nums;\\n letter-spacing: -.06em;\\n \\/\\/border-block-end: 1px solid rgba(220, 240, 255, .2);\\n \\n &:focus {\\n color: yellowgreen;\\n }\\n \\n &:disabled {\\n color: darkslateblue;\\n border: none;\\n }\\n}\\n\\ncanvas {\\n border: 1px dashed #FFFFFF33;\\n border-radius: 8px;\\n width: 100%;\\n max-width: 900px;\\n}\\n\\nh5 {\\n text-align: right;\\n font-weight: 400;\\n color: rgba(220, 240, 255, .3);\\n font-size: clamp(8px, 3vw, 14px);\\n}\\n\\ninput::-webkit-outer-spin-button,\\ninput::-webkit-inner-spin-button {\\n -webkit-appearance: none;\\n}\\ninput[type=number] {\\n -moz-appearance: textfield;\\n}\",\"js\":\"const inputs = [\\n 'sizeMin', \\n 'sizeOpt',\\n 'screenMin',\\n 'screenOptStart',\\n 'screenOptEnd',\\n 'screenMax'\\n];\\n\\nconst CANVAS_HEIGHT = 600;\\nconst CANVAS_WIDTH = 1000;\\nconst max = Math.max;\\nconst min = Math.min;\\nconst clamp = (min, v, max) => Math.max(min, Math.min(v, max));\\n\\nfunction funcLower(vw, {\\n screenMax, \\n screenMin, \\n screenOptStart, \\n screenOptEnd, \\n sizeMin, \\n sizeOpt\\n}) {\\n return clamp(sizeMin, (((sizeOpt - sizeMin) \\/ (screenOptStart - screenMin)) * vw) + (sizeOpt - ((sizeOpt - sizeMin) \\/ (screenOptStart - screenMin)) * screenOptStart), sizeOpt);\\n \\/\\/return clamp(sizeMin, (sizeOpt - sizeMin) \\/ (screenOptStart - screenMin) * (vw - screenMin) + sizeMin, sizeOpt);\\n}\\n\\nfunction funcUpper(vw, {\\n screenMax, \\n screenMin, \\n screenOptStart, \\n screenOptEnd, \\n sizeMin, \\n sizeOpt\\n}) {\\n const upperSize = sizeOpt \\/ screenOptEnd * screenMax;\\n return clamp(0, (upperSize - sizeOpt) \\/ (screenMax - screenOptEnd) * (vw - screenOptEnd) + sizeOpt, upperSize);\\n}\\n\\nfunction funcCombined(vw, {\\n screenMax, \\n screenMin, \\n screenOptStart, \\n screenOptEnd, \\n sizeMin, \\n sizeOpt\\n}) {\\n\\t\\tconst slopeCheck = (sizeOpt - sizeMin) \\/ (screenOptStart - screenMin) * 100 > 1;\\n\\t\\tconst slopeDown = sizeMin + (sizeOpt - sizeMin) * (vw - screenMin) \\/ (screenOptStart - screenMin);\\n\\t\\tconst slopeUp = vw \\/ screenOptEnd * sizeOpt;\\n\\t\\tconst sizeMax = screenMax \\/ screenOptEnd * sizeOpt;\\n\\t\\tif (slopeCheck) {\\n\\t\\t\\treturn clamp(sizeMin, slopeDown, clamp(sizeOpt, slopeUp, sizeMax));\\n\\t\\t} else {\\n\\t\\t\\treturn clamp(clamp(sizeMin, slopeDown, sizeOpt), slopeUp, sizeMax);\\n\\t\\t}\\n}\\n\\nfunction plotFunc({\\n func,\\n ctx,\\n vPad,\\n hPad,\\n w,\\n h,\\n vScale,\\n screenMax, \\n screenMin, \\n screenOptStart, \\n screenOptEnd, \\n sizeMin, \\n sizeOpt\\n}) {\\n for (i = 0; i < w; i++) {\\n const y = h - vPad - (func(i + screenMin - hPad, arguments[0]) - sizeMin) * vScale;\\n if (i === 0) {\\n ctx.moveTo(i, y);\\n } else {\\n ctx.lineTo(i, y);\\n }\\n }\\n}\\n\\nfunction redraw({\\n screenMax, \\n screenMin, \\n screenOptStart, \\n screenOptEnd, \\n sizeMin, \\n sizeOpt\\n}) {\\n const hPad = 200;\\n const vPad = 50;\\n const h = CANVAS_HEIGHT;\\n const w = screenMax - screenMin + 2 * hPad;\\n \\/\\/const w = CANVAS_WIDTH;\\n const upperSize = sizeOpt \\/ screenOptEnd * screenMax;\\n const vScale = (h - 2 * vPad) \\/ (upperSize - sizeMin);\\n \\n const canvas = document.getElementById('canvas');\\n canvas.width = w;\\n canvas.height = h;\\n \\n const ctx = canvas.getContext('2d');\\n ctx.fillStyle = '#000011';\\n ctx.fillRect(0, 0, w, h);\\n \\n \\/\\/ Draw mins\\n ctx.beginPath();\\n ctx.strokeStyle = 'darkslateblue';\\n ctx.lineWidth = 1;\\n ctx.moveTo(0, h - vPad);\\n ctx.lineTo(w, h - vPad);\\n \\n ctx.moveTo(hPad, h);\\n ctx.lineTo(hPad, h - vPad * 1.5);\\n ctx.stroke();\\n \\n \\/\\/ Draw max\\n ctx.beginPath();\\n ctx.strokeStyle = 'darkslateblue';\\n ctx.lineWidth = 1;\\n ctx.moveTo(0, vPad);\\n ctx.lineTo(w, vPad);\\n \\n ctx.moveTo(w - hPad, 0);\\n ctx.lineTo(w - hPad, vPad * 1.5);\\n ctx.stroke();\\n \\n \\/\\/ Draw opt\\n ctx.fillStyle = 'rgba(0,255,255,.05)';\\n ctx.fillRect(hPad + screenOptStart - screenMin, 0, screenOptEnd - screenOptStart, h);\\n \\/\\/ctx.fillRect(0, h - vPad - (sizeOpt - sizeMin) * vScale, w, 1);\\n ctx.beginPath();\\n ctx.strokeStyle = 'yellowgreen';\\n ctx.lineWidth = 2;\\n ctx.moveTo(0, h - vPad - (sizeOpt - sizeMin) * vScale);\\n ctx.lineTo(w, h - vPad - (sizeOpt - sizeMin) * vScale);\\n ctx.stroke();\\n \\/\\/const h = input.sizeM\\n \\n \\/*ctx.strokeStyle = 'rgba(255,0,0,0.3)';\\n ctx.beginPath();\\n plotFunc({...arguments[0], ctx, vPad, hPad, w, h, vScale, func: funcLower});\\n ctx.stroke();\\n \\n ctx.strokeStyle = 'rgba(0,255,0,0.3)';\\n ctx.beginPath();\\n plotFunc({...arguments[0], ctx, vPad, hPad, w, h, vScale, func: funcUpper});\\n ctx.stroke();*\\/\\n \\n ctx.strokeStyle = 'rgba(255,0,255,.5)';\\n ctx.lineWidth = 15;\\n ctx.beginPath();\\n plotFunc({...arguments[0], ctx, vPad, hPad, w, h, vScale, func: funcCombined});\\n ctx.stroke();\\n \\n document.querySelector('#sizeMax').value = (screenMax \\/ screenOptEnd * sizeOpt).toFixed(2)\\n \\n};\\n\\nconst handleInput = () => {\\n redraw(inputs.reduce((accum, id) => {\\n accum[id] = parseInt(document.getElementById(id).value);\\n return accum;\\n }, {}));\\n}\\n\\ninputs.forEach(id => {\\n const input = document.getElementById(id);\\n input.addEventListener('input', handleInput);\\n});\\n\\nhandleInput();\",\"html_pre_processor\":\"pug\",\"css_pre_processor\":\"scss\",\"js_pre_processor\":\"babel\",\"html_classes\":\"\",\"css_starter\":\"neither\",\"js_library\":null,\"created_at\":\"2022-06-13T05:36:22.158Z\",\"updated_at\":\"2022-12-01T10:45:04.265Z\",\"title\":\"FabUnit Visualizer\",\"description\":\"\",\"slug_hash\":\"yLvGMqZ\",\"head\":\"\",\"private\":true,\"slug_hash_private\":\"ed43660a7931e55b2fb2ec35d18e7f8c\",\"has_animation\":false,\"team_id\":0,\"css_prefix\":\"neither\",\"template\":false,\"parent_id\":0,\"comments_count\":0,\"custom_screenshot_filename\":null,\"loves_count\":0,\"pick\":false,\"popularity_score\":0,\"views_count\":0,\"pick_visible_at\":null,\"cpid\":\"01815b90-248e-727f-97c9-9d2ec805f04d\",\"is_new_editor_pen\":false,\"protected\":false,\"access\":\"Private\",\"pen_hash\":null,\"hashid\":\"yLvGMqZ\"}"}