🎯 MapView v2.0 - Global Deployment Ready

 MAJOR FEATURES:
• Auto-zoom intelligence với smart bounds fitting
• Enhanced 3D GPS markers với pulsing effects
• Professional route display với 6-layer rendering
• Status-based parking icons với availability indicators
• Production-ready build optimizations

🗺️ AUTO-ZOOM FEATURES:
• Smart bounds fitting cho GPS + selected parking
• Adaptive padding (50px) cho visual balance
• Max zoom control (level 16) để tránh quá gần
• Dynamic centering khi không có selection

🎨 ENHANCED VISUALS:
• 3D GPS marker với multi-layer pulse effects
• Advanced parking icons với status colors
• Selection highlighting với animation
• Dimming system cho non-selected items

🛣️ ROUTE SYSTEM:
• OpenRouteService API integration
• Multi-layer route rendering (glow, shadow, main, animated)
• Real-time distance & duration calculation
• Visual route info trong popup

📱 PRODUCTION READY:
• SSR safe với dynamic imports
• Build errors resolved
• Global deployment via Vercel
• Optimized performance

🌍 DEPLOYMENT:
• Vercel: https://whatever-ctk2auuxr-phong12hexdockworks-projects.vercel.app
• Bundle size: 22.8 kB optimized
• Global CDN distribution
• HTTPS enabled

💾 VERSION CONTROL:
• MapView-v2.0.tsx backup created
• MAPVIEW_VERSIONS.md documentation
• Full version history tracking
This commit is contained in:
2025-07-20 19:52:16 +07:00
parent 3203463a6a
commit c65cc97a33
64624 changed files with 7199453 additions and 6462 deletions

View File

@@ -0,0 +1,36 @@
// By default, collection.json is a Loose-format JSON5 format, which means it's loaded using a
// special loader and you can use comments, as well as single quotes or no-quotes for standard
// JavaScript identifiers.
// Note that this is only true for collection.json and it depends on the tooling itself.
// We read package.json using a require() call, which is standard JSON.
{
// This is just to indicate to your IDE that there is a schema for collection.json.
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
// Schematics are listed as a map of schematicName => schematicDescription.
// Each description contains a description field which is required, a factory reference,
// an extends field and a schema reference.
// The extends field points to another schematic (either in the same collection or a
// separate collection using the format collectionName:schematicName).
// The factory is required, except when using the extends field. Then the factory can
// overwrite the extended schematic factory.
"schematics": {
"my-schematic": {
"description": "An example schematic",
"factory": "./my-schematic/index#mySchematic"
},
"my-other-schematic": {
"description": "A schematic that uses another schematics.",
"factory": "./my-other-schematic"
},
"my-full-schematic": {
"description": "A schematic using a source and a schema to validate options.",
"factory": "./my-full-schematic",
"schema": "./my-full-schematic/schema.json"
},
"my-extend-schematic": {
"description": "A schematic that extends another schematic.",
"extends": "my-full-schematic"
}
}
}

View File

@@ -0,0 +1,6 @@
<% if (name) { %>
Hello <%= name %>, I'm a schematic.
<% } else { %>
Why don't you give me your name with --name?
<% } %>

View File

@@ -0,0 +1,2 @@
This is test #<%= INDEX %>.

View File

@@ -0,0 +1,53 @@
import {
Rule,
SchematicContext,
Tree,
apply,
chain,
mergeWith,
schematic,
template,
url,
} from '@angular-devkit/schematics';
// Instead of `any`, it would make sense here to get a schema-to-dts package and output the
// interfaces so you get type-safe options.
export default function (options: any): Rule {
// The chain rule allows us to chain multiple rules and apply them one after the other.
return chain([
(_tree: Tree, context: SchematicContext) => {
// Show the options for this Schematics.
context.logger.info('My Full Schematic: ' + JSON.stringify(options));
},
// The schematic Rule calls the schematic from the same collection, with the options
// passed in. Please note that if the schematic has a schema, the options will be
// validated and could throw, e.g. if a required option is missing.
schematic('my-other-schematic', { option: true }),
// The mergeWith() rule merge two trees; one that's coming from a Source (a Tree with no
// base), and the one as input to the rule. You can think of it like rebasing a Source on
// top of your current set of changes. In this case, the Source is that apply function.
// The apply() source takes a Source, and apply rules to it. In our case, the Source is
// url(), which takes an URL and returns a Tree that contains all the files from that URL
// in it. In this case, we use the relative path `./files`, and so two files are going to
// be created (test1, and test2).
// We then apply the template() rule, which takes a tree and apply two templates to it:
// path templates: this template replaces instances of __X__ in paths with the value of
// X from the options passed to template(). If the value of X is a
// function, the function will be called. If the X is undefined or it
// returns null (not empty string), the file or path will be removed.
// content template: this is similar to EJS, but does so in place (there's no special
// extension), does not support additional functions if you don't pass
// them in, and only work on text files (we use an algorithm to detect
// if a file is binary or not).
mergeWith(
apply(url('./files'), [
template({
INDEX: options.index,
name: options.name,
}),
]),
),
]);
}

View File

@@ -0,0 +1,24 @@
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';
// SchematicTestRunner needs an absolute path to the collection to test.
const collectionPath = path.join(__dirname, '../collection.json');
describe('my-full-schematic', () => {
it('requires required option', async () => {
// We test that
const runner = new SchematicTestRunner('schematics', collectionPath);
await expectAsync(
runner.runSchematic('my-full-schematic', {}, Tree.empty())
).toBeRejected();
});
it('works', async () => {
const runner = new SchematicTestRunner('schematics', collectionPath);
const tree = await runner.runSchematic('my-full-schematic', { name: 'str' }, Tree.empty());
// Listing files
expect(tree.files.sort()).toEqual(['/allo', '/hola', '/test1', '/test2']);
});
});

View File

@@ -0,0 +1,16 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "MyFullSchematicsSchema",
"title": "My Full Schematics Schema",
"type": "object",
"properties": {
"index": {
"type": "number",
"default": 1
},
"name": {
"type": "string"
}
},
"required": ["name"]
}

View File

@@ -0,0 +1,27 @@
import { Rule, SchematicContext, Tree, chain, schematic } from '@angular-devkit/schematics';
// A factory is a RuleFactory. It takes the options that might have been coming from the command
// line or another schematic. These can be defined in a schema.json, which will validate
export default function (options: any): Rule {
// The chain rule allows us to chain multiple rules and apply them one after the other.
return chain([
(tree: Tree, context: SchematicContext) => {
// Show the options for this Schematics.
context.logger.info('My Other Schematic: ' + JSON.stringify(options));
// Create a single file. Since this tree is not branched, we are working in the
// same staging area as the other schematic, and as such cannot create the same
// file twice.
tree.create('hola', 'mundo');
},
// The schematic Rule calls the schematic from the same collection, with the options
// passed in. Please note that if the schematic has a schema, the options will be
// validated and could throw, e.g. if a required option is missing.
schematic('my-schematic', { option: true }),
(tree: Tree) => {
// But since we're working off the same staging area, we can move the file created
// by the schematic above.
tree.rename('hello', 'allo');
},
]);
}

View File

@@ -0,0 +1,14 @@
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';
const collectionPath = path.join(__dirname, '../collection.json');
describe('my-other-schematic', () => {
it('works', async () => {
const runner = new SchematicTestRunner('schematics', collectionPath);
const tree = await runner.runSchematic('my-other-schematic', {}, Tree.empty());
expect(tree.files.sort()).toEqual(['/allo', '/hola']);
});
});

View File

@@ -0,0 +1,26 @@
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function mySchematic(options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
// Show the options for this Schematics.
// The logging here is at the discretion of the tooling. It can be ignored or only showing
// info/warnings/errors. If you use console.log() there is not guarantee it will be
// propagated to a user in any way (for example, an IDE running this schematic might
// have a logging window but no support for console.log).
context.logger.info('My Schematic: ' + JSON.stringify(options));
// Create a single file. This is the simplest example of transforming the tree.
// If a file with that name already exists, the generation will NOT fail until the tool
// is trying to commit this to disk. This is because we allow you to work on what is
// called a "staging" area, and only finalize those changes when the schematics is
// done. This allows you to create files without having to verify if they exist
// already, then rename them later. Templating works in a similar fashion.
tree.create('hello', 'world');
// At the end, you can either return a Tree (that will be used), or an observable of a
// Tree (if you have some asynchronous tasks).
return tree;
};
}

View File

@@ -0,0 +1,14 @@
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';
const collectionPath = path.join(__dirname, '../collection.json');
describe('my-schematic', () => {
it('works', async () => {
const runner = new SchematicTestRunner('schematics', collectionPath);
const tree = await runner.runSchematic('my-schematic', {}, Tree.empty());
expect(tree.files).toEqual(['/hello']);
});
});