forked from APIOpsCycles/CanvasCreator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcanvasCreatorUI.v1_5.min.js
1 lines (1 loc) · 37 KB
/
canvasCreatorUI.v1_5.min.js
1
const canvasData={apiBusinessModelCanvas:{id:"apiBusinessModelCanvas",layout:{columns:5,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Alexander Osterwalder","Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"keyPartners",gridPosition:{column:0,row:0,colSpan:1,rowSpan:2},fillOrder:7},{id:"keyActivities",gridPosition:{column:1,row:0,colSpan:1,rowSpan:1},fillOrder:6},{id:"keyResources",gridPosition:{column:1,row:1,colSpan:1,rowSpan:1},fillOrder:5},{id:"apiValueProposition",gridPosition:{column:2,row:0,colSpan:1,rowSpan:2},fillOrder:1,highlight:!0},{id:"developerRelations",gridPosition:{column:3,row:0,colSpan:1,rowSpan:1},fillOrder:3},{id:"channels",gridPosition:{column:3,row:1,colSpan:1,rowSpan:1},fillOrder:4},{id:"apiConsumerSegments",gridPosition:{column:4,row:0,colSpan:1,rowSpan:2},fillOrder:2},{id:"costs",gridPosition:{column:0,row:2,colSpan:2.5,rowSpan:1},fillOrder:9},{id:"benefits",gridPosition:{column:2.5,row:2,colSpan:2.5,rowSpan:1},fillOrder:8}]},apiValuePropositionCanvas:{id:"apiValuePropositionCanvas",layout:{columns:4,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Alexander Osterwalder","Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"tasks",gridPosition:{column:0,row:0,colSpan:4,rowSpan:1},fillOrder:1,highlight:!0,journeySteps:!0},{id:"gainEnablingFeatures",gridPosition:{column:0,row:1,colSpan:2,rowSpan:1},fillOrder:2},{id:"painRelievingFeatures",gridPosition:{column:2,row:1,colSpan:2,rowSpan:1},fillOrder:3},{id:"apiProducts",gridPosition:{column:0,row:2,colSpan:4,rowSpan:1},fillOrder:4}]},businessImpactCanvas:{id:"businessImpactCanvas",layout:{columns:3,rows:2},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"availabilityRisks",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"securityRisks",gridPosition:{column:1,row:0,colSpan:1,rowSpan:1},fillOrder:3,highlight:!0},{id:"dataRisks",gridPosition:{column:2,row:0,colSpan:1,rowSpan:1},fillOrder:5,highlight:!0},{id:"mitigateAvailabilityRisks",gridPosition:{column:0,row:1,colSpan:1,rowSpan:1},fillOrder:2},{id:"mitigateSecurityRisks",gridPosition:{column:1,row:1,colSpan:1,rowSpan:1},fillOrder:4},{id:"mitigateDataRisks",gridPosition:{column:2,row:1,colSpan:1,rowSpan:1},fillOrder:6}]},capacityCanvas:{id:"capacityCanvas",layout:{columns:3,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"currentBusinessVolumes",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"futureConsumptionTrends",gridPosition:{column:1,row:0,colSpan:2,rowSpan:1},fillOrder:2},{id:"peakLoadAndAvailabilityRequirements",gridPosition:{column:0,row:1,colSpan:3,rowSpan:1},fillOrder:3},{id:"cachingStrategies",gridPosition:{column:0,row:2,colSpan:1,rowSpan:1},fillOrder:4},{id:"rateLimitingStrategies",gridPosition:{column:1,row:2,colSpan:1,rowSpan:1},fillOrder:5},{id:"scalingStrategies",gridPosition:{column:2,row:2,colSpan:1,rowSpan:1},fillOrder:6}]},customerJourneyCanvas:{id:"customerJourneyCanvas",layout:{columns:5,rows:4},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"customerDiscoversNeed",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:2},{id:"persona",gridPosition:{column:1,row:0,colSpan:3,rowSpan:1},fillOrder:1,highlight:!0},{id:"pains",gridPosition:{column:0,row:1,colSpan:1,rowSpan:2},fillOrder:5},{id:"journeySteps",gridPosition:{column:1,row:1,colSpan:3,rowSpan:2},fillOrder:4,journeySteps:!0},{id:"customerNeedIsResolved",gridPosition:{column:4,row:0,colSpan:1,rowSpan:1},fillOrder:3},{id:"gains",gridPosition:{column:4,row:1,colSpan:1,rowSpan:2},fillOrder:6},{id:"inputsOutputs",gridPosition:{column:.5,row:3,colSpan:2,rowSpan:1},fillOrder:7},{id:"interactionProcessingRules",gridPosition:{column:2.5,row:3,colSpan:2,rowSpan:1},fillOrder:8}]},domainCanvas:{id:"domainCanvas",layout:{columns:2,rows:4},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"selectedCustomerJourneySteps",gridPosition:{column:0,row:0,colSpan:2,rowSpan:1},fillOrder:1,highlight:!0,journeySteps:!0},{id:"coreEntitiesAndBusinessMeaning",gridPosition:{column:0,row:1,colSpan:1,rowSpan:1},fillOrder:2},{id:"attributesAndBusinessImportance",gridPosition:{column:1,row:1,colSpan:1,rowSpan:2},fillOrder:3},{id:"relationshipsBetweenEntities",gridPosition:{column:0,row:2,colSpan:1,rowSpan:1},fillOrder:4},{id:"businessComplianceAndIntegrityRules",gridPosition:{column:0,row:3,colSpan:1,rowSpan:1},fillOrder:5},{id:"securityAndPrivacyConsiderations",gridPosition:{column:1,row:3,colSpan:1,rowSpan:1},fillOrder:6}]},eventCanvas:{id:"eventCanvas",layout:{columns:4,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"userTaskTrigger",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"inputEventPayload",gridPosition:{column:0,row:1,colSpan:1,rowSpan:2},fillOrder:2},{id:"processingLogic",gridPosition:{column:1,row:1,colSpan:2,rowSpan:2},fillOrder:3},{id:"outputEventResult",gridPosition:{column:3,row:1,colSpan:1,rowSpan:2},fillOrder:4}]},interactionCanvas:{id:"interactionCanvas",layout:{columns:4,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"crudInteractions",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"crudInputOutputModels",gridPosition:{column:0,row:1,colSpan:1,rowSpan:1},fillOrder:2},{id:"crudProcessingValidation",gridPosition:{column:0,row:2,colSpan:1,rowSpan:1},fillOrder:3},{id:"queryDrivenInteractions",gridPosition:{column:1,row:0,colSpan:1,rowSpan:1},fillOrder:4,highlight:!0},{id:"queryDrivenInputOutputModels",gridPosition:{column:1,row:1,colSpan:1,rowSpan:1},fillOrder:5},{id:"queryDrivenProcessingValidation",gridPosition:{column:1,row:2,colSpan:1,rowSpan:1},fillOrder:6},{id:"commandDrivenInteractions",gridPosition:{column:2,row:0,colSpan:1,rowSpan:1},fillOrder:7,highlight:!0},{id:"commandDrivenInputOutputModels",gridPosition:{column:2,row:1,colSpan:1,rowSpan:1},fillOrder:8},{id:"commandDrivenProcessingValidation",gridPosition:{column:2,row:2,colSpan:1,rowSpan:1},fillOrder:9},{id:"eventDrivenInteractions",gridPosition:{column:3,row:0,colSpan:1,rowSpan:1},fillOrder:10,highlight:!0},{id:"eventDrivenInputOutputModels",gridPosition:{column:3,row:1,colSpan:1,rowSpan:1},fillOrder:11},{id:"eventDrivenProcessingValidation",gridPosition:{column:3,row:2,colSpan:1,rowSpan:1},fillOrder:12}]},locationsCanvas:{id:"locationsCanvas",layout:{columns:4,rows:2},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"locationGroups",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"locationGroupCharacteristics",gridPosition:{column:0,row:1,colSpan:1,rowSpan:1},fillOrder:2},{id:"locations",gridPosition:{column:1,row:0,colSpan:1,rowSpan:1},fillOrder:3,highlight:!0},{id:"locationCharacteristics",gridPosition:{column:1,row:1,colSpan:1,rowSpan:1},fillOrder:4},{id:"locationDistances",gridPosition:{column:2,row:0,colSpan:1,rowSpan:1},fillOrder:5},{id:"locationDistanceCharacteristics",gridPosition:{column:2,row:1,colSpan:1,rowSpan:1},fillOrder:6},{id:"locationEndpoints",gridPosition:{column:3,row:0,colSpan:1,rowSpan:1},fillOrder:7},{id:"locationEndpointCharacteristics",gridPosition:{column:3,row:1,colSpan:1,rowSpan:1},fillOrder:8}]},restCanvas:{id:"restCanvas",layout:{columns:4,rows:3},metadata:{source:"APIOps Cycles",license:"CC-BY-SA 4.0",authors:["Osaango Ltd"],website:"www.apiopscycles.com"},sections:[{id:"apiResources",gridPosition:{column:0,row:0,colSpan:1,rowSpan:1},fillOrder:1,highlight:!0},{id:"apiResourceModel",gridPosition:{column:0,row:1,colSpan:1,rowSpan:2},fillOrder:2},{id:"apiVerbs",gridPosition:{column:1,row:0,colSpan:1,rowSpan:1},fillOrder:3,highlight:!0},{id:"apiVerbExample",gridPosition:{column:1,row:1,colSpan:3,rowSpan:2},fillOrder:4}]}},localizedData={"de-DE":{apiBusinessModelCanvas:{title:"API-Geschäftsmodell Canvas",purpose:"Wie praktikabel und wiederverwendbar wird diese API sein? Haben wir einen Business Case aus Kosten-Nutzen-Sicht?",howToUse:"Fassen Sie das Wertversprechen einer API aus dem API-Wertversprechen-Canvas zusammen und folgen Sie dann der nummerierten Reihenfolge.",sections:{keyPartners:{section:"Schlüsselpartner",description:"Wer sind die wichtigsten beteiligten Stakeholder?"},keyActivities:{section:"Schlüsselaktivitäten",description:"Was sind die wichtigsten Maßnahmen, die der API-Anbieter ergreifen muss, um erfolgreich zu arbeiten?"},keyResources:{section:"Schlüsselressourcen",description:"Welche einzigartigen strategischen Vermögenswerte muss der API-Anbieter erwerben oder aufbauen?"},apiValueProposition:{section:"API-Wertversprechen",description:"Welchen Wert bietet die API den API-Konsumenten?"},developerRelations:{section:"Entwicklerbeziehungen",description:"Wie erreicht und unterstützt der API-Anbieter API-Konsumenten?"},channels:{section:"Kanäle",description:"Über welche Mechanismen interagieren API-Konsumenten mit der API?"},apiConsumerSegments:{section:"API-Konsumentensegmente",description:"Wer sind die Zielgruppen für die API?"},costs:{section:"Kosten",description:"Was sind die wesentlichen Kosten für die Erstellung, Bereitstellung und den Betrieb der API?"},benefits:{section:"Vorteile",description:"Was sind die wesentlichen Vorteile oder Einnahmequellen, die durch die API generiert werden?"}}}},"en-US":{apiBusinessModelCanvas:{title:"API Business Model Canvas",purpose:"How feasible and reusable will this API be? Do we have a business case from a cost - benefit point of view?",howToUse:"Summarize the value proposition of one API from the API Value Proposition Canvas, then follow the numbered sequence.",sections:{keyPartners:{section:"Key Partners",description:"Who are the key stakeholders involved?"},keyActivities:{section:"Key Activities",description:"What are the most important actions the API provider must take to operate successfully?"},keyResources:{section:"Key Resources",description:"What unique strategic assets must the API provider acquire or build?"},apiValueProposition:{section:"API Value Proposition",description:"What value does the API offer to API consumers?"},developerRelations:{section:"Developer Relations",description:"How does the API provider reach and support API consumers?"},channels:{section:"Channels",description:"Through which mechanisms do API consumers interact with the API?"},apiConsumerSegments:{section:"API Consumer Segments",description:"Who are the target audiences for the API?"},costs:{section:"Costs",description:"What are the significant costs involved in building, deploying, and operating the API?"},benefits:{section:"Benefits",description:"What are the significant benefits or revenue streams generated by the API?"}}},apiValuePropositionCanvas:{title:"API Value Proposition Canvas",purpose:"Does this API address the jobs, pains, and gains of API consumers?",howToUse:"Describe the API consumer's perspective, starting with their tasks, then their pains and gains, and finally the API's products and features.",sections:{tasks:{section:"Tasks",description:"What are the API consumers trying to achieve?"},gainEnablingFeatures:{section:"Gain Enabling Features",description:"What features enable API consumers to achieve gains?"},painRelievingFeatures:{section:"Pain Relieving Features",description:"What features help API consumers overcome pains?"},apiProducts:{section:"API Products",description:"What API products and features address the tasks, pains, and gains?"}}},businessImpactCanvas:{title:"Business Impact Canvas",purpose:"What are the potential business impacts of API failure?",howToUse:"Consider the potential impact on availability, security, and data for each API.",sections:{availabilityRisks:{section:"Availability Risks",description:"What are the potential risks to API availability?"},securityRisks:{section:"Security Risks",description:"What are the potential security risks associated with the API?"},dataRisks:{section:"Data Risks",description:"What are the potential risks to data integrity or confidentiality?"},mitigateAvailabilityRisks:{section:"Mitigate Availability Risks",description:"How can the API provider mitigate the availability risks?"},mitigateSecurityRisks:{section:"Mitigate Security Risks",description:"How can the API provider mitigate the security risks?"},mitigateDataRisks:{section:"Mitigate Data Risks",description:"How can the API provider mitigate the data risks?"}}},capacityCanvas:{title:"Capacity Canvas",purpose:"How much capacity is needed to support API consumption?",howToUse:"Analyze the current and future capacity requirements for each API.",sections:{currentBusinessVolumes:{section:"Current Business Volumes",description:"What are the current business volumes and transaction rates?"},futureConsumptionTrends:{section:"Future Consumption Trends",description:"What are the anticipated future consumption trends?"},peakLoadAndAvailabilityRequirements:{section:"Peak Load and Availability Requirements",description:"What are the peak load and availability requirements?"},cachingStrategies:{section:"Caching Strategies",description:"What caching strategies can be used to optimize performance?"},rateLimitingStrategies:{section:"Rate Limiting Strategies",description:"What rate limiting strategies can be used to manage consumption?"},scalingStrategies:{section:"Scaling Strategies",description:"What scaling strategies can be used to accommodate growth?"}}},customerJourneyCanvas:{title:"Customer Journey Canvas",purpose:"How do API consumers interact with the API over time?",howToUse:"Map the customer journey for each API, from initial discovery to ongoing use.",sections:{customerDiscoversNeed:{section:"Customer Discovers Need",description:"How does the customer discover the need for the API?"},persona:{section:"Persona",description:"Who is the typical customer or user of the API?"},pains:{section:"Pains",description:"What are the customer's pain points or challenges?"},journeySteps:{section:"Journey Steps",description:"What are the steps the customer takes in their journey?"},customerNeedIsResolved:{section:"Customer Need Is Resolved",description:"How is the customer's need ultimately resolved?"},gains:{section:"Gains",description:"What are the customer's gains or benefits?"},inputsOutputs:{section:"Inputs & Outputs",description:"What are the inputs and outputs at each step?"},interactionProcessingRules:{section:"Interaction & Processing Rules",description:"What are the interaction and processing rules at each step?"}}},domainCanvas:{title:"Domain Canvas",purpose:"What are the core entities and business rules related to the API?",howToUse:"Define the domain model for each API, including entities, attributes, and relationships.",sections:{selectedCustomerJourneySteps:{section:"Selected Customer Journey Steps",description:"Which customer journey steps are relevant to this domain?"},coreEntitiesAndBusinessMeaning:{section:"Core Entities & Business Meaning",description:"What are the core entities and their business meaning?"},attributesAndBusinessImportance:{section:"Attributes & Business Importance",description:"What are the key attributes of each entity and their business importance?"},relationshipsBetweenEntities:{section:"Relationships Between Entities",description:"What are the relationships between the entities?"},businessComplianceAndIntegrityRules:{section:"Business, Compliance & Integrity Rules",description:"What are the business, compliance, and integrity rules related to the entities?"},securityAndPrivacyConsiderations:{section:"Security & Privacy Considerations",description:"What are the security and privacy considerations related to the entities?"}}},eventCanvas:{title:"Event Canvas",purpose:"What events are relevant to the API, and how are they processed?",howToUse:"Define the events, their triggers, and the processing logic for each API.",sections:{userTaskTrigger:{section:"User Task / Trigger",description:"What user action or system event triggers this event operation?"},inputEventPayload:{section:"Input / Event Payload",description:"What data is included in the incoming event payload? Specify key attributes."},processingLogic:{section:"Processing / Logic",description:"Describe the backend processing logic, including validations, transformations, or routing decisions."},outputEventResult:{section:"Output / Event Result",description:"What resulting event or acknowledgment is produced? Include attributes of the output payload."}}},interactionCanvas:{title:"Interaction Canvas",purpose:"What are the different types of interactions supported by the API?",howToUse:"Define the CRUD, query-driven, command-driven, and event-driven interactions for each API.",sections:{crudInteractions:{section:"CRUD Interactions",description:"What are the CRUD (Create, Read, Update, Delete) interactions supported by the API?"},crudInputOutputModels:{section:"CRUD Input & Output Models",description:"What are the input and output models for the CRUD interactions?"},crudProcessingValidation:{section:"CRUD Processing & Validation",description:"What are the processing and validation rules for the CRUD interactions?"},queryDrivenInteractions:{section:"Query-Driven Interactions",description:"What are the query-driven interactions supported by the API?"},queryDrivenInputOutputModels:{section:"Query-Driven Input & Output Models",description:"What are the input and output models for the query-driven interactions?"},queryDrivenProcessingValidation:{section:"Query-Driven Processing & Validation",description:"What are the processing and validation rules for the query-driven interactions?"},commandDrivenInteractions:{section:"Command-Driven Interactions",description:"What are the command-driven interactions supported by the API?"},commandDrivenInputOutputModels:{section:"Command-Driven Input & Output Models",description:"What are the input and output models for the command-driven interactions?"},commandDrivenProcessingValidation:{section:"Command-Driven Processing & Validation",description:"What are the processing and validation rules for the command-driven interactions?"},eventDrivenInteractions:{section:"Event-Driven Interactions",description:"What are the event-driven interactions supported by the API?"},eventDrivenInputOutputModels:{section:"Event-Driven Input & Output Models",description:"What are the input and output models for the event-driven interactions?"},eventDrivenProcessingValidation:{section:"Event-Driven Processing & Validation",description:"What are the processing and validation rules for the event-driven interactions?"}}},locationsCanvas:{title:"Locations Canvas",purpose:"What are the relevant locations and their characteristics?",howToUse:"Define the locations, their distances, and their endpoints for each API.",sections:{locationGroups:{section:"Location Groups",description:"What are the relevant location groups?"},locationGroupCharacteristics:{section:"Location Group Characteristics",description:"What are the characteristics of the location groups?"},locations:{section:"Locations",description:"What are the relevant locations within each group?"},locationCharacteristics:{section:"Location Characteristics",description:"What are the characteristics of the locations?"},locationDistances:{section:"Location Distances",description:"What are the distances between the locations?"},locationDistanceCharacteristics:{section:"Location Distance Characteristics",description:"What are the characteristics of the location distances?"},locationEndpoints:{section:"Location Endpoints",description:"What are the endpoints associated with the locations?"},locationEndpointCharacteristics:{section:"Location Endpoint Characteristics",description:"What are the characteristics of the location endpoints?"}}},restCanvas:{title:"REST Canvas",purpose:"How can the API be designed using RESTful principles?",howToUse:"Define the API resources, verbs, and example requests and responses.",sections:{apiResources:{section:"API Resources",description:"What are the key resources exposed by the API?"},apiResourceModel:{section:"API Resource Model",description:"What is the structure of the API resource model?"},apiVerbs:{section:"API Verbs",description:"What HTTP verbs are used to interact with the API resources?"},apiVerbExample:{section:"API Verb Example",description:"Provide an example of an API request and response for each verb."}}}}};let currentColor=defaultStyles.stickyNoteColor,selectedNote=null;function loadCanvasData(e){return canvasData[e]}function populateLocaleSelector(){const i=document.getElementById("locale");var e=Object.keys(localizedData),t=document.createElement("option");t.value="",t.text="Select Locale",i.add(t),e.forEach(e=>{var t=document.createElement("option");t.value=e,t.text=e,i.add(t)})}function populateCanvasSelector(i){const o=document.getElementById("canvas");o.innerHTML="",Object.keys(localizedData[i]).forEach(e=>{var t=document.createElement("option");t.value=e,t.text=localizedData[i][e].title,o.add(t)})}document.getElementById("locale").addEventListener("change",e=>{e=e.target.value,document.getElementById("canvasSelector").style.display="block",populateCanvasSelector(e),e=document.getElementById("canvas").value;e&&(document.getElementById("canvasCreator").style.display="flex")},{once:!0}),document.querySelectorAll(".canvas-tools").forEach(e=>{e.addEventListener("touchstart",function(e){e.preventDefault(),this.click()},{passive:!1})}),document.getElementById("canvas").addEventListener("change",e=>{loadCanvas(document.getElementById("locale").value,e.target.value)},{once:!0});let canvasDataForId=null,contentData={};function loadCanvas(e,t){if(!(canvasDataForId=canvasData[t]))return void console.error("Canvas data not found for canvasId: "+t);contentData={templateId:t,locale:e,metadata:{source:"",license:"",authors:[],website:""},sections:canvasDataForId.sections?canvasDataForId.sections.map(e=>({sectionId:e.id,stickyNotes:[]})):[]};let f=d3.select("svg");const r=s=>{f.selectAll(".sticky-note").remove(),s&&s.sections&&(s.sections.forEach(i=>{var e=s.templateId;const o=canvasData[e].sections.find(e=>e.id===i.sectionId);i.stickyNotes&&0<i.stickyNotes.length&&((e=f.selectAll(".sticky-note-"+i.sectionId).data(i.stickyNotes).enter().append("g").attr("class","sticky-note sticky-note-"+i.sectionId).attr("id",(e,t)=>`sticky-note-${i.sectionId}-`+t).attr("transform",e=>{var t=(e.position.y||0)+0*(o.gridPosition.row+1);return`translate(${e.position.x||0},${t})`})).on("click touchstart",function(e,t){e.stopPropagation(),e.preventDefault(),selectedNote=t}),e.append("rect").attr("x",0).attr("y",0).attr("width",defaultStyles.stickyNoteSize).attr("height",defaultStyles.stickyNoteSize).attr("fill",e=>e.color||defaultStyles.stickyNoteColor).attr("stroke",defaultStyles.stickyNoteBorderColor).attr("rx",3).attr("ry",3),e.append("text").attr("x",5).attr("y",15).attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize+"px").attr("fill",defaultStyles.contentFontColor).each(function(e){e.content=a(f,e.content);var t=e.content.split("\n");for(let e=0;e<t.length;e++)d3.select(this).append("tspan").attr("x",5).attr("dy",0===e?0:14).text(t[e])}).on("dblclick touchend",function(e,t){e.stopPropagation(),e.preventDefault();const o=d3.select(this.parentNode);o.select("text");o.select("text").style("visibility","hidden");const i=o.append("foreignObject").attr("x",0).attr("y",0).attr("width",defaultStyles.stickyNoteSize).attr("height",defaultStyles.stickyNoteSize).append("xhtml:textarea").attr("value",t.content).style("font-family",defaultStyles.fontFamily).style("font-size",defaultStyles.fontSize+"px").style("width","calc(100% + 0px)").style("height","calc(100% + 0px)").style("border","none").style("padding","5px").style("resize","none");setTimeout(()=>{i.node().focus()},0),i.on("focus",function(){this.value=t.content.replace(/\n{2,}/g,"\n")}).on("blur",function(e,t){var i;i=validateInput(sanitizeInput(this.value)),t.content=a(f,i),o.select("text").selectAll("tspan").remove(),d3.select(this.parentNode).remove(),r(s)})}))}),f.selectAll(".sticky-note").call(d3.drag().on("start",function(e,t){d3.select(this).attr("originalPosition",{x:t.position.x,y:t.position.y})}).on("drag",function(e,t){t.position.x=e.x,t.position.y=e.y,d3.select(this).attr("transform",`translate(${t.position.x},${t.position.y})`)}).on("end",function(e,t){})),f.on("contextmenu",function(e){e.preventDefault();var t=e.offsetX,i=e.offsetY;let o=null;for(let e=0;e<s.sections.length;e++){var n=s.sections[e];for(let e=0;e<n.stickyNotes.length;e++){var a=n.stickyNotes[e];if(t>=a.position.x&&t<=a.position.x+defaultStyles.stickyNoteSize&&i>=a.position.y&&i<=a.position.y+defaultStyles.stickyNoteSize){o=a;break}}if(o)break}o&&confirm("Are you sure you want to delete this sticky note?")&&((e=s.sections.find(e=>e.stickyNotes.includes(o))).stickyNotes=e.stickyNotes.filter(e=>e!==o),r(s))}))};function a(n,e){e=e.replace(/\n{2,}/g,"\n").split(" ");let a="";const s=[];return e.forEach(e=>{var t=a+e+" ",i=n.append("text").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize+"px").text(t),o=i.node().getComputedTextLength();i.remove(),a=o>defaultStyles.maxLineWidth?(s.push(a),e+" "):t}),s.push(a),s.join("\n")}{var s=canvasDataForId,l=contentData;t=localizedData,d3.select("svg").remove();const y=Math.floor((defaultStyles.width-s.layout.columns*defaultStyles.padding)/s.layout.columns),S=Math.floor((defaultStyles.height-defaultStyles.headerHeight-defaultStyles.footerHeight-4*defaultStyles.padding)/s.layout.rows),d=l.locale||defaultStyles.defaultLocale,v=(e=l.templateId,t[d][e]);function n(){f.selectAll("text.footer").remove(),f.append("text").attr("class","footer").attr("x",defaultStyles.width/2).attr("y",defaultStyles.height-defaultStyles.footerHeight-2*defaultStyles.padding).attr("text-anchor","middle").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize).attr("fill",defaultStyles.fontColor).html(`Content by: ${l?.metadata?.source} | ${l?.metadata?.license} | ${l?.metadata?.authors} | <a href='http://${l?.metadata?.website}' target='_blank'>${l?.metadata?.website}</a>`)}0===Object.keys(l).length&&(l.templateId=s.id,l.locale=d,l.metadata={source:"",license:"",authors:[],website:""},l.sections=s.sections.map(e=>({sectionId:e.id,stickyNotes:[]}))),(async(e,t,i=0,o,n=defaultStyles.headerHeight+2*defaultStyles.padding,a=defaultStyles.headerHeight+2*defaultStyles.padding)=>{try{var s=await fetch(e);if(!s.ok)throw new Error("Failed to fetch the logo SVG");var r=await s.text();t.append("g").attr("transform",`translate(${i}, ${o}) scale(${n/100}, ${a/100})`).html(r)}catch(e){}})("/img/apiops-cycles-logo2025-blue.svg",f=d3.select("#canvasCreator").append("svg").attr("width",defaultStyles.width+2*defaultStyles.padding).attr("height",defaultStyles.height).style("background-color",defaultStyles.backgroundColor),defaultStyles.padding,defaultStyles.padding/2,defaultStyles.padding,defaultStyles.padding),f.append("text").attr("x",defaultStyles.headerHeight+2*defaultStyles.padding).attr("y",2*defaultStyles.padding).attr("text-anchor","start").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize+4+"px").attr("font-weight","bold").attr("fill",defaultStyles.fontColor).text(v.title),f.append("text").attr("x",defaultStyles.headerHeight+2*defaultStyles.padding).attr("y",defaultStyles.headerHeight-3*defaultStyles.padding).attr("text-anchor","start").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize+2+"px").attr("fill",defaultStyles.fontColor).text(v.purpose),f.append("text").attr("x",defaultStyles.headerHeight+2*defaultStyles.padding).attr("y",defaultStyles.headerHeight-defaultStyles.padding).attr("text-anchor","start").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize+2+"px").attr("fill",defaultStyles.fontColor).text(v.howToUse),f.append("text").attr("x",defaultStyles.width/2).attr("y",defaultStyles.height-defaultStyles.footerHeight).attr("text-anchor","middle").attr("font-family",defaultStyles.fontFamily).attr("font-size",defaultStyles.fontSize).attr("fill",defaultStyles.fontColor).html(`Template by: ${s.metadata.source} | ${s.metadata.license} | ${s.metadata.authors} | <a href='http://${s.metadata.website}' target='_blank'>${s.metadata.website}</a>`),s.sections.forEach((e,t)=>{var i=e.id,i=v.sections[i];const a=e.gridPosition.column*y+2*defaultStyles.padding,s=e.gridPosition.row*S+defaultStyles.headerHeight;var o=e.gridPosition.colSpan*y,n=e.gridPosition.rowSpan*S;const r={...defaultStyles,...e.style};if(f.append("rect").attr("x",a).attr("y",s).attr("width",o).attr("height",n).attr("fill",r.sectionColor).attr("stroke",r.borderColor).attr("rx",r.cornerRadius).attr("ry",r.cornerRadius).attr("stroke-width",r.lineSize),e.highlight&&f.append("rect").attr("x",a).attr("y",s).attr("width",o).attr("height",n).attr("fill",r.highlightColor).attr("stroke",r.borderColor).attr("rx",r.cornerRadius).attr("ry",r.cornerRadius).attr("stroke-width",2*r.lineSize),e.journeySteps){const h=["","","","",""];n=h.length;const m=Math.max(o/n-2*r.padding,r.stickyNoteSize),g=r.stickyNoteSize;f.append("defs").append("marker").attr("id","arrowhead").attr("markerWidth",4).attr("markerHeight",7).attr("refX",5).attr("refY",3.5).attr("orient","auto").append("polygon").attr("points","0 0, 5 3.5, 0 7").attr("fill",r.borderColor),h.forEach((e,t)=>{var i=a+t*(m+2*r.stickyNoteSpacing),o=i+m/2,n=s+r.stickyNoteSize;f.append("rect").attr("x",i).attr("y",s+r.stickyNoteSize/2+2*r.stickyNoteSpacing).attr("width",m).attr("height",g).attr("fill","#fff").attr("stroke",r.borderColor).attr("stroke-width",r.lineSize).attr("stroke-dasharray",3*r.lineSize).attr("rx",r.cornerRadius/2).attr("ry",r.cornerRadius/2),t<h.length-1&&(t=i+m+2*r.stickyNoteSpacing+m/2,f.append("line").attr("x1",o+m/2).attr("y1",n).attr("x2",t-m/2).attr("y2",n).attr("stroke",r.borderColor).attr("stroke-width",2*r.lineSize).attr("marker-end","url(#arrowhead)"))})}f.append("circle").attr("cx",a+r.padding).attr("cy",s+r.padding).attr("r",r.circleRadius).attr("fill",r.borderColor),f.append("text").attr("x",a+r.padding).attr("y",s+r.padding+5).attr("text-anchor","middle").attr("font-family",r.fontFamily).attr("font-size",r.fontSize+"px").attr("fill",r.fontColor).attr("fill",r.highlightColor).text(e.fillOrder),f.append("text").attr("x",a+r.padding+r.circleRadius).attr("y",s+r.padding+r.circleRadius).attr("font-family",r.fontFamily).attr("font-size",r.fontSize+"px").attr("font-weight","bold").attr("fill",r.fontColor).text(i.section);n=i.description.split(" ");let l="",c=0;const d=r.fontSize+2,u=o-2*r.padding,p=f.append("g");n.forEach(e=>{var t=l+e+" ",i=p.append("text").attr("font-family",r.fontFamily).attr("font-size",r.fontSize+"px").attr("fill",r.fontColor).attr("x",a+r.padding).attr("y",s+r.padding+r.circleRadius+2*r.padding+c*d).text(t);i.node().getComputedTextLength()>u?(i.remove(),f.append("text").attr("x",a+r.padding).attr("y",s+r.padding+r.circleRadius+2*r.padding+c*d).attr("font-family",defaultStyles.fontFamily).attr("font-size",r.fontSize+"px").attr("fill",r.fontColor).text(l),l=e+" ",c++):(i.remove(),l=t)}),f.append("text").attr("x",a+r.padding).attr("y",s+r.padding+r.circleRadius+2*r.padding+c*d).attr("font-family",r.fontFamily).attr("font-size",r.fontSize+"px").attr("fill",r.fontColor).text(l)}),f.append("defs").append("filter").attr("id","shadow").append("feDropShadow").attr("dx",3).attr("dy",3).attr("stdDeviation",2).attr("flood-color",defaultStyles.shadowColor),(t=document.getElementById("exportButton")).dataset.listenerAttached||(t.addEventListener("click",e=>{var t={templateId:s.id,metadata:{...l.metadata,date:(new Date).toISOString()},sections:l.sections.map(e=>({sectionId:e.sectionId,stickyNotes:e.stickyNotes.map(e=>({content:e.content.replace(/\n/g,""),position:e.position,size:e.size,color:e.color}))}))},t=JSON.stringify(t,null,2),i=document.createElement("a"),t=(i.href="data:application/json;charset=utf-8,"+encodeURIComponent(t),""+l.metadata.source+l.templateId+`_${d}.json`);i.download=t,document.body.appendChild(i),i.click(),document.body.removeChild(i)}),t.dataset.listenerAttached=!0),(e=document.getElementById("importButton")).dataset.listenerAttached||(e.addEventListener("click",e=>{e.stopPropagation();e=document.createElement("input");e.type="file",e.accept=".json",e.onchange=e=>{var e=e.target.files[0],t=new FileReader;t.onload=e=>{e=JSON.parse(e.target.result);s.id=e.templateId,l.metadata=e.metadata,document.getElementById("source").value=e.metadata.source,document.getElementById("license").value=e.metadata.license,document.getElementById("authors").value=e.metadata.authors.join(","),document.getElementById("website").value=e.metadata.website,l.sections=e.sections.map((t,e)=>{const i=s.sections.find(e=>e.id===t.sectionId);let o=3*defaultStyles.stickyNoteSpacing,n=defaultStyles.stickyNoteSize;return{sectionId:t.sectionId,stickyNotes:t.stickyNotes.map(e=>{var t={content:validateInput(a(f,e.content.trim())),size:e.size||defaultStyles.stickyNoteSize,color:e.color||defaultStyles.stickyNoteColor};return e.position?t.position=e.position:(t.position={x:i.gridPosition.column*y+o,y:i.gridPosition.row*S+defaultStyles.headerHeight+n},(o+=defaultStyles.stickyNoteSize+defaultStyles.stickyNoteSpacing)+defaultStyles.stickyNoteSize>i.gridPosition.colSpan*y&&(o=2*defaultStyles.stickyNoteSpacing,n+=defaultStyles.stickyNoteSize+defaultStyles.stickyNoteSpacing)),t})}}),(f=d3.select("svg")).node().innerHTML=f.node().innerHTML,r(l),n()},t.readAsText(e)},e.click()}),e.dataset.listenerAttached=!0),(t=document.getElementById("exportSVGButton")).dataset.listenerAttached||(t.addEventListener("click",e=>{var t=f.node(),t=(new XMLSerializer).serializeToString(t),t=new Blob([t],{type:"image/svg+xml;charset=utf-8"}),i=document.createElement("a"),t=(i.href=URL.createObjectURL(t),""+l.metadata.source+l.templateId+`_${d}.svg`);i.download=t,document.body.appendChild(i),i.click(),document.body.removeChild(i)}),t.dataset.listenerAttached=!0),document.querySelectorAll(".colorSwatch").forEach(e=>{e.addEventListener("click",()=>{currentColor=e.dataset.color,selectedNote&&(selectedNote.color=currentColor,r(l),selectedNote=null)})}),document.getElementById("metadataButton").addEventListener("click",()=>{document.getElementById("metadataForm").style.display="block"}),document.getElementById("saveMetadata").addEventListener("click",()=>{l.metadata={source:document.getElementById("source").value,license:document.getElementById("license").value,authors:document.getElementById("authors").value.split(","),website:document.getElementById("website").value},document.getElementById("metadataForm").style.display="none",n()});let i=0,o=0;function c(e,t){let o,n;"mouse"===t?(o=e.offsetX-defaultStyles.stickyNoteSize/2,n=e.offsetY-defaultStyles.stickyNoteSize/2):"touch"===t&&(t=e.changedTouches[0],e=f.node().getBoundingClientRect(),o=t.clientX-e.left-defaultStyles.stickyNoteSize/2,n=t.clientY-e.top-defaultStyles.stickyNoteSize/2);const i=s.sections.find(e=>{var t,i,e={x:e.gridPosition.column*y+2*defaultStyles.padding,y:e.gridPosition.row*S+defaultStyles.headerHeight,width:e.gridPosition.colSpan*y,height:e.gridPosition.rowSpan*S};return t=o+defaultStyles.stickyNoteSize/2,i=n+defaultStyles.stickyNoteSize/2,t>=(e=e).x&&t<=e.x+e.width&&i>=e.y&&i<=e.y+e.height});i&&(l.sections.find(e=>e.sectionId===i.id).stickyNotes.push({content:sanitizeInput("Double-click on text to edit. Click and select color "),position:{x:o,y:n},size:defaultStyles.stickyNoteSize,color:currentColor}),r(l))}f.on("click touchend",function(e){e.preventDefault();var{}=function(e){let t,i;var o,n=f.node().getBoundingClientRect();return i=e.type.startsWith("touch")?(o=e.changedTouches[0],t=o.clientX-n.left,o.clientY-n.top):(t=e.clientX-n.left,e.clientY-n.top),{x:t,y:i}}(e),t=(new Date).getTime();"touchend"===e.type?(t-i<300&&c(e,"touch"),i=t):(t-o<300&&c(e,"mouse"),o=t)}),r(l)}}let hasStickyNotes=!1;function checkForUnsavedChanges(e){var t;if(contentData&&contentData.sections&&(hasStickyNotes=contentData.sections.some(e=>0<e.stickyNotes.length)))return t="You have unsaved changes. Are you sure you want to leave this page?",e.preventDefault(),e.returnValue=t}window.addEventListener("beforeunload",checkForUnsavedChanges),document.getElementById("locale").addEventListener("change",e=>{var e=e.target.value,t=(document.getElementById("canvasSelector").style.display="block",populateCanvasSelector(e),document.getElementById("canvas").value);t&&loadCanvas(e,t)}),document.getElementById("canvas").addEventListener("change",e=>{loadCanvas(document.getElementById("locale").value,e.target.value)}),populateLocaleSelector();const localeSelector=document.getElementById("locale"),canvasSelector=document.getElementById("canvas");function handleSelectorFocus(e){if(contentData&&contentData.sections&&(hasStickyNotes=contentData.sections.some(e=>0<e.stickyNotes.length))){if(confirm("Are you sure you want to remove sticky notes and change canvas?"))return contentData.sections.forEach(e=>{e.stickyNotes=[]}),loadCanvas(localeSelector.value,canvasSelector.value),!1;e.target.blur()}}function sanitizeInput(e){return e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"")}function validateInput(e){return 200<e.length?e.substring(0,200):e}localeSelector.addEventListener("focus",handleSelectorFocus),canvasSelector.addEventListener("focus",handleSelectorFocus);