{"id":1810,"date":"2026-04-10T01:24:09","date_gmt":"2026-04-09T18:24:09","guid":{"rendered":"https:\/\/citytrail.id\/?page_id=1810"},"modified":"2026-04-15T08:28:18","modified_gmt":"2026-04-15T01:28:18","slug":"twibbonizer","status":"publish","type":"page","link":"https:\/\/citytrail.id\/en\/twibbonizer\/","title":{"rendered":"Twibbonizer"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"1810\" class=\"elementor elementor-1810\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-44c4f0e1 e-flex e-con-boxed e-con e-parent\" data-id=\"44c4f0e1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-23c5e7a elementor-widget elementor-widget-spacer\" data-id=\"23c5e7a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-116ecc0e elementor-widget elementor-widget-text-editor\" data-id=\"116ecc0e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"id\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Twibbonizer Event<\/title>\n  <style>\n    * {\n      box-sizing: border-box;\n    }\n\n    body {\n      margin: 0;\n      padding: 30px 15px;\n      font-family: Arial, sans-serif;\n      background: #f7f7f7;\n      color: #111;\n    }\n\n    #twibbon-container {\n      max-width: 440px;\n      margin: auto;\n      text-align: center;\n      background: #fff;\n      padding: 20px;\n      border-radius: 14px;\n      box-shadow: 0 8px 24px rgba(0,0,0,0.08);\n    }\n\n    h2 {\n      margin: 0 0 18px;\n      font-size: 24px;\n      line-height: 1.3;\n    }\n\n    input[type=\"file\"],\n    input[type=\"text\"] {\n      width: 100%;\n      margin: 8px 0;\n      padding: 12px 14px;\n      border: 1px solid #ccc;\n      border-radius: 10px;\n      font-size: 15px;\n    }\n\n    .category-buttons {\n      display: flex;\n      gap: 8px;\n      justify-content: center;\n      margin: 14px 0;\n      flex-wrap: wrap;\n    }\n\n    .category-buttons button {\n      padding: 10px 16px;\n      border: 2px solid #111;\n      background: #fff;\n      color: #111;\n      cursor: pointer;\n      font-weight: bold;\n      border-radius: 10px;\n      transition: 0.2s ease;\n    }\n\n    .category-buttons button.active {\n      background: #111;\n      color: #fff;\n    }\n\n    canvas {\n      width: 100%;\n      height: auto;\n      margin-top: 14px;\n      background: #f2f2f2;\n      border-radius: 12px;\n      display: block;\n    }\n\n    #download {\n      width: 100%;\n      margin-top: 14px;\n      padding: 12px 16px;\n      background: #111;\n      color: #fff;\n      border: none;\n      border-radius: 10px;\n      cursor: pointer;\n      font-size: 15px;\n      font-weight: bold;\n    }\n\n    #download:hover {\n      opacity: 0.92;\n    }\n\n    .note {\n      font-size: 12px;\n      color: #666;\n      margin-top: 10px;\n      line-height: 1.5;\n    }\n  <\/style>\n<\/head>\n<body>\n\n<div id=\"twibbon-container\">\n  <h2>TWIBBONIZER BOGOR CITYTRAIL2026<\/h2>\n\n  <input type=\"file\" id=\"uploadFile\" accept=\"image\/*\">\n  <input type=\"text\" id=\"participantName\" placeholder=\"Masukkan Nama Anda\">\n\n  <div class=\"category-buttons\">\n    <button type=\"button\" data-cat=\"5k\" class=\"active\">5K<\/button>\n    <button type=\"button\" data-cat=\"10k\">10K<\/button>\n    <button type=\"button\" data-cat=\"21k\">21K<\/button>\n  <\/div>\n\n  <canvas id=\"canvas\" width=\"1080\" height=\"1350\"><\/canvas>\n  <button type=\"button\" id=\"download\">Download<\/button>\n\n  <div class=\"note\">\n    Upload foto dulu, isi nama, pilih kategori, lalu download hasilnya.\n  <\/div>\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n  const CANVAS_W = 1080;\n  const CANVAS_H = 1350;\n\n  const canvas = document.getElementById(\"canvas\");\n  const ctx = canvas.getContext(\"2d\");\n\n  canvas.width = CANVAS_W;\n  canvas.height = CANVAS_H;\n\n  const uploadFile = document.getElementById(\"uploadFile\");\n  const downloadBtn = document.getElementById(\"download\");\n  const categoryButtons = document.querySelectorAll(\".category-buttons button\");\n  const nameInput = document.getElementById(\"participantName\");\n\n  let currentCategory = \"5k\";\n  let userImage = null;\n  let frameImage = new Image();\n  let imageLoaded = false;\n\n  function loadFrame() {\n    const framePath = \"\/wp-content\/uploads\/twibbon\/frame-\" + currentCategory + \".png\";\n    frameImage = new Image();\n    frameImage.crossOrigin = \"anonymous\";\n    frameImage.src = framePath + \"?v=\" + Date.now();\n\n    frameImage.onload = function () {\n      render();\n    };\n\n    frameImage.onerror = function () {\n      console.warn(\"Frame gagal dimuat:\", framePath);\n      render();\n    };\n  }\n\n  categoryButtons.forEach(button => {\n    button.addEventListener(\"click\", function () {\n      categoryButtons.forEach(btn => btn.classList.remove(\"active\"));\n      this.classList.add(\"active\");\n      currentCategory = this.dataset.cat;\n      loadFrame();\n    });\n  });\n\n  function drawImageCropToCanvas(img) {\n    const targetRatio = CANVAS_W \/ CANVAS_H;\n    const imgRatio = img.width \/ img.height;\n\n    let sx, sy, sw, sh;\n\n    if (imgRatio > targetRatio) {\n      sh = img.height;\n      sw = sh * targetRatio;\n      sx = (img.width - sw) \/ 2;\n      sy = 0;\n    } else {\n      sw = img.width;\n      sh = sw \/ targetRatio;\n      sx = 0;\n      sy = (img.height - sh) \/ 2;\n    }\n\n    ctx.drawImage(img, sx, sy, sw, sh, 0, 0, CANVAS_W, CANVAS_H);\n  }\n\n  function render() {\n    ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);\n\n    ctx.fillStyle = \"#f2f2f2\";\n    ctx.fillRect(0, 0, CANVAS_W, CANVAS_H);\n\n    if (imageLoaded && userImage) {\n      drawImageCropToCanvas(userImage);\n    }\n\n    if (frameImage.complete && frameImage.naturalWidth > 0) {\n      ctx.save();\n      ctx.imageSmoothingEnabled = true;\n      ctx.drawImage(frameImage, 0, 0, CANVAS_W, CANVAS_H);\n      ctx.restore();\n    }\n\n    const nameText = nameInput.value.trim();\n\n    if (nameText !== \"\") {\n      ctx.save();\n      ctx.font = \"bold 38px Arial\";\n      ctx.textAlign = \"center\";\n      ctx.textBaseline = \"middle\";\n\n      ctx.strokeStyle = \"#ffffff\";\n      ctx.lineWidth = 4;\n\n      ctx.fillStyle = \"#ffffff\";\n\n      ctx.shadowColor = \"rgba(0,0,0,0.55)\";\n      ctx.shadowBlur = 8;\n      ctx.shadowOffsetX = 0;\n      ctx.shadowOffsetY = 3;\n\n      const textX = CANVAS_W \/ 2;\n      const textY = 1221;\n\n      ctx.strokeText(nameText.toUpperCase(), textX, textY);\n      ctx.fillText(nameText.toUpperCase(), textX, textY);\n      ctx.restore();\n    }\n  }\n\n  uploadFile.addEventListener(\"change\", function (e) {\n    const file = e.target.files[0];\n    if (!file) return;\n\n    const reader = new FileReader();\n\n    reader.onload = function (event) {\n      const img = new Image();\n\n      img.onload = function () {\n        userImage = img;\n        imageLoaded = true;\n        render();\n      };\n\n      img.src = event.target.result;\n    };\n\n    reader.readAsDataURL(file);\n  });\n\n  nameInput.addEventListener(\"input\", render);\n  nameInput.addEventListener(\"keyup\", render);\n  nameInput.addEventListener(\"change\", render);\n\n  downloadBtn.addEventListener(\"click\", function () {\n    if (!imageLoaded) {\n      alert(\"Upload foto dulu ya.\");\n      return;\n    }\n\n    const link = document.createElement(\"a\");\n    link.download = \"twibbon-event.png\";\n    link.href = canvas.toDataURL(\"image\/png\");\n    link.click();\n  });\n\n  loadFrame();\n});\n<\/script>\n\n<\/body>\n<\/html>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Twibbonizer Event TWIBBONIZER BOGOR CITYTRAIL2026 5K 10K 21K Download Upload foto dulu, isi nama, pilih kategori, lalu download hasilnya.<\/p>","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-1810","page","type-page","status-publish","hentry"],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/pages\/1810","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/comments?post=1810"}],"version-history":[{"count":35,"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/pages\/1810\/revisions"}],"predecessor-version":[{"id":1855,"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/pages\/1810\/revisions\/1855"}],"wp:attachment":[{"href":"https:\/\/citytrail.id\/en\/wp-json\/wp\/v2\/media?parent=1810"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}