feat: 新版本
@ -1,12 +0,0 @@
|
|||||||
// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包)
|
|
||||||
import React from 'react';
|
|
||||||
import Layout from 'dumi-theme-default/es/layout';
|
|
||||||
|
|
||||||
export default ({ children, ...props }) => (
|
|
||||||
<Layout {...props}>
|
|
||||||
<>
|
|
||||||
<button>反馈</button>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
@ -1,32 +0,0 @@
|
|||||||
// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包)
|
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import Layout from 'dumi-theme-default/es/layout';
|
|
||||||
|
|
||||||
export default ({ children, ...props }) => {
|
|
||||||
const { history } = props;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const header = document.querySelector('.__dumi-default-navbar')
|
|
||||||
const cont = document.querySelector('.__dumi-default-layout-content')
|
|
||||||
const lo = document.querySelector('.__dumi-default-layout')
|
|
||||||
|
|
||||||
if (location.hash === '#/resume' && lo) {
|
|
||||||
|
|
||||||
cont.style.position = 'relative'
|
|
||||||
cont.style.top = '-64px'
|
|
||||||
header.style.display = 'none'
|
|
||||||
} else {
|
|
||||||
cont.style.position = 'relative'
|
|
||||||
cont.style.top = '0'
|
|
||||||
header.style.display = 'flex'
|
|
||||||
}
|
|
||||||
},[location.hash])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout {...props}>
|
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
};
|
|
@ -1,6 +1,7 @@
|
|||||||
import { defineConfig } from 'dumi';
|
import { defineConfig } from 'dumi';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
title: 'nicenote',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
name: 'nicenote',
|
name: 'nicenote',
|
||||||
navs: [
|
navs: [
|
||||||
@ -11,6 +12,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
sitemap: { hostname: 'j710328466.github.io', exclude: [] },
|
||||||
favicons: ['https://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.ico'],
|
favicons: ['https://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.ico'],
|
||||||
// logo: 'http://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.png',
|
// logo: 'http://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.png',
|
||||||
outputPath: 'docs-dist',
|
outputPath: 'docs-dist',
|
||||||
@ -21,8 +23,7 @@ export default defineConfig({
|
|||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
resolve: {
|
resolve: {
|
||||||
docDirs: ['docs'],
|
docDirs: ['docs'],
|
||||||
atomDirs: [{ type: 'component', dir: 'src' }],
|
atomDirs: [{ type: 'component', dir: 'src' }]
|
||||||
codeBlockMode: 'passive',
|
|
||||||
},
|
},
|
||||||
locales: [{ id: 'zh-CN', name: '中文' }], // 2.0 默认值
|
locales: [{ id: 'zh-CN', name: '中文' }], // 2.0 默认值
|
||||||
analyze: {
|
analyze: {
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
if (window.g_initWebpackHotDevClient) {
|
|
||||||
function tryApplyUpdates(onHotUpdateSuccess?: Function) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (!module.hot) {
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isUpdateAvailable() {
|
|
||||||
// @ts-ignore
|
|
||||||
return window.g_getMostRecentCompilationHash() !== __webpack_hash__;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: is update available?
|
|
||||||
// @ts-ignore
|
|
||||||
if (!isUpdateAvailable() || module.hot.status() !== 'idle') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleApplyUpdates(err: Error | null, updatedModules: any) {
|
|
||||||
if (err || !updatedModules || window.g_getHadRuntimeError()) {
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onHotUpdateSuccess?.();
|
|
||||||
|
|
||||||
if (isUpdateAvailable()) {
|
|
||||||
// While we were updating, there was a new update! Do it again.
|
|
||||||
tryApplyUpdates();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
module.hot.check(true).then(
|
|
||||||
function (updatedModules: any) {
|
|
||||||
handleApplyUpdates(null, updatedModules);
|
|
||||||
},
|
|
||||||
function (err: Error) {
|
|
||||||
handleApplyUpdates(err, null);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.g_initWebpackHotDevClient({
|
|
||||||
tryApplyUpdates,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const __mfsu = 1;
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { createBrowserHistory, History } from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_runtime@3.5.41@@umijs/runtime';
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
"basename": "/"
|
|
||||||
};
|
|
||||||
if ((<any>window).routerBase) {
|
|
||||||
options.basename = (<any>window).routerBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove initial history because of ssr
|
|
||||||
let history: History = process.env.__IS_SERVER ? null : createBrowserHistory(options);
|
|
||||||
export const createHistory = (hotReload = false) => {
|
|
||||||
if (!hotReload) {
|
|
||||||
history = createBrowserHistory(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return history;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { history };
|
|
@ -1,8 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { Plugin } from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_runtime@3.5.41@@umijs/runtime';
|
|
||||||
|
|
||||||
const plugin = new Plugin({
|
|
||||||
validKeys: ['modifyClientRenderOpts','patchRoutes','rootContainer','render','onRouteChange','__mfsu',],
|
|
||||||
});
|
|
||||||
|
|
||||||
export { plugin };
|
|
297
.umi/core/pluginConfig.d.ts
vendored
@ -1,297 +0,0 @@
|
|||||||
// Created by Umi Plugin
|
|
||||||
|
|
||||||
export interface IConfigFromPlugins {
|
|
||||||
"404"?: boolean
|
|
||||||
routes?: {
|
|
||||||
/**
|
|
||||||
* Any valid URL path
|
|
||||||
*/
|
|
||||||
path?: string
|
|
||||||
/**
|
|
||||||
* A React component to render only when the location matches.
|
|
||||||
*/
|
|
||||||
component?: (string | (() => any))
|
|
||||||
wrappers?: string[]
|
|
||||||
/**
|
|
||||||
* navigate to a new location
|
|
||||||
*/
|
|
||||||
redirect?: string
|
|
||||||
/**
|
|
||||||
* When true, the active class/style will only be applied if the location is matched exactly.
|
|
||||||
*/
|
|
||||||
exact?: boolean
|
|
||||||
routes?: any[]
|
|
||||||
[k: string]: any
|
|
||||||
}[]
|
|
||||||
history?: {
|
|
||||||
type?: ("browser" | "hash" | "memory")
|
|
||||||
options?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
polyfill?: {
|
|
||||||
imports?: string[]
|
|
||||||
}
|
|
||||||
alias?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
analyze?: {
|
|
||||||
analyzerMode?: ("server" | "static" | "disabled")
|
|
||||||
analyzerHost?: string
|
|
||||||
analyzerPort?: any
|
|
||||||
openAnalyzer?: boolean
|
|
||||||
generateStatsFile?: boolean
|
|
||||||
statsFilename?: string
|
|
||||||
logLevel?: ("info" | "warn" | "error" | "silent")
|
|
||||||
defaultSizes?: ("stat" | "parsed" | "gzip")
|
|
||||||
[k: string]: any
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* postcss autoprefixer, default flexbox: no-2009
|
|
||||||
*/
|
|
||||||
autoprefixer?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
base?: string
|
|
||||||
chainWebpack?: (() => any)
|
|
||||||
chunks?: string[]
|
|
||||||
/**
|
|
||||||
* more css-loader options see https://webpack.js.org/loaders/css-loader/#options
|
|
||||||
*/
|
|
||||||
cssLoader?: {
|
|
||||||
url?: (boolean | (() => any))
|
|
||||||
import?: (boolean | (() => any))
|
|
||||||
modules?: (boolean | string | {
|
|
||||||
|
|
||||||
})
|
|
||||||
sourceMap?: boolean
|
|
||||||
importLoaders?: number
|
|
||||||
onlyLocals?: boolean
|
|
||||||
esModule?: boolean
|
|
||||||
localsConvention?: ("asIs" | "camelCase" | "camelCaseOnly" | "dashes" | "dashesOnly")
|
|
||||||
}
|
|
||||||
cssModulesTypescriptLoader?: {
|
|
||||||
mode?: ("emit" | "verify")
|
|
||||||
}
|
|
||||||
cssnano?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
copy?: any[]
|
|
||||||
define?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
devScripts?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* devServer configs
|
|
||||||
*/
|
|
||||||
devServer?: {
|
|
||||||
/**
|
|
||||||
* devServer port, default 8000
|
|
||||||
*/
|
|
||||||
port?: number
|
|
||||||
host?: string
|
|
||||||
https?: ({
|
|
||||||
key?: string
|
|
||||||
cert?: string
|
|
||||||
http2?: boolean
|
|
||||||
[k: string]: any
|
|
||||||
} | boolean)
|
|
||||||
headers?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
writeToDisk?: (boolean | (() => any))
|
|
||||||
[k: string]: any
|
|
||||||
}
|
|
||||||
devtool?: string
|
|
||||||
/**
|
|
||||||
* Code splitting for performance optimization
|
|
||||||
*/
|
|
||||||
dynamicImport?: {
|
|
||||||
/**
|
|
||||||
* loading the component before loaded
|
|
||||||
*/
|
|
||||||
loading?: string
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Code splitting for import statement syntax
|
|
||||||
*/
|
|
||||||
dynamicImportSyntax?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
exportStatic?: {
|
|
||||||
htmlSuffix?: boolean
|
|
||||||
dynamicRoot?: boolean
|
|
||||||
supportWin?: boolean
|
|
||||||
/**
|
|
||||||
* extra render paths only enable in ssr
|
|
||||||
*/
|
|
||||||
extraRoutePaths?: (() => any)
|
|
||||||
}
|
|
||||||
externals?: ({
|
|
||||||
|
|
||||||
} | string | (() => any))
|
|
||||||
extraBabelIncludes?: any[]
|
|
||||||
extraBabelPlugins?: any[]
|
|
||||||
extraBabelPresets?: any[]
|
|
||||||
extraPostCSSPlugins?: any[]
|
|
||||||
/**
|
|
||||||
* fork-ts-checker-webpack-plugin options see https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#options
|
|
||||||
*/
|
|
||||||
forkTSChecker?: {
|
|
||||||
async?: boolean
|
|
||||||
typescript?: (boolean | {
|
|
||||||
|
|
||||||
})
|
|
||||||
eslint?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
issue?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
formatter?: (string | {
|
|
||||||
|
|
||||||
})
|
|
||||||
logger?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
[k: string]: any
|
|
||||||
}
|
|
||||||
fastRefresh?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
hash?: boolean
|
|
||||||
ignoreMomentLocale?: boolean
|
|
||||||
inlineLimit?: number
|
|
||||||
lessLoader?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
manifest?: {
|
|
||||||
fileName?: string
|
|
||||||
publicPath?: ""
|
|
||||||
basePath?: string
|
|
||||||
writeToFileEmit?: boolean
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* open mfsu feature
|
|
||||||
*/
|
|
||||||
mfsu?: {
|
|
||||||
development?: {
|
|
||||||
output?: string
|
|
||||||
}
|
|
||||||
production?: {
|
|
||||||
output?: string
|
|
||||||
}
|
|
||||||
mfName?: string
|
|
||||||
exportAllMembers?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
chunks?: string[]
|
|
||||||
ignoreNodeBuiltInModules?: boolean
|
|
||||||
}
|
|
||||||
mountElementId?: ""
|
|
||||||
mpa?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
nodeModulesTransform?: {
|
|
||||||
type?: ("all" | "none")
|
|
||||||
exclude?: string[]
|
|
||||||
}
|
|
||||||
outputPath?: ""
|
|
||||||
plugins?: string[]
|
|
||||||
postcssLoader?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
presets?: string[]
|
|
||||||
proxy?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
publicPath?: string
|
|
||||||
runtimePublicPath?: boolean
|
|
||||||
ssr?: {
|
|
||||||
/**
|
|
||||||
* force execing Page getInitialProps functions
|
|
||||||
*/
|
|
||||||
forceInitial?: boolean
|
|
||||||
/**
|
|
||||||
* remove window.g_initialProps in html
|
|
||||||
*/
|
|
||||||
removeWindowInitialProps?: boolean
|
|
||||||
/**
|
|
||||||
* disable serve-side render in umi dev mode.
|
|
||||||
*/
|
|
||||||
devServerRender?: boolean
|
|
||||||
mode?: ("stream" | "string")
|
|
||||||
/**
|
|
||||||
* static markup in static site
|
|
||||||
*/
|
|
||||||
staticMarkup?: boolean
|
|
||||||
}
|
|
||||||
singular?: boolean
|
|
||||||
styleLoader?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
targets?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
terserOptions?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
theme?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
runtimeHistory?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
webpack5?: {
|
|
||||||
lazyCompilation?: {
|
|
||||||
entries?: boolean
|
|
||||||
imports?: boolean
|
|
||||||
test?: any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
workerLoader?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
favicon?: string
|
|
||||||
headScripts?: any[]
|
|
||||||
links?: any[]
|
|
||||||
metas?: any[]
|
|
||||||
scripts?: any[]
|
|
||||||
styles?: any[]
|
|
||||||
title?: string
|
|
||||||
mock?: {
|
|
||||||
exclude?: string[]
|
|
||||||
}
|
|
||||||
themeConfig?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
logo?: (string | boolean)
|
|
||||||
mode?: any
|
|
||||||
description?: string
|
|
||||||
locales?: string[][]
|
|
||||||
resolve?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
menus?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
navs?: (any[] | {
|
|
||||||
|
|
||||||
})
|
|
||||||
algolia?: {
|
|
||||||
appId?: string
|
|
||||||
apiKey?: string
|
|
||||||
indexName?: string
|
|
||||||
debug?: boolean
|
|
||||||
}
|
|
||||||
sitemap?: {
|
|
||||||
hostname?: string
|
|
||||||
excludes?: string[]
|
|
||||||
}
|
|
||||||
apiParser?: {
|
|
||||||
|
|
||||||
}
|
|
||||||
[k: string]: any
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { plugin } from './plugin';
|
|
||||||
|
|
||||||
|
|
||||||
export const __mfsu = 1;
|
|
@ -1,4 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import 'core-js';
|
|
||||||
import 'regenerator-runtime/runtime';
|
|
||||||
export {};
|
|
@ -1,129 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import { ApplyPluginsType } from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_runtime@3.5.41@@umijs/runtime';
|
|
||||||
import * as umiExports from './umiExports';
|
|
||||||
import { plugin } from './plugin';
|
|
||||||
|
|
||||||
export function getRoutes() {
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
"path": "/~demos/:uuid",
|
|
||||||
"layout": false,
|
|
||||||
"wrappers": [require('../dumi/layout').default],
|
|
||||||
"component": ((props) => {
|
|
||||||
const React = require('react');
|
|
||||||
const { default: getDemoRenderArgs } = require('/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_preset-dumi@1.1.53@@umijs/preset-dumi/lib/plugins/features/demo/getDemoRenderArgs');
|
|
||||||
const { default: Previewer } = require('dumi-theme-default/es/builtins/Previewer.js');
|
|
||||||
const { usePrefersColor, context } = require('dumi/theme');
|
|
||||||
|
|
||||||
|
|
||||||
const { demos } = React.useContext(context);
|
|
||||||
const [renderArgs, setRenderArgs] = React.useState([]);
|
|
||||||
|
|
||||||
// update render args when props changed
|
|
||||||
React.useLayoutEffect(() => {
|
|
||||||
setRenderArgs(getDemoRenderArgs(props, demos));
|
|
||||||
}, [props.match.params.uuid, props.location.query.wrapper, props.location.query.capture]);
|
|
||||||
|
|
||||||
// for listen prefers-color-schema media change in demo single route
|
|
||||||
usePrefersColor();
|
|
||||||
|
|
||||||
switch (renderArgs.length) {
|
|
||||||
case 1:
|
|
||||||
// render demo directly
|
|
||||||
return renderArgs[0];
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
// render demo with previewer
|
|
||||||
return React.createElement(
|
|
||||||
Previewer,
|
|
||||||
renderArgs[0],
|
|
||||||
renderArgs[1],
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return `Demo ${props.match.params.uuid} not found :(`;
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/_demos/:uuid",
|
|
||||||
"redirect": "/~demos/:uuid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__dumiRoot": true,
|
|
||||||
"layout": false,
|
|
||||||
"path": "/",
|
|
||||||
"wrappers": [require('../dumi/layout').default, require('/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_dumi-theme-default@1.1.24@dumi-theme-default/es/layout.js').default],
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"path": "/guide",
|
|
||||||
"component": require('/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/new/docs/guide.md').default,
|
|
||||||
"exact": true,
|
|
||||||
"meta": {
|
|
||||||
"filePath": "docs/guide.md",
|
|
||||||
"updatedTime": 1698630719271,
|
|
||||||
"slugs": [],
|
|
||||||
"title": "Guide"
|
|
||||||
},
|
|
||||||
"title": "Guide - nicenote"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/",
|
|
||||||
"component": require('/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/new/docs/index.md').default,
|
|
||||||
"exact": true,
|
|
||||||
"meta": {
|
|
||||||
"filePath": "docs/index.md",
|
|
||||||
"updatedTime": 1698630719273,
|
|
||||||
"title": "A static site based on dumi",
|
|
||||||
"hero": {
|
|
||||||
"title": "Site",
|
|
||||||
"description": "nicenote,nicecode,学习,总结",
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"text": "Hello",
|
|
||||||
"link": "/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "World",
|
|
||||||
"link": "/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"features": [
|
|
||||||
{
|
|
||||||
"title": "Hello",
|
|
||||||
"emoji": "💎",
|
|
||||||
"description": "Put hello description here"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "World",
|
|
||||||
"emoji": "🌈",
|
|
||||||
"description": "Put world description here"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "!",
|
|
||||||
"emoji": "🚀",
|
|
||||||
"description": "Put ! description here"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"slugs": []
|
|
||||||
},
|
|
||||||
"title": "A static site based on dumi - nicenote"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"title": "nicenote",
|
|
||||||
"component": (props) => props.children
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// allow user to extend routes
|
|
||||||
plugin.applyPlugins({
|
|
||||||
key: 'patchRoutes',
|
|
||||||
type: ApplyPluginsType.event,
|
|
||||||
args: { routes },
|
|
||||||
});
|
|
||||||
|
|
||||||
return routes;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
export { history } from './history';
|
|
||||||
export { plugin } from './plugin';
|
|
@ -1 +0,0 @@
|
|||||||
{}
|
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"menus": {
|
|
||||||
"en-US": {
|
|
||||||
"*": [
|
|
||||||
{
|
|
||||||
"path": "/",
|
|
||||||
"title": "A static site based on dumi",
|
|
||||||
"meta": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/guide",
|
|
||||||
"title": "Guide",
|
|
||||||
"meta": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"locales": [
|
|
||||||
{
|
|
||||||
"name": "en-US",
|
|
||||||
"label": "English"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"navs": {},
|
|
||||||
"title": "nicenote",
|
|
||||||
"mode": "doc",
|
|
||||||
"repository": {
|
|
||||||
"url": "",
|
|
||||||
"branch": "master"
|
|
||||||
},
|
|
||||||
"theme": {}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import { dynamic } from 'dumi';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
};
|
|
@ -1,8 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import config from '@@/dumi/config';
|
|
||||||
import demos from '@@/dumi/demos';
|
|
||||||
import apis from '@@/dumi/apis';
|
|
||||||
import Layout from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_preset-dumi@1.1.53@@umijs/preset-dumi/lib/theme/layout';
|
|
||||||
|
|
||||||
export default (props) => <Layout {...props} config={config} demos={demos} apis={apis} />;
|
|
58
.umi/umi.ts
@ -1,58 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import './core/polyfill';
|
|
||||||
import '@@/core/devScripts';
|
|
||||||
import { plugin } from './core/plugin';
|
|
||||||
import './core/pluginRegister';
|
|
||||||
import { createHistory } from './core/history';
|
|
||||||
import { ApplyPluginsType } from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_runtime@3.5.41@@umijs/runtime';
|
|
||||||
import { renderClient } from '/Users/teddyj/Library/Mobile Documents/com~apple~CloudDocs/Documents/workspace/dev/nicenote/node_modules/_@umijs_renderer-react@3.5.41@@umijs/renderer-react/dist/index.js';
|
|
||||||
import { getRoutes } from './core/routes';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getClientRender = (args: { hot?: boolean; routes?: any[] } = {}) => plugin.applyPlugins({
|
|
||||||
key: 'render',
|
|
||||||
type: ApplyPluginsType.compose,
|
|
||||||
initialValue: () => {
|
|
||||||
const opts = plugin.applyPlugins({
|
|
||||||
key: 'modifyClientRenderOpts',
|
|
||||||
type: ApplyPluginsType.modify,
|
|
||||||
initialValue: {
|
|
||||||
routes: args.routes || getRoutes(),
|
|
||||||
plugin,
|
|
||||||
history: createHistory(args.hot),
|
|
||||||
isServer: process.env.__IS_SERVER,
|
|
||||||
rootElement: 'root',
|
|
||||||
defaultTitle: ``,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return renderClient(opts);
|
|
||||||
},
|
|
||||||
args,
|
|
||||||
});
|
|
||||||
|
|
||||||
const clientRender = getClientRender();
|
|
||||||
export default clientRender();
|
|
||||||
|
|
||||||
|
|
||||||
window.g_umi = {
|
|
||||||
version: '3.5.41',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// hot module replacement
|
|
||||||
// @ts-ignore
|
|
||||||
if (module.hot) {
|
|
||||||
// @ts-ignore
|
|
||||||
module.hot.accept('./core/routes', () => {
|
|
||||||
const ret = require('./core/routes');
|
|
||||||
if (ret.then) {
|
|
||||||
ret.then(({ getRoutes }) => {
|
|
||||||
getClientRender({ hot: true, routes: getRoutes() })();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
getClientRender({ hot: true, routes: ret.getRoutes() })();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
39
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.tabSize": 4,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll": true,
|
||||||
|
"source.organizeImports": false
|
||||||
|
},
|
||||||
|
"css.lint.important": "ignore",
|
||||||
|
"scss.lint.important": "ignore",
|
||||||
|
"liveServer.settings.CustomBrowser": "chrome",
|
||||||
|
"cSpell.words": ["ahooks", "antd", "Mapbox"],
|
||||||
|
"terminal.integrated.profiles.windows": {
|
||||||
|
"PowerShell": {
|
||||||
|
"source": "PowerShell",
|
||||||
|
"icon": "terminal-powershell"
|
||||||
|
},
|
||||||
|
"Command Prompt": {
|
||||||
|
"path": [
|
||||||
|
"${env:windir}\\Sysnative\\cmd.exe",
|
||||||
|
"${env:windir}\\System32\\cmd.exe"
|
||||||
|
],
|
||||||
|
"args": [],
|
||||||
|
"icon": "terminal-cmd"
|
||||||
|
},
|
||||||
|
"Git-Bash": {
|
||||||
|
// "source": "Git Bash"
|
||||||
|
"path": "E:\\app\\Git\\git-bash.exe", //设置并添加git-bash的local安装路径
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
"Windows PowerShell": {
|
||||||
|
"path": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"terminal.integrated.defaultProfile.windows": "Git-Bash"
|
||||||
|
}
|
@ -1,105 +0,0 @@
|
|||||||
---
|
|
||||||
nav:
|
|
||||||
title: 后端
|
|
||||||
path: /bed
|
|
||||||
group:
|
|
||||||
title: Go
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## 第一章
|
|
||||||
|
|
||||||
```js
|
|
||||||
// main.go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"learnGo/chapter1/B"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// test1()
|
|
||||||
// test2()
|
|
||||||
// test3()
|
|
||||||
test4()
|
|
||||||
}
|
|
||||||
|
|
||||||
func test1() {
|
|
||||||
var i int
|
|
||||||
var j float32
|
|
||||||
var t complex64
|
|
||||||
var q bool
|
|
||||||
|
|
||||||
fmt.Printf("i 的默认值:%d\n", i)
|
|
||||||
fmt.Printf("j 的默认值:")
|
|
||||||
fmt.Print(j)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print("t 的默认值:")
|
|
||||||
fmt.Print(t)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print("q 的默认值:")
|
|
||||||
fmt.Print(q)
|
|
||||||
fmt.Print("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func test2() {
|
|
||||||
a, _, c := 1, "fun", 3.2
|
|
||||||
var t int8 = 4
|
|
||||||
// var b float32 = 3.01
|
|
||||||
|
|
||||||
q := float32(t)
|
|
||||||
|
|
||||||
fmt.Print(reflect.TypeOf(q))
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print(q)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print(a, c)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print(B.Car)
|
|
||||||
fmt.Print("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// iota 的使用
|
|
||||||
func test3() {
|
|
||||||
// 隐式使用法
|
|
||||||
const (
|
|
||||||
a, b = iota + 1, iota + 3
|
|
||||||
c, d
|
|
||||||
)
|
|
||||||
|
|
||||||
fmt.Print("a 的常量值是:")
|
|
||||||
fmt.Print(a)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print("b 的常量值是:")
|
|
||||||
fmt.Print(b)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print("c 的常量值是:")
|
|
||||||
fmt.Print(c)
|
|
||||||
fmt.Print("\n")
|
|
||||||
fmt.Print("d 的常量值是:")
|
|
||||||
fmt.Print(d)
|
|
||||||
fmt.Print("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// goto break continue
|
|
||||||
func test4() {
|
|
||||||
|
|
||||||
One:
|
|
||||||
fmt.Print("我是代码块一!")
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
goto One
|
|
||||||
}
|
|
||||||
|
|
||||||
// B/b.go
|
|
||||||
package B
|
|
||||||
|
|
||||||
// test 小写为该文件全局变量
|
|
||||||
var test = "fuc"
|
|
||||||
|
|
||||||
// Car 首字母大写为可导出变量
|
|
||||||
var Car = "jeep"
|
|
||||||
|
|
||||||
```
|
|
@ -1,179 +0,0 @@
|
|||||||
---
|
|
||||||
nav:
|
|
||||||
title: 后端
|
|
||||||
path: /bed
|
|
||||||
group:
|
|
||||||
title: Go
|
|
||||||
order: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
## 第二章
|
|
||||||
|
|
||||||
```js
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reader 读取模块
|
|
||||||
type Reader interface {
|
|
||||||
Read(rc chan []byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer 写入模块
|
|
||||||
type Writer interface {
|
|
||||||
Write(wc chan *Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogProcess 定义一个类
|
|
||||||
type LogProcess struct {
|
|
||||||
rc chan []byte
|
|
||||||
wc chan *Message
|
|
||||||
read Reader // 读取文件路径
|
|
||||||
write Writer // influx data source
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadFromFile 读取结构体
|
|
||||||
type ReadFromFile struct {
|
|
||||||
path string
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteToInfluxDB 写入结构体
|
|
||||||
type WriteToInfluxDB struct {
|
|
||||||
influxDBDsn string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message 结构体
|
|
||||||
type Message struct {
|
|
||||||
TimeLocal time.Time
|
|
||||||
bytesSent int
|
|
||||||
Path, Method, Scheme, Status string
|
|
||||||
UpstreamTime, RequestTime float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read 读取模块
|
|
||||||
func (r *ReadFromFile) Read(rc chan []byte) {
|
|
||||||
// 打开文件
|
|
||||||
f, err := os.Open(r.path)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("open file error: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从文件末尾开始逐行读取内容
|
|
||||||
|
|
||||||
// 把字符指针移到文件末尾
|
|
||||||
f.Seek(0, 2)
|
|
||||||
rd := bufio.NewReader(f)
|
|
||||||
|
|
||||||
for {
|
|
||||||
line, err := rd.ReadBytes('\n')
|
|
||||||
if err == io.EOF {
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
} else if err != nil {
|
|
||||||
panic(fmt.Sprintf("ReadBytes error: %s", err.Error()))
|
|
||||||
}
|
|
||||||
rc <- line[:len(line)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer 写入
|
|
||||||
func (w *WriteToInfluxDB) Write(wc chan *Message) {
|
|
||||||
|
|
||||||
for v := range wc {
|
|
||||||
fmt.Println(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process 解析模块
|
|
||||||
func (l *LogProcess) Process() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
172.0.0.12 - - [04/Mar/2018:13:49:52 +0000] http "GET /foo?query=t HTTP/1.0" 200 2133 "-" "KeepAliveClient" "-" 1.005 1.854
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 正则表达式
|
|
||||||
r := regexp.MustCompile(`([\d\.]+)\s+([^ \[]+)\s+([^ \[]+)\s+\[([^\]]+)\]\s+([a-z]+)\s+\"([^"]+)\"\s+(\d{3})\s+(\d+)\s+\"([^"]+)\"\s+\"(.*?)\"\s+\"([\d\.-]+)\"\s+([\d\.-]+)\s+([\d\.-]+)`)
|
|
||||||
|
|
||||||
loc, _ := time.LoadLocation("Asia/ShangHai")
|
|
||||||
for v := range l.rc {
|
|
||||||
ret := r.FindStringSubmatch(string(v))
|
|
||||||
|
|
||||||
if len(ret) != 14 {
|
|
||||||
log.Println("FindStringSubmatch fail:", string(v))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
message := &Message{}
|
|
||||||
t, err := time.ParseInLocation("02/Jan/2006:15:04:05 +0000", ret[4], loc)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("ParseInLocation: fail", err.Error(), ret[4])
|
|
||||||
}
|
|
||||||
message.TimeLocal = t
|
|
||||||
|
|
||||||
byteSent, _ := strconv.Atoi(ret[8])
|
|
||||||
message.bytesSent = byteSent
|
|
||||||
|
|
||||||
// GET /foo?query=t HTTP/1.0
|
|
||||||
reqSli := strings.Split(ret[6], " ")
|
|
||||||
if len(reqSli) != 3 {
|
|
||||||
log.Println("strings.Split fail ", ret[6])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
message.Method = reqSli[0]
|
|
||||||
|
|
||||||
u, err := url.Parse(reqSli[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Println("url parse fail:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
message.Path = u.Path
|
|
||||||
|
|
||||||
message.Scheme = ret[5]
|
|
||||||
message.Status = ret[7]
|
|
||||||
|
|
||||||
upstreamTime, _ := strconv.ParseFloat(ret[12], 64)
|
|
||||||
requestTime, _ := strconv.ParseFloat(ret[13], 64)
|
|
||||||
message.UpstreamTime = upstreamTime
|
|
||||||
message.RequestTime = requestTime
|
|
||||||
|
|
||||||
l.wc <- message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
r := &ReadFromFile{
|
|
||||||
path: "temp/access.log",
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &WriteToInfluxDB{
|
|
||||||
influxDBDsn: "username&password..",
|
|
||||||
}
|
|
||||||
|
|
||||||
lp := &LogProcess{
|
|
||||||
rc: make(chan []byte),
|
|
||||||
wc: make(chan *Message),
|
|
||||||
read: r,
|
|
||||||
write: w,
|
|
||||||
}
|
|
||||||
|
|
||||||
// gorotine 并发执行,提升效率
|
|
||||||
go lp.read.Read(lp.rc)
|
|
||||||
go lp.Process()
|
|
||||||
go lp.write.Write(lp.wc)
|
|
||||||
|
|
||||||
time.Sleep(30 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
nav:
|
|
||||||
title: 后端
|
|
||||||
path: /bed
|
|
||||||
group:
|
|
||||||
title: Go
|
|
||||||
order: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
## 第三章
|
|
||||||
|
|
||||||
```js
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func wsHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Write([]byte("hello world"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// 当有请求访问ws时,执行此回调方法
|
|
||||||
http.HandleFunc("/ws", wsHandler)
|
|
||||||
// 监听127.0.0.1:7777
|
|
||||||
err := http.ListenAndServe("0.0.0.0:7777", nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("ListenAndServe", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 后端
|
title: 其它语言
|
||||||
path: /bed
|
path: /other
|
||||||
group:
|
group:
|
||||||
title: Go
|
title: Go
|
||||||
order: 2
|
order: 2
|
||||||
@ -13,33 +13,33 @@ group:
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadFrom 定义函数
|
// ReadFrom 定义函数
|
||||||
func ReadFrom(reader io.Reader, num int) ([]byte, error) {
|
func ReadFrom(reader io.Reader, num int) ([]byte, error) {
|
||||||
|
|
||||||
p := make([]byte, num)
|
p := make([]byte, num)
|
||||||
|
|
||||||
n, err := reader.Read(p)
|
n, err := reader.Read(p)
|
||||||
|
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
return p[:n], nil
|
return p[:n], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SampleReadFromString 输出例子
|
// SampleReadFromString 输出例子
|
||||||
func SampleReadFromString() {
|
func SampleReadFromString() {
|
||||||
data, _ := ReadFrom(strings.NewReader("from string"), 12)
|
data, _ := ReadFrom(strings.NewReader("from string"), 12)
|
||||||
|
|
||||||
fmt.Println(data)
|
fmt.Println(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
SampleReadFromString()
|
SampleReadFromString()
|
||||||
}
|
}
|
||||||
```
|
```
|
105
docs/db/go/chapter1.md
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 其它语言
|
||||||
|
path: /other
|
||||||
|
group:
|
||||||
|
title: Go
|
||||||
|
order: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第一章
|
||||||
|
|
||||||
|
```js
|
||||||
|
// main.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"learnGo/chapter1/B"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// test1()
|
||||||
|
// test2()
|
||||||
|
// test3()
|
||||||
|
test4()
|
||||||
|
}
|
||||||
|
|
||||||
|
func test1() {
|
||||||
|
var i int
|
||||||
|
var j float32
|
||||||
|
var t complex64
|
||||||
|
var q bool
|
||||||
|
|
||||||
|
fmt.Printf("i 的默认值:%d\n", i)
|
||||||
|
fmt.Printf("j 的默认值:")
|
||||||
|
fmt.Print(j)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print("t 的默认值:")
|
||||||
|
fmt.Print(t)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print("q 的默认值:")
|
||||||
|
fmt.Print(q)
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test2() {
|
||||||
|
a, _, c := 1, "fun", 3.2
|
||||||
|
var t int8 = 4
|
||||||
|
// var b float32 = 3.01
|
||||||
|
|
||||||
|
q := float32(t)
|
||||||
|
|
||||||
|
fmt.Print(reflect.TypeOf(q))
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print(q)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print(a, c)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print(B.Car)
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// iota 的使用
|
||||||
|
func test3() {
|
||||||
|
// 隐式使用法
|
||||||
|
const (
|
||||||
|
a, b = iota + 1, iota + 3
|
||||||
|
c, d
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Print("a 的常量值是:")
|
||||||
|
fmt.Print(a)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print("b 的常量值是:")
|
||||||
|
fmt.Print(b)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print("c 的常量值是:")
|
||||||
|
fmt.Print(c)
|
||||||
|
fmt.Print("\n")
|
||||||
|
fmt.Print("d 的常量值是:")
|
||||||
|
fmt.Print(d)
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// goto break continue
|
||||||
|
func test4() {
|
||||||
|
|
||||||
|
One:
|
||||||
|
fmt.Print("我是代码块一!")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
goto One
|
||||||
|
}
|
||||||
|
|
||||||
|
// B/b.go
|
||||||
|
package B
|
||||||
|
|
||||||
|
// test 小写为该文件全局变量
|
||||||
|
var test = "fuc"
|
||||||
|
|
||||||
|
// Car 首字母大写为可导出变量
|
||||||
|
var Car = "jeep"
|
||||||
|
|
||||||
|
```
|
179
docs/db/go/chapter2.md
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 其它语言
|
||||||
|
path: /other
|
||||||
|
group:
|
||||||
|
title: Go
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第二章
|
||||||
|
|
||||||
|
```js
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reader 读取模块
|
||||||
|
type Reader interface {
|
||||||
|
Read(rc chan []byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writer 写入模块
|
||||||
|
type Writer interface {
|
||||||
|
Write(wc chan *Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogProcess 定义一个类
|
||||||
|
type LogProcess struct {
|
||||||
|
rc chan []byte
|
||||||
|
wc chan *Message
|
||||||
|
read Reader // 读取文件路径
|
||||||
|
write Writer // influx data source
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFromFile 读取结构体
|
||||||
|
type ReadFromFile struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteToInfluxDB 写入结构体
|
||||||
|
type WriteToInfluxDB struct {
|
||||||
|
influxDBDsn string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message 结构体
|
||||||
|
type Message struct {
|
||||||
|
TimeLocal time.Time
|
||||||
|
bytesSent int
|
||||||
|
Path, Method, Scheme, Status string
|
||||||
|
UpstreamTime, RequestTime float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read 读取模块
|
||||||
|
func (r *ReadFromFile) Read(rc chan []byte) {
|
||||||
|
// 打开文件
|
||||||
|
f, err := os.Open(r.path)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("open file error: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从文件末尾开始逐行读取内容
|
||||||
|
|
||||||
|
// 把字符指针移到文件末尾
|
||||||
|
f.Seek(0, 2)
|
||||||
|
rd := bufio.NewReader(f)
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, err := rd.ReadBytes('\n')
|
||||||
|
if err == io.EOF {
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
panic(fmt.Sprintf("ReadBytes error: %s", err.Error()))
|
||||||
|
}
|
||||||
|
rc <- line[:len(line)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writer 写入
|
||||||
|
func (w *WriteToInfluxDB) Write(wc chan *Message) {
|
||||||
|
|
||||||
|
for v := range wc {
|
||||||
|
fmt.Println(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process 解析模块
|
||||||
|
func (l *LogProcess) Process() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
172.0.0.12 - - [04/Mar/2018:13:49:52 +0000] http "GET /foo?query=t HTTP/1.0" 200 2133 "-" "KeepAliveClient" "-" 1.005 1.854
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 正则表达式
|
||||||
|
r := regexp.MustCompile(`([\d\.]+)\s+([^ \[]+)\s+([^ \[]+)\s+\[([^\]]+)\]\s+([a-z]+)\s+\"([^"]+)\"\s+(\d{3})\s+(\d+)\s+\"([^"]+)\"\s+\"(.*?)\"\s+\"([\d\.-]+)\"\s+([\d\.-]+)\s+([\d\.-]+)`)
|
||||||
|
|
||||||
|
loc, _ := time.LoadLocation("Asia/ShangHai")
|
||||||
|
for v := range l.rc {
|
||||||
|
ret := r.FindStringSubmatch(string(v))
|
||||||
|
|
||||||
|
if len(ret) != 14 {
|
||||||
|
log.Println("FindStringSubmatch fail:", string(v))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &Message{}
|
||||||
|
t, err := time.ParseInLocation("02/Jan/2006:15:04:05 +0000", ret[4], loc)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("ParseInLocation: fail", err.Error(), ret[4])
|
||||||
|
}
|
||||||
|
message.TimeLocal = t
|
||||||
|
|
||||||
|
byteSent, _ := strconv.Atoi(ret[8])
|
||||||
|
message.bytesSent = byteSent
|
||||||
|
|
||||||
|
// GET /foo?query=t HTTP/1.0
|
||||||
|
reqSli := strings.Split(ret[6], " ")
|
||||||
|
if len(reqSli) != 3 {
|
||||||
|
log.Println("strings.Split fail ", ret[6])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
message.Method = reqSli[0]
|
||||||
|
|
||||||
|
u, err := url.Parse(reqSli[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("url parse fail:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
message.Path = u.Path
|
||||||
|
|
||||||
|
message.Scheme = ret[5]
|
||||||
|
message.Status = ret[7]
|
||||||
|
|
||||||
|
upstreamTime, _ := strconv.ParseFloat(ret[12], 64)
|
||||||
|
requestTime, _ := strconv.ParseFloat(ret[13], 64)
|
||||||
|
message.UpstreamTime = upstreamTime
|
||||||
|
message.RequestTime = requestTime
|
||||||
|
|
||||||
|
l.wc <- message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := &ReadFromFile{
|
||||||
|
path: "temp/access.log",
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &WriteToInfluxDB{
|
||||||
|
influxDBDsn: "username&password..",
|
||||||
|
}
|
||||||
|
|
||||||
|
lp := &LogProcess{
|
||||||
|
rc: make(chan []byte),
|
||||||
|
wc: make(chan *Message),
|
||||||
|
read: r,
|
||||||
|
write: w,
|
||||||
|
}
|
||||||
|
|
||||||
|
// gorotine 并发执行,提升效率
|
||||||
|
go lp.read.Read(lp.rc)
|
||||||
|
go lp.Process()
|
||||||
|
go lp.write.Write(lp.wc)
|
||||||
|
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
34
docs/db/go/chapter3.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 其它语言
|
||||||
|
path: /other
|
||||||
|
group:
|
||||||
|
title: Go
|
||||||
|
order: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第三章
|
||||||
|
|
||||||
|
```js
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("hello world"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 当有请求访问ws时,执行此回调方法
|
||||||
|
http.HandleFunc("/ws", wsHandler)
|
||||||
|
// 监听127.0.0.1:7777
|
||||||
|
err := http.ListenAndServe("0.0.0.0:7777", nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("ListenAndServe", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 后端
|
title: 其它语言
|
||||||
path: /bed
|
path: /other
|
||||||
group:
|
group:
|
||||||
title: Go
|
title: Go
|
||||||
order: 1
|
order: 1
|
||||||
@ -42,7 +42,7 @@ group:
|
|||||||
- 介绍
|
- 介绍
|
||||||
- 每次碰到 const 会被重置为 0,如果没碰到每新增一个常量声明,就会自增 +1
|
- 每次碰到 const 会被重置为 0,如果没碰到每新增一个常量声明,就会自增 +1
|
||||||
- 使用技巧
|
- 使用技巧
|
||||||
- 跳值使用法:使用 _ , 每一个 _ 能使 iota 的值跳过 1 , 要跳多少就给多少个 \_
|
- 跳值使用法:使用 _, 每一个_ 能使 iota 的值跳过 1 , 要跳多少就给多少个 \_
|
||||||
- 插队使用法:在变量声明中再插入一个赋值的变量不会对 iota 自增产生影响
|
- 插队使用法:在变量声明中再插入一个赋值的变量不会对 iota 自增产生影响
|
||||||
- 隐式使用法:如果不声明值,则默认使用最后一个表达式的赋值格式
|
- 隐式使用法:如果不声明值,则默认使用最后一个表达式的赋值格式
|
||||||
|
|
@ -1,30 +1,36 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 数据库
|
title: 其它语言
|
||||||
path: /db
|
path: /other
|
||||||
group:
|
group:
|
||||||
title: 💊 mongoDB
|
title: mongoDB
|
||||||
order: 1
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# 💊 mongoDB
|
|
||||||
|
|
||||||
## mac 安装
|
## mac 安装
|
||||||
|
|
||||||
### 1.1 到官网下载指定版本的安装包
|
### 1.1 到官网下载指定版本的安装包
|
||||||
|
|
||||||
[https://www.mongodb.com/try/download/community?jmp=nav](https://www.mongodb.com/try/download/community?jmp=nav)
|
[https://www.mongodb.com/try/download/community?jmp=nav](https://www.mongodb.com/try/download/community?jmp=nav)
|
||||||
|
|
||||||
|
|
||||||
### 1.2 将安装包放到指定文件夹
|
### 1.2 将安装包放到指定文件夹
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
open /usr/local
|
open / usr / local;
|
||||||
```
|
```
|
||||||
###
|
|
||||||
### 1.3 配置数据库data目录
|
###
|
||||||
|
|
||||||
|
### 1.3 配置数据库 data 目录
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sudo mkdir -p /data/db
|
sudo mkdir -p /data/db
|
||||||
```
|
```
|
||||||
##
|
|
||||||
|
##
|
||||||
|
|
||||||
### 1.4 配置环境变量
|
### 1.4 配置环境变量
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
# 1. 打开 bash 文件
|
# 1. 打开 bash 文件
|
||||||
open ~/.bash_profile
|
open ~/.bash_profile
|
||||||
@ -35,19 +41,23 @@ PATH=$PATH:/usr/local/mongoDB/bin
|
|||||||
# 3. 保存 bash,并触发生效
|
# 3. 保存 bash,并触发生效
|
||||||
source ~/.bash_profile
|
source ~/.bash_profile
|
||||||
```
|
```
|
||||||
##
|
|
||||||
### 1.5 启动 mongodb
|
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
### 1.5 启动 mongodb
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
mongod --dbpath /usr/local/mongodb/db
|
mongod --dbpath /usr/local/mongodb/db
|
||||||
|
|
||||||
mongod --dbpath /usr/local/mongodb/db -f /etc/mongod.conf
|
mongod --dbpath /usr/local/mongodb/db -f /etc/mongod.conf
|
||||||
```
|
```
|
||||||
## centOS安装
|
|
||||||
|
## centOS 安装
|
||||||
|
|
||||||
### 2.1 添加源
|
### 2.1 添加源
|
||||||
|
|
||||||
- sudo vi /etc/yum.repos.d/mongodb-org-4.0.repo
|
- sudo vi /etc/yum.repos.d/mongodb-org-4.0.repo
|
||||||
|
|
||||||
### 2.2 添加配置信息
|
### 2.2 添加配置信息
|
||||||
|
|
||||||
- [mongodb-org-4.0]
|
- [mongodb-org-4.0]
|
||||||
@ -56,42 +66,49 @@ mongod --dbpath /usr/local/mongodb/db -f /etc/mongod.conf
|
|||||||
- gpgcheck=1
|
- gpgcheck=1
|
||||||
- enabled=1
|
- enabled=1
|
||||||
- gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
|
- gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
|
||||||
|
|
||||||
### 2.3 安装
|
### 2.3 安装
|
||||||
|
|
||||||
- sudo yum install -y mongodb-org
|
- sudo yum install -y mongodb-org
|
||||||
|
|
||||||
### 2.4 检验
|
### 2.4 检验
|
||||||
|
|
||||||
- rpm -qa |grep mongodb
|
- rpm -qa |grep mongodb
|
||||||
- rpm -ql mongodb-org-server
|
- rpm -ql mongodb-org-server
|
||||||
|
|
||||||
### 2.4 启动服务
|
### 2.4 启动服务
|
||||||
|
|
||||||
- 建议加上 --auth 权限验证
|
- 建议加上 --auth 权限验证
|
||||||
- service mongod start
|
- service mongod start
|
||||||
- systemctl start mongod.service
|
- systemctl start mongod.service
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> 通过本地文件启动:mongod -f /usr/local/mongodb/mongodb.conf
|
> 通过本地文件启动:mongod -f /usr/local/mongodb/mongodb.conf
|
||||||
|
|
||||||
### 2.5 查看端口
|
### 2.5 查看端口
|
||||||
|
|
||||||
- netstat -natp | grep 27017
|
- netstat -natp | grep 27017
|
||||||
|
|
||||||
### 2.6 查看是否成功
|
### 2.6 查看是否成功
|
||||||
|
|
||||||
- ps -aux | grep mongod # 查看数据库的进程是否存在
|
- ps -aux | grep mongod # 查看数据库的进程是否存在
|
||||||
|
|
||||||
### 2.7 开机自启
|
### 2.7 开机自启
|
||||||
|
|
||||||
- chkconfig mongod on
|
- chkconfig mongod on
|
||||||
- systemctl enable mongod.service
|
- systemctl enable mongod.service
|
||||||
|
|
||||||
### 2.8 关闭
|
### 2.8 关闭
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
pkill mongod
|
pkill mongod
|
||||||
```
|
```
|
||||||
## 目录介绍
|
|
||||||
### 配置文件:
|
|
||||||
|
|
||||||
|
## 目录介绍
|
||||||
|
|
||||||
|
### 配置文件
|
||||||
|
|
||||||
/etc/mongod.conf
|
/etc/mongod.conf
|
||||||
|
|
||||||
```json
|
```json
|
||||||
port=27017 #端口
|
port=27017 #端口
|
||||||
dbpath=/usr/local/mongodb/db #数据库文件存放目录
|
dbpath=/usr/local/mongodb/db #数据库文件存放目录
|
||||||
@ -103,18 +120,25 @@ journal=true #每次写入会记录一条操作日志
|
|||||||
bind_ip=0.0.0.0 #可外部访问
|
bind_ip=0.0.0.0 #可外部访问
|
||||||
auth=true #用户认证
|
auth=true #用户认证
|
||||||
```
|
```
|
||||||
###
|
|
||||||
### 数据库保存目录:
|
###
|
||||||
|
|
||||||
|
### 数据库保存目录
|
||||||
|
|
||||||
- /usr/local/mongodb/db
|
- /usr/local/mongodb/db
|
||||||
### 日志目录:
|
|
||||||
|
### 日志目录
|
||||||
|
|
||||||
- /usr/local/mongodb/logs/mongodb.log
|
- /usr/local/mongodb/logs/mongodb.log
|
||||||
|
|
||||||
> 如果需要修改数据目录和日志目录,只需修改 /etc/mongod.conf 中的 storage.dbPath 和 systemLog.path 即可。
|
> 如果需要修改数据目录和日志目录,只需修改 /etc/mongod.conf 中的 storage.dbPath 和 systemLog.path 即可。
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
## 卸载
|
## 卸载
|
||||||
|
|
||||||
### 4.1 关闭服务
|
### 4.1 关闭服务
|
||||||
|
|
||||||
```json
|
```json
|
||||||
service mongod stop
|
service mongod stop
|
||||||
|
|
||||||
@ -123,58 +147,70 @@ or
|
|||||||
systemctl stop mongod.service
|
systemctl stop mongod.service
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2 删除相关的包
|
### 4.2 删除相关的包
|
||||||
|
|
||||||
```json
|
```json
|
||||||
yum erase $(rpm -qa | grep mongodb-org)
|
yum erase $(rpm -qa | grep mongodb-org)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.3 删除目录和文件
|
### 4.3 删除目录和文件
|
||||||
|
|
||||||
```json
|
```json
|
||||||
rm -r /var/log/mongodbrm -r /var/lib/mongo
|
rm -r /var/log/mongodbrm -r /var/lib/mongo
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.4 彻底卸载
|
### 4.4 彻底卸载
|
||||||
|
|
||||||
```json
|
```json
|
||||||
sudo yum erase $(rpm -qa | grep mongodb-org) # 卸载
|
sudo yum erase $(rpm -qa | grep mongodb-org) # 卸载
|
||||||
MongoDB sudo rm -r /var/log/mongodb # 删除日志文件
|
MongoDB sudo rm -r /var/log/mongodb # 删除日志文件
|
||||||
sudo rm -r /var/lib/mongo # 删除数据文件
|
sudo rm -r /var/lib/mongo # 删除数据文件
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 常见命令
|
## 常见命令
|
||||||
|
|
||||||
### 登录
|
### 登录
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
• mongo '数据库名' -u '用户名' -p '密码'
|
• mongo '数据库名' -u '用户名' -p '密码'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 重启
|
### 重启
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sudo service mongod restart
|
sudo service mongod restart
|
||||||
```
|
```
|
||||||
|
|
||||||
### 查看日志
|
### 查看日志
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
/var/log/mongo/mongod.log
|
/var/log/mongo/mongod.log
|
||||||
```
|
```
|
||||||
|
|
||||||
### 命令行打开
|
### 命令行打开
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
• sudo mongod --port 27017 --dbpath /data/db --bind_ip 0.0.0.0 --auth -f /etc/mongod.conf
|
• sudo mongod --port 27017 --dbpath /data/db --bind_ip 0.0.0.0 --auth -f /etc/mongod.conf
|
||||||
```
|
```
|
||||||
###
|
|
||||||
### 用户权限
|
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
### 用户权限
|
||||||
|
|
||||||
#### 权限列表
|
#### 权限列表
|
||||||
|
|
||||||
|
|
||||||
- .1. 数据库用户角色:read、readWrite;
|
- .1. 数据库用户角色:read、readWrite;
|
||||||
- .2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
|
- .2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
|
||||||
- .3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
|
- .3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
|
||||||
- .4. 备份恢复角色:backup、restore;
|
- .4. 备份恢复角色:backup、restore;
|
||||||
- .5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
|
- .5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
|
||||||
- .6. 超级用户角色:root
|
- .6. 超级用户角色:root
|
||||||
- // 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
|
- // 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
|
||||||
- .7. 内部角色:__system
|
- .7. 内部角色:\_\_system
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 新增用户
|
#### 新增用户
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 切换根数据库
|
// 切换根数据库
|
||||||
use admin
|
use admin
|
||||||
@ -183,21 +219,24 @@ db.createUser({user:"h5creator",pwd:"123456mjw",roles:[{role:"dbAdmin",db:"test"
|
|||||||
// 登录用户
|
// 登录用户
|
||||||
db.auth(${name}, ${pwd})
|
db.auth(${name}, ${pwd})
|
||||||
```
|
```
|
||||||
###
|
|
||||||
|
###
|
||||||
|
|
||||||
#### 修改用户权限
|
#### 修改用户权限
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
db.grantRolesToUser("h5creator",[{role:"readWrite", db:"test"}])
|
db.grantRolesToUser('h5creator', [{ role: 'readWrite', db: 'test' }]);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### 更新字段
|
#### 更新字段
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
db.collection.update(
|
db.collection.update(
|
||||||
<query>,
|
<query>,
|
||||||
<update>,
|
<update>,
|
||||||
{
|
{
|
||||||
upsert: <boolean>, // 如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
|
upsert: <boolean>, // 如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
|
||||||
multi: <boolean>, // 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新
|
multi: <boolean>, // 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新
|
||||||
writeConcern: <document> // 抛出异常的级别
|
writeConcern: <document> // 抛出异常的级别
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -209,35 +248,41 @@ db.collection.update({},{"$unset":{"key":""}},{multi:true})
|
|||||||
db.getCollection('article').update({}, {$set: {type:NumberInt('1')}}, {multi: true})
|
db.getCollection('article').update({}, {$set: {type:NumberInt('1')}}, {multi: true})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### 开发对外端口
|
### 开发对外端口
|
||||||
|
|
||||||
#### 方案一
|
#### 方案一
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
• systemctl status firewalld # 查看防火墙状态
|
• systemctl status firewalld # 查看防火墙状态
|
||||||
• firewall-cmd --zone=public --add-port=27017/tcp --permanent # mongodb默认端口号
|
• firewall-cmd --zone=public --add-port=27017/tcp --permanent # mongodb默认端口号
|
||||||
• firewall-cmd --reload # 重新加载防火墙
|
• firewall-cmd --reload # 重新加载防火墙
|
||||||
• firewall-cmd --zone=public --query-port=27017/tcp # 查看端口号是否开放成功,输出yes开放成功,no则失败
|
• firewall-cmd --zone=public --query-port=27017/tcp # 查看端口号是否开放成功,输出yes开放成功,no则失败
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 方案二
|
#### 方案二
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
• iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 27017 -j ACCEPT
|
• iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 27017 -j ACCEPT
|
||||||
```
|
```
|
||||||
|
|
||||||
## 偶遇问题
|
## 偶遇问题
|
||||||
|
|
||||||
### 1) Failed to unlink socket file /tmp/mongodb-27017.sock Operation not permitted
|
### 1) Failed to unlink socket file /tmp/mongodb-27017.sock Operation not permitted
|
||||||
|
|
||||||
- 解决方案:删除该文件
|
- 解决方案:删除该文件
|
||||||
|
|
||||||
### 2) Unable to lock file: /var/lib/mongo/mongod.lock
|
### 2) Unable to lock file: /var/lib/mongo/mongod.lock
|
||||||
|
|
||||||
- 解决方案:清空该文件内容
|
- 解决方案:清空该文件内容
|
||||||
|
|
||||||
### 3) 无法持续运行在后台
|
### 3) 无法持续运行在后台
|
||||||
|
|
||||||
- 解决方案:mongod --fork --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs/mongodb2.log --logappend
|
- 解决方案:mongod --fork --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/logs/mongodb2.log --logappend
|
||||||
4. 无法启动 mongodb
|
|
||||||
> 1. 进入 mongod 上一次启动的时候指定的 data 目录 --dbpath=/data/mongodb
|
|
||||||
>
|
|
||||||
删除掉该文件:
|
|
||||||
> rm /data/db/mongo.lock
|
|
||||||
> 2. 修复
|
|
||||||
>
|
|
||||||
./mongod --repair
|
|
||||||
|
|
||||||
|
4. 无法启动 mongodb
|
||||||
|
> 1. 进入 mongod 上一次启动的时候指定的 data 目录 --dbpath=/data/mongodb
|
||||||
|
>
|
||||||
|
> 删除掉该文件:
|
||||||
|
> rm /data/db/mongo.lock 2. 修复
|
||||||
|
>
|
||||||
|
> ./mongod --repair
|
||||||
|
@ -1,44 +1,48 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 数据库
|
title: 其它语言
|
||||||
path: /db
|
path: /other
|
||||||
group:
|
group:
|
||||||
title: 💊 redis
|
title: redis
|
||||||
order: 2
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
# 安装与配置
|
# 安装与配置
|
||||||
|
|
||||||
- redis-cli -h 101.132.156.228 -a r-uf60a44b13666134:'123456Jzx'
|
- redis-cli -h 101.132.156.228 -a r-uf60a44b13666134:'123456Jzx'
|
||||||
## 在云服务器 ECS Linux 中安装 rinetd。
|
|
||||||
|
|
||||||
- wget [http://www.boutell.com/rinetd/http/rinetd.tar.gz&&tar](http://www.boutell.com/rinetd/http/rinetd.tar.gz&&tar) -xvf rinetd.tar.gz&&cd rinetd
|
## 在云服务器 ECS Linux 中安装 rinetd
|
||||||
- sed -i 's/65536/65535/g' rinetd.c (修改端口范围)
|
|
||||||
- mkdir /usr/man&&make&&make install
|
- wget [http://www.boutell.com/rinetd/http/rinetd.tar.gz&&tar](http://www.boutell.com/rinetd/http/rinetd.tar.gz&&tar) -xvf rinetd.tar.gz&&cd rinetd
|
||||||
- > 注意:rinetd 安装包下载地址不确保下载可用性,您可以自行搜索安装包进行下载使用。
|
- sed -i 's/65536/65535/g' rinetd.c (修改端口范围)
|
||||||
## 2.打开配置文件 rinetd.conf。
|
- mkdir /usr/man&&make&&make install
|
||||||
|
- > 注意:rinetd 安装包下载地址不确保下载可用性,您可以自行搜索安装包进行下载使用。
|
||||||
|
|
||||||
|
## 2.打开配置文件 rinetd.conf
|
||||||
|
|
||||||
|
- vi /etc/rinetd.conf
|
||||||
|
|
||||||
- vi /etc/rinetd.conf
|
|
||||||
> 注意:配置文件可能为 /usr/local/etc/redis.conf
|
> 注意:配置文件可能为 /usr/local/etc/redis.conf
|
||||||
|
|
||||||
## 3.在配置文件中输入如下内容:
|
## 3.在配置文件中输入如下内容
|
||||||
|
|
||||||
- 0.0.0.0 6379 Redis 的链接地址 6379
|
- 0.0.0.0 6379 Redis 的链接地址 6379
|
||||||
- logfile /var/log/rinetd.log
|
- logfile /var/log/rinetd.log
|
||||||
- 说明:您可以使用 cat /etc/rinetd.conf命令来检验配置文件是否修改正确。
|
- 说明:您可以使用 cat /etc/rinetd.conf 命令来检验配置文件是否修改正确。
|
||||||
- 
|
- 
|
||||||
-
|
-
|
||||||
|
|
||||||
## 4.执行如下命令启动 rinetd。
|
## 4.执行如下命令启动 rinetd
|
||||||
|
|
||||||
- rinetd
|
- rinetd
|
||||||
- 注意
|
- 注意
|
||||||
- 您可以通过 echo rinetd >>/etc/rc.local 将 rinetd 设置为自启动。
|
- 您可以通过 echo rinetd >>/etc/rc.local 将 rinetd 设置为自启动。
|
||||||
- 若遇到绑定报错,可以执行 pkill rinetd 结束进程,再执行 rinetd启动进程 rinetd。
|
- 若遇到绑定报错,可以执行 pkill rinetd 结束进程,再执行 rinetd 启动进程 rinetd。
|
||||||
- rinetd 正常启动后, 执行netstat -anp | grep 6379 确认服务是否正常运行。
|
- rinetd 正常启动后, 执行 netstat -anp | grep 6379 确认服务是否正常运行。
|
||||||
- 
|
- 
|
||||||
## 5.在本地进行验证测试。
|
|
||||||
|
|
||||||
- 您可以在本地通过 redis-cli 连接 ECS Linux 服务器后进行登录验证,比如安装了 rinetd 的服务器的 IP 是 1.1.1.1,即redis-cli -h 1.1.1.1 -a Redis的实例ID:Redis密码。或者通过 telent 连接 ECS Linux 服务器后进行操作验证。假设 ECS Linux 服务器的 IP 是 1.1.1.1,即 telnet 1.1.1.1 6379。
|
## 5.在本地进行验证测试
|
||||||
- 连接上 ECS Linux 服务器后,输入连接 Redis 的密码:auth Redis的连接密码。
|
|
||||||
- 进行数据写入及查询验证。
|
- 您可以在本地通过 redis-cli 连接 ECS Linux 服务器后进行登录验证,比如安装了 rinetd 的服务器的 IP 是 1.1.1.1,即 redis-cli -h 1.1.1.1 -a Redis 的实例 ID:Redis 密码。或者通过 telent 连接 ECS Linux 服务器后进行操作验证。假设 ECS Linux 服务器的 IP 是 1.1.1.1,即 telnet 1.1.1.1 6379。
|
||||||
|
- 连接上 ECS Linux 服务器后,输入连接 Redis 的密码:auth Redis 的连接密码。
|
||||||
|
- 进行数据写入及查询验证。
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 数据库
|
title: 其它语言
|
||||||
path: /db
|
path: /other
|
||||||
group:
|
group:
|
||||||
title: 💊 redis
|
title: redis
|
||||||
order: 1
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -11,13 +11,10 @@ group:
|
|||||||
|
|
||||||
## 下载
|
## 下载
|
||||||
|
|
||||||
|
|
||||||
[官方网站](https://redis.io/)
|
[官方网站](https://redis.io/)
|
||||||
|
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
解压
|
解压
|
||||||
tar zxvf redis-4.0.8.tar.gz
|
tar zxvf redis-4.0.8.tar.gz
|
||||||
@ -31,18 +28,16 @@ sudo make test
|
|||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 启动
|
## 启动
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
redis-server
|
redis - server;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 配置
|
## 配置
|
||||||
|
|
||||||
### 新建目录
|
### 新建目录
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo mkdir redis-4.0.8/bin
|
sudo mkdir redis-4.0.8/bin
|
||||||
sudo mkdir redis-4.0.8/etc
|
sudo mkdir redis-4.0.8/etc
|
||||||
@ -59,8 +54,7 @@ cp src/redis-cli bin
|
|||||||
cp src/redis-server bin
|
cp src/redis-server bin
|
||||||
```
|
```
|
||||||
|
|
||||||
## 修改redis.conf
|
## 修改 redis.conf
|
||||||
|
|
||||||
|
|
||||||
```t
|
```t
|
||||||
#修改为守护模式
|
#修改为守护模式
|
||||||
@ -101,28 +95,30 @@ appendonly no
|
|||||||
appendfsync everysec
|
appendfsync everysec
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 启动服务
|
## 启动服务
|
||||||
|
|
||||||
|
|
||||||
### 启动
|
### 启动
|
||||||
|
|
||||||
> ./bin/redis-server etc/redis.conf
|
> ./bin/redis-server etc/redis.conf
|
||||||
|
|
||||||
### 查看日志
|
### 查看日志
|
||||||
|
|
||||||
> tail -f log-redis.log
|
> tail -f log-redis.log
|
||||||
|
|
||||||
### OK
|
### OK
|
||||||
|
|
||||||
> ./bin/redis-cli
|
> ./bin/redis-cli
|
||||||
|
|
||||||
## 基本命令
|
## 基本命令
|
||||||
|
|
||||||
|
|
||||||
### 查看所有数据
|
### 查看所有数据
|
||||||
> keys *
|
|
||||||
|
> keys \*
|
||||||
|
|
||||||
### 插入键值对
|
### 插入键值对
|
||||||
|
|
||||||
> set a b
|
> set a b
|
||||||
|
|
||||||
### 查看数据
|
### 查看数据
|
||||||
> get a
|
|
||||||
|
|
||||||
|
> get a
|
||||||
|
410
docs/fc/canvas/base.md
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: FC
|
||||||
|
path: /funny
|
||||||
|
group:
|
||||||
|
order: 2
|
||||||
|
path: /canvas
|
||||||
|
title: Canvas
|
||||||
|
---
|
||||||
|
|
||||||
|
# 基础形状
|
||||||
|
|
||||||
|
### 矩形
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制矩形
|
||||||
|
* fillRect(x, y, w, h) 填充矩形
|
||||||
|
* strokeRect(x, y, w, h) 边框矩形
|
||||||
|
* clearRect(x, y, w, h) 清除指定区域
|
||||||
|
*/
|
||||||
|
function fillRect() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 实心矩形
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
ctx.fillRect(25, 25, 50, 50);
|
||||||
|
|
||||||
|
// 空心矩形
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.strokeRect(75, 75, 50, 50);
|
||||||
|
|
||||||
|
// 清除区域
|
||||||
|
ctx.clearRect(50, 50, 50, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fillRect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 三角形
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制三角形
|
||||||
|
*/
|
||||||
|
function tri() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 实心三角形
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(90, 25);
|
||||||
|
ctx.lineTo(25, 90);
|
||||||
|
ctx.lineTo(155, 90);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(90, 155);
|
||||||
|
ctx.lineTo(25, 90);
|
||||||
|
ctx.lineTo(155, 90);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
tri();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 绘制圆弧
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
// 绘制圆弧
|
||||||
|
function drawArc() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let x = 90,
|
||||||
|
y = 90,
|
||||||
|
r = 30,
|
||||||
|
startAngle = 0,
|
||||||
|
endAngle = (Math.PI / 180) * 180;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, r, startAngle, endAngle, false);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, r, startAngle, endAngle, true);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
drawArc();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 绘制贝塞尔曲线
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* quadraticCurveTo(cp1x, cp1y, x, y) cp1 为控制点
|
||||||
|
* bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) cp1、cp2 为控制点
|
||||||
|
* x、y 为结束点
|
||||||
|
*/
|
||||||
|
function bezier() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 二次贝塞尔曲线
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(30, 90);
|
||||||
|
ctx.quadraticCurveTo(15, 15, 90, 30);
|
||||||
|
ctx.quadraticCurveTo(165, 15, 150, 90);
|
||||||
|
ctx.quadraticCurveTo(148, 130, 70, 120);
|
||||||
|
ctx.quadraticCurveTo(65, 140, 40, 140);
|
||||||
|
ctx.quadraticCurveTo(65, 135, 55, 120);
|
||||||
|
ctx.quadraticCurveTo(30, 115, 30, 90);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.font = '18px bold 黑体';
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText('聊天框', 120, 160);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
bezier();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 绘制三次贝塞尔曲线
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制三次贝塞尔曲线
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function beziers() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 三次贝塞尔曲线
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(90, 40);
|
||||||
|
ctx.bezierCurveTo(90, 36, 70, 25, 50, 25);
|
||||||
|
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
|
||||||
|
ctx.bezierCurveTo(20, 80, 40, 120, 90, 140);
|
||||||
|
ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5);
|
||||||
|
ctx.bezierCurveTo(160, 22, 140, 25, 130, 25);
|
||||||
|
ctx.bezierCurveTo(120, 25, 110, 30, 90, 40);
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.font = '18px bold 黑体';
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText('爱心', 120, 160);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
beziers();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 绘制笑脸
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制笑脸
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function fillSmile() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(75, 75, 50, 0, Math.PI * 2, true);
|
||||||
|
ctx.moveTo(110, 75);
|
||||||
|
ctx.arc(75, 75, 35, 0, Math.PI, false);
|
||||||
|
ctx.moveTo(65, 65);
|
||||||
|
ctx.arc(60, 65, 5, 0, Math.PI * 2, true);
|
||||||
|
ctx.moveTo(95, 65);
|
||||||
|
ctx.arc(90, 65, 5, 0, Math.PI * 2, true);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.font = '18px bold 黑体';
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText('笑脸', 120, 160);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fillSmile();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 吃豆人
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 吃豆人
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function bean() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 外墙
|
||||||
|
_roundedRect(ctx, 12, 12, 160, 160, 15);
|
||||||
|
_roundedRect(ctx, 18, 18, 148, 148, 9);
|
||||||
|
// 内墙
|
||||||
|
_roundedRect(ctx, 45, 50, 45, 30, 6);
|
||||||
|
_roundedRect(ctx, 115, 50, 45, 30, 6);
|
||||||
|
_roundedRect(ctx, 115, 110, 45, 50, 6);
|
||||||
|
_roundedRect(ctx, 45, 110, 45, 25, 6);
|
||||||
|
|
||||||
|
// 绘制吃豆人
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false);
|
||||||
|
ctx.lineTo(31, 37);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// 绘制魔鬼
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(83, 116);
|
||||||
|
ctx.lineTo(83, 102);
|
||||||
|
ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
|
||||||
|
ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
|
||||||
|
ctx.lineTo(111, 116);
|
||||||
|
ctx.lineTo(106.3, 111.3);
|
||||||
|
ctx.lineTo(97.3, 111);
|
||||||
|
ctx.lineTo(92, 116);
|
||||||
|
ctx.lineTo(87, 111);
|
||||||
|
ctx.lineTo(83, 116);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// 绘制小点
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
ctx.fillRect(52 + i * 16, 35, 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制小点
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
ctx.fillRect(28, 52 + i * 16, 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制小点
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
ctx.fillRect(100, 52 + i * 16, 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制小点
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
ctx.fillRect(44 + i * 16, 92, 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制小点
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
ctx.fillRect(44 + i * 16, 148, 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fillStyle = 'white';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(91, 96);
|
||||||
|
ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
|
||||||
|
ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
|
||||||
|
ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
|
||||||
|
ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
|
||||||
|
ctx.moveTo(103, 96);
|
||||||
|
ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
|
||||||
|
ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
|
||||||
|
ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
|
||||||
|
ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// 右眼
|
||||||
|
ctx.fillStyle = 'blue';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(101, 102, 2, 0, Math.PI * 2, true);
|
||||||
|
ctx.fill();
|
||||||
|
// 左眼
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(89, 102, 2, 0, Math.PI * 2, true);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.font = '18px bold 黑体';
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText('吃豆人', 180, 180);
|
||||||
|
|
||||||
|
ctx.clearRect(150, 0, 100, 200);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制圆角矩形的函数
|
||||||
|
*
|
||||||
|
* @param {*} ctx 画笔
|
||||||
|
* @param {*} x x 坐标
|
||||||
|
* @param {*} y y 坐标
|
||||||
|
* @param {*} w 宽
|
||||||
|
* @param {*} h 高
|
||||||
|
* @param {*} r 半径
|
||||||
|
*/
|
||||||
|
function _roundedRect(ctx, x, y, w, h, radius) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, y + radius);
|
||||||
|
ctx.lineTo(x, y + h - radius);
|
||||||
|
ctx.quadraticCurveTo(x, y + h, x + radius, y + h);
|
||||||
|
ctx.lineTo(x + w - radius, y + h);
|
||||||
|
ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - radius);
|
||||||
|
ctx.lineTo(x + w, y + radius);
|
||||||
|
ctx.quadraticCurveTo(x + w, y, x + w - radius, y);
|
||||||
|
ctx.lineTo(x + radius, y);
|
||||||
|
ctx.quadraticCurveTo(x, y, x, y + radius);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
bean();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
|
||||||
|
```
|
302
docs/fc/canvas/color.md
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: FC
|
||||||
|
path: /funny
|
||||||
|
group:
|
||||||
|
order: 2
|
||||||
|
title: Canvas
|
||||||
|
---
|
||||||
|
|
||||||
|
# 颜色
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
const canvasRef2 = useRef();
|
||||||
|
const canvasRef3 = useRef();
|
||||||
|
const canvasRef4 = useRef();
|
||||||
|
const canvasRef5 = useRef();
|
||||||
|
const canvasRef6 = useRef();
|
||||||
|
const canvasRef7 = useRef();
|
||||||
|
const canvasRef8 = useRef();
|
||||||
|
const canvasRef9 = useRef();
|
||||||
|
const canvasRef10 = useRef();
|
||||||
|
const canvasRef11 = useRef();
|
||||||
|
const canvasRef12 = useRef();
|
||||||
|
|
||||||
|
function demo1() {
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
for (let j = 0; j < 6; j++) {
|
||||||
|
ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(
|
||||||
|
255 - 42.5 * j,
|
||||||
|
)}, 0)`;
|
||||||
|
ctx.fillRect(j * 25, i * 25, 25, 25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo2() {
|
||||||
|
let canvas = canvasRef2.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
for (let j = 0; j < 6; j++) {
|
||||||
|
ctx.strokeStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(
|
||||||
|
255 - 42.5 * j,
|
||||||
|
)}, 0)`;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo3() {
|
||||||
|
let canvas = canvasRef3.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = '#fd0';
|
||||||
|
ctx.fillRect(0, 0, 75, 75);
|
||||||
|
ctx.fillStyle = '#6c0';
|
||||||
|
ctx.fillRect(75, 0, 75, 75);
|
||||||
|
ctx.fillStyle = '#09f';
|
||||||
|
ctx.fillRect(0, 75, 75, 75);
|
||||||
|
ctx.fillStyle = '#f30';
|
||||||
|
ctx.fillRect(75, 75, 75, 75);
|
||||||
|
|
||||||
|
ctx.fillStyle = '#fff';
|
||||||
|
ctx.globalAlpha = 0.2;
|
||||||
|
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo4() {
|
||||||
|
let canvas = canvasRef4.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = 'rgb(255, 221, 0)';
|
||||||
|
ctx.fillRect(0, 0, 200, 50);
|
||||||
|
ctx.fillStyle = 'rgb(102, 204, 0)';
|
||||||
|
ctx.fillRect(0, 50, 200, 50);
|
||||||
|
ctx.fillStyle = 'rgb(0, 153, 255)';
|
||||||
|
ctx.fillRect(0, 100, 200, 50);
|
||||||
|
ctx.fillStyle = 'rgb(255, 51, 0)';
|
||||||
|
ctx.fillRect(0, 150, 200, 50);
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
ctx.fillStyle = `rgba(255, 255, 255, ${(i + 1) / 10})`;
|
||||||
|
for (let j = 0; j < 4; j++) {
|
||||||
|
ctx.fillRect(10 + 18 * i, 5 + j * 50, 18, 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo5() {
|
||||||
|
let canvas = canvasRef5.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
ctx.lineWidth = 1 + i;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(5.5 + i * 14, 5.5);
|
||||||
|
ctx.lineTo(5.5 + i * 14, 140.5);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo6() {
|
||||||
|
let canvas = canvasRef6.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let lineCap = ['butt', 'round', 'square'];
|
||||||
|
|
||||||
|
ctx.strokeStyle = '#09f';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(10, 20);
|
||||||
|
ctx.lineTo(140, 20);
|
||||||
|
ctx.moveTo(10, 130);
|
||||||
|
ctx.lineTo(140, 130);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'black';
|
||||||
|
for (let i = 0; i < lineCap.length; i++) {
|
||||||
|
ctx.lineWidth = 15;
|
||||||
|
ctx.lineCap = lineCap[i];
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(25 + i * 50, 20);
|
||||||
|
ctx.lineTo(25 + i * 50, 130);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* round 圆角线段
|
||||||
|
* bevel 不让线段超过最大
|
||||||
|
*/
|
||||||
|
function demo7() {
|
||||||
|
let canvas = canvasRef7.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let lineJoin = ['round', 'bevel', 'miter'];
|
||||||
|
|
||||||
|
ctx.lineWidth = 10;
|
||||||
|
for (let i = 0; i < lineJoin.length; i++) {
|
||||||
|
ctx.lineJoin = lineJoin[i];
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(-5, 5 + i * 40);
|
||||||
|
ctx.lineTo(35, 45 + i * 40);
|
||||||
|
ctx.lineTo(75, 5 + i * 40);
|
||||||
|
ctx.lineTo(115, 45 + i * 40);
|
||||||
|
ctx.lineTo(155, 5 + i * 40);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setLineDash 虚线交替样式
|
||||||
|
* lineDashOffset 偏移量
|
||||||
|
*/
|
||||||
|
function demo8() {
|
||||||
|
let canvas = canvasRef8.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
function march() {
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
if (offset > 16) {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
_draw();
|
||||||
|
setTimeout(march, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.setLineDash([4, 2]);
|
||||||
|
ctx.lineDashOffset = -offset;
|
||||||
|
ctx.strokeRect(10, 10, 100, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
march();
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo9() {
|
||||||
|
let canvas = canvasRef9.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let lineargradient = ctx.createLinearGradient(0, 0, 0, 150);
|
||||||
|
lineargradient.addColorStop(0, '#00abeb');
|
||||||
|
lineargradient.addColorStop(0.5, '#fff');
|
||||||
|
lineargradient.addColorStop(0.5, '#26c000');
|
||||||
|
lineargradient.addColorStop(1, '#fff');
|
||||||
|
|
||||||
|
let radialgradient = ctx.createLinearGradient(0, 50, 0, 95);
|
||||||
|
radialgradient.addColorStop(0.5, '#000');
|
||||||
|
radialgradient.addColorStop(1, 'rgba(0, 0, 0, 0');
|
||||||
|
|
||||||
|
ctx.fillStyle = lineargradient;
|
||||||
|
ctx.strokeStyle = radialgradient;
|
||||||
|
|
||||||
|
ctx.fillRect(10, 10, 130, 130);
|
||||||
|
ctx.strokeRect(50, 50, 50, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo10() {
|
||||||
|
let canvas = canvasRef10.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let radgrad = ctx.createRadialGradient(45, 50, 10, 52, 50, 30);
|
||||||
|
radgrad.addColorStop(0, '#a7d30c');
|
||||||
|
radgrad.addColorStop(0.9, '#019f62');
|
||||||
|
radgrad.addColorStop(1, 'rgba(1, 159, 98, 0');
|
||||||
|
|
||||||
|
let radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
|
||||||
|
radgrad2.addColorStop(0, '#fff');
|
||||||
|
radgrad2.addColorStop(0.75, '#ff0188');
|
||||||
|
radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)');
|
||||||
|
|
||||||
|
let radgrad3 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
|
||||||
|
radgrad3.addColorStop(0, '#f4f201');
|
||||||
|
radgrad3.addColorStop(0.8, '#00B5E2');
|
||||||
|
radgrad3.addColorStop(1, '#00B5E2');
|
||||||
|
|
||||||
|
ctx.fillStyle = radgrad3;
|
||||||
|
ctx.fillRect(0, 0, 150, 150);
|
||||||
|
ctx.fillStyle = radgrad2;
|
||||||
|
ctx.fillRect(0, 0, 150, 150);
|
||||||
|
ctx.fillStyle = radgrad;
|
||||||
|
ctx.fillRect(0, 0, 150, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo11() {
|
||||||
|
let canvas = canvasRef11.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 创建 img,作为图案
|
||||||
|
let img = new Image();
|
||||||
|
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
|
||||||
|
|
||||||
|
img.onload = function () {
|
||||||
|
let ptrn = ctx.createPattern(img, 'repeat');
|
||||||
|
ctx.fillStyle = ptrn;
|
||||||
|
ctx.fillRect(0, 0, 150, 150);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo12() {
|
||||||
|
let canvas = canvasRef12.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = '#aaa';
|
||||||
|
ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
|
||||||
|
ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
|
||||||
|
ctx.fill('evenodd');
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
demo1();
|
||||||
|
demo2();
|
||||||
|
demo3();
|
||||||
|
demo4();
|
||||||
|
demo5();
|
||||||
|
demo6();
|
||||||
|
demo7();
|
||||||
|
demo8();
|
||||||
|
demo9();
|
||||||
|
demo10();
|
||||||
|
demo11();
|
||||||
|
demo12();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef2} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef3} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef4} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef5} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef6} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef7} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef8} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef9} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef10} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef11} width="200" height="200" />
|
||||||
|
<canvas ref={canvasRef12} width="200" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
|
||||||
|
```
|
@ -3,12 +3,12 @@ nav:
|
|||||||
title: FC
|
title: FC
|
||||||
path: /funny
|
path: /funny
|
||||||
group:
|
group:
|
||||||
title: canvas
|
order: 99
|
||||||
order: 4
|
|
||||||
path: /canvas
|
path: /canvas
|
||||||
|
title: Canvas
|
||||||
---
|
---
|
||||||
|
|
||||||
# canvas
|
# 案例欣赏
|
||||||
|
|
||||||
### 粒子背景
|
### 粒子背景
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ group:
|
|||||||
|
|
||||||
### 大转盘(doing)
|
### 大转盘(doing)
|
||||||
|
|
||||||
```jsx
|
```js
|
||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
class Global {
|
class Global {
|
||||||
@ -67,7 +67,7 @@ class Global {
|
|||||||
let bbox = canvas.getBoundingClientRect(),
|
let bbox = canvas.getBoundingClientRect(),
|
||||||
x = this.IsPC() ? e.clientX || event.clientX : e.changedTouches[0].clientX,
|
x = this.IsPC() ? e.clientX || event.clientX : e.changedTouches[0].clientX,
|
||||||
y = this.IsPC() ? e.clientY || event.clientY : e.changedTouches[0].clientY;
|
y = this.IsPC() ? e.clientY || event.clientY : e.changedTouches[0].clientY;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: x - bbox.left,
|
x: x - bbox.left,
|
||||||
y: y - bbox.top
|
y: y - bbox.top
|
||||||
@ -85,7 +85,7 @@ class Global {
|
|||||||
*/
|
*/
|
||||||
drawText(context, t, x, y, w, lineHeight = 20){
|
drawText(context, t, x, y, w, lineHeight = 20){
|
||||||
let chr = t.split(''),
|
let chr = t.split(''),
|
||||||
temp = '',
|
temp = '',
|
||||||
row = [];
|
row = [];
|
||||||
|
|
||||||
for (let a = 0; a < chr.length; a++){
|
for (let a = 0; a < chr.length; a++){
|
||||||
@ -109,11 +109,11 @@ class Global {
|
|||||||
/**
|
/**
|
||||||
* 定义圆角矩形的方法
|
* 定义圆角矩形的方法
|
||||||
* @param {Obj} context
|
* @param {Obj} context
|
||||||
* @param {Num} cornerX
|
* @param {Num} cornerX
|
||||||
* @param {Num} cornerY
|
* @param {Num} cornerY
|
||||||
* @param {Num} width
|
* @param {Num} width
|
||||||
* @param {Num} height
|
* @param {Num} height
|
||||||
* @param {Num} cornerRadius
|
* @param {Num} cornerRadius
|
||||||
*/
|
*/
|
||||||
roundedRect(context, cornerX, cornerY, width, height, cornerRadius) {
|
roundedRect(context, cornerX, cornerY, width, height, cornerRadius) {
|
||||||
if (width > 0) context.moveTo(cornerX + cornerRadius, cornerY);
|
if (width > 0) context.moveTo(cornerX + cornerRadius, cornerY);
|
||||||
@ -189,7 +189,7 @@ class RouletteWheel extends Global{
|
|||||||
ctx.closePath(); //绘制路径
|
ctx.closePath(); //绘制路径
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.beginPath(); //开始绘制路径
|
ctx.beginPath(); //开始绘制路径
|
||||||
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
|
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
|
||||||
ctx.arc(250, 250, 250, Math.PI / 2, Math.PI);
|
ctx.arc(250, 250, 250, Math.PI / 2, Math.PI);
|
||||||
@ -240,8 +240,7 @@ export default () => {
|
|||||||
|
|
||||||
### 星空
|
### 星空
|
||||||
|
|
||||||
|
```js
|
||||||
```jsx
|
|
||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,7 +249,7 @@ import React, { useRef, useEffect } from 'react';
|
|||||||
class NightSky {
|
class NightSky {
|
||||||
constructor(opt) {
|
constructor(opt) {
|
||||||
this.opt = {
|
this.opt = {
|
||||||
width: 500,
|
width: 500,
|
||||||
height: 500,
|
height: 500,
|
||||||
num: 120,
|
num: 120,
|
||||||
canvas: null,
|
canvas: null,
|
||||||
@ -359,8 +358,7 @@ export default () => {
|
|||||||
|
|
||||||
### 移动(doing)
|
### 移动(doing)
|
||||||
|
|
||||||
|
```js
|
||||||
```jsx
|
|
||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
class Move {
|
class Move {
|
||||||
@ -373,7 +371,7 @@ class Move {
|
|||||||
para: {
|
para: {
|
||||||
num: 100,
|
num: 100,
|
||||||
color: false, // 颜色 如果是false 则是随机渐变颜色
|
color: false, // 颜色 如果是false 则是随机渐变颜色
|
||||||
r: 0.9, // 圆每次增加的半径
|
r: 0.9, // 圆每次增加的半径
|
||||||
o: 0.09, // 判断圆消失的条件,数值越大,消失的越快
|
o: 0.09, // 判断圆消失的条件,数值越大,消失的越快
|
||||||
},
|
},
|
||||||
...opt
|
...opt
|
||||||
@ -403,7 +401,7 @@ class Move {
|
|||||||
opt.round_arr.push({
|
opt.round_arr.push({
|
||||||
mouseX,
|
mouseX,
|
||||||
mouseY,
|
mouseY,
|
||||||
r: opt.option.para.r, // 设置半径每次增大的数值
|
r: opt.option.para.r, // 设置半径每次增大的数值
|
||||||
o: 1, // 判断圆消失的条件,数值越大,消失得越快
|
o: 1, // 判断圆消失的条件,数值越大,消失得越快
|
||||||
})
|
})
|
||||||
tempSum = 0
|
tempSum = 0
|
||||||
@ -424,11 +422,11 @@ class Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _move() {
|
function _move() {
|
||||||
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
for (var i = 0; i < round_arr.length; i++) {
|
for (var i = 0; i < round_arr.length; i++) {
|
||||||
|
|
||||||
ctx.fillStyle = color2;
|
ctx.fillStyle = color2;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY, round_arr[i].r, 0, Math.PI * 2);
|
ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY, round_arr[i].r, 0, Math.PI * 2);
|
||||||
@ -436,7 +434,7 @@ class Move {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
round_arr[i].r += para.r;
|
round_arr[i].r += para.r;
|
||||||
round_arr[i].o -= para.o;
|
round_arr[i].o -= para.o;
|
||||||
|
|
||||||
if( round_arr[i].o <= 0){
|
if( round_arr[i].o <= 0){
|
||||||
round_arr.splice(i,1);
|
round_arr.splice(i,1);
|
||||||
i--;
|
i--;
|
||||||
@ -469,8 +467,7 @@ export default () => {
|
|||||||
|
|
||||||
### 棒棒糖
|
### 棒棒糖
|
||||||
|
|
||||||
|
```js
|
||||||
```jsx
|
|
||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
class Lollipop {
|
class Lollipop {
|
||||||
@ -500,7 +497,7 @@ class Lollipop {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 画圆
|
* 画圆
|
||||||
* @param {*} ctx
|
* @param {*} ctx
|
||||||
*/
|
*/
|
||||||
_drawCircle(ctx) {
|
_drawCircle(ctx) {
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
@ -514,7 +511,7 @@ class Lollipop {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 棍子
|
* 棍子
|
||||||
* @param {*} ctx
|
* @param {*} ctx
|
||||||
*/
|
*/
|
||||||
_drawStick(ctx) {
|
_drawStick(ctx) {
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
75
docs/fc/canvas/font.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: FC
|
||||||
|
path: /funny
|
||||||
|
group:
|
||||||
|
order: 3
|
||||||
|
title: Canvas
|
||||||
|
---
|
||||||
|
|
||||||
|
# 字体
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const canvasRef = useRef();
|
||||||
|
const canvasRef2 = useRef();
|
||||||
|
const canvasRef3 = useRef();
|
||||||
|
|
||||||
|
// 填充文本
|
||||||
|
function demo1() {
|
||||||
|
// 声明DOM
|
||||||
|
let canvas = canvasRef.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.shadowOffsetY = 8;
|
||||||
|
ctx.shadowOffsetX = 8;
|
||||||
|
ctx.shadowBlur = 3;
|
||||||
|
ctx.shadowColor = '#ccc';
|
||||||
|
|
||||||
|
ctx.font = '40px serif';
|
||||||
|
ctx.fillText('1. 你是个智障!', 50, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo2() {
|
||||||
|
let canvas = canvasRef2.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.font = '48px serif';
|
||||||
|
ctx.strokeText('2. hello world', 10, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function demo3() {
|
||||||
|
let canvas = canvasRef3.current;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
ctx.font = '40px serif';
|
||||||
|
ctx.textBaseline = 'top';
|
||||||
|
ctx.textAlign = 'start';
|
||||||
|
ctx.strokeText('hello world', 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
demo1();
|
||||||
|
demo2();
|
||||||
|
demo3();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<canvas ref={canvasRef} width="500" height="200" />
|
||||||
|
<canvas ref={canvasRef2} width="500" height="200" />
|
||||||
|
<canvas ref={canvasRef3} width="500" height="200" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
window.onload = function () {
|
||||||
|
demo1();
|
||||||
|
demo2();
|
||||||
|
demo3();
|
||||||
|
};
|
||||||
|
```
|
12
docs/fc/css/demos/HeartBeat/index.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import './index.less';
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
return (
|
||||||
|
<div className="cont">
|
||||||
|
<div className="card">
|
||||||
|
{/* <div className={styles.card_heart}>♥</div> */}
|
||||||
|
{/* <h1 className={styles.card_title}>hello! motherfucker!</h1> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 684 KiB After Width: | Height: | Size: 684 KiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 329 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 329 KiB |
@ -3,13 +3,12 @@ nav:
|
|||||||
title: FC
|
title: FC
|
||||||
path: /funny
|
path: /funny
|
||||||
group:
|
group:
|
||||||
title: css
|
|
||||||
order: 3
|
order: 3
|
||||||
path: /css
|
path: /css
|
||||||
|
title: CSS
|
||||||
---
|
---
|
||||||
|
|
||||||
# css
|
# 案例赏析
|
||||||
|
|
||||||
|
|
||||||
### 心跳卡片
|
### 心跳卡片
|
||||||
|
|
@ -3,12 +3,12 @@ nav:
|
|||||||
title: 前端
|
title: 前端
|
||||||
path: /fea
|
path: /fea
|
||||||
group:
|
group:
|
||||||
title: 💊 css
|
|
||||||
order: 1
|
order: 1
|
||||||
path: /css
|
path: /css
|
||||||
|
title: CSS
|
||||||
---
|
---
|
||||||
|
|
||||||
## 基础介绍
|
# 基础介绍
|
||||||
|
|
||||||
## 布局
|
## 布局
|
||||||
|
|
@ -3,12 +3,12 @@ nav:
|
|||||||
title: 前端
|
title: 前端
|
||||||
path: /fea
|
path: /fea
|
||||||
group:
|
group:
|
||||||
title: 💊 css
|
order: 2
|
||||||
order: 3
|
|
||||||
path: /css
|
path: /css
|
||||||
|
title: CSS
|
||||||
---
|
---
|
||||||
|
|
||||||
## SASS 语法
|
# SASS 语法
|
||||||
|
|
||||||
### if 语句
|
### if 语句
|
||||||
|
|
||||||
@ -178,21 +178,21 @@ index(1px solid red, 1px)
|
|||||||
|
|
||||||
```css
|
```css
|
||||||
$map: (
|
$map: (
|
||||||
$key1: $value1;
|
$key1: $value1;
|
||||||
$key2: $value2;
|
$key2: $value2;
|
||||||
)
|
)
|
||||||
|
|
||||||
$theme-color: (
|
$theme-color: (
|
||||||
default: (
|
default: (
|
||||||
bgcolor: #fff;
|
bgcolor: #fff;
|
||||||
text-color: #444;
|
text-color: #444;
|
||||||
link-color: #39f;
|
link-color: #39f;
|
||||||
),
|
),
|
||||||
primary: (
|
primary: (
|
||||||
bgcolor: #000;
|
bgcolor: #000;
|
||||||
text-color: #fff;
|
text-color: #fff;
|
||||||
link-color: #93f;
|
link-color: #93f;
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
38
docs/fc/index.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: FC
|
||||||
|
path: /funny
|
||||||
|
group:
|
||||||
|
order: 1
|
||||||
|
path: /code
|
||||||
|
---
|
||||||
|
|
||||||
|
# 说明
|
||||||
|
|
||||||
|
FC(funny code),记录一些有意思的酷炫 code demo.
|
||||||
|
|
||||||
|
## 迪士尼动画 12 原则
|
||||||
|
|
||||||
|
1. 挤压与拉伸
|
||||||
|
2. 预备动作
|
||||||
|
3. 表情与呈像方式
|
||||||
|
4. 逐帧画法与关键帧画法
|
||||||
|
5. 动作的惯性跟随和重叠
|
||||||
|
6. 慢入与慢出
|
||||||
|
7. 弧形运动轨迹
|
||||||
|
8. 次要动作
|
||||||
|
9. 节奏
|
||||||
|
10. 夸张
|
||||||
|
11. 熟练的手绘技法
|
||||||
|
12. 吸引力
|
||||||
|
|
||||||
|
## 提升动画性能技巧
|
||||||
|
|
||||||
|
简单页面渲染顺序:htmlTree - cssTree - jsTree - layout(重排) - paint(重绘) - composite(组合)
|
||||||
|
|
||||||
|
从上面的流程可以发现,重排一定会触发重绘,但是重绘不一定会触发重排
|
||||||
|
|
||||||
|
- translate 替换为 left\top\right\bottom
|
||||||
|
- scale 替换为 width\height
|
||||||
|
- opacity 替换为 display\visibility
|
||||||
|
- 设置 translate3D, 打开 GPU 加速
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 前端
|
title: FC
|
||||||
path: /fea
|
path: /funny
|
||||||
group:
|
group:
|
||||||
title: 💊 webGL
|
title: webGL
|
||||||
order: 100
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# 常见问题
|
# 常见问题
|
22
docs/fc/webgl/demo.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: FC
|
||||||
|
path: /funny
|
||||||
|
group:
|
||||||
|
title: webGL
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# 案例赏析
|
||||||
|
|
||||||
|
## 创建基础元素
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx" ></code>
|
||||||
|
|
||||||
|
## 创建一个地球的场景
|
||||||
|
|
||||||
|
<code src="./demo/earth.tsx" ></code>
|
||||||
|
|
||||||
|
## 地图
|
||||||
|
|
||||||
|
<code src="./demo/map-gl.tsx" ></code>
|
@ -9,7 +9,7 @@ export default () => {
|
|||||||
const ref = useRef(null)
|
const ref = useRef(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ref.current && init(ref.current)
|
ref.current && init(ref.current)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const init = (dom: HTMLElement) => {
|
const init = (dom: HTMLElement) => {
|
||||||
@ -18,11 +18,11 @@ export default () => {
|
|||||||
// camera.lookAt( 0, 0, 0 );
|
// camera.lookAt( 0, 0, 0 );
|
||||||
camera.position.set(25, 5, 40)
|
camera.position.set(25, 5, 40)
|
||||||
camera.rotation.set(10, 0, 40)
|
camera.rotation.set(10, 0, 40)
|
||||||
const cameraHelper = new THREE.CameraHelper( camera );
|
const cameraHelper = new THREE.CameraHelper(camera);
|
||||||
scene.add( cameraHelper );
|
scene.add(cameraHelper);
|
||||||
|
|
||||||
// 渲染器
|
// 渲染器
|
||||||
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: dom });
|
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: dom });
|
||||||
// renderer.setSize(window.innerWidth, window.innerHeight);
|
// renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
THREE.Cache.enabled = true;
|
THREE.Cache.enabled = true;
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ export default () => {
|
|||||||
cube.position.y = -1
|
cube.position.y = -1
|
||||||
scene.add(cube);
|
scene.add(cube);
|
||||||
|
|
||||||
const edges = new THREE.EdgesGeometry( geometry );
|
const edges = new THREE.EdgesGeometry(geometry);
|
||||||
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
|
const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffffff }));
|
||||||
line.position.y = -1
|
line.position.y = -1
|
||||||
scene.add( line );
|
scene.add(line);
|
||||||
|
|
||||||
// 创建一个胶囊
|
// 创建一个胶囊
|
||||||
const capGeometry = new THREE.CapsuleGeometry(1, 1, 10, 20)
|
const capGeometry = new THREE.CapsuleGeometry(1, 1, 10, 20)
|
||||||
@ -91,12 +91,12 @@ export default () => {
|
|||||||
|
|
||||||
// 车削缓冲几何体()
|
// 车削缓冲几何体()
|
||||||
const points = [];
|
const points = [];
|
||||||
for ( let i = 0; i < 10; i ++ ) {
|
for (let i = 0; i < 10; i++) {
|
||||||
points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
|
points.push(new THREE.Vector2(Math.sin(i * 0.2) * 10 + 5, (i - 5) * 2));
|
||||||
}
|
}
|
||||||
const latheGeometry = new THREE.LatheGeometry( points );
|
const latheGeometry = new THREE.LatheGeometry(points);
|
||||||
const latheMaterial = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
|
const latheMaterial = new THREE.MeshLambertMaterial({ color: 0xffff00 });
|
||||||
const lathe = new THREE.Mesh( latheGeometry, latheMaterial );
|
const lathe = new THREE.Mesh(latheGeometry, latheMaterial);
|
||||||
lathe.position.y = 6
|
lathe.position.y = 6
|
||||||
lathe.position.x = 6
|
lathe.position.x = 6
|
||||||
lathe.position.z = 1
|
lathe.position.z = 1
|
||||||
@ -104,26 +104,26 @@ export default () => {
|
|||||||
|
|
||||||
// 多面缓冲几何体,自定义坐标
|
// 多面缓冲几何体,自定义坐标
|
||||||
const verticesOfCube = [
|
const verticesOfCube = [
|
||||||
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
|
-1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1,
|
||||||
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
|
-1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,
|
||||||
];
|
];
|
||||||
|
|
||||||
const indicesOfFaces = [
|
const indicesOfFaces = [
|
||||||
2,1,0, 0,3,2,
|
2, 1, 0, 0, 3, 2,
|
||||||
0,4,7, 7,3,0,
|
0, 4, 7, 7, 3, 0,
|
||||||
0,1,5, 5,4,0,
|
0, 1, 5, 5, 4, 0,
|
||||||
1,2,6, 6,5,1,
|
1, 2, 6, 6, 5, 1,
|
||||||
2,3,7, 7,6,2,
|
2, 3, 7, 7, 6, 2,
|
||||||
4,5,6, 6,7,4
|
4, 5, 6, 6, 7, 4
|
||||||
];
|
];
|
||||||
|
|
||||||
const polyGeometry = new THREE.PolyhedronGeometry( verticesOfCube, indicesOfFaces, 6, 3 );
|
const polyGeometry = new THREE.PolyhedronGeometry(verticesOfCube, indicesOfFaces, 6, 3);
|
||||||
const polyMaterial = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
|
const polyMaterial = new THREE.MeshLambertMaterial({ color: 0xffff00 });
|
||||||
const poly = new THREE.Mesh( polyGeometry, polyMaterial );
|
const poly = new THREE.Mesh(polyGeometry, polyMaterial);
|
||||||
poly.position.y = -3
|
poly.position.y = -3
|
||||||
poly.position.x = 7
|
poly.position.x = 7
|
||||||
poly.position.z = -3
|
poly.position.z = -3
|
||||||
scene.add( poly );
|
scene.add(poly);
|
||||||
|
|
||||||
// 创建一个圆环(内半径、外半径、圆环的分段)
|
// 创建一个圆环(内半径、外半径、圆环的分段)
|
||||||
const ringGeometry = new THREE.RingGeometry(1, 3)
|
const ringGeometry = new THREE.RingGeometry(1, 3)
|
||||||
@ -148,7 +148,7 @@ export default () => {
|
|||||||
heartShape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
|
heartShape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
|
||||||
|
|
||||||
|
|
||||||
const shapeGeo = new THREE.ExtrudeGeometry( heartShape, {
|
const shapeGeo = new THREE.ExtrudeGeometry(heartShape, {
|
||||||
steps: 2,
|
steps: 2,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
bevelEnabled: true,
|
bevelEnabled: true,
|
||||||
@ -156,13 +156,13 @@ export default () => {
|
|||||||
bevelSize: 1,
|
bevelSize: 1,
|
||||||
bevelSegments: 5
|
bevelSegments: 5
|
||||||
});
|
});
|
||||||
const shapeMat = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
|
const shapeMat = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
|
||||||
const heart = new THREE.Mesh( shapeGeo, shapeMat ) ;
|
const heart = new THREE.Mesh(shapeGeo, shapeMat);
|
||||||
heart.position.y = 6
|
heart.position.y = 6
|
||||||
heart.position.z = 6
|
heart.position.z = 6
|
||||||
heart.rotation.z = Math.PI * 1
|
heart.rotation.z = Math.PI * 1
|
||||||
shapeMat.side = THREE.DoubleSide
|
shapeMat.side = THREE.DoubleSide
|
||||||
scene.add( heart );
|
scene.add(heart);
|
||||||
|
|
||||||
// 球体
|
// 球体
|
||||||
const ballGeometry = new THREE.SphereGeometry(1, 19)
|
const ballGeometry = new THREE.SphereGeometry(1, 19)
|
||||||
@ -193,13 +193,13 @@ export default () => {
|
|||||||
scene.add(torus);
|
scene.add(torus);
|
||||||
|
|
||||||
// 圆环扭结(半径,粗细,)
|
// 圆环扭结(半径,粗细,)
|
||||||
const kontGeometry = new THREE.TorusKnotGeometry( 2, 0.3 );
|
const kontGeometry = new THREE.TorusKnotGeometry(2, 0.3);
|
||||||
const kontMaterial = new THREE.MeshLambertMaterial( { color: 0xffddd0 } );
|
const kontMaterial = new THREE.MeshLambertMaterial({ color: 0xffddd0 });
|
||||||
const knot = new THREE.Mesh( kontGeometry, kontMaterial );
|
const knot = new THREE.Mesh(kontGeometry, kontMaterial);
|
||||||
knot.position.y = -5
|
knot.position.y = -5
|
||||||
knot.position.x = -15
|
knot.position.x = -15
|
||||||
knot.position.z = -1
|
knot.position.z = -1
|
||||||
scene.add( knot );
|
scene.add(knot);
|
||||||
|
|
||||||
//创建线段
|
//创建线段
|
||||||
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff })
|
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff })
|
||||||
@ -208,14 +208,14 @@ export default () => {
|
|||||||
linePoints.push(new THREE.Vector3(0, 0, 0))
|
linePoints.push(new THREE.Vector3(0, 0, 0))
|
||||||
linePoints.push(new THREE.Vector3(0, 100, 0))
|
linePoints.push(new THREE.Vector3(0, 100, 0))
|
||||||
const lineGeometry = new THREE.BufferGeometry().setFromPoints(points)
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints(points)
|
||||||
const line2 = new THREE.Line( lineGeometry, lineMaterial );
|
const line2 = new THREE.Line(lineGeometry, lineMaterial);
|
||||||
scene.add( line2 );
|
scene.add(line2);
|
||||||
|
|
||||||
// 创建文字
|
// 创建文字
|
||||||
const fontLoader = new FontLoader();
|
const fontLoader = new FontLoader();
|
||||||
let textMesh
|
let textMesh
|
||||||
fontLoader.load('https://fancy-content-test.oss-cn-beijing.aliyuncs.com/helvetiker_regular.typeface.json', function ( font ) {
|
fontLoader.load('https://fancy-content-test.oss-cn-beijing.aliyuncs.com/helvetiker_regular.typeface.json', function (font) {
|
||||||
const textGeometry = new TextGeometry('ykx, I Love U!', {
|
const textGeometry = new TextGeometry('XXX, I Love U!', {
|
||||||
font: font,
|
font: font,
|
||||||
size: 6,
|
size: 6,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
@ -228,40 +228,40 @@ export default () => {
|
|||||||
});
|
});
|
||||||
textGeometry.computeBoundingBox();
|
textGeometry.computeBoundingBox();
|
||||||
|
|
||||||
const centerOffset = - 0.5 * ( textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x );
|
const centerOffset = - 0.5 * (textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x);
|
||||||
|
|
||||||
|
|
||||||
const materials = [
|
const materials = [
|
||||||
new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } ), // front
|
new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }), // front
|
||||||
new THREE.MeshPhongMaterial( { color: 0xf00fff } ) // side
|
new THREE.MeshPhongMaterial({ color: 0xf00fff }) // side
|
||||||
];
|
];
|
||||||
textMesh = new THREE.Mesh( textGeometry, materials );
|
textMesh = new THREE.Mesh(textGeometry, materials);
|
||||||
|
|
||||||
textMesh.position.z = 10;
|
textMesh.position.z = 10;
|
||||||
textMesh.position.x = centerOffset;
|
textMesh.position.x = centerOffset;
|
||||||
|
|
||||||
scene.add( textMesh )
|
scene.add(textMesh)
|
||||||
} );
|
});
|
||||||
|
|
||||||
// --------------------- 光线 ------------------------------
|
// --------------------- 光线 ------------------------------
|
||||||
|
|
||||||
// 半球光
|
// 半球光
|
||||||
const fillLight = new THREE.HemisphereLight( 0x8dc1de, 0x00668d, 1.5 );
|
const fillLight = new THREE.HemisphereLight(0x8dc1de, 0x00668d, 1.5);
|
||||||
fillLight.position.set( 0, 1, 1 );
|
fillLight.position.set(0, 1, 1);
|
||||||
scene.add( fillLight );
|
scene.add(fillLight);
|
||||||
|
|
||||||
// const helper = new THREE.HemisphereLightHelper( fillLight, 5 );
|
// const helper = new THREE.HemisphereLightHelper( fillLight, 5 );
|
||||||
// scene.add( helper );
|
// scene.add( helper );
|
||||||
|
|
||||||
// 平行光
|
// 平行光
|
||||||
const directionalLight = new THREE.DirectionalLight( 0xffffff, 2.5 );
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5);
|
||||||
directionalLight.position.set( - 5, 25, - 1 );
|
directionalLight.position.set(- 5, 25, - 1);
|
||||||
directionalLight.castShadow = true;
|
directionalLight.castShadow = true;
|
||||||
directionalLight.shadow.camera.near = 0.01;
|
directionalLight.shadow.camera.near = 0.01;
|
||||||
directionalLight.shadow.camera.far = 500;
|
directionalLight.shadow.camera.far = 500;
|
||||||
directionalLight.shadow.camera.right = 30;
|
directionalLight.shadow.camera.right = 30;
|
||||||
directionalLight.shadow.camera.left = - 30;
|
directionalLight.shadow.camera.left = - 30;
|
||||||
directionalLight.shadow.camera.top = 30;
|
directionalLight.shadow.camera.top = 30;
|
||||||
directionalLight.shadow.camera.bottom = - 30;
|
directionalLight.shadow.camera.bottom = - 30;
|
||||||
directionalLight.shadow.mapSize.width = 1024;
|
directionalLight.shadow.mapSize.width = 1024;
|
||||||
directionalLight.shadow.mapSize.height = 1024;
|
directionalLight.shadow.mapSize.height = 1024;
|
||||||
@ -270,7 +270,7 @@ export default () => {
|
|||||||
scene.add(directionalLight);
|
scene.add(directionalLight);
|
||||||
|
|
||||||
|
|
||||||
const controls = new OrbitControls( camera, renderer.domElement );
|
const controls = new OrbitControls(camera, renderer.domElement);
|
||||||
controls.autoRotate = true
|
controls.autoRotate = true
|
||||||
|
|
||||||
function render() {
|
function render() {
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
||||||
import { resizeRendererToDisplaySize, addControls } from '../utils'
|
import { resizeRendererToDisplaySize, addControls } from '../utils'
|
||||||
@ -35,10 +35,16 @@ class AxisGridHelper {
|
|||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const ref = useRef(null)
|
const ref = useRef(null)
|
||||||
|
const controlRef = useRef(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ref.current && init(ref.current)
|
ref.current && init(ref.current)
|
||||||
})
|
return () => {
|
||||||
|
console.log('controlRef.current', controlRef.current)
|
||||||
|
controlRef.current?.destroy()
|
||||||
|
controlRef.current = null
|
||||||
|
}
|
||||||
|
}, [ref])
|
||||||
|
|
||||||
|
|
||||||
const init = (dom: any) => {
|
const init = (dom: any) => {
|
||||||
@ -47,7 +53,9 @@ export default () => {
|
|||||||
camera.position.set(0, 50, 0)
|
camera.position.set(0, 50, 0)
|
||||||
camera.up.set(0, 0, 1)
|
camera.up.set(0, 0, 1)
|
||||||
camera.lookAt(0, 0, 0)
|
camera.lookAt(0, 0, 0)
|
||||||
const gui = new GUI();
|
const gui = new GUI({ container: document.getElementById( 'earth-cont' ) });
|
||||||
|
|
||||||
|
controlRef.current = gui
|
||||||
|
|
||||||
{
|
{
|
||||||
const light = new THREE.PointLight(0xffffff, 500)
|
const light = new THREE.PointLight(0xffffff, 500)
|
||||||
@ -117,7 +125,7 @@ export default () => {
|
|||||||
addControls(camera, renderer);
|
addControls(camera, renderer);
|
||||||
|
|
||||||
function render(time) {
|
function render(time) {
|
||||||
time *= 0.001
|
time *= 0.0001
|
||||||
|
|
||||||
if (resizeRendererToDisplaySize(renderer)) {
|
if (resizeRendererToDisplaySize(renderer)) {
|
||||||
const canvas = renderer.domElement;
|
const canvas = renderer.domElement;
|
||||||
@ -137,6 +145,8 @@ export default () => {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<canvas ref={ref} id="earth" style={{ width: '100%', height: '500px'}} />
|
<div id="earth-cont">
|
||||||
|
<canvas ref={ref} id="earth" style={{ width: '100%', height: '500px'}} />
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
77
docs/fc/webgl/demo/map-gl.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import Map, { MapRef } from 'react-map-gl';
|
||||||
|
import DrawControl from '../utils/drowControl';
|
||||||
|
|
||||||
|
const TOKEN = 'pk.eyJ1IjoiZGluZ2xpMTIzIiwiYSI6ImNra204ODhjczBobTgyeHJ6MmJpZHMxNWgifQ.NbKrXh_hb2gvjr5CEMDnyQ'
|
||||||
|
|
||||||
|
export const MapConfig = {
|
||||||
|
mapboxAccessToken: TOKEN,
|
||||||
|
|
||||||
|
maxZoom: 18,
|
||||||
|
minZoom: 4,
|
||||||
|
style: { height: 600 },
|
||||||
|
dragRotate: false,
|
||||||
|
initialViewState: {
|
||||||
|
longitude: -91.874,
|
||||||
|
latitude: 42.76,
|
||||||
|
zoom: 12
|
||||||
|
},
|
||||||
|
mapStyle: 'mapbox://styles/mapbox/satellite-v9'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const [features, setFeatures] = useState({});
|
||||||
|
const drawRef = React.useRef<MapboxDraw>();
|
||||||
|
const mapRef = React.useRef<MapRef>();
|
||||||
|
const [drawMode, setDrawMode] = React.useState<string>("draw_rect");
|
||||||
|
|
||||||
|
const onUpdate = useCallback(e => {
|
||||||
|
setFeatures(currFeatures => {
|
||||||
|
const newFeatures = { ...currFeatures };
|
||||||
|
for (const f of e.features) {
|
||||||
|
newFeatures[f.id] = f;
|
||||||
|
}
|
||||||
|
console.log(newFeatures)
|
||||||
|
return newFeatures;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onDelete = useCallback(e => {
|
||||||
|
setFeatures(currFeatures => {
|
||||||
|
const newFeatures = { ...currFeatures };
|
||||||
|
for (const f of e.features) {
|
||||||
|
delete newFeatures[f.id];
|
||||||
|
}
|
||||||
|
console.log(newFeatures)
|
||||||
|
return newFeatures;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const changeModeTo = (mode: string) => {
|
||||||
|
drawRef.current?.changeMode(mode as string);
|
||||||
|
setDrawMode(mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
onClick={() => changeModeTo('drag_circle')}>
|
||||||
|
Change to drag_circle
|
||||||
|
</button>
|
||||||
|
<Map
|
||||||
|
ref={mapRef}
|
||||||
|
{...MapConfig}
|
||||||
|
>
|
||||||
|
<DrawControl
|
||||||
|
mapRef={mapRef}
|
||||||
|
ref={drawRef}
|
||||||
|
position="top-left"
|
||||||
|
defaultMode={drawMode}
|
||||||
|
onCreate={onUpdate}
|
||||||
|
onUpdate={onUpdate}
|
||||||
|
onDelete={onDelete}
|
||||||
|
/>
|
||||||
|
</Map>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
107
docs/fc/webgl/demo/mapBox-gl.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import DeckGL from '@deck.gl/react';
|
||||||
|
import { EditableGeoJsonLayer } from '@nebula.gl/layers';
|
||||||
|
import { Toolbox } from '@nebula.gl/editor';
|
||||||
|
import { ViewMode } from '@nebula.gl/edit-modes';
|
||||||
|
import { StaticMap } from 'react-map-gl';
|
||||||
|
|
||||||
|
const MAPBOX_ACCESS_TOKEN =
|
||||||
|
'pk.eyJ1IjoiZGluZ2xpMTIzIiwiYSI6ImNra204ODhjczBobTgyeHJ6MmJpZHMxNWgifQ.NbKrXh_hb2gvjr5CEMDnyQ';
|
||||||
|
|
||||||
|
const initialViewState = {
|
||||||
|
longitude: -122.43,
|
||||||
|
latitude: 37.775,
|
||||||
|
zoom: 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Example() {
|
||||||
|
const [geoJson, setGeoJson] = React.useState({
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [
|
||||||
|
[
|
||||||
|
[-122.46212548792364, 37.79026033616934],
|
||||||
|
[-122.48435831844807, 37.77160302698496],
|
||||||
|
[-122.45884849905971, 37.74414218845571],
|
||||||
|
[-122.42863676726826, 37.76266965836386],
|
||||||
|
[-122.46212548792364, 37.79026033616934],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [
|
||||||
|
[
|
||||||
|
[-122.4136573004723, 37.78826678755718],
|
||||||
|
[-122.44875601708893, 37.782670574261324],
|
||||||
|
[-122.43793598592286, 37.74322062447909],
|
||||||
|
[-122.40836932539945, 37.75125290412125],
|
||||||
|
[-122.4136573004723, 37.78826678755718],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const [selectedFeatureIndexes, setSelectedFeatureIndexes] = React.useState([0]);
|
||||||
|
const [mode, setMode] = React.useState(() => ViewMode);
|
||||||
|
const [modeConfig, setModeConfig] = React.useState({});
|
||||||
|
|
||||||
|
const layer = new EditableGeoJsonLayer({
|
||||||
|
data: geoJson,
|
||||||
|
mode,
|
||||||
|
modeConfig,
|
||||||
|
selectedFeatureIndexes,
|
||||||
|
onEdit: ({ updatedData }) => {
|
||||||
|
setGeoJson(updatedData);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DeckGL
|
||||||
|
initialViewState={initialViewState}
|
||||||
|
controller={{
|
||||||
|
doubleClickZoom: false,
|
||||||
|
}}
|
||||||
|
layers={[layer]}
|
||||||
|
getCursor={layer.getCursor.bind(layer)}
|
||||||
|
onClick={(info) => {
|
||||||
|
if (mode === ViewMode)
|
||||||
|
if (info) {
|
||||||
|
setSelectedFeatureIndexes([info.index]);
|
||||||
|
} else {
|
||||||
|
setSelectedFeatureIndexes([]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
|
||||||
|
</DeckGL>
|
||||||
|
|
||||||
|
<Toolbox
|
||||||
|
geoJson={geoJson}
|
||||||
|
mode={mode}
|
||||||
|
modeConfig={modeConfig}
|
||||||
|
onSetMode={setMode}
|
||||||
|
onSetModeConfig={setModeConfig}
|
||||||
|
onImport={(imported) =>
|
||||||
|
setGeoJson({
|
||||||
|
...geoJson,
|
||||||
|
features: [...geoJson.features, ...imported.features],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onSetGeoJson={setGeoJson}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,19 +1,13 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 前端
|
title: FC
|
||||||
path: /fea
|
path: /funny
|
||||||
group:
|
group:
|
||||||
title: 💊 webGL
|
title: webGL
|
||||||
order: 1
|
order: 10
|
||||||
---
|
---
|
||||||
|
|
||||||
# 基础
|
# 介绍
|
||||||
|
|
||||||
## 介绍
|
|
||||||
|
|
||||||
:::info{title=记录日志}
|
|
||||||
本文档从 2023 年 10 月 20 开始,主要用来记录 threejs 的学习过程和踩坑记录,方便复盘与总结。
|
|
||||||
:::
|
|
||||||
|
|
||||||
### 基本对象
|
### 基本对象
|
||||||
|
|
24
docs/fc/webgl/utils/doubleClickZoom.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const doubleClickZoom = {
|
||||||
|
enable(ctx) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (
|
||||||
|
!ctx.map ||
|
||||||
|
!ctx.map.doubleClickZoom ||
|
||||||
|
!ctx._ctx ||
|
||||||
|
!ctx._ctx.store ||
|
||||||
|
!ctx._ctx.store.getInitialConfigValue
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
if (!ctx._ctx.store.getInitialConfigValue('doubleClickZoom')) return;
|
||||||
|
ctx.map.doubleClickZoom.enable();
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
disable(ctx) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!ctx.map || !ctx.map.doubleClickZoom) return;
|
||||||
|
ctx.map.doubleClickZoom.disable();
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default doubleClickZoom;
|
69
docs/fc/webgl/utils/drawCircleMode.draw.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||||
|
import doubleClickZoom from './doubleClickZoom';
|
||||||
|
import * as turf from '@turf/turf';
|
||||||
|
const { circle, distance, helpers: turfHelpers } = turf;
|
||||||
|
const drawCircleMode = { ...MapboxDraw.modes.draw_polygon };
|
||||||
|
drawCircleMode.onSetup = function () {
|
||||||
|
const polygon = this.newFeature({
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
isCircle: true,
|
||||||
|
center: [],
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [[]],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addFeature(polygon);
|
||||||
|
|
||||||
|
this.clearSelectedFeatures();
|
||||||
|
doubleClickZoom.disable(this);
|
||||||
|
// dragPan.disable(this);
|
||||||
|
this.updateUIClasses({ mouse: 'add' });
|
||||||
|
this.activateUIButton('Polygon');
|
||||||
|
this.setActionableState({
|
||||||
|
trash: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
polygon,
|
||||||
|
currentVertexPosition: 0,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
drawCircleMode.onClick = drawCircleMode.onTap = function (state, e) {
|
||||||
|
const currentCenter = state.polygon.properties.center;
|
||||||
|
if (currentCenter.length === 0) {
|
||||||
|
// dragPan.disable(this)
|
||||||
|
state.polygon.properties.center = [e.lngLat.lng, e.lngLat.lat];
|
||||||
|
} else {
|
||||||
|
// dragPan.enable(this);
|
||||||
|
return this.changeMode('simple_select', { featureIds: [state.polygon.id] });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
drawCircleMode.onDrag = drawCircleMode.onMouseMove = function (state, e) {
|
||||||
|
const center = state.polygon.properties.center;
|
||||||
|
if (center.length > 0) {
|
||||||
|
const distanceInKm = distance(
|
||||||
|
turfHelpers.point(center),
|
||||||
|
turfHelpers.point([e.lngLat.lng, e.lngLat.lat]),
|
||||||
|
{
|
||||||
|
units: 'kilometers',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const circleFeature = circle(center, distanceInKm);
|
||||||
|
state.polygon.incomingCoords(circleFeature.geometry.coordinates);
|
||||||
|
state.polygon.properties.radiusInKm = distanceInKm;
|
||||||
|
state.polygon.properties.lastClickCoord = [e.lngLat.lng, e.lngLat.lat];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//它决定当前 Drew 数据存储中的哪些特性将在地图上呈现。
|
||||||
|
//所有传递给“显示”的特性都将被渲染,因此可以为每个内部特性传递多个显示特性。
|
||||||
|
//有关如何制作显示特性的建议,请参阅‘ styling-pull’in‘ API.md’
|
||||||
|
drawCircleMode.toDisplayFeatures = function (state, geojson, display) {
|
||||||
|
const isActivePolygon = geojson.properties.id === state.polygon.id;
|
||||||
|
geojson.properties.active = isActivePolygon ? 'true' : 'false';
|
||||||
|
display(geojson);
|
||||||
|
};
|
||||||
|
export default drawCircleMode;
|
131
docs/fc/webgl/utils/drawDirectMode.draw.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||||
|
import createSupplementaryPoints from '@mapbox/mapbox-gl-draw';
|
||||||
|
import moveFeatures from '@mapbox/mapbox-gl-draw';
|
||||||
|
import constrainFeatureMovement from '@mapbox/mapbox-gl-draw';
|
||||||
|
import createVertex from '@mapbox/mapbox-gl-draw';
|
||||||
|
import * as turf from '@turf/turf';
|
||||||
|
const { constants } = MapboxDraw;
|
||||||
|
const { circle, distance, helpers: turfHelpers } = turf;
|
||||||
|
|
||||||
|
function createSupplementaryPointsForCircle(geojson) {
|
||||||
|
const { properties, geometry } = geojson;
|
||||||
|
|
||||||
|
if (!properties.user_isCircle) return null;
|
||||||
|
|
||||||
|
const supplementaryPoints = [];
|
||||||
|
const vertices = geometry.coordinates[0].slice(0, -1);
|
||||||
|
for (let index = 0; index < vertices.length; index += Math.round(vertices.length / 4)) {
|
||||||
|
supplementaryPoints.push(createVertex(properties.id, vertices[index], `0.${index}`, false));
|
||||||
|
}
|
||||||
|
return supplementaryPoints;
|
||||||
|
}
|
||||||
|
const drawDirectMode = { ...MapboxDraw.modes.direct_select };
|
||||||
|
|
||||||
|
drawDirectMode.dragFeature = function (state, e, delta) {
|
||||||
|
moveFeatures(this.getSelected(), delta);
|
||||||
|
this.getSelected()
|
||||||
|
.filter((feature) => feature.properties.isCircle)
|
||||||
|
.map((circle) => circle.properties.center)
|
||||||
|
.forEach((center) => {
|
||||||
|
center[0] += delta.lng;
|
||||||
|
center[1] += delta.lat;
|
||||||
|
});
|
||||||
|
state.dragMoveLocation = e.lngLat;
|
||||||
|
};
|
||||||
|
|
||||||
|
drawDirectMode.dragVertex = function (state, e, delta) {
|
||||||
|
//圆处理
|
||||||
|
if (state.feature.properties.isCircle) {
|
||||||
|
const center = state.feature.properties.center;
|
||||||
|
const movedVertex = [e.lngLat.lng, e.lngLat.lat];
|
||||||
|
const radius = distance(turfHelpers.point(center), turfHelpers.point(movedVertex), {
|
||||||
|
units: 'kilometers',
|
||||||
|
});
|
||||||
|
const circleFeature = circle(center, radius);
|
||||||
|
state.feature.incomingCoords(circleFeature.geometry.coordinates);
|
||||||
|
state.feature.properties.radiusInKm = radius;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//矩形处理
|
||||||
|
if (state.feature.properties.isRect) {
|
||||||
|
state.selectedCoordPaths.forEach((coordPath) => {
|
||||||
|
const selectCoord = state.feature.getCoordinate(coordPath);
|
||||||
|
//更新边缘2点
|
||||||
|
const [featureIndex, coordIndex] = coordPath.split('.');
|
||||||
|
const coordinates = state.feature.getCoordinates()[featureIndex];
|
||||||
|
//对立点判断
|
||||||
|
const coordPosMap = {
|
||||||
|
1: '3',
|
||||||
|
2: '0',
|
||||||
|
3: '1',
|
||||||
|
0: '2',
|
||||||
|
};
|
||||||
|
const mapCoord = state.feature.getCoordinate(`${featureIndex}.${coordPosMap[coordIndex]}`);
|
||||||
|
//如果对立点和坐标x||y 一致 则返回
|
||||||
|
if (mapCoord[0] === e.lngLat.lng || mapCoord[1] === e.lngLat.lat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
const coord = coordinates[i];
|
||||||
|
if (coordIndex == i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coord[0] === selectCoord[0]) {
|
||||||
|
state.feature.updateCoordinate(`${featureIndex}.${i}`, e.lngLat.lng, coord[1]);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (coord[1] === selectCoord[1]) {
|
||||||
|
state.feature.updateCoordinate(`${featureIndex}.${i}`, coord[0], e.lngLat.lat);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//更新拖拽的点
|
||||||
|
state.feature.updateCoordinate(coordPath, e.lngLat.lng, e.lngLat.lat);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//其他走回默认
|
||||||
|
const selectedCoords = state.selectedCoordPaths.map((coordPath) =>
|
||||||
|
state.feature.getCoordinate(coordPath)
|
||||||
|
);
|
||||||
|
const selectedCoordPoints = selectedCoords.map((coords) => ({
|
||||||
|
type: constants.geojsonTypes.FEATURE,
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: constants.geojsonTypes.POINT,
|
||||||
|
coordinates: coords,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta);
|
||||||
|
for (let i = 0; i < selectedCoords.length; i++) {
|
||||||
|
const coord = selectedCoords[i];
|
||||||
|
state.feature.updateCoordinate(
|
||||||
|
state.selectedCoordPaths[i],
|
||||||
|
coord[0] + constrainedDelta.lng,
|
||||||
|
coord[1] + constrainedDelta.lat
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
drawDirectMode.toDisplayFeatures = function (state, geojson, push) {
|
||||||
|
if (state.featureId === geojson.properties.id) {
|
||||||
|
geojson.properties.active = constants.activeStates.ACTIVE;
|
||||||
|
push(geojson);
|
||||||
|
const supplementaryPoints = geojson.properties.user_isCircle
|
||||||
|
? createSupplementaryPointsForCircle(geojson)
|
||||||
|
: createSupplementaryPoints(geojson, {
|
||||||
|
map: this.map,
|
||||||
|
midpoints: true,
|
||||||
|
selectedPaths: state.selectedCoordPaths,
|
||||||
|
});
|
||||||
|
supplementaryPoints.forEach(push);
|
||||||
|
} else {
|
||||||
|
geojson.properties.active = constants.activeStates.INACTIVE;
|
||||||
|
push(geojson);
|
||||||
|
}
|
||||||
|
this.fireActionable(state);
|
||||||
|
};
|
||||||
|
export default drawDirectMode;
|
165
docs/fc/webgl/utils/drawLineSelectMode.draw.js
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||||
|
import doubleClickZoom from './doubleClickZoom';
|
||||||
|
const { constants, lib } = MapboxDraw;
|
||||||
|
const drawLineSelectMode = {
|
||||||
|
//当模式启动时,这个函数将被调用。
|
||||||
|
//draw.changeMode(drawLineSelectMode,params}); 切换模式时,params = opts
|
||||||
|
//返回的值应该是一个对象,并将传递给所有其他生命周期函数
|
||||||
|
onSetup: function (opts) {
|
||||||
|
const featureId = opts.featureId;
|
||||||
|
let line;
|
||||||
|
let currentVertexPosition = 0;
|
||||||
|
let direction = 'forward';
|
||||||
|
if (featureId) {
|
||||||
|
line = this.getFeature(featureId);
|
||||||
|
if (!line) {
|
||||||
|
throw new Error('Could not find a feature with the provided featureId');
|
||||||
|
}
|
||||||
|
let from = opts.from;
|
||||||
|
if (from && from.type === 'Feature' && from.geometry && from.geometry.type === 'Point') {
|
||||||
|
from = from.geometry;
|
||||||
|
}
|
||||||
|
if (from && from.type === 'Point' && from.coordinates && from.coordinates.length === 2) {
|
||||||
|
from = from.coordinates;
|
||||||
|
}
|
||||||
|
if (!from || !Array.isArray(from)) {
|
||||||
|
throw new Error(
|
||||||
|
'Please use the `from` property to indicate which point to continue the line from'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const lastCoord = line.coordinates.length - 1;
|
||||||
|
if (
|
||||||
|
line.coordinates[lastCoord][0] === from[0] &&
|
||||||
|
line.coordinates[lastCoord][1] === from[1]
|
||||||
|
) {
|
||||||
|
currentVertexPosition = lastCoord + 1;
|
||||||
|
line.addCoordinate(currentVertexPosition, ...line.coordinates[lastCoord]);
|
||||||
|
} else if (line.coordinates[0][0] === from[0] && line.coordinates[0][1] === from[1]) {
|
||||||
|
direction = 'backwards';
|
||||||
|
currentVertexPosition = 0;
|
||||||
|
line.addCoordinate(currentVertexPosition, ...line.coordinates[0]);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'`from` should match the point at either the start or the end of the provided LineString'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
line = this.newFeature({
|
||||||
|
type: constants.geojsonTypes.FEATURE,
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: constants.geojsonTypes.LINE_STRING,
|
||||||
|
coordinates: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
currentVertexPosition = 0;
|
||||||
|
this.addFeature(line);
|
||||||
|
}
|
||||||
|
this.clearSelectedFeatures();
|
||||||
|
doubleClickZoom.disable(this);
|
||||||
|
this.updateUIClasses({ mouse: 'add' }); //"+"
|
||||||
|
this.setActionableState({
|
||||||
|
//添加地图事件'draw.actionable'
|
||||||
|
trash: true,
|
||||||
|
combineFeatures: false,
|
||||||
|
uncombineFeatures: false,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
line,
|
||||||
|
currentVertexPosition,
|
||||||
|
direction,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
clickAnywhere: function (state, e) {
|
||||||
|
if (
|
||||||
|
(state.currentVertexPosition > 0 &&
|
||||||
|
lib.isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition - 1])) ||
|
||||||
|
(state.direction === 'backwards' &&
|
||||||
|
lib.isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition + 1]))
|
||||||
|
) {
|
||||||
|
return this.changeMode(constants.modes.SIMPLE_SELECT, {
|
||||||
|
featureIds: [state.line.id],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateUIClasses({ mouse: constants.cursors.ADD });
|
||||||
|
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
|
||||||
|
if (state.direction === 'forward') {
|
||||||
|
state.currentVertexPosition++;
|
||||||
|
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
|
||||||
|
} else {
|
||||||
|
state.line.addCoordinate(0, e.lngLat.lng, e.lngLat.lat);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clickOnVertex: function (state) {
|
||||||
|
//点击在已经有点上
|
||||||
|
state.line.properties.name = 'line_select';
|
||||||
|
return this.changeMode(constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] });
|
||||||
|
},
|
||||||
|
onMouseMove: function (state, e) {
|
||||||
|
state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
|
||||||
|
if (lib.CommonSelectors.isVertex(e)) {
|
||||||
|
//再次将鼠标放在之前已经有的点上,改变鼠标样式
|
||||||
|
this.updateUIClasses({ mouse: constants.cursors.POINTER });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClick: function (state, e) {
|
||||||
|
//再次将鼠标放在之前已经有的点上
|
||||||
|
if (lib.CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e);
|
||||||
|
this.clickAnywhere(state, e);
|
||||||
|
},
|
||||||
|
onKeyUp: function (state, e) {
|
||||||
|
if (lib.CommonSelectors.isEnterKey(e)) {
|
||||||
|
this.changeMode(constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] });
|
||||||
|
} else if (lib.CommonSelectors.isEscapeKey(e)) {
|
||||||
|
this.deleteFeature([state.line.id], { silent: true });
|
||||||
|
this.changeMode(constants.modes.SIMPLE_SELECT);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStop: function (state) {
|
||||||
|
doubleClickZoom.enable(this);
|
||||||
|
if (this.getFeature(state.line.id) === undefined) return;
|
||||||
|
state.line.removeCoordinate(`${state.currentVertexPosition}`); //双击停止时,最后两个点位是一样的
|
||||||
|
if (state.line.isValid()) {
|
||||||
|
//'draw.create'
|
||||||
|
this.map.fire(constants.events.CREATE, {
|
||||||
|
features: [state.line.toGeoJSON()],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.deleteFeature([state.line.id], { silent: true });
|
||||||
|
this.changeMode(constants.modes.SIMPLE_SELECT, {}, { silent: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTrash: function (state) {
|
||||||
|
this.deleteFeature([state.line.id], { silent: true });
|
||||||
|
this.changeMode(constants.modes.SIMPLE_SELECT);
|
||||||
|
},
|
||||||
|
//它决定当前 Drew 数据存储中的哪些特性将在地图上呈现。
|
||||||
|
//所有传递给“显示”的特性都将被渲染,因此可以为每个内部特性传递多个显示特性。
|
||||||
|
//有关如何制作显示特性的建议,请参阅‘ styling-pull’in‘ API.md’
|
||||||
|
toDisplayFeatures: function (state, geojson, display) {
|
||||||
|
const isActiveLine = geojson.properties.id === state.line.id;
|
||||||
|
geojson.properties.active = isActiveLine
|
||||||
|
? constants.activeStates.ACTIVE
|
||||||
|
: constants.activeStates.INACTIVE;
|
||||||
|
if (!isActiveLine) {
|
||||||
|
display(geojson);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (geojson.geometry.coordinates.length < 2) return;
|
||||||
|
geojson.properties.meta = 'line_distance';
|
||||||
|
geojson.properties.name = 'line_distance';
|
||||||
|
display(
|
||||||
|
lib.createVertex(
|
||||||
|
state.line.id,
|
||||||
|
geojson.geometry.coordinates[
|
||||||
|
state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1
|
||||||
|
],
|
||||||
|
`${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
display(geojson);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default drawLineSelectMode;
|
125
docs/fc/webgl/utils/drawRectMode.draw.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
const doubleClickZoom = {
|
||||||
|
enable: (ctx) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
// First check we've got a map and some context.
|
||||||
|
if (
|
||||||
|
!ctx.map ||
|
||||||
|
!ctx.map.doubleClickZoom ||
|
||||||
|
!ctx._ctx ||
|
||||||
|
!ctx._ctx.store ||
|
||||||
|
!ctx._ctx.store.getInitialConfigValue
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
// Now check initial state wasn't false (we leave it disabled if so)
|
||||||
|
if (!ctx._ctx.store.getInitialConfigValue('doubleClickZoom')) return;
|
||||||
|
ctx.map.doubleClickZoom.enable();
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
disable(ctx) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!ctx.map || !ctx.map.doubleClickZoom) return;
|
||||||
|
// Always disable here, as it's necessary in some cases.
|
||||||
|
ctx.map.doubleClickZoom.disable();
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DrawRectangle = {
|
||||||
|
// When the mode starts this function will be called.
|
||||||
|
onSetup: function () {
|
||||||
|
const rectangle = this.newFeature({
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
isRect: true,
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [[]],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.addFeature(rectangle);
|
||||||
|
this.clearSelectedFeatures();
|
||||||
|
doubleClickZoom.disable(this);
|
||||||
|
this.updateUIClasses({ mouse: 'add' });
|
||||||
|
this.setActionableState({
|
||||||
|
trash: true,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
rectangle,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// support mobile taps
|
||||||
|
onTap: function (state, e) {
|
||||||
|
// emulate 'move mouse' to update feature coords
|
||||||
|
if (state.startPoint) this.onMouseMove(state, e);
|
||||||
|
// emulate onClick
|
||||||
|
this.onClick(state, e);
|
||||||
|
},
|
||||||
|
// Whenever a user clicks on the map, Draw will call `onClick`
|
||||||
|
onClick: function (state, e) {
|
||||||
|
// if state.startPoint exist, means its second click
|
||||||
|
//change to simple_select mode
|
||||||
|
if (
|
||||||
|
state.startPoint &&
|
||||||
|
state.startPoint[0] !== e.lngLat.lng &&
|
||||||
|
state.startPoint[1] !== e.lngLat.lat
|
||||||
|
) {
|
||||||
|
this.updateUIClasses({ mouse: 'pointer' });
|
||||||
|
state.endPoint = [e.lngLat.lng, e.lngLat.lat];
|
||||||
|
this.changeMode('simple_select', { featuresId: state.rectangle.id });
|
||||||
|
}
|
||||||
|
// on first click, save clicked point coords as starting for rectangle
|
||||||
|
const startPoint = [e.lngLat.lng, e.lngLat.lat];
|
||||||
|
state.startPoint = startPoint;
|
||||||
|
},
|
||||||
|
onMouseMove: function (state, e) {
|
||||||
|
// if startPoint, update the feature coordinates, using the bounding box concept
|
||||||
|
// we are simply using the startingPoint coordinates and the current Mouse Position
|
||||||
|
// coordinates to calculate the bounding box on the fly, which will be our rectangle
|
||||||
|
if (state.startPoint) {
|
||||||
|
state.rectangle.updateCoordinate('0.0', state.startPoint[0], state.startPoint[1]); //minX, minY - the starting point
|
||||||
|
state.rectangle.updateCoordinate('0.1', e.lngLat.lng, state.startPoint[1]); // maxX, minY
|
||||||
|
state.rectangle.updateCoordinate('0.2', e.lngLat.lng, e.lngLat.lat); // maxX, maxY
|
||||||
|
state.rectangle.updateCoordinate('0.3', state.startPoint[0], e.lngLat.lat); // minX,maxY
|
||||||
|
state.rectangle.updateCoordinate('0.4', state.startPoint[0], state.startPoint[1]); //minX,minY - ending point (equals to starting point)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Whenever a user clicks on a key while focused on the map, it will be sent here
|
||||||
|
onKeyUp: function (state, e) {
|
||||||
|
if (e.keyCode === 27) return this.changeMode('simple_select');
|
||||||
|
},
|
||||||
|
onStop: function (state) {
|
||||||
|
doubleClickZoom.enable(this);
|
||||||
|
this.updateUIClasses({ mouse: 'none' });
|
||||||
|
this.activateUIButton();
|
||||||
|
|
||||||
|
// check to see if we've deleted this feature
|
||||||
|
if (this.getFeature(state.rectangle.id) === undefined) return;
|
||||||
|
|
||||||
|
//remove last added coordinate
|
||||||
|
state.rectangle.removeCoordinate('0.4');
|
||||||
|
if (state.rectangle.isValid()) {
|
||||||
|
this.map.fire('draw.create', {
|
||||||
|
features: [state.rectangle.toGeoJSON()],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.deleteFeature([state.rectangle.id], { silent: true });
|
||||||
|
this.changeMode('simple_select', {}, { silent: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toDisplayFeatures: function (state, geojson, display) {
|
||||||
|
const isActivePolygon = geojson.properties.id === state.rectangle.id;
|
||||||
|
geojson.properties.active = isActivePolygon ? 'true' : 'false';
|
||||||
|
if (!isActivePolygon) return display(geojson);
|
||||||
|
|
||||||
|
// Only render the rectangular polygon if it has the starting point
|
||||||
|
if (!state.startPoint) return;
|
||||||
|
return display(geojson);
|
||||||
|
},
|
||||||
|
onTrash: function (state) {
|
||||||
|
this.deleteFeature([state.rectangle.id], { silent: true });
|
||||||
|
this.changeMode('simple_select');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DrawRectangle;
|
86
docs/fc/webgl/utils/drawSimpleSelectMode.draw.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||||
|
import createSupplementaryPoints from '@mapbox/mapbox-gl-draw';
|
||||||
|
import moveFeatures from '@mapbox/mapbox-gl-draw';
|
||||||
|
import createVertex from '@mapbox/mapbox-gl-draw';
|
||||||
|
import { lineToPoly } from './index';
|
||||||
|
const { constants } = MapboxDraw;
|
||||||
|
|
||||||
|
function createSupplementaryPointsForCircle(geojson) {
|
||||||
|
const { properties, geometry } = geojson;
|
||||||
|
|
||||||
|
if (!properties.user_isCircle) return null;
|
||||||
|
|
||||||
|
const supplementaryPoints = [];
|
||||||
|
const vertices = geometry.coordinates[0].slice(0, -1);
|
||||||
|
for (let index = 0; index < vertices.length; index += Math.round(vertices.length / 4)) {
|
||||||
|
supplementaryPoints.push(createVertex(properties.id, vertices[index], `0.${index}`, false));
|
||||||
|
}
|
||||||
|
return supplementaryPoints;
|
||||||
|
}
|
||||||
|
const drawSimpleSelectMode = { ...MapboxDraw.modes.simple_select };
|
||||||
|
|
||||||
|
drawSimpleSelectMode.dragMove = function (state, e) {
|
||||||
|
// Dragging when drag move is enabled
|
||||||
|
state.dragMoving = true;
|
||||||
|
e.originalEvent.stopPropagation();
|
||||||
|
|
||||||
|
const delta = {
|
||||||
|
lng: e.lngLat.lng - state.dragMoveLocation.lng,
|
||||||
|
lat: e.lngLat.lat - state.dragMoveLocation.lat,
|
||||||
|
};
|
||||||
|
|
||||||
|
moveFeatures(this.getSelected(), delta);
|
||||||
|
|
||||||
|
this.getSelected()
|
||||||
|
.filter((feature) => feature.properties.isCircle)
|
||||||
|
.map((circle) => circle.properties.center)
|
||||||
|
.forEach((center) => {
|
||||||
|
center[0] += delta.lng;
|
||||||
|
center[1] += delta.lat;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.dragMoveLocation = e.lngLat;
|
||||||
|
};
|
||||||
|
|
||||||
|
drawSimpleSelectMode.toDisplayFeatures = function (state, geojson, display) {
|
||||||
|
geojson.properties.active = this.isSelected(geojson.properties.id)
|
||||||
|
? constants.activeStates.ACTIVE
|
||||||
|
: constants.activeStates.INACTIVE;
|
||||||
|
|
||||||
|
if (geojson.properties.user_name === 'line_select') {
|
||||||
|
const union = lineToPoly(geojson);
|
||||||
|
display(union);
|
||||||
|
}
|
||||||
|
display(geojson);
|
||||||
|
this.fireActionable();
|
||||||
|
//如果是线 每次都创建点
|
||||||
|
if (
|
||||||
|
geojson?.properties.active !== constants.activeStates.ACTIVE &&
|
||||||
|
geojson.geometry.type === constants.geojsonTypes.LINE_STRING &&
|
||||||
|
geojson.properties.user_name !== 'line_select'
|
||||||
|
) {
|
||||||
|
const points = createSupplementaryPoints(geojson);
|
||||||
|
points.forEach(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
geojson.properties.active !== constants.activeStates.ACTIVE ||
|
||||||
|
geojson.geometry.type === constants.geojsonTypes.POINT
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let supplementaryPoints;
|
||||||
|
if (geojson.properties.user_isCircle) {
|
||||||
|
supplementaryPoints = createSupplementaryPointsForCircle(geojson);
|
||||||
|
} else {
|
||||||
|
supplementaryPoints = createSupplementaryPoints(geojson);
|
||||||
|
}
|
||||||
|
supplementaryPoints.forEach(display);
|
||||||
|
|
||||||
|
// if(geojson.properties.)
|
||||||
|
};
|
||||||
|
|
||||||
|
//阻止框选图形拖拽
|
||||||
|
drawSimpleSelectMode.onTap = drawSimpleSelectMode.onClick = function () { };
|
||||||
|
export default drawSimpleSelectMode;
|
14
docs/fc/webgl/utils/drawStaticMode.draw.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import doubleClickZoom from './doubleClickZoom';
|
||||||
|
|
||||||
|
var StaticMode = {};
|
||||||
|
|
||||||
|
StaticMode.onSetup = function () {
|
||||||
|
this.setActionableState(); // default actionable state is false for all actions
|
||||||
|
doubleClickZoom.disable(this); //静态model 不运行双击
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
StaticMode.toDisplayFeatures = function (state, geojson, display) {
|
||||||
|
display(geojson);
|
||||||
|
};
|
||||||
|
export default StaticMode;
|
144
docs/fc/webgl/utils/drawStyle.ts
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
//自定义画框样式
|
||||||
|
const mapboxDrawStyle = [
|
||||||
|
// ACTIVE (being drawn)
|
||||||
|
// line stroke
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'gl-draw-line',
|
||||||
|
type: 'line',
|
||||||
|
filter: [
|
||||||
|
'all',
|
||||||
|
['==', '$type', 'LineString'],
|
||||||
|
['!=', 'mode', 'static'],
|
||||||
|
['==', 'active', 'true'],
|
||||||
|
],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': 'rgba(246,67,72,1)',
|
||||||
|
'line-dasharray': [0.2, 2],
|
||||||
|
'line-width': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gl-draw-line-not-active',
|
||||||
|
type: 'line',
|
||||||
|
filter: ['all', ['==', '$type', 'LineString'], ['!=', 'active', 'true']],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': 'rgba(246,67,72,1)',
|
||||||
|
'line-width': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// polygon fill
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-fill',
|
||||||
|
type: 'fill',
|
||||||
|
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
|
||||||
|
paint: {
|
||||||
|
'fill-color': 'rgba(246,67,72,0.2)',
|
||||||
|
'fill-outline-color': 'rgba(246,67,72,0.2)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// polygon outline stroke
|
||||||
|
// This doesn't style the first edge of the polygon, which uses the line stroke styling instead
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-stroke-active',
|
||||||
|
type: 'line',
|
||||||
|
filter: [
|
||||||
|
'all',
|
||||||
|
['==', '$type', 'Polygon'],
|
||||||
|
['!=', 'mode', 'static'],
|
||||||
|
['==', 'active', 'false'],
|
||||||
|
],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': 'rgba(246,67,72,1)',
|
||||||
|
'line-width': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-stroke-active-select',
|
||||||
|
type: 'line',
|
||||||
|
filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static'], ['==', 'active', 'true']],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': 'rgba(246,67,72,1)',
|
||||||
|
'line-dasharray': [0.2, 2],
|
||||||
|
'line-width': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// vertex point halos
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-and-line-vertex-halo-active',
|
||||||
|
type: 'circle',
|
||||||
|
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
|
||||||
|
paint: {
|
||||||
|
'circle-radius': 5,
|
||||||
|
'circle-color': '#FFF',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// vertex points
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-and-line-vertex-active',
|
||||||
|
type: 'circle',
|
||||||
|
filter: ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
|
||||||
|
paint: {
|
||||||
|
'circle-radius': 3,
|
||||||
|
'circle-color': 'rgba(246,67,72,1)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// INACTIVE (static, already drawn)
|
||||||
|
// line stroke
|
||||||
|
{
|
||||||
|
id: 'gl-draw-line-static',
|
||||||
|
type: 'line',
|
||||||
|
filter: ['all', ['==', '$type', 'LineString'], ['==', 'mode', 'static']],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': '#E13F3F',
|
||||||
|
'line-width': 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// polygon fill
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-fill-static',
|
||||||
|
type: 'fill',
|
||||||
|
filter: ['all', ['==', '$type', 'Polygon'], ['==', 'mode', 'static']],
|
||||||
|
paint: {
|
||||||
|
'fill-color': 'rgba(225, 63, 63, 0.2)',
|
||||||
|
'fill-outline-color': 'rgba(225, 63, 63, 0.2)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// polygon outline
|
||||||
|
{
|
||||||
|
id: 'gl-draw-polygon-stroke-static',
|
||||||
|
type: 'line',
|
||||||
|
filter: ['all', ['==', '$type', 'Polygon'], ['==', 'mode', 'static']],
|
||||||
|
layout: {
|
||||||
|
'line-cap': 'round',
|
||||||
|
'line-join': 'round',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': '#E13F3F',
|
||||||
|
'line-width': 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export default mapboxDrawStyle;
|
74
docs/fc/webgl/utils/drowControl.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
|
||||||
|
import React from 'react'
|
||||||
|
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||||
|
import { useControl } from 'react-map-gl';
|
||||||
|
import type { MapboxMap, MapRef, ControlPosition } from 'react-map-gl';
|
||||||
|
import drawLineSelectMode from './drawLineSelectMode.draw.js';
|
||||||
|
import drawRectMode from './drawRectMode.draw.js';
|
||||||
|
import drawStaticMode from './drawStaticMode.draw.js';
|
||||||
|
import {
|
||||||
|
CircleMode,
|
||||||
|
DragCircleMode,
|
||||||
|
DirectMode,
|
||||||
|
SimpleSelectMode
|
||||||
|
} from 'mapbox-gl-draw-circle';
|
||||||
|
import mapboxDrawStyle from './drawStyle';
|
||||||
|
|
||||||
|
type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
|
||||||
|
position?: ControlPosition;
|
||||||
|
|
||||||
|
onCreate?: (evt: { features: object[] }) => void;
|
||||||
|
onUpdate?: (evt: { features: object[]; action: string }) => void;
|
||||||
|
onDelete?: (evt: { features: object[] }) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DrawControl = React.forwardRef((props: DrawControlProps, ref) => {
|
||||||
|
|
||||||
|
if (!props.mapRef) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawRef = useControl<MapboxDraw>(
|
||||||
|
() => new MapboxDraw({
|
||||||
|
styles: mapboxDrawStyle,
|
||||||
|
displayControlsDefault: false, // 取消默认的按钮
|
||||||
|
controls: {
|
||||||
|
polygon: false,
|
||||||
|
trash: false
|
||||||
|
},
|
||||||
|
maxZoom: 18,
|
||||||
|
minZoom: 4,
|
||||||
|
dragRotate: false,
|
||||||
|
modes: {
|
||||||
|
...MapboxDraw.modes,
|
||||||
|
draw_circle: CircleMode,
|
||||||
|
drag_circle: DragCircleMode,
|
||||||
|
direct_select: DirectMode,
|
||||||
|
simple_select: SimpleSelectMode,
|
||||||
|
draw_line_select: drawLineSelectMode,
|
||||||
|
draw_line_string: drawLineSelectMode,
|
||||||
|
draw_rect: drawRectMode,
|
||||||
|
static: drawStaticMode,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
({ map }: { map: MapRef }) => {
|
||||||
|
map.on('draw.create', props.onCreate);
|
||||||
|
map.on('draw.update', props.onUpdate);
|
||||||
|
map.on('draw.delete', props.onDelete);
|
||||||
|
},
|
||||||
|
({ map }: { map: MapRef }) => {
|
||||||
|
map.off('draw.create', props.onCreate);
|
||||||
|
map.off('draw.update', props.onUpdate);
|
||||||
|
map.off('draw.delete', props.onDelete);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: props.position
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useImperativeHandle(ref, () => drawRef, [drawRef]); // This way I exposed drawRef outside the component
|
||||||
|
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
|
||||||
|
export default DrawControl;
|
58
docs/fc/webgl/utils/index.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||||
|
import union from '@turf/union';
|
||||||
|
import * as turf from '@turf/turf';
|
||||||
|
|
||||||
|
export const resizeRendererToDisplaySize = (renderer) => {
|
||||||
|
const canvas = renderer.domElement;
|
||||||
|
const pixelRatio = window.devicePixelRatio;
|
||||||
|
const width = canvas.clientWidth * pixelRatio | 0;
|
||||||
|
const height = canvas.clientHeight * pixelRatio | 0;
|
||||||
|
const needResize = canvas.width !== width || canvas.height !== height;
|
||||||
|
if (needResize) {
|
||||||
|
renderer.setSize(width, height, false);
|
||||||
|
}
|
||||||
|
return needResize;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addControls = (camera: any, renderer: any) => {
|
||||||
|
const controls = new OrbitControls(camera, renderer.domElement);
|
||||||
|
controls.autoRotate = true
|
||||||
|
return controls
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算与纬线的角度,正方向向上
|
||||||
|
const calcAng = (point, p) => (Math.atan2(point[1] - p[1], point[0] - p[0]) * 180) / Math.PI + 180;
|
||||||
|
|
||||||
|
// 多段折线转polygon,直线左右默认范围50米
|
||||||
|
export const lineToPoly = (geojson, r = 50) => {
|
||||||
|
const linesPolygon = [];
|
||||||
|
const circlePolygon = [];
|
||||||
|
for (let i = 0; i < geojson.geometry.coordinates.length - 1; i++) {
|
||||||
|
const [pointA, pointB] = [geojson.geometry.coordinates[i], geojson.geometry.coordinates[i + 1]];
|
||||||
|
const line = turf.lineString([pointA, pointB]);
|
||||||
|
const ang = calcAng(pointA, pointB);
|
||||||
|
// 与经线的夹角为偏移方向,右正左负, 右偏移-左偏移 = 180
|
||||||
|
const translatedPolyA = turf.transformTranslate(line, r / 1000, -ang);
|
||||||
|
const translatedPolyB = turf.transformTranslate(line, r / 1000, -ang + 180);
|
||||||
|
const _line = turf.lineString([
|
||||||
|
// 逆时针闭合
|
||||||
|
...translatedPolyA.geometry.coordinates.reverse(),
|
||||||
|
...translatedPolyB.geometry.coordinates,
|
||||||
|
]);
|
||||||
|
const linePolygon = turf.lineToPolygon(_line);
|
||||||
|
linesPolygon.push(linePolygon);
|
||||||
|
circlePolygon.push(turf.circle(pointA, r / 1000));
|
||||||
|
if (i == geojson.geometry.coordinates.length - 2) {
|
||||||
|
circlePolygon.push(turf.circle(pointB, r / 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _union;
|
||||||
|
try {
|
||||||
|
//todo: 新版本union和老版本行为不一致 先用老版本 后续观察原因
|
||||||
|
// _union = turf.union(...circlePolygon, ...linesPolygon);
|
||||||
|
_union = union(...circlePolygon, ...linesPolygon);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
return _union;
|
||||||
|
};
|
@ -3,11 +3,11 @@ nav:
|
|||||||
title: 前端
|
title: 前端
|
||||||
path: /fea
|
path: /fea
|
||||||
group:
|
group:
|
||||||
title: 💊 Q&A
|
title: Q&A
|
||||||
order: 100
|
order: 100
|
||||||
---
|
---
|
||||||
|
|
||||||
# 💊 Q&A
|
# Q&A
|
||||||
|
|
||||||
## 页面弹框之后请求一直失败?
|
## 页面弹框之后请求一直失败?
|
||||||
|
|
||||||
|