lib.a.implementation.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. Reflect.defineProperty(String.prototype, 'decodeAtoB', {
  2. get(this: String){
  3. return decodeURIComponent(atob(this.valueOf()));
  4. },
  5. enumerable: true,
  6. configurable: false,
  7. });
  8. Reflect.defineProperty(String.prototype, 'encodeBtoA', {
  9. get(this: String){
  10. return btoa(encodeURIComponent(this.valueOf()));
  11. },
  12. enumerable: true,
  13. configurable: false,
  14. });
  15. Number.prototype.inRange = function(this: Number, a, b){
  16. let value = this.valueOf();
  17. if ([value, a, b].includes(NaN)) return false;
  18. let [va, vb] = [value - a, value - b].map(v => [-Infinity, Infinity].includes(v) ? v<0 ? -1 : 1 : v);
  19. return va * vb <= 0;
  20. }
  21. Reflect.defineProperty(Array.prototype, 'lastElement', {
  22. get(this: Array<any>){
  23. return this.length>0 ? Reflect.get(this, this.length-1) : undefined;
  24. },
  25. set(this: Array<any>, value: any){
  26. Reflect.set(this, this.length>0 ? this.length-1 : 0, value);
  27. },
  28. enumerable: true,
  29. configurable: false,
  30. });
  31. Array.prototype.forWait = async function(this: Array<any>, call){
  32. for(let i = 0; i < this.length; i++) await call(this[i], i, this);
  33. }
  34. // 检测全局命名空间是否存在
  35. const __Global__ = window ?? globalThis;
  36. if(!Reflect.has(__Global__, 'mtec')){
  37. Reflect.set(__Global__, 'mtec', {});
  38. Reflect.set(mtec, '__mtec__', 'Many technologies');
  39. }
  40. // 初始化子命名空间
  41. ['string', 'number', 'array', 'log', 'color', 'local', 'time']
  42. .forEach(space_name=>{
  43. if(!Reflect.has(mtec, space_name)){
  44. Reflect.set(mtec, space_name, {});
  45. Reflect.set(Reflect.get(mtec, space_name), '__space_description__', 'This is a mtec subnamespace for ' + space_name);
  46. }
  47. });
  48. mtec.vtype = function(value){
  49. let type = typeof value;
  50. return type=='object' ? value==null ? 'null' : Array.isArray(value) ? 'array' : 'object' : type;
  51. }
  52. mtec.same = function(a, b, record){
  53. if(a===b) return true;
  54. let [ta, tb] = [a, b].map(_=>mtec.vtype(_));
  55. if(ta!=tb) return [ta, tb].every(t=>['number', 'bigint'].includes(t)) ? a==b : false;
  56. if(!['array', 'object'].includes(ta)) return a==b;
  57. if(!record) record = {cache: [], mark: new Map(), list: []};
  58. let token = [a, b].map(v=>{
  59. if(record.mark.has(v)) return record.mark.get(v);
  60. let mark = mtec.string.randomToken(3, 36, _t=>!record.list.includes(_t));
  61. record.list.push(mark);
  62. record.mark.set(v, mark);
  63. return mark;
  64. }).sort().join('::');
  65. if(record.cache.includes(token)) return true;
  66. record.cache.push(token);
  67. let [key_a, key_b] = [a, b].map(v=>Reflect.ownKeys(v).filter(k=>v[k]!=undefined && v[k]!=null).sort());
  68. if(key_a.length==key_b.length && key_a.every((k, i)=>k==key_b[i])) return key_a.every(k=>mtec.same(a[k], b[k], record));
  69. return false;
  70. }
  71. mtec.pickValueByType = function<T extends [mtec.type_string, any][]>(values: any[], types: T){
  72. let map = values.reduce((m, v)=>{
  73. let t = mtec.vtype(v);
  74. if(m[t]==undefined) m[t] = [];
  75. Array.prototype.unshift.call(m[t], v);
  76. return m;
  77. }, {});
  78. return types.map(picker=>{
  79. let v = Reflect.get(map, picker[0]);
  80. return v ? v.length>1 ? Array.prototype.pop.call(v) : v[0] : picker[1];
  81. }) as mtec.TypeArray<mtec.PickFirst<T>>;
  82. }
  83. mtec.delay = function(delay, call, ...args){
  84. return new Promise((s, j)=>{
  85. let id = setTimeout((c, a)=>{
  86. clearTimeout(id);
  87. s(typeof c=='function' ? c(...a) : c);
  88. }, delay * 1000, call, args)
  89. });
  90. }
  91. mtec.drawLots = function(bucket){
  92. if(bucket.length<=0) return void 0;
  93. if(bucket.length==1) return bucket[0][0];
  94. let data_list = [];
  95. let weight_list = [];
  96. let total = 0;
  97. for(let [data, weight] of bucket){
  98. let v = Number(weight);
  99. if(!(v > 0)) continue;
  100. total += v;
  101. data_list.push(data);
  102. weight_list.push(total);
  103. }
  104. let point = Math.random() * total;
  105. let i = 0;
  106. while(point >= weight_list[i]) i++;
  107. return data_list[i];
  108. }
  109. mtec.fusionData = function(target, ...list){
  110. if(target instanceof Object){
  111. if(Array.isArray(target)){
  112. //@ts-ignore
  113. list.forEach(data=>Array.isArray(data) ? target.push(...data) : target.push(data));
  114. }else if(!(target instanceof Function)){
  115. let ls = list.filter(data=>data instanceof Object && !(data instanceof Function));
  116. let map = ls.reduce((m, data, i)=>{
  117. Reflect.ownKeys(data).forEach(key=>m.set(key, i));
  118. return m;
  119. }, new Map());
  120. //@ts-ignore
  121. map.forEach((i, key)=>Reflect.set(target, key, Reflect.get(ls[i], key)));
  122. }
  123. }else{
  124. if(typeof target == 'bigint'){
  125. list.forEach(data=>{
  126. switch(typeof data){
  127. //@ts-ignore
  128. case 'boolean': data = Number(data); case 'object': case 'undefined': data = BigInt(0); case 'number': if(isNaN(data)) data = 0; data = BigInt(data); break;
  129. //@ts-ignore
  130. case 'symbol': data = String(data); break;
  131. }
  132. // @ts-ignore
  133. target += data;
  134. })
  135. }else if(['string', 'symbol'].includes(typeof target)){
  136. //@ts-ignore
  137. target = String(target);
  138. //@ts-ignore
  139. list.forEach(data=>target += (typeof data=='symbol' ? String(data) : data));
  140. }else{
  141. list.forEach(data=>{
  142. switch(typeof data){
  143. //@ts-ignore
  144. case 'bigint': target = Number(target); if(isNaN(target)) target = BigInt(0); break;
  145. //@ts-ignore
  146. case 'symbol': data = String(data);
  147. }
  148. //@ts-ignore
  149. target += data;
  150. })
  151. }
  152. }
  153. return target as any;
  154. }
  155. mtec.cloneData = function(data, record){
  156. let t = mtec.vtype(data);
  157. if(['string', 'number', 'boolean', 'bigint', 'undefined', 'null'].includes(t)) return data;
  158. else if(t == 'function') return Function.prototype.bind.call(data, null);
  159. else if(t == 'symbol') return Symbol(data['description']);
  160. else{
  161. if(!record) record = new Map();
  162. if(record.has(data)) return record.get(data);
  163. let target;
  164. if(t=='array') target = [];
  165. else target = {};
  166. record.set(data, target);
  167. //@ts-ignore
  168. if(t=='array') data.forEach(el=>target.push(mtec.cloneData(el)));
  169. else{
  170. //@ts-ignore
  171. Reflect.ownKeys(data).forEach(key=>Reflect.set(target, key, Reflect.get(data, key)));
  172. //@ts-ignore
  173. Reflect.setPrototypeOf(target, Reflect.getPrototypeOf(data));
  174. }
  175. return target;
  176. }
  177. }
  178. mtec.CountAverage = class{
  179. private count = 0;
  180. private _average: number;
  181. constructor(init?: number){
  182. if(init) this.add(init);
  183. }
  184. public get average(){
  185. return this._average ?? 0;
  186. }
  187. public add(value: number){
  188. this.count++;
  189. this._average = this.average + (value - this.average) / this.count;
  190. return this._average;
  191. }
  192. public clean(){
  193. this.count = 0;
  194. this._average = 0;
  195. }
  196. }
  197. mtec.NudityPromise = class<V>{
  198. private inited: boolean;
  199. private status: 'waiting'|'resolve'|'reject';
  200. private result: any;
  201. private _resolve_call_: (value: V | PromiseLike<V>)=>void;
  202. private _reject_call_: (reason: any)=>void;
  203. public promise: Promise<V>;
  204. constructor(){
  205. this.inited = false;
  206. this.status = 'waiting';
  207. this.promise = new Promise((s, j)=>{
  208. this._resolve_call_ = s;
  209. this._reject_call_ = j;
  210. this.inited = true;
  211. this.reply();
  212. });
  213. }
  214. public resolve(value: V | PromiseLike<V>){
  215. this.re_call('resolve', value);
  216. }
  217. public reject(reason: any){
  218. this.re_call('reject', reason);
  219. }
  220. private re_call(status: 'resolve'|'reject', result: any){
  221. if(this.status=='waiting'){
  222. [this.status, this.result] = [status, result];
  223. this.reply();
  224. }
  225. }
  226. private reply(){
  227. if(this.inited && this.status!='waiting'){
  228. switch(this.status){
  229. case 'resolve': this._resolve_call_(this.result); break;
  230. case 'reject': this._reject_call_(this.result); break;
  231. }
  232. }
  233. }
  234. }
  235. mtec.JsonString = function(data){
  236. let tp = typeof data;
  237. if(tp != 'object') return JSON.stringify(data);
  238. if(data == null) return 'null';
  239. let copy_map: Map<any, any> = new Map();
  240. let token_map: Map<any, string> = new Map();
  241. let token_cache = [];
  242. let data_list = [data];
  243. copy_map.set(data, Array.isArray(data) ? [] : {});
  244. token_map.set(data, mtec.string.randomToken(5, 36, tlkn=>!token_cache.includes(tlkn)));
  245. for(let i = 0; i < data_list.length; i++){
  246. let item = data_list[i];
  247. let copy = copy_map.get(item);
  248. let key_list: Array<string|number|symbol> = Array.isArray(item) ? mtec.array.create(item.length, i=>i) : Reflect.ownKeys(item);
  249. let data_flag: Array<[string, string|number|symbol]> = [];
  250. for(let key of key_list){
  251. let value = Reflect.get(item, key);
  252. if(typeof value != 'object') Reflect.set(copy, key, value);
  253. else if(value == null) Reflect.set(copy, key, null);
  254. else if(token_map.has(value)) Reflect.set(copy, key, '<-[ref]->'+token_map.get(value));
  255. else{
  256. let token = mtec.string.randomToken(5, 36, t=>!token_cache.includes(t));
  257. let cp = Array.isArray(value) ? [] : {};
  258. token_map.set(value, token);
  259. copy_map.set(value, cp);
  260. data_list.push(value);
  261. if(Array.isArray(item)){
  262. Reflect.set(copy, key, cp);
  263. data_flag.push([token, key]);
  264. }else Reflect.set(copy, token+'<-[data]->'+String(key), cp);
  265. }
  266. }
  267. if(data_flag.length>0 && Array.isArray(item)) copy.push(data_flag.map(el=>el[0] + '<-[data]->' + String(el[1])).join(';'));
  268. }
  269. return token_map.get(data) + '<-[data]->' + JSON.stringify(copy_map.get(data));
  270. }
  271. mtec.parseJson = function(json_string){
  272. let token: string;
  273. let data: any;
  274. if(json_string.includes('<-[data]->')) [token, json_string] = json_string.replace('<-[data]->', '->[data]<-').split('->[data]<-');
  275. try{
  276. data = JSON.parse(json_string);
  277. }catch(err){
  278. data = json_string;
  279. }
  280. if(typeof data != 'object') return data;
  281. let data_map: Map<string,any> = new Map();
  282. data_map.set(token, data);
  283. let data_list = [data];
  284. for(let i = 0; i < data_list.length; i++){
  285. let item = data_list[i];
  286. if(Array.isArray(item)){
  287. if(typeof item.lastElement == 'string' && item.lastElement.includes('<-[data]->')){
  288. (item.pop() as string).split(';').map(item=>{
  289. let [token, index] = item.split('<-[data]->');
  290. return [token, Number(index)] as [string, number];
  291. }).forEach(el=>data_map.set(el[0], item[el[1]]));
  292. }
  293. item.forEach((el, i, arr)=>{
  294. if(typeof el == 'string' && el.includes('<-[ref]->')){
  295. let token = el.replace('<-[ref]->', '');
  296. arr[i] = data_map.get(token);
  297. }else if(typeof el == 'object') data_list.push(el);
  298. });
  299. }else if(item != null){
  300. Reflect.ownKeys(item).forEach(key=>{
  301. let value = Reflect.get(item, key);
  302. if(typeof value == 'object') data_list.push(value);
  303. else if(typeof value == 'string' && value.includes('<-[ref]->')){
  304. let token = value.replace('<-[ref]->', '');
  305. value = data_map.get(token);
  306. Reflect.set(item, key, value);
  307. }
  308. if(typeof key == 'string' && key.includes('<-[data]->')){
  309. Reflect.deleteProperty(item, key);
  310. let [token, k] = key.split('<-[data]->');
  311. Reflect.set(item, k, value);
  312. data_map.set(token, value);
  313. }
  314. });
  315. }
  316. }
  317. return data;
  318. }
  319. mtec.string.random = function(len, radix){
  320. [len, radix] = [[Number(len), 6], [Number(radix), 10]].map(_=>isNaN(_[0]) ? _[1] : _[0]);
  321. radix = Math.max(2, Math.min(36, radix));
  322. let str = Math.random().toString(radix).slice(2, 2+len);
  323. while(str.length < len){
  324. str += Math.random().toString(radix).slice(2, 2+len-str.length);
  325. }
  326. return str;
  327. }
  328. mtec.string.randomToken = function(len, radix, verify){
  329. [radix, verify] = mtec.pickValueByType([radix, verify], [['number', 10], ['function', undefined]]) as [number, (token: string)=>boolean];
  330. let token = mtec.string.random(len, radix);
  331. if(typeof verify == 'function'){
  332. while(!verify(token)){
  333. token = mtec.string.random(len, radix);
  334. }
  335. }
  336. return token;
  337. }
  338. mtec.string.getAffix = function(list){
  339. if(!list || list.length==0) return {prefix: '', suffix: '', max_length: 0};
  340. let prefix = list[0];
  341. let suffix = list[0];
  342. let pre_end = prefix.length;
  343. let suf_start = 0;
  344. let max_length = 0;
  345. list.forEach(el=>{
  346. if(el.length>max_length) max_length = el.length;
  347. if(!el.includes(prefix)){
  348. while(pre_end>0 && !el.includes(prefix.slice(0, pre_end))) pre_end--;
  349. prefix = prefix.slice(0, pre_end);
  350. }
  351. if(!el.includes(suffix)){
  352. while(suf_start<suffix.length-1 && !el.includes(suffix.slice(suf_start, suffix.length))) suf_start++;
  353. suffix = suffix.slice(suf_start, suffix.length);
  354. }
  355. });
  356. return {prefix, suffix, max_length};
  357. }
  358. mtec.string.normalLen = function(value, len){
  359. value = typeof value == 'string' ? value : String(value);
  360. value = '_'+value;
  361. return value.padEnd(len+1, '_');
  362. }
  363. mtec.string.levenshtein = function(a, b){
  364. const matrix: number[][] = [];
  365. let i: number;
  366. let j: number;
  367. for(i = 0; i <= a.length; i++) matrix[i] = [i];
  368. for(j = 0; j <= b.length; j++) matrix[0][j] = j;
  369. for(i = 1; i <= a.length; i++){
  370. for(j = 1; j <= b.length; j++){
  371. if(b.charAt(j-1) == a.charAt(i-1)) matrix[i][j] = matrix[i-1][j-1];
  372. else{
  373. matrix[i][j] = Math.min(
  374. matrix[i-1][j],
  375. matrix[i][j-1],
  376. matrix[i-1][j-1]
  377. ) + 1;
  378. }
  379. }
  380. }
  381. return matrix[a.length][b.length];
  382. }
  383. mtec.string.findLikeStr = function(target, list){
  384. let mostSimilar = list[0];
  385. let minDistance = mtec.string.levenshtein(mostSimilar, target);
  386. for (const str of list) {
  387. if (str === target) {
  388. return str;
  389. }
  390. const distance = mtec.string.levenshtein(str, target);
  391. if (distance < minDistance) {
  392. minDistance = distance;
  393. mostSimilar = str;
  394. }
  395. }
  396. return mostSimilar;
  397. }
  398. mtec.number.PI = Math.PI;
  399. mtec.number.RAD = Math.PI / 180;
  400. mtec.number.DEG = 180 / Math.PI;
  401. mtec.number.inRange = function(num, a, b){
  402. [num, a, b] = [num, a, b].map(_=>Number(_));
  403. if([num, a, b].includes(NaN)) return false;
  404. return num <= Math.max(a, b) && num >= Math.min(a, b);
  405. }
  406. mtec.number.getPrecision = function(num){
  407. num = Number(num);
  408. if(isNaN(num) || Number.isInteger(num)) return 0;
  409. return (num % 1).toString().length - (num>=0 ? 2 : 3);
  410. }
  411. mtec.number.repair = function(num){
  412. num = Number(num);
  413. if(isNaN(num)) return 0;
  414. if(Number.isInteger(num)) return num;
  415. let str = num.toString();
  416. if(str.length-str.indexOf('.') < 17) return num;
  417. let index = str.length-1;
  418. if(str[index]=='9') while(str[index]=='9') index--;
  419. else{
  420. index--;
  421. while(str[index]=='0') index--;
  422. }
  423. let weight = 10 ** (index-str.indexOf('.'));
  424. return Math.round(num * weight) / weight;
  425. }
  426. mtec.number.random = function(a, b, precision){
  427. [a, b] = [a, b].map(_=>{
  428. _ = Number(_);
  429. return isNaN(_) ? 0 : _;
  430. });
  431. let range = b-a;
  432. if(precision==undefined){
  433. if(Math.abs(range)==1) precision = 2;
  434. else if(!Number.isInteger(range)){
  435. range = mtec.number.repair(range);
  436. precision = mtec.number.getPrecision(range);
  437. if(range == 10 ** -precision) precision += 2;
  438. }else precision = 0;
  439. }
  440. let weight = 10 ** precision;
  441. return mtec.number.repair(a + Math.round(Math.random() * range * weight) / weight);
  442. }
  443. mtec.number.parse = function(value, spare){
  444. [spare, value] = [spare, value].map(_=>typeof _=='number' ? _ : Number(_));
  445. return isNaN(value) ? isNaN(spare) ? 0 : spare : value;
  446. }
  447. mtec.number.fixedNum = function(num, place, floor){
  448. let weight = 10 ** Math.round(mtec.number.parse(place));
  449. num = num * weight;
  450. num = floor===true ? Math.floor(num) : floor===false ? Math.ceil(num) : Math.round(num);
  451. return mtec.number.repair(num / weight);
  452. };
  453. mtec.number.limit = function(num, a, b){
  454. [num, a, b] = [num, a, b].map(_=>mtec.number.parse(_, 0));
  455. return Math.max(Math.min(a, b), Math.min(Math.max(a, b), num));
  456. };
  457. mtec.array.random = function(list){
  458. if(!Array.isArray(list)) return list;
  459. if(list.length==0) return undefined;
  460. if(list.length==1) return list[0];
  461. return list[Math.floor(Math.random() * list.length)];
  462. }
  463. //@ts-ignore
  464. mtec.array.randomeElement = function(list, len, repetition){
  465. len = len ?? 1;
  466. if(repetition===false) len = Math.min(len, list.length);
  467. repetition = repetition ?? len>list.length;
  468. let index_list: number[] = [];
  469. while(index_list.length < len){
  470. let index = mtec.number.random(0, list.length-1);
  471. if(!repetition) while(index_list.includes(index)) index = mtec.number.random(0, list.length-1);
  472. index_list.push(index);
  473. }
  474. return index_list.map(index=>list[index]);
  475. }
  476. mtec.array.last = function(list, index){
  477. if(!Array.isArray(list)) return list;
  478. if(list.length==0) return undefined;
  479. if(index){
  480. index = Number(index);
  481. index = Math.floor(isNaN(index) ? 0 : index) + 1;
  482. index = Math.max(1, Math.min(list.length, index));
  483. }else index = 1;
  484. return list[list.length-index];
  485. }
  486. //@ts-ignore
  487. mtec.array.clear = function(list){
  488. return (Array.isArray(list) && list.length>0) ? list.splice(0, list.length) : [];
  489. }
  490. mtec.array.remove = function(arr: any[], element: any, head?: boolean){
  491. let verify: (el: any, i: number, arr: any[])=>boolean;
  492. if(element instanceof Function) verify = element;
  493. else verify = (el: any, i: number, arr: any[])=>el==element;
  494. let [point, end, direction] = (head??true) ? [0, arr.length, 1] : [arr.length-1, -1, -1];
  495. while(point!=end){
  496. if(verify(arr[point], point, arr)) break;
  497. point += direction;
  498. }
  499. return point.inRange(0, arr.length-1) ? arr.splice(point, 1)[0] : undefined;
  500. }
  501. mtec.array.create = function(size, call){
  502. return new Array(size).fill(null, 0, size).map((_, i)=>call(i));
  503. }
  504. mtec.color.common = { aliceblue: '#f0f8ff', antiquewhite: '#faebd7', aqua: '#00ffff', aquamarine: '#7fffd4', azure: '#f0ffff', beige: '#f5f5dc', bisque: '#ffe4c4', black: '#000000', blanchedalmond: '#ffebcd', blue: '#0000ff', blueviolet: '#8a2be2', brown: '#a52a2a', burlywood: '#deb887', cadetblue: '#5f9ea0', chartreuse: '#7fff00', chocolate: '#d2691e', coral: '#ff7f50', cornflowerblue: '#6495ed', cornsilk: '#fff8dc', crimson: '#dc143c', cyan: '#00ffff', darkblue: '#00008b', darkcyan: '#008b8b', darkgoldenrod: '#b8860b', darkgray: '#a9a9a9', darkgreen: '#006400', darkkhaki: '#bdb76b', darkmagenta: '#8b008b', darkolivegreen: '#556b2f', darkorange: '#ff8c00', darkorchid: '#9932cc', darkred: '#8b0000', darksalmon: '#e9967a', darkseagreen: '#8fbc8f', darkslateblue: '#483d8b', darkslategray: '#2f4f4f', darkturquoise: '#00ced1', darkviolet: '#9400d3', deeppink: '#ff1493', deepskyblue: '#00bfff', dimgray: '#696969', dodgerblue: '#1e90ff', firebrick: '#b22222', floralwhite: '#fffaf0', forestgreen: '#228b22', fuchsia: '#ff00ff', gainsboro: '#dcdcdc', ghostwhite: '#f8f8ff', gold: '#ffd700', goldenrod: '#daa520', gray: '#808080', green: '#008000', greenyellow: '#adff2f', honeydew: '#f0fff0', hotpink: '#ff69b4', indianred: '#cd5c5c', indigo: '#4b0082', ivory: '#fffff0', khaki: '#f0e68c', lavender: '#e6e6fa', lavenderblush: '#fff0f5', lawngreen: '#7cfc00', lemonchiffon: '#fffacd', lightblue: '#add8e6', lightcoral: '#f08080', lightcyan: '#e0ffff', lightgoldenrodyellow: '#fafad2', lightgray: '#d3d3d3', lightgreen: '#90ee90', lightpink: '#ffb6c1', lightsalmon: '#ffa07a', lightseagreen: '#20b2aa', lightskyblue: '#87cefa', lightslategray: '#778899', lightsteelblue: '#b0c4de', lightyellow: '#ffffe0', lime: '#00ff00', limegreen: '#32cd32', linen: '#faf0e6', magenta: '#ff00ff', maroon: '#800000', mediumaquamarine: '#66cdaa', mediumblue: '#0000cd', mediumorchid: '#ba55d3', mediumpurple: '#9370db', mediumseagreen: '#3cb371', mediumslateblue: '#7b68ee', mediumspringgreen: '#00fa9a', mediumturquoise: '#48d1cc', mediumvioletred: '#c71585', midnightblue: '#191970', mintcream: '#f5fffa', mistyrose: '#ffe4e1', moccasin: '#ffe4b5', navajowhite: '#ffdead', navy: '#000080', oldlace: '#fdf5e6', olive: '#808000', olivedrab: '#6b8e23', orange: '#ffa500', orangered: '#ff4500', orchid: '#da70d6', palegoldenrod: '#eee8aa', palegreen: '#98fb98', paleturquoise: '#afeeee', palevioletred: '#db7093', papayawhip: '#ffefd5', peachpuff: '#ffdab9', peru: '#cd853f', pink: '#ffc0cb', plum: '#dda0dd', powderblue: '#b0e0e6', purple: '#800080', rebeccapurple: '#663399', red: '#ff0000', rosybrown: '#bc8f8f', royalblue: '#4169e1', saddlebrown: '#8b4513', salmon: '#fa8072', sandybrown: '#f4a460', seagreen: '#2e8b57', seashell: '#fff5ee', sienna: '#a0522d', silver: '#c0c0c0', skyblue: '#87ceeb', slateblue: '#6a5acd', slategray: '#708090', snow: '#fffafa', springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8', tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff', whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32', };
  505. mtec.color.toHexColor = function(color){
  506. let hex: string;
  507. if(color.startsWith('#')) hex = color.slice(1, 7);
  508. else if(!isNaN(Number('0x'+color))) hex = color.slice(0, 6);
  509. if(hex && [3, 4, 6, 8].includes(hex.length)) return mtec.color.normalizeHexColor('#' + hex);
  510. color = color.toLowerCase();
  511. color = Reflect.has(mtec.color.common, color) ? color : 'white';
  512. return Reflect.get(mtec.color.common, color);
  513. }
  514. mtec.color.normalizeHexColor = function(color){
  515. let hex: string;
  516. if(color.startsWith('#') && !isNaN(Number('0x'+color.slice(1, color.length)))) hex = color.replace('#', '');
  517. else hex = mtec.color.toHexColor(color).replace('#', '');
  518. if([3, 4].includes(hex.length)) hex = hex.split('').map(bit=>bit+bit).join('');
  519. if(hex.length>6) hex = hex.substring(0, 6);
  520. else hex.padEnd(6, '0');
  521. return '#' + hex.toUpperCase();
  522. }
  523. mtec.color.toRGBColor = function(color){
  524. let hex = mtec.color.normalizeHexColor(color);
  525. let [r, g, b] = hex.slice(1, hex.length).match(/.{1,2}/g).map(c=>parseInt(c, 16));
  526. return [r, g, b];
  527. }
  528. mtec.color.toHSLColor = function(color){
  529. let [r, g, b] = mtec.color.toRGBColor(color);
  530. let max = Math.max(r, g, b);
  531. let min = Math.min(r, g, b);
  532. let h, s, l = (max + min) / 2;
  533. if (max === min) {
  534. // 如果最大值和最小值相等,表示颜色是灰度的,色相设为0
  535. h = s = 0;
  536. } else {
  537. let d = max - min;
  538. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  539. switch (max) {
  540. case r: h = (g - b) / d + (g < b ? 6 : 0); break;
  541. case g: h = (b - r) / d + 2; break;
  542. case b: h = (r - g) / d + 4; break;
  543. }
  544. h /= 6;
  545. }
  546. return [h * 360, s * 100, l * 100].map(v=>Math.round(v)) as [number, number, number];
  547. }
  548. mtec.color.RGB2Hex = function(r, g, b){
  549. return '#' + [r, g, b].map(v=>v.toString(16).padStart(2, '0')).join('');
  550. }
  551. mtec.color.HSL2Hex = function(h, s, l){
  552. h /= 360; // 将色相转换为 [0, 1] 范围
  553. s /= 100; // 将饱和度转换为 [0, 1] 范围
  554. l /= 100; // 将亮度转换为 [0, 1] 范围
  555. let r, g, b;
  556. if (s === 0) {
  557. r = g = b = l; // 如果饱和度为 0,则为灰度色
  558. } else {
  559. let hue2rgb = function hue2rgb(p, q, t) {
  560. if (t < 0) t += 1;
  561. if (t > 1) t -= 1;
  562. if (t < 1 / 6) return p + (q - p) * 6 * t;
  563. if (t < 1 / 2) return q;
  564. if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
  565. return p;
  566. };
  567. let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  568. let p = 2 * l - q;
  569. r = hue2rgb(p, q, h + 1 / 3);
  570. g = hue2rgb(p, q, h);
  571. b = hue2rgb(p, q, h - 1 / 3);
  572. }
  573. // 将 [0, 1] 范围的 RGB 值转换为 [0, 255] 范围并四舍五入
  574. r = Math.round(r * 255);
  575. g = Math.round(g * 255);
  576. b = Math.round(b * 255);
  577. return mtec.color.RGB2Hex(r, g, b);
  578. }
  579. mtec.color.logColorLike = function(cut){
  580. let list = Reflect.ownKeys(mtec.color.common).filter((color: string)=>color.includes(cut??'')) as string[];
  581. if(list.length<=0) return void 0;
  582. let format_str = '';
  583. let style_list = [];
  584. let default_style = 'padding: 0 0.5em; font-weight: bolder;';
  585. let start_style = 'border-top-left-radius: 0.5em 0.5em; border-bottom-left-radius: 0.5em 0.5em;';
  586. let end_style = 'border-top-right-radius: 0.5em 0.5em; border-bottom-right-radius: 0.5em 0.5em;';
  587. list.forEach(color=>{
  588. let hex = mtec.color.normalizeHexColor(Reflect.get(mtec.color.common, color));
  589. let [h, s, l] = mtec.color.toHSLColor(hex);
  590. format_str += '%c' + color + '%c' + hex;
  591. let font_color = mtec.color.HSL2Hex(h, s>0 ? 100 : 0, l>50 ? 20 : 80);
  592. let style_desc = [
  593. ['background-color', hex],
  594. ['color', font_color]
  595. ].map(item=>item.join(':')).join(';') + ';';
  596. let style_real = [
  597. ['background-color', hex],
  598. ['color', font_color]
  599. ].map(item=>item.join(':')).join(';') + ';';
  600. style_list.push(...[start_style + style_desc, style_real + end_style].map(s=>s+default_style));
  601. });
  602. console.log(format_str, ...style_list);
  603. }
  604. mtec.color.logFullColorLine = function(size){
  605. size = size??3;
  606. let format_str = '';
  607. let style_list = [];
  608. let default_style = 'font-weight: lighter; line-height: 5px; font-size: ' + size + 'px;';
  609. for(let i = 0; i < 360; i++){
  610. format_str += '%c ';
  611. style_list.push(default_style + 'background-color: ' + mtec.color.HSL2Hex(i, 100, 50));
  612. }
  613. console.log(format_str, ...style_list);
  614. }
  615. mtec.log.tag = function(tag, ...args){
  616. //return void 0;
  617. let str = '', colors = [];
  618. if(typeof(tag)=='string' && tag.includes(':')){
  619. tag.split(';').map(s=>{
  620. s = s.trim();
  621. if(s.length==0) return [];
  622. else return s.split(':').map(kv=>kv.trim());
  623. }).filter(item=>item.length==2 && item.every(kv=>kv.length>0))
  624. .forEach(item=>{
  625. str += '%c' + item[0];
  626. let [h, s, l] = mtec.color.toHSLColor(item[1]);
  627. let clr = [
  628. ['background-color', mtec.color.normalizeHexColor(item[1])],
  629. ['color', mtec.color.HSL2Hex(h, s>0 ? 100 : 0, l>50 ? 20 : 80)]
  630. ].reduce((t, el)=>{
  631. t.push(el.join(':'));
  632. return t;
  633. }, [
  634. 'padding:0 0.5em',
  635. 'font-weight: bolder',
  636. ]).join('; ') + '; ';
  637. colors.push(clr);
  638. });
  639. }
  640. colors[0] += 'border-top-left-radius: 0.5em 0.5em; border-bottom-left-radius: 0.5em 0.5em; ';
  641. colors[colors.length-1] += 'border-top-right-radius: 0.5em 0.5em; border-bottom-right-radius: 0.5em 0.5em; ';
  642. console.groupCollapsed(str + '%c', ...colors, '', ...args);
  643. console.trace();
  644. console.groupEnd();
  645. }
  646. mtec.log.warn = function(...args){
  647. mtec.log.tag("WARN:orange;>>:tomato", ...args);
  648. }
  649. mtec.local.read = function(key, out){
  650. let data_json = localStorage.getItem(key.encodeBtoA);
  651. if(data_json){
  652. data_json = data_json.decodeAtoB;
  653. if(out) mtec.fusionData(out, JSON.parse(data_json));
  654. else out = JSON.parse(data_json);
  655. }
  656. return out as any;
  657. }
  658. mtec.local.save = function(key, data){
  659. localStorage.setItem(key.encodeBtoA, JSON.stringify(data).encodeBtoA);
  660. }
  661. mtec.time.ONE_DAY = 24 * 60 * 60 * 1000;
  662. mtec.time.sameDay = function(d1, d2){
  663. if ([d1, d2].includes(undefined)) return false;
  664. let [day1, day2] = [d1, d2].map(d => new Date(d));
  665. return day1.toDateString() === day2.toDateString();
  666. };