openfree commited on
Commit
292bb51
ยท
verified ยท
1 Parent(s): 1eaa353

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +335 -328
index.html CHANGED
@@ -395,6 +395,7 @@
395
  transition: all 0.3s ease;
396
  position: relative;
397
  overflow: hidden;
 
398
  }
399
 
400
  .option-card.selected {
@@ -420,7 +421,7 @@
420
  font-weight: bold;
421
  }
422
 
423
- .option-card:hover {
424
  border-color: #00d2ff;
425
  background: rgba(255, 255, 255, 0.1);
426
  transform: translateY(-2px);
@@ -1392,333 +1393,339 @@
1392
  </div>
1393
  </div>
1394
 
1395
- ```html
1396
- </div>
1397
- </div>
1398
-
1399
- <!-- ๊ธฐ๊ฐ„๋ณ„ ๋น„์šฉ ์ฐจํŠธ -->
1400
- <div class="chart-container">
1401
- <canvas id="customChart"></canvas>
1402
- </div>
1403
- </div>
1404
- </div>
1405
- </div>
1406
- </div>
1407
-
1408
- <script>
1409
- // ์ „์—ญ ๋ณ€์ˆ˜
1410
- let selectedComponents = {
1411
- service: [],
1412
- db: null,
1413
- auth: null,
1414
- credit: null,
1415
- payment: null,
1416
- marketing: null,
1417
- support: null,
1418
- monitoring: null,
1419
- additional: []
1420
- };
1421
-
1422
- let customChart = null;
1423
- let currentPeriod = 3;
1424
-
1425
- // ์˜ต์…˜ ์นด๋“œ ํด๋ฆญ ์ด๋ฒคํŠธ
1426
- document.querySelectorAll('.option-card').forEach(card => {
1427
- card.addEventListener('click', function() {
1428
- const category = this.dataset.category;
1429
- const id = this.dataset.id;
1430
-
1431
- if (category === 'service' || category === 'additional') {
1432
- // ๋ณต์ˆ˜ ์„ ํƒ ๊ฐ€๋Šฅ
1433
- this.classList.toggle('selected');
1434
-
1435
- if (this.classList.contains('selected')) {
1436
- if (!selectedComponents[category].includes(id)) {
1437
- selectedComponents[category].push(id);
1438
- }
1439
- } else {
1440
- const index = selectedComponents[category].indexOf(id);
1441
- if (index > -1) {
1442
- selectedComponents[category].splice(index, 1);
1443
- }
1444
- }
1445
- } else {
1446
- // ๋‹จ์ผ ์„ ํƒ
1447
- document.querySelectorAll(`[data-category="${category}"]`).forEach(c => {
1448
- c.classList.remove('selected');
1449
- });
1450
-
1451
- this.classList.add('selected');
1452
- selectedComponents[category] = id;
1453
- }
1454
- });
1455
- });
1456
-
1457
- // ํƒญ ์ „ํ™˜ ํ•จ์ˆ˜
1458
- function switchTab(tabId) {
1459
- document.querySelectorAll('.tab').forEach(tab => {
1460
- tab.classList.remove('active');
1461
- });
1462
- document.querySelectorAll('.tab-content').forEach(content => {
1463
- content.classList.remove('active');
1464
- });
1465
-
1466
- event.target.classList.add('active');
1467
- document.getElementById(tabId).classList.add('active');
1468
- }
1469
-
1470
- // ์ปค์Šคํ…€ ๋น„์šฉ ๊ณ„์‚ฐ ํ•จ์ˆ˜
1471
- function calculateCustomCost() {
1472
- let totalInitialCost = 0;
1473
- let totalResourceCost = 0;
1474
- let maxTime = 0;
1475
- let componentDetails = [];
1476
-
1477
- // ์„œ๋น„์Šค ๋น„์šฉ ๊ณ„์‚ฐ
1478
- selectedComponents.service.forEach(serviceId => {
1479
- const card = document.querySelector(`[data-id="${serviceId}"]`);
1480
- const cost = parseFloat(card.dataset.cost);
1481
- const time = parseFloat(card.dataset.time);
1482
- const resource = parseFloat(card.dataset.resource) || 0;
1483
- const name = card.querySelector('.option-name').textContent;
1484
-
1485
- totalInitialCost += cost;
1486
- totalResourceCost += resource;
1487
- maxTime = Math.max(maxTime, time);
1488
-
1489
- componentDetails.push({
1490
- name: name,
1491
- cost: cost,
1492
- type: 'service'
1493
- });
1494
- });
1495
-
1496
- // ๊ธฐํƒ€ ๊ตฌ์„ฑ ์š”์†Œ ๋น„์šฉ ๊ณ„์‚ฐ
1497
- ['db', 'auth', 'credit', 'payment', 'marketing', 'monitoring'].forEach(category => {
1498
- if (selectedComponents[category]) {
1499
- const card = document.querySelector(`[data-category="${category}"][data-id="${selectedComponents[category]}"]`);
1500
- const cost = parseFloat(card.dataset.cost);
1501
- const time = parseFloat(card.dataset.time);
1502
- const name = card.querySelector('.option-name').textContent;
1503
-
1504
- totalInitialCost += cost;
1505
- maxTime = Math.max(maxTime, time);
1506
-
1507
- componentDetails.push({
1508
- name: name,
1509
- cost: cost,
1510
- type: category
1511
- });
1512
- }
1513
- });
1514
-
1515
- // ์ง€์› ์„œ๋น„์Šค (์›”๊ฐ„ ๋น„์šฉ)
1516
- let monthlySupport = 0;
1517
- if (selectedComponents.support) {
1518
- const card = document.querySelector(`[data-category="support"][data-id="${selectedComponents.support]}"]`);
1519
- monthlySupport = parseFloat(card.dataset.cost);
1520
- const name = card.querySelector('.option-name').textContent;
1521
-
1522
- componentDetails.push({
1523
- name: name,
1524
- cost: monthlySupport,
1525
- type: 'monthly'
1526
- });
1527
- }
1528
-
1529
- // ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋น„์šฉ ๊ณ„์‚ฐ
1530
- selectedComponents.additional.forEach(additionalId => {
1531
- const card = document.querySelector(`[data-category="additional"][data-id="${additionalId}"]`);
1532
- const cost = parseFloat(card.dataset.cost);
1533
- const time = parseFloat(card.dataset.time);
1534
- const name = card.querySelector('.option-name').textContent;
1535
-
1536
- totalInitialCost += cost;
1537
- maxTime = Math.max(maxTime, time);
1538
-
1539
- componentDetails.push({
1540
- name: name,
1541
- cost: cost,
1542
- type: 'additional'
1543
- });
1544
- });
1545
-
1546
- // ์›”๊ฐ„ ์šด์˜ ๋น„์šฉ ๊ณ„์‚ฐ
1547
- const serverCost = totalInitialCost > 100 ? 5 : totalInitialCost > 50 ? 3 : totalInitialCost > 20 ? 2 : 1;
1548
- const resourceCost = totalResourceCost;
1549
- const maintenanceCost = totalInitialCost * 0.05; // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 5%
1550
- const totalMonthlyCost = serverCost + resourceCost + maintenanceCost + monthlySupport;
1551
-
1552
- // ๊ฒฐ๊ณผ ํ‘œ์‹œ
1553
- document.getElementById('initialCost').textContent = `$${totalInitialCost}K`;
1554
- document.getElementById('devTime').textContent = `${maxTime}๊ฐœ์›”`;
1555
- document.getElementById('serverCost').textContent = `$${serverCost}K`;
1556
- document.getElementById('resourceCost').textContent = `$${resourceCost.toFixed(1)}K`;
1557
- document.getElementById('maintenanceCost').textContent = `$${maintenanceCost.toFixed(1)}K`;
1558
- document.getElementById('totalMonthlyCost').textContent = `$${totalMonthlyCost.toFixed(1)}K`;
1559
-
1560
- // ์ด ๋น„์šฉ ๊ณ„์‚ฐ (๊ธฐ๊ฐ„๋ณ„)
1561
- updateTotalCost(totalInitialCost, totalMonthlyCost);
1562
-
1563
- // ์„ ํƒํ•œ ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก ํ‘œ์‹œ
1564
- displayComponentList(componentDetails);
1565
-
1566
- // ๊ตฌ์ถ• ๋ฐฉ์‹๋ณ„ ๋น„๊ต
1567
- compareBuilderMethods(totalInitialCost, totalMonthlyCost, maxTime);
1568
-
1569
- // ์ฐจํŠธ ์—…๋ฐ์ดํŠธ
1570
- updateCustomChart(totalInitialCost, totalMonthlyCost);
1571
-
1572
- // ๊ฒฐ๊ณผ ์„น์…˜ ํ‘œ์‹œ
1573
- document.getElementById('customResult').style.display = 'block';
1574
- }
1575
 
1576
- // ์ด ๋น„์šฉ ์—…๋ฐ์ดํŠธ
1577
- function updateTotalCost(initialCost, monthlyCost) {
1578
- const totalCost = initialCost + (monthlyCost * currentPeriod);
1579
- document.getElementById('totalCost').textContent = `$${totalCost.toFixed(1)}K`;
1580
- }
1581
 
1582
- // ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก ํ‘œ์‹œ
1583
- function displayComponentList(components) {
1584
- const listContainer = document.getElementById('componentList');
1585
- listContainer.innerHTML = '';
1586
-
1587
- components.forEach(component => {
1588
- const item = document.createElement('div');
1589
- item.className = 'component-list-item';
1590
-
1591
- let costDisplay = component.type === 'monthly'
1592
- ? `์›” $${component.cost}K`
1593
- : `$${component.cost}K`;
1594
-
1595
- item.innerHTML = `
1596
- <span>${component.name}</span>
1597
- <span style="color: #00d2ff;">${costDisplay}</span>
1598
- `;
1599
-
1600
- listContainer.appendChild(item);
1601
- });
1602
- }
1603
-
1604
- // ๊ตฌ์ถ• ๋ฐฉ์‹๋ณ„ ๋น„๊ต
1605
- function compareBuilderMethods(initialCost, monthlyCost, devTime) {
1606
- // ์™ธ์ฃผ ์šฉ์—ญ ๊ฐœ๋ฐœ
1607
- const outsourceInitial = initialCost;
1608
- const outsourceMonthly = monthlyCost;
1609
- const outsourceTotal = outsourceInitial + (outsourceMonthly * currentPeriod);
1610
-
1611
- // ์ž์ฒด ์ธ๋ ฅ ๊ฐœ๋ฐœ
1612
- const developerSalary = 10; // ์›” $10K
1613
- const teamSize = Math.ceil(initialCost / 50); // $50K๋‹น 1๋ช…
1614
- const inhouseDevTime = Math.max(devTime * 1.5, 3); // ์ตœ์†Œ 3๊ฐœ์›”
1615
- const inhouseInitial = developerSalary * teamSize * inhouseDevTime;
1616
- const inhouseMonthly = monthlyCost + (developerSalary * Math.ceil(teamSize / 2)); // ์œ ์ง€๋ณด์ˆ˜ ์ธ๋ ฅ
1617
- const inhouseTotal = inhouseInitial + (inhouseMonthly * currentPeriod);
1618
-
1619
- // ํ”Œ๋žซํผ ๋Œ€์—ฌ
1620
- const platformInitial = 1; // ์„ค์ • ๋น„์šฉ
1621
- const platformMonthly = monthlyCost * 2 + 5; // ํ”Œ๋žซํผ ์ˆ˜์ˆ˜๋ฃŒ ํฌํ•จ
1622
- const platformTotal = platformInitial + (platformMonthly * currentPeriod);
1623
-
1624
- // ๊ฒฐ๊ณผ ํ‘œ์‹œ
1625
- document.getElementById('outsourceInitial').textContent = `$${outsourceInitial}K`;
1626
- document.getElementById('outsourceMonthly').textContent = `$${outsourceMonthly.toFixed(1)}K`;
1627
- document.getElementById('outsourceTotal').textContent = `$${outsourceTotal.toFixed(1)}K`;
1628
-
1629
- document.getElementById('inhouseInitial').textContent = `$${inhouseInitial}K`;
1630
- document.getElementById('inhouseMonthly').textContent = `$${inhouseMonthly.toFixed(1)}K`;
1631
- document.getElementById('inhouseTotal').textContent = `$${inhouseTotal.toFixed(1)}K`;
1632
-
1633
- document.getElementById('platformInitial').textContent = `$${platformInitial}K`;
1634
- document.getElementById('platformMonthly').textContent = `$${platformMonthly.toFixed(1)}K`;
1635
- document.getElementById('platformTotal').textContent = `$${platformTotal.toFixed(1)}K`;
1636
- }
1637
-
1638
- // ์ฐจํŠธ ์—…๋ฐ์ดํŠธ
1639
- function updateCustomChart(initialCost, monthlyCost) {
1640
- const ctx = document.getElementById('customChart').getContext('2d');
1641
-
1642
- if (customChart) {
1643
- customChart.destroy();
1644
- }
1645
-
1646
- const months = Array.from({length: 12}, (_, i) => `${i + 1}๊ฐœ์›”`);
1647
- const outsourceData = months.map((_, i) => initialCost + (monthlyCost * (i + 1)));
1648
- const inhouseData = months.map((_, i) => {
1649
- const teamSize = Math.ceil(initialCost / 50);
1650
- const inhouseInitial = 10 * teamSize * 3;
1651
- const inhouseMonthly = monthlyCost + (10 * Math.ceil(teamSize / 2));
1652
- return inhouseInitial + (inhouseMonthly * (i + 1));
1653
- });
1654
- const platformData = months.map((_, i) => 1 + ((monthlyCost * 2 + 5) * (i + 1)));
1655
-
1656
- customChart = new Chart(ctx, {
1657
- type: 'line',
1658
- data: {
1659
- labels: months,
1660
- datasets: [{
1661
- label: '์™ธ์ฃผ ์šฉ์—ญ ๊ฐœ๋ฐœ',
1662
- data: outsourceData,
1663
- borderColor: '#764ba2',
1664
- backgroundColor: 'rgba(118, 75, 162, 0.1)',
1665
- tension: 0.4
1666
- }, {
1667
- label: '์ž์ฒด ์ธ๋ ฅ ๊ฐœ๋ฐœ',
1668
- data: inhouseData,
1669
- borderColor: '#f5576c',
1670
- backgroundColor: 'rgba(245, 87, 108, 0.1)',
1671
- tension: 0.4
1672
- }, {
1673
- label: 'ํ”Œ๋žซํผ ๋Œ€์—ฌ',
1674
- data: platformData,
1675
- borderColor: '#4facfe',
1676
- backgroundColor: 'rgba(79, 172, 254, 0.1)',
1677
- tension: 0.4
1678
- }]
1679
- },
1680
- options: {
1681
- responsive: true,
1682
- maintainAspectRatio: false,
1683
- plugins: {
1684
- legend: {
1685
- labels: {
1686
- color: '#ffffff'
1687
- }
1688
- },
1689
- tooltip: {
1690
- callbacks: {
1691
- label: function(context) {
1692
- return context.dataset.label + ': $' + context.parsed.y.toFixed(1) + 'K';
1693
- }
1694
- }
1695
- }
1696
- },
1697
- scales: {
1698
- x: {
1699
- grid: {
1700
- color: 'rgba(255, 255, 255, 0.1)'
1701
- },
1702
- ticks: {
1703
- color: '#a8a8b3'
1704
- }
1705
- },
1706
- y: {
1707
- grid: {
1708
- color: 'rgba(255, 255, 255, 0.1)'
1709
- },
1710
- ticks: {
1711
- color: '#a8a8b3',
1712
- callback: function(value) {
1713
- return '$' + value + 'K';
1714
- }
1715
- }
1716
- }
1717
- }
1718
- }
1719
- });
1720
- }
1721
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1722
  </body>
1723
- </html>
1724
-
 
395
  transition: all 0.3s ease;
396
  position: relative;
397
  overflow: hidden;
398
+ user-select: none;
399
  }
400
 
401
  .option-card.selected {
 
421
  font-weight: bold;
422
  }
423
 
424
+ .option-card:hover:not(.selected) {
425
  border-color: #00d2ff;
426
  background: rgba(255, 255, 255, 0.1);
427
  transform: translateY(-2px);
 
1393
  </div>
1394
  </div>
1395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1396
 
 
 
 
 
 
1397
 
1398
+ </div>
1399
+ </div>
1400
+
1401
+ <!-- ๊ธฐ๊ฐ„๋ณ„ ๋น„์šฉ ์ฐจํŠธ -->
1402
+ <div class="chart-container">
1403
+ <canvas id="customChart"></canvas>
1404
+ </div>
1405
+ </div>
1406
+ </div>
1407
+ </div>
1408
+ </div>
1409
+
1410
+ <script>
1411
+ // ์ „์—ญ ๋ณ€์ˆ˜
1412
+ let selectedComponents = {
1413
+ service: [],
1414
+ db: null,
1415
+ auth: null,
1416
+ credit: null,
1417
+ payment: null,
1418
+ marketing: null,
1419
+ support: null,
1420
+ monitoring: null,
1421
+ additional: []
1422
+ };
1423
+
1424
+ let customChart = null;
1425
+ let currentPeriod = 3;
1426
+
1427
+ // ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก
1428
+ document.addEventListener('DOMContentLoaded', function() {
1429
+ // ์˜ต์…˜ ์นด๋“œ ํด๋ฆญ ์ด๋ฒคํŠธ
1430
+ document.querySelectorAll('.option-card').forEach(card => {
1431
+ card.addEventListener('click', function(e) {
1432
+ e.preventDefault();
1433
+ const category = this.dataset.category;
1434
+ const id = this.dataset.id;
1435
+
1436
+ if (category === 'service' || category === 'additional') {
1437
+ // ๋ณต์ˆ˜ ์„ ํƒ ๊ฐ€๋Šฅ
1438
+ this.classList.toggle('selected');
1439
+
1440
+ if (this.classList.contains('selected')) {
1441
+ if (!selectedComponents[category].includes(id)) {
1442
+ selectedComponents[category].push(id);
1443
+ }
1444
+ } else {
1445
+ const index = selectedComponents[category].indexOf(id);
1446
+ if (index > -1) {
1447
+ selectedComponents[category].splice(index, 1);
1448
+ }
1449
+ }
1450
+ } else {
1451
+ // ๋‹จ์ผ ์„ ํƒ
1452
+ document.querySelectorAll(`[data-category="${category}"]`).forEach(c => {
1453
+ c.classList.remove('selected');
1454
+ });
1455
+
1456
+ this.classList.add('selected');
1457
+ selectedComponents[category] = id;
1458
+ }
1459
+
1460
+ console.log('Selected:', selectedComponents); // ๋””๋ฒ„๊น…์šฉ
1461
+ });
1462
+ });
1463
+ });
1464
+
1465
+ // ํƒญ ์ „ํ™˜ ํ•จ์ˆ˜
1466
+ function switchTab(tabId) {
1467
+ document.querySelectorAll('.tab').forEach(tab => {
1468
+ tab.classList.remove('active');
1469
+ });
1470
+ document.querySelectorAll('.tab-content').forEach(content => {
1471
+ content.classList.remove('active');
1472
+ });
1473
+
1474
+ event.target.classList.add('active');
1475
+ document.getElementById(tabId).classList.add('active');
1476
+ }
1477
+
1478
+ // ์ปค์Šคํ…€ ๋น„์šฉ ๊ณ„์‚ฐ ํ•จ์ˆ˜
1479
+ function calculateCustomCost() {
1480
+ let totalInitialCost = 0;
1481
+ let totalResourceCost = 0;
1482
+ let maxTime = 0;
1483
+ let componentDetails = [];
1484
+
1485
+ // ์„œ๋น„์Šค ๋น„์šฉ ๊ณ„์‚ฐ
1486
+ selectedComponents.service.forEach(serviceId => {
1487
+ const card = document.querySelector(`[data-id="${serviceId}"]`);
1488
+ const cost = parseFloat(card.dataset.cost);
1489
+ const time = parseFloat(card.dataset.time);
1490
+ const resource = parseFloat(card.dataset.resource) || 0;
1491
+ const name = card.querySelector('.option-name').textContent;
1492
+
1493
+ totalInitialCost += cost;
1494
+ totalResourceCost += resource;
1495
+ maxTime = Math.max(maxTime, time);
1496
+
1497
+ componentDetails.push({
1498
+ name: name,
1499
+ cost: cost,
1500
+ type: 'service'
1501
+ });
1502
+ });
1503
+
1504
+ // ๊ธฐํƒ€ ๊ตฌ์„ฑ ์š”์†Œ ๋น„์šฉ ๊ณ„์‚ฐ
1505
+ ['db', 'auth', 'credit', 'payment', 'marketing', 'monitoring'].forEach(category => {
1506
+ if (selectedComponents[category]) {
1507
+ const card = document.querySelector(`[data-category="${category}"][data-id="${selectedComponents[category]}"]`);
1508
+ const cost = parseFloat(card.dataset.cost);
1509
+ const time = parseFloat(card.dataset.time);
1510
+ const name = card.querySelector('.option-name').textContent;
1511
+
1512
+ totalInitialCost += cost;
1513
+ maxTime = Math.max(maxTime, time);
1514
+
1515
+ componentDetails.push({
1516
+ name: name,
1517
+ cost: cost,
1518
+ type: category
1519
+ });
1520
+ }
1521
+ });
1522
+
1523
+ // ์ง€์› ์„œ๋น„์Šค (์›”๊ฐ„ ๋น„์šฉ)
1524
+ let monthlySupport = 0;
1525
+ if (selectedComponents.support) {
1526
+ const card = document.querySelector(`[data-category="support"][data-id="${selectedComponents.support]}"]`);
1527
+ monthlySupport = parseFloat(card.dataset.cost);
1528
+ const name = card.querySelector('.option-name').textContent;
1529
+
1530
+ componentDetails.push({
1531
+ name: name,
1532
+ cost: monthlySupport,
1533
+ type: 'monthly'
1534
+ });
1535
+ }
1536
+
1537
+ // ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋น„์šฉ ๊ณ„์‚ฐ
1538
+ selectedComponents.additional.forEach(additionalId => {
1539
+ const card = document.querySelector(`[data-category="additional"][data-id="${additionalId}"]`);
1540
+ const cost = parseFloat(card.dataset.cost);
1541
+ const time = parseFloat(card.dataset.time);
1542
+ const name = card.querySelector('.option-name').textContent;
1543
+
1544
+ totalInitialCost += cost;
1545
+ maxTime = Math.max(maxTime, time);
1546
+
1547
+ componentDetails.push({
1548
+ name: name,
1549
+ cost: cost,
1550
+ type: 'additional'
1551
+ });
1552
+ });
1553
+
1554
+ // ์›”๊ฐ„ ์šด์˜ ๋น„์šฉ ๊ณ„์‚ฐ
1555
+ const serverCost = totalInitialCost > 100 ? 5 : totalInitialCost > 50 ? 3 : totalInitialCost > 20 ? 2 : 1;
1556
+ const resourceCost = totalResourceCost;
1557
+ const maintenanceCost = totalInitialCost * 0.05; // ์ดˆ๊ธฐ ๋น„์šฉ์˜ 5%
1558
+ const totalMonthlyCost = serverCost + resourceCost + maintenanceCost + monthlySupport;
1559
+
1560
+ // ๊ฒฐ๊ณผ ํ‘œ์‹œ
1561
+ document.getElementById('initialCost').textContent = `$${totalInitialCost}K`;
1562
+ document.getElementById('devTime').textContent = `${maxTime}๊ฐœ์›”`;
1563
+ document.getElementById('serverCost').textContent = `$${serverCost}K`;
1564
+ document.getElementById('resourceCost').textContent = `$${resourceCost.toFixed(1)}K`;
1565
+ document.getElementById('maintenanceCost').textContent = `$${maintenanceCost.toFixed(1)}K`;
1566
+ document.getElementById('totalMonthlyCost').textContent = `$${totalMonthlyCost.toFixed(1)}K`;
1567
+
1568
+ // ์ด ๋น„์šฉ ๊ณ„์‚ฐ (๊ธฐ๊ฐ„๋ณ„)
1569
+ updateTotalCost(totalInitialCost, totalMonthlyCost);
1570
+
1571
+ // ์„ ํƒํ•œ ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก ํ‘œ์‹œ
1572
+ displayComponentList(componentDetails);
1573
+
1574
+ // ๊ตฌ์ถ• ๋ฐฉ์‹๋ณ„ ๋น„๊ต
1575
+ compareBuilderMethods(totalInitialCost, totalMonthlyCost, maxTime);
1576
+
1577
+ // ์ฐจํŠธ ์—…๋ฐ์ดํŠธ
1578
+ updateCustomChart(totalInitialCost, totalMonthlyCost);
1579
+
1580
+ // ๊ฒฐ๊ณผ ์„น์…˜ ํ‘œ์‹œ
1581
+ document.getElementById('customResult').style.display = 'block';
1582
+ }
1583
+
1584
+ // ์ด ๋น„์šฉ ์—…๋ฐ์ดํŠธ
1585
+ function updateTotalCost(initialCost, monthlyCost) {
1586
+ const totalCost = initialCost + (monthlyCost * currentPeriod);
1587
+ document.getElementById('totalCost').textContent = `$${totalCost.toFixed(1)}K`;
1588
+ }
1589
+
1590
+ // ๊ตฌ์„ฑ ์š”์†Œ ๋ชฉ๋ก ํ‘œ์‹œ
1591
+ function displayComponentList(components) {
1592
+ const listContainer = document.getElementById('componentList');
1593
+ listContainer.innerHTML = '';
1594
+
1595
+ components.forEach(component => {
1596
+ const item = document.createElement('div');
1597
+ item.className = 'component-list-item';
1598
+
1599
+ let costDisplay = component.type === 'monthly'
1600
+ ? `์›” $${component.cost}K`
1601
+ : `$${component.cost}K`;
1602
+
1603
+ item.innerHTML = `
1604
+ <span>${component.name}</span>
1605
+ <span style="color: #00d2ff;">${costDisplay}</span>
1606
+ `;
1607
+
1608
+ listContainer.appendChild(item);
1609
+ });
1610
+ }
1611
+
1612
+ // ๊ตฌ์ถ• ๋ฐฉ์‹๋ณ„ ๋น„๊ต
1613
+ function compareBuilderMethods(initialCost, monthlyCost, devTime) {
1614
+ // ์™ธ์ฃผ ์šฉ์—ญ ๊ฐœ๋ฐœ
1615
+ const outsourceInitial = initialCost;
1616
+ const outsourceMonthly = monthlyCost;
1617
+ const outsourceTotal = outsourceInitial + (outsourceMonthly * currentPeriod);
1618
+
1619
+ // ์ž์ฒด ์ธ๋ ฅ ๊ฐœ๋ฐœ
1620
+ const developerSalary = 10; // ์›” $10K
1621
+ const teamSize = Math.ceil(initialCost / 50); // $50K๋‹น 1๋ช…
1622
+ const inhouseDevTime = Math.max(devTime * 1.5, 3); // ์ตœ์†Œ 3๊ฐœ์›”
1623
+ const inhouseInitial = developerSalary * teamSize * inhouseDevTime;
1624
+ const inhouseMonthly = monthlyCost + (developerSalary * Math.ceil(teamSize / 2)); // ์œ ์ง€๋ณด์ˆ˜ ์ธ๋ ฅ
1625
+ const inhouseTotal = inhouseInitial + (inhouseMonthly * currentPeriod);
1626
+
1627
+ // ํ”Œ๋žซํผ ๋Œ€์—ฌ
1628
+ const platformInitial = 1; // ์„ค์ • ๋น„์šฉ
1629
+ const platformMonthly = monthlyCost * 2 + 5; // ํ”Œ๋žซํผ ์ˆ˜์ˆ˜๋ฃŒ ํฌํ•จ
1630
+ const platformTotal = platformInitial + (platformMonthly * currentPeriod);
1631
+
1632
+ // ๊ฒฐ๊ณผ ํ‘œ์‹œ
1633
+ document.getElementById('outsourceInitial').textContent = `$${outsourceInitial}K`;
1634
+ document.getElementById('outsourceMonthly').textContent = `$${outsourceMonthly.toFixed(1)}K`;
1635
+ document.getElementById('outsourceTotal').textContent = `$${outsourceTotal.toFixed(1)}K`;
1636
+
1637
+ document.getElementById('inhouseInitial').textContent = `$${inhouseInitial}K`;
1638
+ document.getElementById('inhouseMonthly').textContent = `$${inhouseMonthly.toFixed(1)}K`;
1639
+ document.getElementById('inhouseTotal').textContent = `$${inhouseTotal.toFixed(1)}K`;
1640
+
1641
+ document.getElementById('platformInitial').textContent = `$${platformInitial}K`;
1642
+ document.getElementById('platformMonthly').textContent = `$${platformMonthly.toFixed(1)}K`;
1643
+ document.getElementById('platformTotal').textContent = `$${platformTotal.toFixed(1)}K`;
1644
+ }
1645
+
1646
+ // ์ฐจํŠธ ์—…๋ฐ์ดํŠธ
1647
+ function updateCustomChart(initialCost, monthlyCost) {
1648
+ const ctx = document.getElementById('customChart').getContext('2d');
1649
+
1650
+ if (customChart) {
1651
+ customChart.destroy();
1652
+ }
1653
+
1654
+ const months = Array.from({length: 12}, (_, i) => `${i + 1}๊ฐœ์›”`);
1655
+ const outsourceData = months.map((_, i) => initialCost + (monthlyCost * (i + 1)));
1656
+ const inhouseData = months.map((_, i) => {
1657
+ const teamSize = Math.ceil(initialCost / 50);
1658
+ const inhouseInitial = 10 * teamSize * 3;
1659
+ const inhouseMonthly = monthlyCost + (10 * Math.ceil(teamSize / 2));
1660
+ return inhouseInitial + (inhouseMonthly * (i + 1));
1661
+ });
1662
+ const platformData = months.map((_, i) => 1 + ((monthlyCost * 2 + 5) * (i + 1)));
1663
+
1664
+ customChart = new Chart(ctx, {
1665
+ type: 'line',
1666
+ data: {
1667
+ labels: months,
1668
+ datasets: [{
1669
+ label: '์™ธ์ฃผ ์šฉ์—ญ ๊ฐœ๋ฐœ',
1670
+ data: outsourceData,
1671
+ borderColor: '#764ba2',
1672
+ backgroundColor: 'rgba(118, 75, 162, 0.1)',
1673
+ tension: 0.4
1674
+ }, {
1675
+ label: '์ž์ฒด ์ธ๋ ฅ ๊ฐœ๋ฐœ',
1676
+ data: inhouseData,
1677
+ borderColor: '#f5576c',
1678
+ backgroundColor: 'rgba(245, 87, 108, 0.1)',
1679
+ tension: 0.4
1680
+ }, {
1681
+ label: 'ํ”Œ๋žซํผ ๋Œ€์—ฌ',
1682
+ data: platformData,
1683
+ borderColor: '#4facfe',
1684
+ backgroundColor: 'rgba(79, 172, 254, 0.1)',
1685
+ tension: 0.4
1686
+ }]
1687
+ },
1688
+ options: {
1689
+ responsive: true,
1690
+ maintainAspectRatio: false,
1691
+ plugins: {
1692
+ legend: {
1693
+ labels: {
1694
+ color: '#ffffff'
1695
+ }
1696
+ },
1697
+ tooltip: {
1698
+ callbacks: {
1699
+ label: function(context) {
1700
+ return context.dataset.label + ': $' + context.parsed.y.toFixed(1) + 'K';
1701
+ }
1702
+ }
1703
+ }
1704
+ },
1705
+ scales: {
1706
+ x: {
1707
+ grid: {
1708
+ color: 'rgba(255, 255, 255, 0.1)'
1709
+ },
1710
+ ticks: {
1711
+ color: '#a8a8b3'
1712
+ }
1713
+ },
1714
+ y: {
1715
+ grid: {
1716
+ color: 'rgba(255, 255, 255, 0.1)'
1717
+ },
1718
+ ticks: {
1719
+ color: '#a8a8b3',
1720
+ callback: function(value) {
1721
+ return '$' + value + 'K';
1722
+ }
1723
+ }
1724
+ }
1725
+ }
1726
+ }
1727
+ });
1728
+ }
1729
+ </script>
1730
  </body>
1731
+ </html>