help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
cpp-shape-drawer
RSK World
cpp-shape-drawer
C++ Shape Drawer - Advanced Graphics Application + Raylib + OOP Design + Shape Tools + Transformation + Export + Educational Design
cpp-shape-drawer
  • include
  • src
  • CMakeLists.txt1.2 KB
  • LICENSE1.3 KB
  • README.md2.7 KB
  • RELEASE_NOTES.md3.1 KB
  • demo.html25.8 KB
  • index.html32.1 KB
  • release_note.html4.8 KB
demo.html
demo.html
Raw Download
Find: Go to:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>C++ Shape Drawer - Interactive Demo | RSK World</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #333;
            overflow: hidden;
        }

        .container {
            position: relative;
            width: 100vw;
            height: 100vh;
        }

        canvas {
            display: block;
            background: #f0f2f5;
            cursor: crosshair;
        }

        .ui-panel {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 10px 15px;
            font-size: 14px;
            font-family: monospace;
            z-index: 1000;
        }

        .status-bar {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.9);
            color: white;
            padding: 8px 15px;
            font-size: 14px;
            z-index: 1000;
        }

        .instructions {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(255, 255, 255, 0.95);
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
            z-index: 1001;
            max-width: 400px;
        }

        .instructions h3 {
            margin-bottom: 15px;
            color: #333;
        }

        .instructions p {
            margin-bottom: 10px;
            font-size: 14px;
            color: #666;
        }

        .instructions .close-btn {
            background: #667eea;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 5px;
            cursor: pointer;
            margin-top: 10px;
        }

        .instructions .close-btn:hover {
            background: #5a67d8;
        }

        .color-palette {
            position: absolute;
            right: 20px;
            top: 60px;
            display: flex;
            flex-direction: column;
            gap: 5px;
            z-index: 1000;
        }

        .color-btn {
            width: 30px;
            height: 30px;
            border: 2px solid white;
            border-radius: 50%;
            cursor: pointer;
            transition: all 0.2s;
        }

        .color-btn:hover {
            transform: scale(1.1);
        }

        .color-btn.active {
            border-color: #333;
            box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
        }

        .shape-selector {
            position: absolute;
            left: 20px;
            top: 60px;
            display: flex;
            flex-direction: column;
            gap: 5px;
            z-index: 1000;
        }

        .shape-btn {
            background: rgba(255, 255, 255, 0.9);
            border: none;
            width: 40px;
            height: 40px;
            border-radius: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            transition: all 0.2s;
        }

        .shape-btn:hover {
            background: white;
            transform: scale(1.05);
        }

        .shape-btn.active {
            background: #667eea;
            color: white;
        }

        .controls-info {
            position: absolute;
            left: 80px;
            top: 60px;
            background: rgba(255, 255, 255, 0.9);
            padding: 10px;
            border-radius: 8px;
            font-size: 12px;
            max-width: 200px;
            z-index: 1000;
        }

        .controls-info h4 {
            margin-bottom: 8px;
            color: #333;
        }

        .controls-info p {
            margin-bottom: 5px;
            color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="ui-panel">
            <strong>C++ Shape Drawer Demo</strong> |
            Left Click: Place Shape | Right Click: Pan | Scroll: Zoom |
            Keys: 1-6 Shapes | R/G/B/Y/P Colors | Q/E Rotate | +/- Scale | Z Undo | C Clear
        </div>

        <canvas id="canvas"></canvas>

        <div class="shape-selector">
            <button class="shape-btn active" data-shape="circle">⭕</button>
            <button class="shape-btn" data-shape="rectangle">▭</button>
            <button class="shape-btn" data-shape="triangle">△</button>
            <button class="shape-btn" data-shape="star">⭐</button>
            <button class="shape-btn" data-shape="polygon">⬡</button>
            <button class="shape-btn" data-shape="text">📝</button>
        </div>

        <div class="color-palette">
            <button class="color-btn active" data-color="#FF0000" style="background: #FF0000;"></button>
            <button class="color-btn" data-color="#00FF00" style="background: #00FF00;"></button>
            <button class="color-btn" data-color="#0000FF" style="background: #0000FF;"></button>
            <button class="color-btn" data-color="#FFFF00" style="background: #FFFF00;"></button>
            <button class="color-btn" data-color="#FF00FF" style="background: #FF00FF;"></button>
        </div>

        <div class="controls-info">
            <h4>Quick Controls</h4>
            <p><strong>A</strong> - Toggle Animation</p>
            <p><strong>G</strong> - Toggle Gradient</p>
            <p><strong>F</strong> - Fill/Outline</p>
            <p><strong>Space</strong> - Random Pattern</p>
        </div>

        <div class="status-bar">
            <span id="status">Ready | Shapes: 0 | Zoom: 1.00x | Mode: Circle | Color: Red</span>
        </div>

        <div class="instructions" id="instructions">
            <h3>🎨 Welcome to C++ Shape Drawer Demo!</h3>
            <p>This interactive demo simulates the C++ Shape Drawer application in your browser.</p>
            <p><strong>How to use:</strong></p>
            <p>• Click anywhere on the canvas to place shapes</p>
            <p>• Use the shape buttons (1-6) to change shape types</p>
            <p>• Select colors with the palette or R/G/B/Y/P keys</p>
            <p>• Press Q/E to rotate, +/- to scale shapes</p>
            <p>• Right-click and drag to pan, scroll to zoom</p>
            <button class="close-btn" onclick="hideInstructions()">Start Drawing! 🎨</button>
        </div>
    </div>

    <script>
        class Shape {
            constructor(x, y, type, color, filled = true) {
                this.x = x;
                this.y = y;
                this.type = type;
                this.color = color;
                this.filled = filled;
                this.rotation = 0;
                this.scale = 1;
                this.alpha = 1;
                this.gradient = false;
                this.animation = 0; // 0: none, 1: pulse, 2: bounce, 3: shake
                this.animTime = 0;
                this.selected = false;
                this.id = Math.random();
            }

            draw(ctx, camera, time) {
                ctx.save();

                // Apply camera transform
                ctx.translate(this.x - camera.x, this.y - camera.y);
                ctx.rotate(this.rotation * Math.PI / 180);
                ctx.scale(this.scale, this.scale);

                // Animation effects
                let animOffset = { x: 0, y: 0 };
                let animScale = 1;

                if (this.animation === 1) { // Pulse
                    animScale = 1 + Math.sin(time * 0.005) * 0.2;
                } else if (this.animation === 2) { // Bounce
                    animOffset.y = Math.sin(time * 0.01) * 10;
                } else if (this.animation === 3) { // Shake
                    animOffset.x = Math.sin(time * 0.02) * 5;
                    animOffset.y = Math.cos(time * 0.015) * 3;
                }

                ctx.translate(animOffset.x, animOffset.y);
                ctx.scale(animScale, animScale);

                ctx.globalAlpha = this.alpha;

                if (this.gradient) {
                    const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 50);
                    gradient.addColorStop(0, this.color);
                    gradient.addColorStop(1, this.lightenColor(this.color, 0.5));
                    ctx.fillStyle = gradient;
                    ctx.strokeStyle = this.color;
                } else {
                    ctx.fillStyle = this.color;
                    ctx.strokeStyle = this.color;
                }

                ctx.lineWidth = 2;

                this.drawShape(ctx);

                // Selection indicator
                if (this.selected) {
                    ctx.strokeStyle = '#FF0000';
                    ctx.lineWidth = 2;
                    ctx.setLineDash([5, 5]);
                    ctx.strokeRect(-60, -60, 120, 120);
                    ctx.setLineDash([]);
                }

                ctx.restore();
            }

            drawShape(ctx) {
                switch (this.type) {
                    case 'circle':
                        this.drawCircle(ctx);
                        break;
                    case 'rectangle':
                        this.drawRectangle(ctx);
                        break;
                    case 'triangle':
                        this.drawTriangle(ctx);
                        break;
                    case 'star':
                        this.drawStar(ctx);
                        break;
                    case 'polygon':
                        this.drawPolygon(ctx);
                        break;
                    case 'text':
                        this.drawText(ctx);
                        break;
                }
            }

            drawCircle(ctx) {
                ctx.beginPath();
                ctx.arc(0, 0, 30, 0, Math.PI * 2);
                if (this.filled) ctx.fill();
                ctx.stroke();
            }

            drawRectangle(ctx) {
                if (this.filled) {
                    ctx.fillRect(-40, -25, 80, 50);
                }
                ctx.strokeRect(-40, -25, 80, 50);
            }

            drawTriangle(ctx) {
                ctx.beginPath();
                ctx.moveTo(0, -35);
                ctx.lineTo(30, 25);
                ctx.lineTo(-30, 25);
                ctx.closePath();
                if (this.filled) ctx.fill();
                ctx.stroke();
            }

            drawStar(ctx) {
                const spikes = 5;
                const outerRadius = 30;
                const innerRadius = 15;

                ctx.beginPath();
                for (let i = 0; i < spikes * 2; i++) {
                    const radius = i % 2 === 0 ? outerRadius : innerRadius;
                    const angle = (i * Math.PI) / spikes;
                    const x = Math.cos(angle) * radius;
                    const y = Math.sin(angle) * radius;

                    if (i === 0) ctx.moveTo(x, y);
                    else ctx.lineTo(x, y);
                }
                ctx.closePath();
                if (this.filled) ctx.fill();
                ctx.stroke();
            }

            drawPolygon(ctx) {
                const sides = 6;
                const radius = 30;

                ctx.beginPath();
                for (let i = 0; i < sides; i++) {
                    const angle = (i * Math.PI * 2) / sides;
                    const x = Math.cos(angle) * radius;
                    const y = Math.sin(angle) * radius;

                    if (i === 0) ctx.moveTo(x, y);
                    else ctx.lineTo(x, y);
                }
                ctx.closePath();
                if (this.filled) ctx.fill();
                ctx.stroke();
            }

            drawText(ctx) {
                ctx.font = '20px Arial';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillStyle = this.color;
                ctx.fillText('RSK', 0, 0);
            }

            lightenColor(color, amount) {
                const num = parseInt(color.replace("#", ""), 16);
                const amt = Math.round(2.55 * amount * 100);
                const R = (num >> 16) + amt;
                const G = (num >> 8 & 0x00FF) + amt;
                const B = (num & 0x0000FF) + amt;
                return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
                    (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
                    (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
            }

            contains(x, y) {
                const dx = x - this.x;
                const dy = y - this.y;
                return Math.sqrt(dx * dx + dy * dy) < 50;
            }
        }

        class ShapeDrawerDemo {
            constructor() {
                this.canvas = document.getElementById('canvas');
                this.ctx = this.canvas.getContext('2d');
                this.shapes = [];
                this.camera = { x: 0, y: 0, zoom: 1 };
                this.currentShape = 'circle';
                this.currentColor = '#FF0000';
                this.filled = true;
                this.selectedShape = null;
                this.dragging = false;
                this.dragOffset = { x: 0, y: 0 };
                this.panning = false;
                this.lastMousePos = { x: 0, y: 0 };

                this.resize();
                this.setupEventListeners();
                this.animate();
            }

            resize() {
                this.canvas.width = window.innerWidth;
                this.canvas.height = window.innerHeight;
                this.updateStatus();
            }

            setupEventListeners() {
                // Mouse events
                this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));
                this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e));
                this.canvas.addEventListener('mouseup', () => this.handleMouseUp());
                this.canvas.addEventListener('wheel', (e) => this.handleWheel(e));

                // Keyboard events
                document.addEventListener('keydown', (e) => this.handleKeyDown(e));

                // Shape selector buttons
                document.querySelectorAll('.shape-btn').forEach(btn => {
                    btn.addEventListener('click', () => {
                        document.querySelectorAll('.shape-btn').forEach(b => b.classList.remove('active'));
                        btn.classList.add('active');
                        this.currentShape = btn.dataset.shape;
                        this.updateStatus();
                    });
                });

                // Color buttons
                document.querySelectorAll('.color-btn').forEach(btn => {
                    btn.addEventListener('click', () => {
                        document.querySelectorAll('.color-btn').forEach(b => b.classList.remove('active'));
                        btn.classList.add('active');
                        this.currentColor = btn.dataset.color;
                        this.updateStatus();
                    });
                });

                // Window resize
                window.addEventListener('resize', () => this.resize());
            }

            handleMouseDown(e) {
                const rect = this.canvas.getBoundingClientRect();
                const x = (e.clientX - rect.left) / this.camera.zoom + this.camera.x;
                const y = (e.clientY - rect.top) / this.camera.zoom + this.camera.y;

                if (e.button === 0) { // Left click
                    const clickedShape = this.getShapeAt(x, y);
                    if (clickedShape) {
                        this.selectedShape = clickedShape;
                        this.dragging = true;
                        this.dragOffset.x = x - clickedShape.x;
                        this.dragOffset.y = y - clickedShape.y;
                        clickedShape.selected = true;
                    } else {
                        this.addShape(x, y);
                    }
                } else if (e.button === 2) { // Right click
                    this.panning = true;
                }

                this.lastMousePos = { x: e.clientX, y: e.clientY };
                e.preventDefault();
            }

            handleMouseMove(e) {
                if (this.dragging && this.selectedShape) {
                    const rect = this.canvas.getBoundingClientRect();
                    const x = (e.clientX - rect.left) / this.camera.zoom + this.camera.x;
                    const y = (e.clientY - rect.top) / this.camera.zoom + this.camera.y;

                    this.selectedShape.x = x - this.dragOffset.x;
                    this.selectedShape.y = y - this.dragOffset.y;
                } else if (this.panning) {
                    const deltaX = e.clientX - this.lastMousePos.x;
                    const deltaY = e.clientY - this.lastMousePos.y;

                    this.camera.x -= deltaX / this.camera.zoom;
                    this.camera.y -= deltaY / this.camera.zoom;

                    this.lastMousePos = { x: e.clientX, y: e.clientY };
                }
            }

            handleMouseUp() {
                if (this.selectedShape) {
                    this.selectedShape.selected = false;
                }
                this.dragging = false;
                this.panning = false;
                this.selectedShape = null;
            }

            handleWheel(e) {
                e.preventDefault();
                const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
                const rect = this.canvas.getBoundingClientRect();
                const mouseX = e.clientX - rect.left;
                const mouseY = e.clientY - rect.top;

                // Zoom towards mouse position
                const worldX = mouseX / this.camera.zoom + this.camera.x;
                const worldY = mouseY / this.camera.zoom + this.camera.y;

                this.camera.zoom *= zoomFactor;
                this.camera.zoom = Math.max(0.1, Math.min(5, this.camera.zoom));

                this.camera.x = worldX - mouseX / this.camera.zoom;
                this.camera.y = worldY - mouseY / this.camera.zoom;

                this.updateStatus();
            }

            handleKeyDown(e) {
                switch (e.key.toLowerCase()) {
                    case '1': this.setShape('circle'); break;
                    case '2': this.setShape('rectangle'); break;
                    case '3': this.setShape('triangle'); break;
                    case '4': this.setShape('star'); break;
                    case '5': this.setShape('polygon'); break;
                    case '6': this.setShape('text'); break;

                    case 'r': this.setColor('#FF0000'); break;
                    case 'g': this.setColor('#00FF00'); break;
                    case 'b': this.setColor('#0000FF'); break;
                    case 'y': this.setColor('#FFFF00'); break;
                    case 'p': this.setColor('#FF00FF'); break;

                    case 'f': this.filled = !this.filled; break;
                    case 'z': this.undo(); break;
                    case 'c': this.clear(); break;

                    case 'q': if (this.selectedShape) this.selectedShape.rotation -= 15; break;
                    case 'e': if (this.selectedShape) this.selectedShape.rotation += 15; break;

                    case '=': case '+': if (this.selectedShape) this.selectedShape.scale *= 1.1; break;
                    case '-': if (this.selectedShape) this.selectedShape.scale *= 0.9; break;

                    case 'a': if (this.selectedShape) {
                        this.selectedShape.animation = (this.selectedShape.animation + 1) % 4;
                    } break;

                    case ' ': this.generateRandomPattern(); e.preventDefault(); break;
                }

                this.updateStatus();
            }

            setShape(shape) {
                this.currentShape = shape;
                document.querySelectorAll('.shape-btn').forEach(btn => {
                    btn.classList.toggle('active', btn.dataset.shape === shape);
                });
            }

            setColor(color) {
                this.currentColor = color;
                document.querySelectorAll('.color-btn').forEach(btn => {
                    btn.classList.toggle('active', btn.dataset.color === color);
                });
            }

            addShape(x, y) {
                const shape = new Shape(x, y, this.currentShape, this.currentColor, this.filled);
                this.shapes.push(shape);
                this.updateStatus();
            }

            getShapeAt(x, y) {
                for (let i = this.shapes.length - 1; i >= 0; i--) {
                    if (this.shapes[i].contains(x, y)) {
                        return this.shapes[i];
                    }
                }
                return null;
            }

            undo() {
                if (this.shapes.length > 0) {
                    this.shapes.pop();
                    this.updateStatus();
                }
            }

            clear() {
                this.shapes = [];
                this.updateStatus();
            }

            generateRandomPattern() {
                const centerX = this.camera.x + this.canvas.width / 2 / this.camera.zoom;
                const centerY = this.camera.y + this.canvas.height / 2 / this.camera.zoom;

                // Generate spiral pattern
                for (let i = 0; i < 20; i++) {
                    const angle = i * 0.3;
                    const radius = i * 15;
                    const x = centerX + Math.cos(angle) * radius;
                    const y = centerY + Math.sin(angle) * radius;

                    const hue = (i * 20) % 360;
                    const color = `hsl(${hue}, 70%, 60%)`;

                    const shape = new Shape(x, y, ['circle', 'star', 'triangle'][i % 3], color, true);
                    shape.scale = 0.5 + Math.random() * 0.5;
                    this.shapes.push(shape);
                }

                this.updateStatus();
            }

            updateStatus() {
                const status = document.getElementById('status');
                const colorNames = {
                    '#FF0000': 'Red',
                    '#00FF00': 'Green',
                    '#0000FF': 'Blue',
                    '#FFFF00': 'Yellow',
                    '#FF00FF': 'Purple'
                };

                status.textContent = `Ready | Shapes: ${this.shapes.length} | Zoom: ${this.camera.zoom.toFixed(2)}x | Mode: ${this.currentShape.charAt(0).toUpperCase() + this.currentShape.slice(1)} | Color: ${colorNames[this.currentColor] || 'Custom'}`;
            }

            animate() {
                const time = Date.now();

                // Clear canvas
                this.ctx.fillStyle = '#f0f2f5';
                this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

                // Apply camera transform
                this.ctx.save();
                this.ctx.scale(this.camera.zoom, this.camera.zoom);
                this.ctx.translate(-this.camera.x, -this.camera.y);

                // Draw grid
                this.drawGrid();

                // Draw shapes
                this.shapes.forEach(shape => shape.draw(this.ctx, this.camera, time));

                this.ctx.restore();

                requestAnimationFrame(() => this.animate());
            }

            drawGrid() {
                const gridSize = 50;
                const startX = Math.floor(this.camera.x / gridSize) * gridSize;
                const startY = Math.floor(this.camera.y / gridSize) * gridSize;
                const endX = startX + (this.canvas.width / this.camera.zoom) + gridSize;
                const endY = startY + (this.canvas.height / this.camera.zoom) + gridSize;

                this.ctx.strokeStyle = '#e0e0e0';
                this.ctx.lineWidth = 1;

                for (let x = startX; x <= endX; x += gridSize) {
                    this.ctx.beginPath();
                    this.ctx.moveTo(x, startY);
                    this.ctx.lineTo(x, endY);
                    this.ctx.stroke();
                }

                for (let y = startY; y <= endY; y += gridSize) {
                    this.ctx.beginPath();
                    this.ctx.moveTo(startX, y);
                    this.ctx.lineTo(endX, y);
                    this.ctx.stroke();
                }
            }
        }

        function hideInstructions() {
            document.getElementById('instructions').style.display = 'none';
        }

        // Initialize demo when page loads
        document.addEventListener('DOMContentLoaded', () => {
            new ShapeDrawerDemo();
        });

        // Prevent context menu on right click
        document.addEventListener('contextmenu', (e) => {
            if (e.target === document.getElementById('canvas')) {
                e.preventDefault();
            }
        });
    </script>
</body>
</html>
725 lines•25.8 KB
markup

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer